actor: Unconditionally set show_on_set_parent
[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   priv->show_on_set_parent = set_show;
1558   g_object_notify_by_pspec (G_OBJECT (self),
1559                             obj_props[PROP_SHOW_ON_SET_PARENT]);
1560 }
1561
1562 /**
1563  * clutter_actor_show:
1564  * @self: A #ClutterActor
1565  *
1566  * Flags an actor to be displayed. An actor that isn't shown will not
1567  * be rendered on the stage.
1568  *
1569  * Actors are visible by default.
1570  *
1571  * If this function is called on an actor without a parent, the
1572  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1573  * effect.
1574  */
1575 void
1576 clutter_actor_show (ClutterActor *self)
1577 {
1578   ClutterActorPrivate *priv;
1579
1580   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1581
1582   /* simple optimization */
1583   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1584     {
1585       /* we still need to set the :show-on-set-parent property, in
1586        * case show() is called on an unparented actor
1587        */
1588       set_show_on_set_parent (self, TRUE);
1589       return;
1590     }
1591
1592 #ifdef CLUTTER_ENABLE_DEBUG
1593   clutter_actor_verify_map_state (self);
1594 #endif
1595
1596   priv = self->priv;
1597
1598   g_object_freeze_notify (G_OBJECT (self));
1599
1600   set_show_on_set_parent (self, TRUE);
1601
1602   g_signal_emit (self, actor_signals[SHOW], 0);
1603   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1604
1605   if (priv->parent != NULL)
1606     clutter_actor_queue_redraw (priv->parent);
1607
1608   g_object_thaw_notify (G_OBJECT (self));
1609 }
1610
1611 /**
1612  * clutter_actor_show_all:
1613  * @self: a #ClutterActor
1614  *
1615  * Calls clutter_actor_show() on all children of an actor (if any).
1616  *
1617  * Since: 0.2
1618  *
1619  * Deprecated: 1.10: Actors are visible by default
1620  */
1621 void
1622 clutter_actor_show_all (ClutterActor *self)
1623 {
1624   ClutterActorClass *klass;
1625
1626   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1627
1628   klass = CLUTTER_ACTOR_GET_CLASS (self);
1629   if (klass->show_all)
1630     klass->show_all (self);
1631 }
1632
1633 static void
1634 clutter_actor_real_hide (ClutterActor *self)
1635 {
1636   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1637     {
1638       ClutterActorPrivate *priv = self->priv;
1639
1640       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1641
1642       /* we notify on the "visible" flag in the clutter_actor_hide()
1643        * wrapper so the entire hide signal emission completes first
1644        * (?)
1645        */
1646       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1647
1648       /* we queue a relayout unless the actor is inside a
1649        * container that explicitly told us not to
1650        */
1651       if (priv->parent != NULL &&
1652           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1653         clutter_actor_queue_relayout (priv->parent);
1654     }
1655 }
1656
1657 /**
1658  * clutter_actor_hide:
1659  * @self: A #ClutterActor
1660  *
1661  * Flags an actor to be hidden. A hidden actor will not be
1662  * rendered on the stage.
1663  *
1664  * Actors are visible by default.
1665  *
1666  * If this function is called on an actor without a parent, the
1667  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1668  * as a side-effect.
1669  */
1670 void
1671 clutter_actor_hide (ClutterActor *self)
1672 {
1673   ClutterActorPrivate *priv;
1674
1675   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1676
1677   /* simple optimization */
1678   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1679     {
1680       /* we still need to set the :show-on-set-parent property, in
1681        * case hide() is called on an unparented actor
1682        */
1683       set_show_on_set_parent (self, FALSE);
1684       return;
1685     }
1686
1687 #ifdef CLUTTER_ENABLE_DEBUG
1688   clutter_actor_verify_map_state (self);
1689 #endif
1690
1691   priv = self->priv;
1692
1693   g_object_freeze_notify (G_OBJECT (self));
1694
1695   set_show_on_set_parent (self, FALSE);
1696
1697   g_signal_emit (self, actor_signals[HIDE], 0);
1698   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1699
1700   if (priv->parent != NULL)
1701     clutter_actor_queue_redraw (priv->parent);
1702
1703   g_object_thaw_notify (G_OBJECT (self));
1704 }
1705
1706 /**
1707  * clutter_actor_hide_all:
1708  * @self: a #ClutterActor
1709  *
1710  * Calls clutter_actor_hide() on all child actors (if any).
1711  *
1712  * Since: 0.2
1713  *
1714  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1715  *   prevent its children from being painted as well.
1716  */
1717 void
1718 clutter_actor_hide_all (ClutterActor *self)
1719 {
1720   ClutterActorClass *klass;
1721
1722   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1723
1724   klass = CLUTTER_ACTOR_GET_CLASS (self);
1725   if (klass->hide_all)
1726     klass->hide_all (self);
1727 }
1728
1729 /**
1730  * clutter_actor_realize:
1731  * @self: A #ClutterActor
1732  *
1733  * Realization informs the actor that it is attached to a stage. It
1734  * can use this to allocate resources if it wanted to delay allocation
1735  * until it would be rendered. However it is perfectly acceptable for
1736  * an actor to create resources before being realized because Clutter
1737  * only ever has a single rendering context so that actor is free to
1738  * be moved from one stage to another.
1739  *
1740  * This function does nothing if the actor is already realized.
1741  *
1742  * Because a realized actor must have realized parent actors, calling
1743  * clutter_actor_realize() will also realize all parents of the actor.
1744  *
1745  * This function does not realize child actors, except in the special
1746  * case that realizing the stage, when the stage is visible, will
1747  * suddenly map (and thus realize) the children of the stage.
1748  **/
1749 void
1750 clutter_actor_realize (ClutterActor *self)
1751 {
1752   ClutterActorPrivate *priv;
1753
1754   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1755
1756   priv = self->priv;
1757
1758 #ifdef CLUTTER_ENABLE_DEBUG
1759   clutter_actor_verify_map_state (self);
1760 #endif
1761
1762   if (CLUTTER_ACTOR_IS_REALIZED (self))
1763     return;
1764
1765   /* To be realized, our parent actors must be realized first.
1766    * This will only succeed if we're inside a toplevel.
1767    */
1768   if (priv->parent != NULL)
1769     clutter_actor_realize (priv->parent);
1770
1771   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1772     {
1773       /* toplevels can be realized at any time */
1774     }
1775   else
1776     {
1777       /* "Fail" the realization if parent is missing or unrealized;
1778        * this should really be a g_warning() not some kind of runtime
1779        * failure; how can an app possibly recover? Instead it's a bug
1780        * in the app and the app should get an explanatory warning so
1781        * someone can fix it. But for now it's too hard to fix this
1782        * because e.g. ClutterTexture needs reworking.
1783        */
1784       if (priv->parent == NULL ||
1785           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1786         return;
1787     }
1788
1789   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1790
1791   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1792   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1793
1794   g_signal_emit (self, actor_signals[REALIZE], 0);
1795
1796   /* Stage actor is allowed to unset the realized flag again in its
1797    * default signal handler, though that is a pathological situation.
1798    */
1799
1800   /* If realization "failed" we'll have to update child state. */
1801   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1802 }
1803
1804 static void
1805 clutter_actor_real_unrealize (ClutterActor *self)
1806 {
1807   /* we must be unmapped (implying our children are also unmapped) */
1808   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1809 }
1810
1811 /**
1812  * clutter_actor_unrealize:
1813  * @self: A #ClutterActor
1814  *
1815  * Unrealization informs the actor that it may be being destroyed or
1816  * moved to another stage. The actor may want to destroy any
1817  * underlying graphics resources at this point. However it is
1818  * perfectly acceptable for it to retain the resources until the actor
1819  * is destroyed because Clutter only ever uses a single rendering
1820  * context and all of the graphics resources are valid on any stage.
1821  *
1822  * Because mapped actors must be realized, actors may not be
1823  * unrealized if they are mapped. This function hides the actor to be
1824  * sure it isn't mapped, an application-visible side effect that you
1825  * may not be expecting.
1826  *
1827  * This function should not be called by application code.
1828  */
1829 void
1830 clutter_actor_unrealize (ClutterActor *self)
1831 {
1832   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1833   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1834
1835 /* This function should not really be in the public API, because
1836  * there isn't a good reason to call it. ClutterActor will already
1837  * unrealize things for you when it's important to do so.
1838  *
1839  * If you were using clutter_actor_unrealize() in a dispose
1840  * implementation, then don't, just chain up to ClutterActor's
1841  * dispose.
1842  *
1843  * If you were using clutter_actor_unrealize() to implement
1844  * unrealizing children of your container, then don't, ClutterActor
1845  * will already take care of that.
1846  *
1847  * If you were using clutter_actor_unrealize() to re-realize to
1848  * create your resources in a different way, then use
1849  * _clutter_actor_rerealize() (inside Clutter) or just call your
1850  * code that recreates your resources directly (outside Clutter).
1851  */
1852
1853 #ifdef CLUTTER_ENABLE_DEBUG
1854   clutter_actor_verify_map_state (self);
1855 #endif
1856
1857   clutter_actor_hide (self);
1858
1859   clutter_actor_unrealize_not_hiding (self);
1860 }
1861
1862 static ClutterActorTraverseVisitFlags
1863 unrealize_actor_before_children_cb (ClutterActor *self,
1864                                     int depth,
1865                                     void *user_data)
1866 {
1867   /* If an actor is already unrealized we know its children have also
1868    * already been unrealized... */
1869   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1870     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1871
1872   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1873
1874   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1875 }
1876
1877 static ClutterActorTraverseVisitFlags
1878 unrealize_actor_after_children_cb (ClutterActor *self,
1879                                    int depth,
1880                                    void *user_data)
1881 {
1882   /* We want to unset the realized flag only _after_
1883    * child actors are unrealized, to maintain invariants.
1884    */
1885   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1886   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1887   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1888 }
1889
1890 /*
1891  * clutter_actor_unrealize_not_hiding:
1892  * @self: A #ClutterActor
1893  *
1894  * Unrealization informs the actor that it may be being destroyed or
1895  * moved to another stage. The actor may want to destroy any
1896  * underlying graphics resources at this point. However it is
1897  * perfectly acceptable for it to retain the resources until the actor
1898  * is destroyed because Clutter only ever uses a single rendering
1899  * context and all of the graphics resources are valid on any stage.
1900  *
1901  * Because mapped actors must be realized, actors may not be
1902  * unrealized if they are mapped. You must hide the actor or one of
1903  * its parents before attempting to unrealize.
1904  *
1905  * This function is separate from clutter_actor_unrealize() because it
1906  * does not automatically hide the actor.
1907  * Actors need not be hidden to be unrealized, they just need to
1908  * be unmapped. In fact we don't want to mess up the application's
1909  * setting of the "visible" flag, so hiding is very undesirable.
1910  *
1911  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1912  * backward compatibility.
1913  */
1914 static void
1915 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1916 {
1917   _clutter_actor_traverse (self,
1918                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1919                            unrealize_actor_before_children_cb,
1920                            unrealize_actor_after_children_cb,
1921                            NULL);
1922 }
1923
1924 /*
1925  * _clutter_actor_rerealize:
1926  * @self: A #ClutterActor
1927  * @callback: Function to call while unrealized
1928  * @data: data for callback
1929  *
1930  * If an actor is already unrealized, this just calls the callback.
1931  *
1932  * If it is realized, it unrealizes temporarily, calls the callback,
1933  * and then re-realizes the actor.
1934  *
1935  * As a side effect, leaves all children of the actor unrealized if
1936  * the actor was realized but not showing.  This is because when we
1937  * unrealize the actor temporarily we must unrealize its children
1938  * (e.g. children of a stage can't be realized if stage window is
1939  * gone). And we aren't clever enough to save the realization state of
1940  * all children. In most cases this should not matter, because
1941  * the children will automatically realize when they next become mapped.
1942  */
1943 void
1944 _clutter_actor_rerealize (ClutterActor    *self,
1945                           ClutterCallback  callback,
1946                           void            *data)
1947 {
1948   gboolean was_mapped;
1949   gboolean was_showing;
1950   gboolean was_realized;
1951
1952   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1953
1954 #ifdef CLUTTER_ENABLE_DEBUG
1955   clutter_actor_verify_map_state (self);
1956 #endif
1957
1958   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1959   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1960   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1961
1962   /* Must be unmapped to unrealize. Note we only have to hide this
1963    * actor if it was mapped (if all parents were showing).  If actor
1964    * is merely visible (but not mapped), then that's fine, we can
1965    * leave it visible.
1966    */
1967   if (was_mapped)
1968     clutter_actor_hide (self);
1969
1970   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1971
1972   /* unrealize self and all children */
1973   clutter_actor_unrealize_not_hiding (self);
1974
1975   if (callback != NULL)
1976     {
1977       (* callback) (self, data);
1978     }
1979
1980   if (was_showing)
1981     clutter_actor_show (self); /* will realize only if mapping implies it */
1982   else if (was_realized)
1983     clutter_actor_realize (self); /* realize self and all parents */
1984 }
1985
1986 static void
1987 clutter_actor_real_pick (ClutterActor       *self,
1988                          const ClutterColor *color)
1989 {
1990   /* the default implementation is just to paint a rectangle
1991    * with the same size of the actor using the passed color
1992    */
1993   if (clutter_actor_should_pick_paint (self))
1994     {
1995       ClutterActorBox box = { 0, };
1996       float width, height;
1997
1998       clutter_actor_get_allocation_box (self, &box);
1999
2000       width = box.x2 - box.x1;
2001       height = box.y2 - box.y1;
2002
2003       cogl_set_source_color4ub (color->red,
2004                                 color->green,
2005                                 color->blue,
2006                                 color->alpha);
2007
2008       cogl_rectangle (0, 0, width, height);
2009     }
2010
2011   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2012    * with existing container classes that override the pick() virtual
2013    * and chain up to the default implementation - otherwise we'll end up
2014    * painting our children twice.
2015    *
2016    * this has to go away for 2.0; hopefully along the pick() itself.
2017    */
2018   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2019     {
2020       ClutterActor *iter;
2021
2022       for (iter = self->priv->first_child;
2023            iter != NULL;
2024            iter = iter->priv->next_sibling)
2025         clutter_actor_paint (iter);
2026     }
2027 }
2028
2029 /**
2030  * clutter_actor_should_pick_paint:
2031  * @self: A #ClutterActor
2032  *
2033  * Should be called inside the implementation of the
2034  * #ClutterActor::pick virtual function in order to check whether
2035  * the actor should paint itself in pick mode or not.
2036  *
2037  * This function should never be called directly by applications.
2038  *
2039  * Return value: %TRUE if the actor should paint its silhouette,
2040  *   %FALSE otherwise
2041  */
2042 gboolean
2043 clutter_actor_should_pick_paint (ClutterActor *self)
2044 {
2045   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2046
2047   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2048       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2049        CLUTTER_ACTOR_IS_REACTIVE (self)))
2050     return TRUE;
2051
2052   return FALSE;
2053 }
2054
2055 static void
2056 clutter_actor_real_get_preferred_width (ClutterActor *self,
2057                                         gfloat        for_height,
2058                                         gfloat       *min_width_p,
2059                                         gfloat       *natural_width_p)
2060 {
2061   ClutterActorPrivate *priv = self->priv;
2062
2063   if (priv->n_children != 0 &&
2064       priv->layout_manager != NULL)
2065     {
2066       ClutterContainer *container = CLUTTER_CONTAINER (self);
2067
2068       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2069                     "for the preferred width",
2070                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2071                     priv->layout_manager);
2072
2073       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2074                                                   container,
2075                                                   for_height,
2076                                                   min_width_p,
2077                                                   natural_width_p);
2078
2079       return;
2080     }
2081
2082   /* Default implementation is always 0x0, usually an actor
2083    * using this default is relying on someone to set the
2084    * request manually
2085    */
2086   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2087
2088   if (min_width_p)
2089     *min_width_p = 0;
2090
2091   if (natural_width_p)
2092     *natural_width_p = 0;
2093 }
2094
2095 static void
2096 clutter_actor_real_get_preferred_height (ClutterActor *self,
2097                                          gfloat        for_width,
2098                                          gfloat       *min_height_p,
2099                                          gfloat       *natural_height_p)
2100 {
2101   ClutterActorPrivate *priv = self->priv;
2102
2103   if (priv->n_children != 0 &&
2104       priv->layout_manager != NULL)
2105     {
2106       ClutterContainer *container = CLUTTER_CONTAINER (self);
2107
2108       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2109                     "for the preferred height",
2110                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2111                     priv->layout_manager);
2112
2113       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2114                                                    container,
2115                                                    for_width,
2116                                                    min_height_p,
2117                                                    natural_height_p);
2118
2119       return;
2120     }
2121   /* Default implementation is always 0x0, usually an actor
2122    * using this default is relying on someone to set the
2123    * request manually
2124    */
2125   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2126
2127   if (min_height_p)
2128     *min_height_p = 0;
2129
2130   if (natural_height_p)
2131     *natural_height_p = 0;
2132 }
2133
2134 static void
2135 clutter_actor_store_old_geometry (ClutterActor    *self,
2136                                   ClutterActorBox *box)
2137 {
2138   *box = self->priv->allocation;
2139 }
2140
2141 static inline void
2142 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2143                                           const ClutterActorBox *old)
2144 {
2145   ClutterActorPrivate *priv = self->priv;
2146   GObject *obj = G_OBJECT (self);
2147
2148   g_object_freeze_notify (obj);
2149
2150   /* to avoid excessive requisition or allocation cycles we
2151    * use the cached values.
2152    *
2153    * - if we don't have an allocation we assume that we need
2154    *   to notify anyway
2155    * - if we don't have a width or a height request we notify
2156    *   width and height
2157    * - if we have a valid allocation then we check the old
2158    *   bounding box with the current allocation and we notify
2159    *   the changes
2160    */
2161   if (priv->needs_allocation)
2162     {
2163       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2164       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2165       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2166       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2167     }
2168   else if (priv->needs_width_request || priv->needs_height_request)
2169     {
2170       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2171       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2172     }
2173   else
2174     {
2175       gfloat x, y;
2176       gfloat width, height;
2177
2178       x = priv->allocation.x1;
2179       y = priv->allocation.y1;
2180       width = priv->allocation.x2 - priv->allocation.x1;
2181       height = priv->allocation.y2 - priv->allocation.y1;
2182
2183       if (x != old->x1)
2184         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2185
2186       if (y != old->y1)
2187         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2188
2189       if (width != (old->x2 - old->x1))
2190         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2191
2192       if (height != (old->y2 - old->y1))
2193         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2194     }
2195
2196   g_object_thaw_notify (obj);
2197 }
2198
2199 /*< private >
2200  * clutter_actor_set_allocation_internal:
2201  * @self: a #ClutterActor
2202  * @box: a #ClutterActorBox
2203  * @flags: allocation flags
2204  *
2205  * Stores the allocation of @self.
2206  *
2207  * This function only performs basic storage and property notification.
2208  *
2209  * This function should be called by clutter_actor_set_allocation()
2210  * and by the default implementation of #ClutterActorClass.allocate().
2211  *
2212  * Return value: %TRUE if the allocation of the #ClutterActor has been
2213  *   changed, and %FALSE otherwise
2214  */
2215 static inline gboolean
2216 clutter_actor_set_allocation_internal (ClutterActor           *self,
2217                                        const ClutterActorBox  *box,
2218                                        ClutterAllocationFlags  flags)
2219 {
2220   ClutterActorPrivate *priv = self->priv;
2221   GObject *obj;
2222   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2223   gboolean flags_changed;
2224   gboolean retval;
2225   ClutterActorBox old_alloc = { 0, };
2226
2227   obj = G_OBJECT (self);
2228
2229   g_object_freeze_notify (obj);
2230
2231   clutter_actor_store_old_geometry (self, &old_alloc);
2232
2233   x1_changed = priv->allocation.x1 != box->x1;
2234   y1_changed = priv->allocation.y1 != box->y1;
2235   x2_changed = priv->allocation.x2 != box->x2;
2236   y2_changed = priv->allocation.y2 != box->y2;
2237
2238   flags_changed = priv->allocation_flags != flags;
2239
2240   priv->allocation = *box;
2241   priv->allocation_flags = flags;
2242
2243   /* allocation is authoritative */
2244   priv->needs_width_request = FALSE;
2245   priv->needs_height_request = FALSE;
2246   priv->needs_allocation = FALSE;
2247
2248   if (x1_changed || y1_changed ||
2249       x2_changed || y2_changed ||
2250       flags_changed)
2251     {
2252       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2253                     _clutter_actor_get_debug_name (self));
2254
2255       priv->transform_valid = FALSE;
2256
2257       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2258
2259       /* if the allocation changes, so does the content box */
2260       if (priv->content != NULL)
2261         {
2262           priv->content_box_valid = FALSE;
2263           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2264         }
2265
2266       retval = TRUE;
2267     }
2268   else
2269     retval = FALSE;
2270
2271   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2272
2273   g_object_thaw_notify (obj);
2274
2275   return retval;
2276 }
2277
2278 static void clutter_actor_real_allocate (ClutterActor           *self,
2279                                          const ClutterActorBox  *box,
2280                                          ClutterAllocationFlags  flags);
2281
2282 static inline void
2283 clutter_actor_maybe_layout_children (ClutterActor           *self,
2284                                      const ClutterActorBox  *allocation,
2285                                      ClutterAllocationFlags  flags)
2286 {
2287   ClutterActorPrivate *priv = self->priv;
2288
2289   /* this is going to be a bit hard to follow, so let's put an explanation
2290    * here.
2291    *
2292    * we want ClutterActor to have a default layout manager if the actor was
2293    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2294    *
2295    * we also want any subclass of ClutterActor that does not override the
2296    * ::allocate() virtual function to delegate to a layout manager.
2297    *
2298    * finally, we want to allow people subclassing ClutterActor and overriding
2299    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2300    *
2301    * on the other hand, we want existing actor subclasses overriding the
2302    * ::allocate() virtual function and chaining up to the parent's
2303    * implementation to continue working without allocating their children
2304    * twice, or without entering an allocation loop.
2305    *
2306    * for the first two points, we check if the class of the actor is
2307    * overridding the ::allocate() virtual function; if it isn't, then we
2308    * follow through with checking whether we have children and a layout
2309    * manager, and eventually calling clutter_layout_manager_allocate().
2310    *
2311    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2312    * allocation flags that we got passed, and if it is present, we continue
2313    * with the check above.
2314    *
2315    * if neither of these two checks yields a positive result, we just
2316    * assume that the ::allocate() virtual function that resulted in this
2317    * function being called will also allocate the children of the actor.
2318    */
2319
2320   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2321     goto check_layout;
2322
2323   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2324     goto check_layout;
2325
2326   return;
2327
2328 check_layout:
2329   if (priv->n_children != 0 &&
2330       priv->layout_manager != NULL)
2331     {
2332       ClutterContainer *container = CLUTTER_CONTAINER (self);
2333       ClutterAllocationFlags children_flags;
2334       ClutterActorBox children_box;
2335
2336       /* normalize the box passed to the layout manager */
2337       children_box.x1 = children_box.y1 = 0.f;
2338       children_box.x2 = (allocation->x2 - allocation->x1);
2339       children_box.y2 = (allocation->y2 - allocation->y1);
2340
2341       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2342        * the actor's children, since it refers only to the current
2343        * actor's allocation.
2344        */
2345       children_flags = flags;
2346       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2347
2348       CLUTTER_NOTE (LAYOUT,
2349                     "Allocating %d children of %s "
2350                     "at { %.2f, %.2f - %.2f x %.2f } "
2351                     "using %s",
2352                     priv->n_children,
2353                     _clutter_actor_get_debug_name (self),
2354                     allocation->x1,
2355                     allocation->y1,
2356                     (allocation->x2 - allocation->x1),
2357                     (allocation->y2 - allocation->y1),
2358                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2359
2360       clutter_layout_manager_allocate (priv->layout_manager,
2361                                        container,
2362                                        &children_box,
2363                                        children_flags);
2364     }
2365 }
2366
2367 static void
2368 clutter_actor_real_allocate (ClutterActor           *self,
2369                              const ClutterActorBox  *box,
2370                              ClutterAllocationFlags  flags)
2371 {
2372   ClutterActorPrivate *priv = self->priv;
2373   gboolean changed;
2374
2375   g_object_freeze_notify (G_OBJECT (self));
2376
2377   changed = clutter_actor_set_allocation_internal (self, box, flags);
2378
2379   /* we allocate our children before we notify changes in our geometry,
2380    * so that people connecting to properties will be able to get valid
2381    * data out of the sub-tree of the scene graph that has this actor at
2382    * the root.
2383    */
2384   clutter_actor_maybe_layout_children (self, box, flags);
2385
2386   if (changed)
2387     {
2388       ClutterActorBox signal_box = priv->allocation;
2389       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2390
2391       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2392                      &signal_box,
2393                      signal_flags);
2394     }
2395
2396   g_object_thaw_notify (G_OBJECT (self));
2397 }
2398
2399 static void
2400 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2401                                     ClutterActor *origin)
2402 {
2403   /* no point in queuing a redraw on a destroyed actor */
2404   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2405     return;
2406
2407   /* NB: We can't bail out early here if the actor is hidden in case
2408    * the actor bas been cloned. In this case the clone will need to
2409    * receive the signal so it can queue its own redraw.
2410    */
2411
2412   /* calls klass->queue_redraw in default handler */
2413   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2414 }
2415
2416 static void
2417 clutter_actor_real_queue_redraw (ClutterActor *self,
2418                                  ClutterActor *origin)
2419 {
2420   ClutterActor *parent;
2421
2422   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2423                 _clutter_actor_get_debug_name (self),
2424                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2425                                : "same actor");
2426
2427   /* no point in queuing a redraw on a destroyed actor */
2428   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2429     return;
2430
2431   /* If the queue redraw is coming from a child then the actor has
2432      become dirty and any queued effect is no longer valid */
2433   if (self != origin)
2434     {
2435       self->priv->is_dirty = TRUE;
2436       self->priv->effect_to_redraw = NULL;
2437     }
2438
2439   /* If the actor isn't visible, we still had to emit the signal
2440    * to allow for a ClutterClone, but the appearance of the parent
2441    * won't change so we don't have to propagate up the hierarchy.
2442    */
2443   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2444     return;
2445
2446   /* Although we could determine here that a full stage redraw
2447    * has already been queued and immediately bail out, we actually
2448    * guarantee that we will propagate a queue-redraw signal to our
2449    * parent at least once so that it's possible to implement a
2450    * container that tracks which of its children have queued a
2451    * redraw.
2452    */
2453   if (self->priv->propagated_one_redraw)
2454     {
2455       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2456       if (stage != NULL &&
2457           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2458         return;
2459     }
2460
2461   self->priv->propagated_one_redraw = TRUE;
2462
2463   /* notify parents, if they are all visible eventually we'll
2464    * queue redraw on the stage, which queues the redraw idle.
2465    */
2466   parent = clutter_actor_get_parent (self);
2467   if (parent != NULL)
2468     {
2469       /* this will go up recursively */
2470       _clutter_actor_signal_queue_redraw (parent, origin);
2471     }
2472 }
2473
2474 static void
2475 clutter_actor_real_queue_relayout (ClutterActor *self)
2476 {
2477   ClutterActorPrivate *priv = self->priv;
2478
2479   /* no point in queueing a redraw on a destroyed actor */
2480   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2481     return;
2482
2483   priv->needs_width_request  = TRUE;
2484   priv->needs_height_request = TRUE;
2485   priv->needs_allocation     = TRUE;
2486
2487   /* reset the cached size requests */
2488   memset (priv->width_requests, 0,
2489           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2490   memset (priv->height_requests, 0,
2491           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2492
2493   /* We need to go all the way up the hierarchy */
2494   if (priv->parent != NULL)
2495     _clutter_actor_queue_only_relayout (priv->parent);
2496 }
2497
2498 /**
2499  * clutter_actor_apply_relative_transform_to_point:
2500  * @self: A #ClutterActor
2501  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2502  *   default #ClutterStage
2503  * @point: A point as #ClutterVertex
2504  * @vertex: (out caller-allocates): The translated #ClutterVertex
2505  *
2506  * Transforms @point in coordinates relative to the actor into
2507  * ancestor-relative coordinates using the relevant transform
2508  * stack (i.e. scale, rotation, etc).
2509  *
2510  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2511  * this case, the coordinates returned will be the coordinates on
2512  * the stage before the projection is applied. This is different from
2513  * the behaviour of clutter_actor_apply_transform_to_point().
2514  *
2515  * Since: 0.6
2516  */
2517 void
2518 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2519                                                  ClutterActor        *ancestor,
2520                                                  const ClutterVertex *point,
2521                                                  ClutterVertex       *vertex)
2522 {
2523   gfloat w;
2524   CoglMatrix matrix;
2525
2526   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2527   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2528   g_return_if_fail (point != NULL);
2529   g_return_if_fail (vertex != NULL);
2530
2531   *vertex = *point;
2532   w = 1.0;
2533
2534   if (ancestor == NULL)
2535     ancestor = _clutter_actor_get_stage_internal (self);
2536
2537   if (ancestor == NULL)
2538     {
2539       *vertex = *point;
2540       return;
2541     }
2542
2543   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2544   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2545 }
2546
2547 static gboolean
2548 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2549                                          const ClutterVertex *vertices_in,
2550                                          ClutterVertex *vertices_out,
2551                                          int n_vertices)
2552 {
2553   ClutterActor *stage;
2554   CoglMatrix modelview;
2555   CoglMatrix projection;
2556   float viewport[4];
2557
2558   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2559
2560   stage = _clutter_actor_get_stage_internal (self);
2561
2562   /* We really can't do anything meaningful in this case so don't try
2563    * to do any transform */
2564   if (stage == NULL)
2565     return FALSE;
2566
2567   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2568    * that gets us to stage coordinates, we want to go all the way to eye
2569    * coordinates */
2570   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2571
2572   /* Fetch the projection and viewport */
2573   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2574   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2575                                &viewport[0],
2576                                &viewport[1],
2577                                &viewport[2],
2578                                &viewport[3]);
2579
2580   _clutter_util_fully_transform_vertices (&modelview,
2581                                           &projection,
2582                                           viewport,
2583                                           vertices_in,
2584                                           vertices_out,
2585                                           n_vertices);
2586
2587   return TRUE;
2588 }
2589
2590 /**
2591  * clutter_actor_apply_transform_to_point:
2592  * @self: A #ClutterActor
2593  * @point: A point as #ClutterVertex
2594  * @vertex: (out caller-allocates): The translated #ClutterVertex
2595  *
2596  * Transforms @point in coordinates relative to the actor
2597  * into screen-relative coordinates with the current actor
2598  * transformation (i.e. scale, rotation, etc)
2599  *
2600  * Since: 0.4
2601  **/
2602 void
2603 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2604                                         const ClutterVertex *point,
2605                                         ClutterVertex       *vertex)
2606 {
2607   g_return_if_fail (point != NULL);
2608   g_return_if_fail (vertex != NULL);
2609   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2610 }
2611
2612 /*
2613  * _clutter_actor_get_relative_transformation_matrix:
2614  * @self: The actor whose coordinate space you want to transform from.
2615  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2616  *            or %NULL if you want to transform all the way to eye coordinates.
2617  * @matrix: A #CoglMatrix to store the transformation
2618  *
2619  * This gets a transformation @matrix that will transform coordinates from the
2620  * coordinate space of @self into the coordinate space of @ancestor.
2621  *
2622  * For example if you need a matrix that can transform the local actor
2623  * coordinates of @self into stage coordinates you would pass the actor's stage
2624  * pointer as the @ancestor.
2625  *
2626  * If you pass %NULL then the transformation will take you all the way through
2627  * to eye coordinates. This can be useful if you want to extract the entire
2628  * modelview transform that Clutter applies before applying the projection
2629  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2630  * using cogl_set_modelview_matrix() for example then you would want a matrix
2631  * that transforms into eye coordinates.
2632  *
2633  * <note><para>This function explicitly initializes the given @matrix. If you just
2634  * want clutter to multiply a relative transformation with an existing matrix
2635  * you can use clutter_actor_apply_relative_transformation_matrix()
2636  * instead.</para></note>
2637  *
2638  */
2639 /* XXX: We should consider caching the stage relative modelview along with
2640  * the actor itself */
2641 static void
2642 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2643                                                    ClutterActor *ancestor,
2644                                                    CoglMatrix *matrix)
2645 {
2646   cogl_matrix_init_identity (matrix);
2647
2648   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2649 }
2650
2651 /* Project the given @box into stage window coordinates, writing the
2652  * transformed vertices to @verts[]. */
2653 static gboolean
2654 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2655                                           const ClutterActorBox *box,
2656                                           ClutterVertex          verts[])
2657 {
2658   ClutterVertex box_vertices[4];
2659
2660   box_vertices[0].x = box->x1;
2661   box_vertices[0].y = box->y1;
2662   box_vertices[0].z = 0;
2663   box_vertices[1].x = box->x2;
2664   box_vertices[1].y = box->y1;
2665   box_vertices[1].z = 0;
2666   box_vertices[2].x = box->x1;
2667   box_vertices[2].y = box->y2;
2668   box_vertices[2].z = 0;
2669   box_vertices[3].x = box->x2;
2670   box_vertices[3].y = box->y2;
2671   box_vertices[3].z = 0;
2672
2673   return
2674     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2675 }
2676
2677 /**
2678  * clutter_actor_get_allocation_vertices:
2679  * @self: A #ClutterActor
2680  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2681  *   against, or %NULL to use the #ClutterStage
2682  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2683  *   location for an array of 4 #ClutterVertex in which to store the result
2684  *
2685  * Calculates the transformed coordinates of the four corners of the
2686  * actor in the plane of @ancestor. The returned vertices relate to
2687  * the #ClutterActorBox coordinates as follows:
2688  * <itemizedlist>
2689  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2690  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2691  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2692  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2693  * </itemizedlist>
2694  *
2695  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2696  * this case, the coordinates returned will be the coordinates on
2697  * the stage before the projection is applied. This is different from
2698  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2699  *
2700  * Since: 0.6
2701  */
2702 void
2703 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2704                                        ClutterActor  *ancestor,
2705                                        ClutterVertex  verts[])
2706 {
2707   ClutterActorPrivate *priv;
2708   ClutterActorBox box;
2709   ClutterVertex vertices[4];
2710   CoglMatrix modelview;
2711
2712   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2713   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2714
2715   if (ancestor == NULL)
2716     ancestor = _clutter_actor_get_stage_internal (self);
2717
2718   /* Fallback to a NOP transform if the actor isn't parented under a
2719    * stage. */
2720   if (ancestor == NULL)
2721     ancestor = self;
2722
2723   priv = self->priv;
2724
2725   /* if the actor needs to be allocated we force a relayout, so that
2726    * we will have valid values to use in the transformations */
2727   if (priv->needs_allocation)
2728     {
2729       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2730       if (stage)
2731         _clutter_stage_maybe_relayout (stage);
2732       else
2733         {
2734           box.x1 = box.y1 = 0;
2735           /* The result isn't really meaningful in this case but at
2736            * least try to do something *vaguely* reasonable... */
2737           clutter_actor_get_size (self, &box.x2, &box.y2);
2738         }
2739     }
2740
2741   clutter_actor_get_allocation_box (self, &box);
2742
2743   vertices[0].x = box.x1;
2744   vertices[0].y = box.y1;
2745   vertices[0].z = 0;
2746   vertices[1].x = box.x2;
2747   vertices[1].y = box.y1;
2748   vertices[1].z = 0;
2749   vertices[2].x = box.x1;
2750   vertices[2].y = box.y2;
2751   vertices[2].z = 0;
2752   vertices[3].x = box.x2;
2753   vertices[3].y = box.y2;
2754   vertices[3].z = 0;
2755
2756   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2757                                                      &modelview);
2758
2759   cogl_matrix_transform_points (&modelview,
2760                                 3,
2761                                 sizeof (ClutterVertex),
2762                                 vertices,
2763                                 sizeof (ClutterVertex),
2764                                 vertices,
2765                                 4);
2766 }
2767
2768 /**
2769  * clutter_actor_get_abs_allocation_vertices:
2770  * @self: A #ClutterActor
2771  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2772  *   of 4 #ClutterVertex where to store the result.
2773  *
2774  * Calculates the transformed screen coordinates of the four corners of
2775  * the actor; the returned vertices relate to the #ClutterActorBox
2776  * coordinates  as follows:
2777  * <itemizedlist>
2778  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2779  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2780  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2781  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2782  * </itemizedlist>
2783  *
2784  * Since: 0.4
2785  */
2786 void
2787 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2788                                            ClutterVertex  verts[])
2789 {
2790   ClutterActorPrivate *priv;
2791   ClutterActorBox actor_space_allocation;
2792
2793   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2794
2795   priv = self->priv;
2796
2797   /* if the actor needs to be allocated we force a relayout, so that
2798    * the actor allocation box will be valid for
2799    * _clutter_actor_transform_and_project_box()
2800    */
2801   if (priv->needs_allocation)
2802     {
2803       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2804       /* There's nothing meaningful we can do now */
2805       if (!stage)
2806         return;
2807
2808       _clutter_stage_maybe_relayout (stage);
2809     }
2810
2811   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2812    * own coordinate space... */
2813   actor_space_allocation.x1 = 0;
2814   actor_space_allocation.y1 = 0;
2815   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2816   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2817   _clutter_actor_transform_and_project_box (self,
2818                                             &actor_space_allocation,
2819                                             verts);
2820 }
2821
2822 static void
2823 clutter_actor_real_apply_transform (ClutterActor *self,
2824                                     CoglMatrix   *matrix)
2825 {
2826   ClutterActorPrivate *priv = self->priv;
2827
2828   if (!priv->transform_valid)
2829     {
2830       CoglMatrix *transform = &priv->transform;
2831       const ClutterTransformInfo *info;
2832
2833       info = _clutter_actor_get_transform_info_or_defaults (self);
2834
2835       cogl_matrix_init_identity (transform);
2836
2837       cogl_matrix_translate (transform,
2838                              priv->allocation.x1,
2839                              priv->allocation.y1,
2840                              0.0);
2841
2842       if (info->depth)
2843         cogl_matrix_translate (transform, 0, 0, info->depth);
2844
2845       /*
2846        * because the rotation involves translations, we must scale
2847        * before applying the rotations (if we apply the scale after
2848        * the rotations, the translations included in the rotation are
2849        * not scaled and so the entire object will move on the screen
2850        * as a result of rotating it).
2851        */
2852       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2853         {
2854           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2855                                         &info->scale_center,
2856                                         cogl_matrix_scale (transform,
2857                                                            info->scale_x,
2858                                                            info->scale_y,
2859                                                            1.0));
2860         }
2861
2862       if (info->rz_angle)
2863         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2864                                       &info->rz_center,
2865                                       cogl_matrix_rotate (transform,
2866                                                           info->rz_angle,
2867                                                           0, 0, 1.0));
2868
2869       if (info->ry_angle)
2870         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2871                                       &info->ry_center,
2872                                       cogl_matrix_rotate (transform,
2873                                                           info->ry_angle,
2874                                                           0, 1.0, 0));
2875
2876       if (info->rx_angle)
2877         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2878                                       &info->rx_center,
2879                                       cogl_matrix_rotate (transform,
2880                                                           info->rx_angle,
2881                                                           1.0, 0, 0));
2882
2883       if (!clutter_anchor_coord_is_zero (&info->anchor))
2884         {
2885           gfloat x, y, z;
2886
2887           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2888           cogl_matrix_translate (transform, -x, -y, -z);
2889         }
2890
2891       priv->transform_valid = TRUE;
2892     }
2893
2894   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2895 }
2896
2897 /* Applies the transforms associated with this actor to the given
2898  * matrix. */
2899 void
2900 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2901                                           CoglMatrix *matrix)
2902 {
2903   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2904 }
2905
2906 /*
2907  * clutter_actor_apply_relative_transformation_matrix:
2908  * @self: The actor whose coordinate space you want to transform from.
2909  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2910  *            or %NULL if you want to transform all the way to eye coordinates.
2911  * @matrix: A #CoglMatrix to apply the transformation too.
2912  *
2913  * This multiplies a transform with @matrix that will transform coordinates
2914  * from the coordinate space of @self into the coordinate space of @ancestor.
2915  *
2916  * For example if you need a matrix that can transform the local actor
2917  * coordinates of @self into stage coordinates you would pass the actor's stage
2918  * pointer as the @ancestor.
2919  *
2920  * If you pass %NULL then the transformation will take you all the way through
2921  * to eye coordinates. This can be useful if you want to extract the entire
2922  * modelview transform that Clutter applies before applying the projection
2923  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2924  * using cogl_set_modelview_matrix() for example then you would want a matrix
2925  * that transforms into eye coordinates.
2926  *
2927  * <note>This function doesn't initialize the given @matrix, it simply
2928  * multiplies the requested transformation matrix with the existing contents of
2929  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2930  * before calling this function, or you can use
2931  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2932  */
2933 void
2934 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2935                                                      ClutterActor *ancestor,
2936                                                      CoglMatrix *matrix)
2937 {
2938   ClutterActor *parent;
2939
2940   /* Note we terminate before ever calling stage->apply_transform()
2941    * since that would conceptually be relative to the underlying
2942    * window OpenGL coordinates so we'd need a special @ancestor
2943    * value to represent the fake parent of the stage. */
2944   if (self == ancestor)
2945     return;
2946
2947   parent = clutter_actor_get_parent (self);
2948
2949   if (parent != NULL)
2950     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2951                                                          matrix);
2952
2953   _clutter_actor_apply_modelview_transform (self, matrix);
2954 }
2955
2956 static void
2957 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2958                                        ClutterPaintVolume *pv,
2959                                        const char *label,
2960                                        const CoglColor *color)
2961 {
2962   static CoglPipeline *outline = NULL;
2963   CoglPrimitive *prim;
2964   ClutterVertex line_ends[12 * 2];
2965   int n_vertices;
2966   CoglContext *ctx =
2967     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2968   /* XXX: at some point we'll query this from the stage but we can't
2969    * do that until the osx backend uses Cogl natively. */
2970   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2971
2972   if (outline == NULL)
2973     outline = cogl_pipeline_new (ctx);
2974
2975   _clutter_paint_volume_complete (pv);
2976
2977   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2978
2979   /* Front face */
2980   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2981   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2982   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2983   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2984
2985   if (!pv->is_2d)
2986     {
2987       /* Back face */
2988       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2989       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2990       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2991       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2992
2993       /* Lines connecting front face to back face */
2994       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2995       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2996       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2997       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2998     }
2999
3000   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3001                                 n_vertices,
3002                                 (CoglVertexP3 *)line_ends);
3003
3004   cogl_pipeline_set_color (outline, color);
3005   cogl_framebuffer_draw_primitive (fb, outline, prim);
3006   cogl_object_unref (prim);
3007
3008   if (label)
3009     {
3010       PangoLayout *layout;
3011       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3012       pango_layout_set_text (layout, label, -1);
3013       cogl_pango_render_layout (layout,
3014                                 pv->vertices[0].x,
3015                                 pv->vertices[0].y,
3016                                 color,
3017                                 0);
3018       g_object_unref (layout);
3019     }
3020 }
3021
3022 static void
3023 _clutter_actor_draw_paint_volume (ClutterActor *self)
3024 {
3025   ClutterPaintVolume *pv;
3026   CoglColor color;
3027
3028   pv = _clutter_actor_get_paint_volume_mutable (self);
3029   if (!pv)
3030     {
3031       gfloat width, height;
3032       ClutterPaintVolume fake_pv;
3033
3034       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3035       _clutter_paint_volume_init_static (&fake_pv, stage);
3036
3037       clutter_actor_get_size (self, &width, &height);
3038       clutter_paint_volume_set_width (&fake_pv, width);
3039       clutter_paint_volume_set_height (&fake_pv, height);
3040
3041       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3042       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3043                                              _clutter_actor_get_debug_name (self),
3044                                              &color);
3045
3046       clutter_paint_volume_free (&fake_pv);
3047     }
3048   else
3049     {
3050       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3051       _clutter_actor_draw_paint_volume_full (self, pv,
3052                                              _clutter_actor_get_debug_name (self),
3053                                              &color);
3054     }
3055 }
3056
3057 static void
3058 _clutter_actor_paint_cull_result (ClutterActor *self,
3059                                   gboolean success,
3060                                   ClutterCullResult result)
3061 {
3062   ClutterPaintVolume *pv;
3063   CoglColor color;
3064
3065   if (success)
3066     {
3067       if (result == CLUTTER_CULL_RESULT_IN)
3068         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3069       else if (result == CLUTTER_CULL_RESULT_OUT)
3070         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3071       else
3072         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3073     }
3074   else
3075     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3076
3077   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3078     _clutter_actor_draw_paint_volume_full (self, pv,
3079                                            _clutter_actor_get_debug_name (self),
3080                                            &color);
3081   else
3082     {
3083       PangoLayout *layout;
3084       char *label =
3085         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3086       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3087       cogl_set_source_color (&color);
3088
3089       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3090       pango_layout_set_text (layout, label, -1);
3091       cogl_pango_render_layout (layout,
3092                                 0,
3093                                 0,
3094                                 &color,
3095                                 0);
3096       g_free (label);
3097       g_object_unref (layout);
3098     }
3099 }
3100
3101 static int clone_paint_level = 0;
3102
3103 void
3104 _clutter_actor_push_clone_paint (void)
3105 {
3106   clone_paint_level++;
3107 }
3108
3109 void
3110 _clutter_actor_pop_clone_paint (void)
3111 {
3112   clone_paint_level--;
3113 }
3114
3115 static gboolean
3116 in_clone_paint (void)
3117 {
3118   return clone_paint_level > 0;
3119 }
3120
3121 /* Returns TRUE if the actor can be ignored */
3122 /* FIXME: we should return a ClutterCullResult, and
3123  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3124  * means there's no point in trying to cull descendants of the current
3125  * node. */
3126 static gboolean
3127 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3128 {
3129   ClutterActorPrivate *priv = self->priv;
3130   ClutterActor *stage;
3131   const ClutterPlane *stage_clip;
3132
3133   if (!priv->last_paint_volume_valid)
3134     {
3135       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3136                     "->last_paint_volume_valid == FALSE",
3137                     _clutter_actor_get_debug_name (self));
3138       return FALSE;
3139     }
3140
3141   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3142     return FALSE;
3143
3144   stage = _clutter_actor_get_stage_internal (self);
3145   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3146   if (G_UNLIKELY (!stage_clip))
3147     {
3148       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3149                     "No stage clip set",
3150                     _clutter_actor_get_debug_name (self));
3151       return FALSE;
3152     }
3153
3154   if (cogl_get_draw_framebuffer () !=
3155       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3156     {
3157       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3158                     "Current framebuffer doesn't correspond to stage",
3159                     _clutter_actor_get_debug_name (self));
3160       return FALSE;
3161     }
3162
3163   *result_out =
3164     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3165   return TRUE;
3166 }
3167
3168 static void
3169 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3170 {
3171   ClutterActorPrivate *priv = self->priv;
3172   const ClutterPaintVolume *pv;
3173
3174   if (priv->last_paint_volume_valid)
3175     {
3176       clutter_paint_volume_free (&priv->last_paint_volume);
3177       priv->last_paint_volume_valid = FALSE;
3178     }
3179
3180   pv = clutter_actor_get_paint_volume (self);
3181   if (!pv)
3182     {
3183       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3184                     "Actor failed to report a paint volume",
3185                     _clutter_actor_get_debug_name (self));
3186       return;
3187     }
3188
3189   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3190
3191   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3192                                             NULL); /* eye coordinates */
3193
3194   priv->last_paint_volume_valid = TRUE;
3195 }
3196
3197 static inline gboolean
3198 actor_has_shader_data (ClutterActor *self)
3199 {
3200   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3201 }
3202
3203 guint32
3204 _clutter_actor_get_pick_id (ClutterActor *self)
3205 {
3206   if (self->priv->pick_id < 0)
3207     return 0;
3208
3209   return self->priv->pick_id;
3210 }
3211
3212 /* This is the same as clutter_actor_add_effect except that it doesn't
3213    queue a redraw and it doesn't notify on the effect property */
3214 static void
3215 _clutter_actor_add_effect_internal (ClutterActor  *self,
3216                                     ClutterEffect *effect)
3217 {
3218   ClutterActorPrivate *priv = self->priv;
3219
3220   if (priv->effects == NULL)
3221     {
3222       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3223       priv->effects->actor = self;
3224     }
3225
3226   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3227 }
3228
3229 /* This is the same as clutter_actor_remove_effect except that it doesn't
3230    queue a redraw and it doesn't notify on the effect property */
3231 static void
3232 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3233                                        ClutterEffect *effect)
3234 {
3235   ClutterActorPrivate *priv = self->priv;
3236
3237   if (priv->effects == NULL)
3238     return;
3239
3240   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3241
3242   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3243     g_clear_object (&priv->effects);
3244 }
3245
3246 static gboolean
3247 needs_flatten_effect (ClutterActor *self)
3248 {
3249   ClutterActorPrivate *priv = self->priv;
3250
3251   if (G_UNLIKELY (clutter_paint_debug_flags &
3252                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3253     return FALSE;
3254
3255   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3256     return TRUE;
3257   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3258     {
3259       if (clutter_actor_get_paint_opacity (self) < 255 &&
3260           clutter_actor_has_overlaps (self))
3261         return TRUE;
3262     }
3263
3264   return FALSE;
3265 }
3266
3267 static void
3268 add_or_remove_flatten_effect (ClutterActor *self)
3269 {
3270   ClutterActorPrivate *priv = self->priv;
3271
3272   /* Add or remove the flatten effect depending on the
3273      offscreen-redirect property. */
3274   if (needs_flatten_effect (self))
3275     {
3276       if (priv->flatten_effect == NULL)
3277         {
3278           ClutterActorMeta *actor_meta;
3279           gint priority;
3280
3281           priv->flatten_effect = _clutter_flatten_effect_new ();
3282           /* Keep a reference to the effect so that we can queue
3283              redraws from it */
3284           g_object_ref_sink (priv->flatten_effect);
3285
3286           /* Set the priority of the effect to high so that it will
3287              always be applied to the actor first. It uses an internal
3288              priority so that it won't be visible to applications */
3289           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3290           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3291           _clutter_actor_meta_set_priority (actor_meta, priority);
3292
3293           /* This will add the effect without queueing a redraw */
3294           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3295         }
3296     }
3297   else
3298     {
3299       if (priv->flatten_effect != NULL)
3300         {
3301           /* Destroy the effect so that it will lose its fbo cache of
3302              the actor */
3303           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3304           g_clear_object (&priv->flatten_effect);
3305         }
3306     }
3307 }
3308
3309 static void
3310 clutter_actor_real_paint (ClutterActor *actor)
3311 {
3312   ClutterActorPrivate *priv = actor->priv;
3313   ClutterActor *iter;
3314
3315   for (iter = priv->first_child;
3316        iter != NULL;
3317        iter = iter->priv->next_sibling)
3318     {
3319       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3320                     _clutter_actor_get_debug_name (iter),
3321                     _clutter_actor_get_debug_name (actor),
3322                     iter->priv->allocation.x1,
3323                     iter->priv->allocation.y1,
3324                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3325                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3326
3327       clutter_actor_paint (iter);
3328     }
3329 }
3330
3331 static gboolean
3332 clutter_actor_paint_node (ClutterActor     *actor,
3333                           ClutterPaintNode *root)
3334 {
3335   ClutterActorPrivate *priv = actor->priv;
3336
3337   if (root == NULL)
3338     return FALSE;
3339
3340   if (priv->bg_color_set &&
3341       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3342     {
3343       ClutterPaintNode *node;
3344       ClutterColor bg_color;
3345       ClutterActorBox box;
3346
3347       box.x1 = 0.f;
3348       box.y1 = 0.f;
3349       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3350       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3351
3352       bg_color = priv->bg_color;
3353       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3354                      * priv->bg_color.alpha
3355                      / 255;
3356
3357       node = clutter_color_node_new (&bg_color);
3358       clutter_paint_node_set_name (node, "backgroundColor");
3359       clutter_paint_node_add_rectangle (node, &box);
3360       clutter_paint_node_add_child (root, node);
3361       clutter_paint_node_unref (node);
3362     }
3363
3364   if (priv->content != NULL)
3365     _clutter_content_paint_content (priv->content, actor, root);
3366
3367   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3368     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3369
3370   if (clutter_paint_node_get_n_children (root) == 0)
3371     return FALSE;
3372
3373 #ifdef CLUTTER_ENABLE_DEBUG
3374   if (CLUTTER_HAS_DEBUG (PAINT))
3375     {
3376       /* dump the tree only if we have one */
3377       _clutter_paint_node_dump_tree (root);
3378     }
3379 #endif /* CLUTTER_ENABLE_DEBUG */
3380
3381   _clutter_paint_node_paint (root);
3382
3383 #if 0
3384   /* XXX: Uncomment this when we disable emitting the paint signal */
3385   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3386 #endif
3387
3388   return TRUE;
3389 }
3390
3391 /**
3392  * clutter_actor_paint:
3393  * @self: A #ClutterActor
3394  *
3395  * Renders the actor to display.
3396  *
3397  * This function should not be called directly by applications.
3398  * Call clutter_actor_queue_redraw() to queue paints, instead.
3399  *
3400  * This function is context-aware, and will either cause a
3401  * regular paint or a pick paint.
3402  *
3403  * This function will emit the #ClutterActor::paint signal or
3404  * the #ClutterActor::pick signal, depending on the context.
3405  *
3406  * This function does not paint the actor if the actor is set to 0,
3407  * unless it is performing a pick paint.
3408  */
3409 void
3410 clutter_actor_paint (ClutterActor *self)
3411 {
3412   ClutterActorPrivate *priv;
3413   ClutterPickMode pick_mode;
3414   gboolean clip_set = FALSE;
3415   gboolean shader_applied = FALSE;
3416
3417   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3418                           "Actor real-paint counter",
3419                           "Increments each time any actor is painted",
3420                           0 /* no application private data */);
3421   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3422                           "Actor pick-paint counter",
3423                           "Increments each time any actor is painted "
3424                           "for picking",
3425                           0 /* no application private data */);
3426
3427   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3428
3429   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3430     return;
3431
3432   priv = self->priv;
3433
3434   pick_mode = _clutter_context_get_pick_mode ();
3435
3436   if (pick_mode == CLUTTER_PICK_NONE)
3437     priv->propagated_one_redraw = FALSE;
3438
3439   /* It's an important optimization that we consider painting of
3440    * actors with 0 opacity to be a NOP... */
3441   if (pick_mode == CLUTTER_PICK_NONE &&
3442       /* ignore top-levels, since they might be transparent */
3443       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3444       /* Use the override opacity if its been set */
3445       ((priv->opacity_override >= 0) ?
3446        priv->opacity_override : priv->opacity) == 0)
3447     return;
3448
3449   /* if we aren't paintable (not in a toplevel with all
3450    * parents paintable) then do nothing.
3451    */
3452   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3453     return;
3454
3455   /* mark that we are in the paint process */
3456   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3457
3458   cogl_push_matrix();
3459
3460   if (priv->enable_model_view_transform)
3461     {
3462       CoglMatrix matrix;
3463
3464       /* XXX: It could be better to cache the modelview with the actor
3465        * instead of progressively building up the transformations on
3466        * the matrix stack every time we paint. */
3467       cogl_get_modelview_matrix (&matrix);
3468       _clutter_actor_apply_modelview_transform (self, &matrix);
3469
3470 #ifdef CLUTTER_ENABLE_DEBUG
3471       /* Catch when out-of-band transforms have been made by actors not as part
3472        * of an apply_transform vfunc... */
3473       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3474         {
3475           CoglMatrix expected_matrix;
3476
3477           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3478                                                              &expected_matrix);
3479
3480           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3481             {
3482               GString *buf = g_string_sized_new (1024);
3483               ClutterActor *parent;
3484
3485               parent = self;
3486               while (parent != NULL)
3487                 {
3488                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3489
3490                   if (parent->priv->parent != NULL)
3491                     g_string_append (buf, "->");
3492
3493                   parent = parent->priv->parent;
3494                 }
3495
3496               g_warning ("Unexpected transform found when painting actor "
3497                          "\"%s\". This will be caused by one of the actor's "
3498                          "ancestors (%s) using the Cogl API directly to transform "
3499                          "children instead of using ::apply_transform().",
3500                          _clutter_actor_get_debug_name (self),
3501                          buf->str);
3502
3503               g_string_free (buf, TRUE);
3504             }
3505         }
3506 #endif /* CLUTTER_ENABLE_DEBUG */
3507
3508       cogl_set_modelview_matrix (&matrix);
3509     }
3510
3511   if (priv->has_clip)
3512     {
3513       cogl_clip_push_rectangle (priv->clip.x,
3514                                 priv->clip.y,
3515                                 priv->clip.x + priv->clip.width,
3516                                 priv->clip.y + priv->clip.height);
3517       clip_set = TRUE;
3518     }
3519   else if (priv->clip_to_allocation)
3520     {
3521       gfloat width, height;
3522
3523       width  = priv->allocation.x2 - priv->allocation.x1;
3524       height = priv->allocation.y2 - priv->allocation.y1;
3525
3526       cogl_clip_push_rectangle (0, 0, width, height);
3527       clip_set = TRUE;
3528     }
3529
3530   if (pick_mode == CLUTTER_PICK_NONE)
3531     {
3532       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3533
3534       /* We check whether we need to add the flatten effect before
3535          each paint so that we can avoid having a mechanism for
3536          applications to notify when the value of the
3537          has_overlaps virtual changes. */
3538       add_or_remove_flatten_effect (self);
3539     }
3540   else
3541     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3542
3543   /* We save the current paint volume so that the next time the
3544    * actor queues a redraw we can constrain the redraw to just
3545    * cover the union of the new bounding box and the old.
3546    *
3547    * We also fetch the current paint volume to perform culling so
3548    * we can avoid painting actors outside the current clip region.
3549    *
3550    * If we are painting inside a clone, we should neither update
3551    * the paint volume or use it to cull painting, since the paint
3552    * box represents the location of the source actor on the
3553    * screen.
3554    *
3555    * XXX: We are starting to do a lot of vertex transforms on
3556    * the CPU in a typical paint, so at some point we should
3557    * audit these and consider caching some things.
3558    *
3559    * NB: We don't perform culling while picking at this point because
3560    * clutter-stage.c doesn't setup the clipping planes appropriately.
3561    *
3562    * NB: We don't want to update the last-paint-volume during picking
3563    * because the last-paint-volume is used to determine the old screen
3564    * space location of an actor that has moved so we can know the
3565    * minimal region to redraw to clear an old view of the actor. If we
3566    * update this during picking then by the time we come around to
3567    * paint then the last-paint-volume would likely represent the new
3568    * actor position not the old.
3569    */
3570   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3571     {
3572       gboolean success;
3573       /* annoyingly gcc warns if uninitialized even though
3574        * the initialization is redundant :-( */
3575       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3576
3577       if (G_LIKELY ((clutter_paint_debug_flags &
3578                      (CLUTTER_DEBUG_DISABLE_CULLING |
3579                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3580                     (CLUTTER_DEBUG_DISABLE_CULLING |
3581                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3582         _clutter_actor_update_last_paint_volume (self);
3583
3584       success = cull_actor (self, &result);
3585
3586       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3587         _clutter_actor_paint_cull_result (self, success, result);
3588       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3589         goto done;
3590     }
3591
3592   if (priv->effects == NULL)
3593     {
3594       if (pick_mode == CLUTTER_PICK_NONE &&
3595           actor_has_shader_data (self))
3596         {
3597           _clutter_actor_shader_pre_paint (self, FALSE);
3598           shader_applied = TRUE;
3599         }
3600
3601       priv->next_effect_to_paint = NULL;
3602     }
3603   else
3604     priv->next_effect_to_paint =
3605       _clutter_meta_group_peek_metas (priv->effects);
3606
3607   clutter_actor_continue_paint (self);
3608
3609   if (shader_applied)
3610     _clutter_actor_shader_post_paint (self);
3611
3612   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3613                   pick_mode == CLUTTER_PICK_NONE))
3614     _clutter_actor_draw_paint_volume (self);
3615
3616 done:
3617   /* If we make it here then the actor has run through a complete
3618      paint run including all the effects so it's no longer dirty */
3619   if (pick_mode == CLUTTER_PICK_NONE)
3620     priv->is_dirty = FALSE;
3621
3622   if (clip_set)
3623     cogl_clip_pop();
3624
3625   cogl_pop_matrix();
3626
3627   /* paint sequence complete */
3628   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3629 }
3630
3631 /**
3632  * clutter_actor_continue_paint:
3633  * @self: A #ClutterActor
3634  *
3635  * Run the next stage of the paint sequence. This function should only
3636  * be called within the implementation of the ‘run’ virtual of a
3637  * #ClutterEffect. It will cause the run method of the next effect to
3638  * be applied, or it will paint the actual actor if the current effect
3639  * is the last effect in the chain.
3640  *
3641  * Since: 1.8
3642  */
3643 void
3644 clutter_actor_continue_paint (ClutterActor *self)
3645 {
3646   ClutterActorPrivate *priv;
3647
3648   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3649   /* This should only be called from with in the ‘run’ implementation
3650      of a ClutterEffect */
3651   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3652
3653   priv = self->priv;
3654
3655   /* Skip any effects that are disabled */
3656   while (priv->next_effect_to_paint &&
3657          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3658     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3659
3660   /* If this has come from the last effect then we'll just paint the
3661      actual actor */
3662   if (priv->next_effect_to_paint == NULL)
3663     {
3664       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3665         {
3666           ClutterPaintNode *dummy;
3667
3668           /* XXX - this will go away in 2.0, when we can get rid of this
3669            * stuff and switch to a pure retained render tree of PaintNodes
3670            * for the entire frame, starting from the Stage; the paint()
3671            * virtual function can then be called directly.
3672            */
3673           dummy = _clutter_dummy_node_new (self);
3674           clutter_paint_node_set_name (dummy, "Root");
3675
3676           /* XXX - for 1.12, we use the return value of paint_node() to
3677            * decide whether we should emit the ::paint signal.
3678            */
3679           clutter_actor_paint_node (self, dummy);
3680           clutter_paint_node_unref (dummy);
3681
3682           g_signal_emit (self, actor_signals[PAINT], 0);
3683         }
3684       else
3685         {
3686           ClutterColor col = { 0, };
3687
3688           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3689
3690           /* Actor will then paint silhouette of itself in supplied
3691            * color.  See clutter_stage_get_actor_at_pos() for where
3692            * picking is enabled.
3693            */
3694           g_signal_emit (self, actor_signals[PICK], 0, &col);
3695         }
3696     }
3697   else
3698     {
3699       ClutterEffect *old_current_effect;
3700       ClutterEffectPaintFlags run_flags = 0;
3701
3702       /* Cache the current effect so that we can put it back before
3703          returning */
3704       old_current_effect = priv->current_effect;
3705
3706       priv->current_effect = priv->next_effect_to_paint->data;
3707       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3708
3709       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3710         {
3711           if (priv->is_dirty)
3712             {
3713               /* If there's an effect queued with this redraw then all
3714                  effects up to that one will be considered dirty. It
3715                  is expected the queued effect will paint the cached
3716                  image and not call clutter_actor_continue_paint again
3717                  (although it should work ok if it does) */
3718               if (priv->effect_to_redraw == NULL ||
3719                   priv->current_effect != priv->effect_to_redraw)
3720                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3721             }
3722
3723           _clutter_effect_paint (priv->current_effect, run_flags);
3724         }
3725       else
3726         {
3727           /* We can't determine when an actor has been modified since
3728              its last pick so lets just assume it has always been
3729              modified */
3730           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3731
3732           _clutter_effect_pick (priv->current_effect, run_flags);
3733         }
3734
3735       priv->current_effect = old_current_effect;
3736     }
3737 }
3738
3739 static ClutterActorTraverseVisitFlags
3740 invalidate_queue_redraw_entry (ClutterActor *self,
3741                                int           depth,
3742                                gpointer      user_data)
3743 {
3744   ClutterActorPrivate *priv = self->priv;
3745
3746   if (priv->queue_redraw_entry != NULL)
3747     {
3748       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3749       priv->queue_redraw_entry = NULL;
3750     }
3751
3752   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3753 }
3754
3755 static inline void
3756 remove_child (ClutterActor *self,
3757               ClutterActor *child)
3758 {
3759   ClutterActor *prev_sibling, *next_sibling;
3760
3761   prev_sibling = child->priv->prev_sibling;
3762   next_sibling = child->priv->next_sibling;
3763
3764   if (prev_sibling != NULL)
3765     prev_sibling->priv->next_sibling = next_sibling;
3766
3767   if (next_sibling != NULL)
3768     next_sibling->priv->prev_sibling = prev_sibling;
3769
3770   if (self->priv->first_child == child)
3771     self->priv->first_child = next_sibling;
3772
3773   if (self->priv->last_child == child)
3774     self->priv->last_child = prev_sibling;
3775
3776   child->priv->parent = NULL;
3777   child->priv->prev_sibling = NULL;
3778   child->priv->next_sibling = NULL;
3779 }
3780
3781 typedef enum {
3782   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3783   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3784   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3785   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3786   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3787   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3788
3789   /* default flags for public API */
3790   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3791                                     REMOVE_CHILD_EMIT_PARENT_SET |
3792                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3793                                     REMOVE_CHILD_CHECK_STATE |
3794                                     REMOVE_CHILD_FLUSH_QUEUE |
3795                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3796
3797   /* flags for legacy/deprecated API */
3798   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3799                                     REMOVE_CHILD_FLUSH_QUEUE |
3800                                     REMOVE_CHILD_EMIT_PARENT_SET |
3801                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3802 } ClutterActorRemoveChildFlags;
3803
3804 /*< private >
3805  * clutter_actor_remove_child_internal:
3806  * @self: a #ClutterActor
3807  * @child: the child of @self that has to be removed
3808  * @flags: control the removal operations
3809  *
3810  * Removes @child from the list of children of @self.
3811  */
3812 static void
3813 clutter_actor_remove_child_internal (ClutterActor                 *self,
3814                                      ClutterActor                 *child,
3815                                      ClutterActorRemoveChildFlags  flags)
3816 {
3817   ClutterActor *old_first, *old_last;
3818   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3819   gboolean flush_queue;
3820   gboolean notify_first_last;
3821   gboolean was_mapped;
3822
3823   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3824   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3825   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3826   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3827   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3828   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3829
3830   g_object_freeze_notify (G_OBJECT (self));
3831
3832   if (destroy_meta)
3833     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3834
3835   if (check_state)
3836     {
3837       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3838
3839       /* we need to unrealize *before* we set parent_actor to NULL,
3840        * because in an unrealize method actors are dissociating from the
3841        * stage, which means they need to be able to
3842        * clutter_actor_get_stage().
3843        *
3844        * yhis should unmap and unrealize, unless we're reparenting.
3845        */
3846       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3847     }
3848   else
3849     was_mapped = FALSE;
3850
3851   if (flush_queue)
3852     {
3853       /* We take this opportunity to invalidate any queue redraw entry
3854        * associated with the actor and descendants since we won't be able to
3855        * determine the appropriate stage after this.
3856        *
3857        * we do this after we updated the mapped state because actors might
3858        * end up queueing redraws inside their mapped/unmapped virtual
3859        * functions, and if we invalidate the redraw entry we could end up
3860        * with an inconsistent state and weird memory corruption. see
3861        * bugs:
3862        *
3863        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3864        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3865        */
3866       _clutter_actor_traverse (child,
3867                                0,
3868                                invalidate_queue_redraw_entry,
3869                                NULL,
3870                                NULL);
3871     }
3872
3873   old_first = self->priv->first_child;
3874   old_last = self->priv->last_child;
3875
3876   remove_child (self, child);
3877
3878   self->priv->n_children -= 1;
3879
3880   self->priv->age += 1;
3881
3882   /* clutter_actor_reparent() will emit ::parent-set for us */
3883   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3884     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3885
3886   /* if the child was mapped then we need to relayout ourselves to account
3887    * for the removed child
3888    */
3889   if (was_mapped)
3890     clutter_actor_queue_relayout (self);
3891
3892   /* we need to emit the signal before dropping the reference */
3893   if (emit_actor_removed)
3894     g_signal_emit_by_name (self, "actor-removed", child);
3895
3896   if (notify_first_last)
3897     {
3898       if (old_first != self->priv->first_child)
3899         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3900
3901       if (old_last != self->priv->last_child)
3902         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3903     }
3904
3905   g_object_thaw_notify (G_OBJECT (self));
3906
3907   /* remove the reference we acquired in clutter_actor_add_child() */
3908   g_object_unref (child);
3909 }
3910
3911 static const ClutterTransformInfo default_transform_info = {
3912   0.0, { 0, },          /* rotation-x */
3913   0.0, { 0, },          /* rotation-y */
3914   0.0, { 0, },          /* rotation-z */
3915
3916   1.0, 1.0, { 0, },     /* scale */
3917
3918   { 0, },               /* anchor */
3919
3920   0.0,                  /* depth */
3921 };
3922
3923 /*< private >
3924  * _clutter_actor_get_transform_info_or_defaults:
3925  * @self: a #ClutterActor
3926  *
3927  * Retrieves the ClutterTransformInfo structure associated to an actor.
3928  *
3929  * If the actor does not have a ClutterTransformInfo structure associated
3930  * to it, then the default structure will be returned.
3931  *
3932  * This function should only be used for getters.
3933  *
3934  * Return value: a const pointer to the ClutterTransformInfo structure
3935  */
3936 const ClutterTransformInfo *
3937 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3938 {
3939   ClutterTransformInfo *info;
3940
3941   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3942   if (info != NULL)
3943     return info;
3944
3945   return &default_transform_info;
3946 }
3947
3948 static void
3949 clutter_transform_info_free (gpointer data)
3950 {
3951   if (data != NULL)
3952     g_slice_free (ClutterTransformInfo, data);
3953 }
3954
3955 /*< private >
3956  * _clutter_actor_get_transform_info:
3957  * @self: a #ClutterActor
3958  *
3959  * Retrieves a pointer to the ClutterTransformInfo structure.
3960  *
3961  * If the actor does not have a ClutterTransformInfo associated to it, one
3962  * will be created and initialized to the default values.
3963  *
3964  * This function should be used for setters.
3965  *
3966  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3967  * instead.
3968  *
3969  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3970  *   structure
3971  */
3972 ClutterTransformInfo *
3973 _clutter_actor_get_transform_info (ClutterActor *self)
3974 {
3975   ClutterTransformInfo *info;
3976
3977   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3978   if (info == NULL)
3979     {
3980       info = g_slice_new (ClutterTransformInfo);
3981
3982       *info = default_transform_info;
3983
3984       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3985                                info,
3986                                clutter_transform_info_free);
3987     }
3988
3989   return info;
3990 }
3991
3992 /*< private >
3993  * clutter_actor_set_rotation_angle_internal:
3994  * @self: a #ClutterActor
3995  * @axis: the axis of the angle to change
3996  * @angle: the angle of rotation
3997  *
3998  * Sets the rotation angle on the given axis without affecting the
3999  * rotation center point.
4000  */
4001 static inline void
4002 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4003                                            ClutterRotateAxis  axis,
4004                                            gdouble            angle)
4005 {
4006   GObject *obj = G_OBJECT (self);
4007   ClutterTransformInfo *info;
4008
4009   info = _clutter_actor_get_transform_info (self);
4010
4011   g_object_freeze_notify (obj);
4012
4013   switch (axis)
4014     {
4015     case CLUTTER_X_AXIS:
4016       info->rx_angle = angle;
4017       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4018       break;
4019
4020     case CLUTTER_Y_AXIS:
4021       info->ry_angle = angle;
4022       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4023       break;
4024
4025     case CLUTTER_Z_AXIS:
4026       info->rz_angle = angle;
4027       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4028       break;
4029     }
4030
4031   self->priv->transform_valid = FALSE;
4032
4033   g_object_thaw_notify (obj);
4034
4035   clutter_actor_queue_redraw (self);
4036 }
4037
4038 static inline void
4039 clutter_actor_set_rotation_angle (ClutterActor      *self,
4040                                   ClutterRotateAxis  axis,
4041                                   gdouble            angle)
4042 {
4043   const ClutterTransformInfo *info;
4044   const double *cur_angle_p = NULL;
4045   GParamSpec *pspec = NULL;
4046
4047   info = _clutter_actor_get_transform_info_or_defaults (self);
4048
4049   switch (axis)
4050     {
4051     case CLUTTER_X_AXIS:
4052       cur_angle_p = &info->rx_angle;
4053       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4054       break;
4055
4056     case CLUTTER_Y_AXIS:
4057       cur_angle_p = &info->ry_angle;
4058       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4059       break;
4060
4061     case CLUTTER_Z_AXIS:
4062       cur_angle_p = &info->rz_angle;
4063       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4064       break;
4065     }
4066
4067   g_assert (pspec != NULL);
4068   g_assert (cur_angle_p != NULL);
4069
4070   if (_clutter_actor_get_transition (self, pspec) == NULL)
4071     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4072   else
4073     _clutter_actor_update_transition (self, pspec, angle);
4074
4075   clutter_actor_queue_redraw (self);
4076 }
4077
4078 /*< private >
4079  * clutter_actor_set_rotation_center_internal:
4080  * @self: a #ClutterActor
4081  * @axis: the axis of the center to change
4082  * @center: the coordinates of the rotation center
4083  *
4084  * Sets the rotation center on the given axis without affecting the
4085  * rotation angle.
4086  */
4087 static inline void
4088 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4089                                             ClutterRotateAxis    axis,
4090                                             const ClutterVertex *center)
4091 {
4092   GObject *obj = G_OBJECT (self);
4093   ClutterTransformInfo *info;
4094   ClutterVertex v = { 0, 0, 0 };
4095
4096   info = _clutter_actor_get_transform_info (self);
4097
4098   if (center != NULL)
4099     v = *center;
4100
4101   g_object_freeze_notify (obj);
4102
4103   switch (axis)
4104     {
4105     case CLUTTER_X_AXIS:
4106       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4107       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4108       break;
4109
4110     case CLUTTER_Y_AXIS:
4111       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4112       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4113       break;
4114
4115     case CLUTTER_Z_AXIS:
4116       /* if the previously set rotation center was fractional, then
4117        * setting explicit coordinates will have to notify the
4118        * :rotation-center-z-gravity property as well
4119        */
4120       if (info->rz_center.is_fractional)
4121         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4122
4123       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4124       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4125       break;
4126     }
4127
4128   self->priv->transform_valid = FALSE;
4129
4130   g_object_thaw_notify (obj);
4131
4132   clutter_actor_queue_redraw (self);
4133 }
4134
4135 static void
4136 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4137                                          double factor,
4138                                          GParamSpec *pspec)
4139 {
4140   GObject *obj = G_OBJECT (self);
4141   ClutterTransformInfo *info;
4142
4143   info = _clutter_actor_get_transform_info (self);
4144
4145   if (pspec == obj_props[PROP_SCALE_X])
4146     info->scale_x = factor;
4147   else
4148     info->scale_y = factor;
4149
4150   self->priv->transform_valid = FALSE;
4151   clutter_actor_queue_redraw (self);
4152   g_object_notify_by_pspec (obj, pspec);
4153 }
4154
4155 static inline void
4156 clutter_actor_set_scale_factor (ClutterActor      *self,
4157                                 ClutterRotateAxis  axis,
4158                                 gdouble            factor)
4159 {
4160   const ClutterTransformInfo *info;
4161   const double *scale_p = NULL;
4162   GParamSpec *pspec = NULL;
4163
4164   info = _clutter_actor_get_transform_info_or_defaults (self);
4165
4166   switch (axis)
4167     {
4168     case CLUTTER_X_AXIS:
4169       pspec = obj_props[PROP_SCALE_X];
4170       scale_p = &info->scale_x;
4171       break;
4172
4173     case CLUTTER_Y_AXIS:
4174       pspec = obj_props[PROP_SCALE_Y];
4175       scale_p = &info->scale_y;
4176       break;
4177
4178     case CLUTTER_Z_AXIS:
4179       break;
4180     }
4181
4182   g_assert (pspec != NULL);
4183   g_assert (scale_p != NULL);
4184
4185   if (_clutter_actor_get_transition (self, pspec) == NULL)
4186     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4187   else
4188     _clutter_actor_update_transition (self, pspec, factor);
4189
4190   clutter_actor_queue_redraw (self);
4191 }
4192
4193 static inline void
4194 clutter_actor_set_scale_center (ClutterActor      *self,
4195                                 ClutterRotateAxis  axis,
4196                                 gfloat             coord)
4197 {
4198   GObject *obj = G_OBJECT (self);
4199   ClutterTransformInfo *info;
4200   gfloat center_x, center_y;
4201
4202   info = _clutter_actor_get_transform_info (self);
4203
4204   g_object_freeze_notify (obj);
4205
4206   /* get the current scale center coordinates */
4207   clutter_anchor_coord_get_units (self, &info->scale_center,
4208                                   &center_x,
4209                                   &center_y,
4210                                   NULL);
4211
4212   /* we need to notify this too, because setting explicit coordinates will
4213    * change the gravity as a side effect
4214    */
4215   if (info->scale_center.is_fractional)
4216     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4217
4218   switch (axis)
4219     {
4220     case CLUTTER_X_AXIS:
4221       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4222       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4223       break;
4224
4225     case CLUTTER_Y_AXIS:
4226       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4227       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4228       break;
4229
4230     default:
4231       g_assert_not_reached ();
4232     }
4233
4234   self->priv->transform_valid = FALSE;
4235
4236   clutter_actor_queue_redraw (self);
4237
4238   g_object_thaw_notify (obj);
4239 }
4240
4241 static inline void
4242 clutter_actor_set_scale_gravity (ClutterActor   *self,
4243                                  ClutterGravity  gravity)
4244 {
4245   ClutterTransformInfo *info;
4246   GObject *obj;
4247
4248   info = _clutter_actor_get_transform_info (self);
4249   obj = G_OBJECT (self);
4250
4251   if (gravity == CLUTTER_GRAVITY_NONE)
4252     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4253   else
4254     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4255
4256   self->priv->transform_valid = FALSE;
4257
4258   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4259   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4260   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4261
4262   clutter_actor_queue_redraw (self);
4263 }
4264
4265 static inline void
4266 clutter_actor_set_anchor_coord (ClutterActor      *self,
4267                                 ClutterRotateAxis  axis,
4268                                 gfloat             coord)
4269 {
4270   GObject *obj = G_OBJECT (self);
4271   ClutterTransformInfo *info;
4272   gfloat anchor_x, anchor_y;
4273
4274   info = _clutter_actor_get_transform_info (self);
4275
4276   g_object_freeze_notify (obj);
4277
4278   clutter_anchor_coord_get_units (self, &info->anchor,
4279                                   &anchor_x,
4280                                   &anchor_y,
4281                                   NULL);
4282
4283   if (info->anchor.is_fractional)
4284     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4285
4286   switch (axis)
4287     {
4288     case CLUTTER_X_AXIS:
4289       clutter_anchor_coord_set_units (&info->anchor,
4290                                       coord,
4291                                       anchor_y,
4292                                       0.0);
4293       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4294       break;
4295
4296     case CLUTTER_Y_AXIS:
4297       clutter_anchor_coord_set_units (&info->anchor,
4298                                       anchor_x,
4299                                       coord,
4300                                       0.0);
4301       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4302       break;
4303
4304     default:
4305       g_assert_not_reached ();
4306     }
4307
4308   self->priv->transform_valid = FALSE;
4309
4310   clutter_actor_queue_redraw (self);
4311
4312   g_object_thaw_notify (obj);
4313 }
4314
4315 static void
4316 clutter_actor_set_property (GObject      *object,
4317                             guint         prop_id,
4318                             const GValue *value,
4319                             GParamSpec   *pspec)
4320 {
4321   ClutterActor *actor = CLUTTER_ACTOR (object);
4322   ClutterActorPrivate *priv = actor->priv;
4323
4324   switch (prop_id)
4325     {
4326     case PROP_X:
4327       clutter_actor_set_x (actor, g_value_get_float (value));
4328       break;
4329
4330     case PROP_Y:
4331       clutter_actor_set_y (actor, g_value_get_float (value));
4332       break;
4333
4334     case PROP_WIDTH:
4335       clutter_actor_set_width (actor, g_value_get_float (value));
4336       break;
4337
4338     case PROP_HEIGHT:
4339       clutter_actor_set_height (actor, g_value_get_float (value));
4340       break;
4341
4342     case PROP_FIXED_X:
4343       clutter_actor_set_x (actor, g_value_get_float (value));
4344       break;
4345
4346     case PROP_FIXED_Y:
4347       clutter_actor_set_y (actor, g_value_get_float (value));
4348       break;
4349
4350     case PROP_FIXED_POSITION_SET:
4351       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4352       break;
4353
4354     case PROP_MIN_WIDTH:
4355       clutter_actor_set_min_width (actor, g_value_get_float (value));
4356       break;
4357
4358     case PROP_MIN_HEIGHT:
4359       clutter_actor_set_min_height (actor, g_value_get_float (value));
4360       break;
4361
4362     case PROP_NATURAL_WIDTH:
4363       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4364       break;
4365
4366     case PROP_NATURAL_HEIGHT:
4367       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4368       break;
4369
4370     case PROP_MIN_WIDTH_SET:
4371       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4372       break;
4373
4374     case PROP_MIN_HEIGHT_SET:
4375       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4376       break;
4377
4378     case PROP_NATURAL_WIDTH_SET:
4379       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4380       break;
4381
4382     case PROP_NATURAL_HEIGHT_SET:
4383       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4384       break;
4385
4386     case PROP_REQUEST_MODE:
4387       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4388       break;
4389
4390     case PROP_DEPTH:
4391       clutter_actor_set_depth (actor, g_value_get_float (value));
4392       break;
4393
4394     case PROP_OPACITY:
4395       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4396       break;
4397
4398     case PROP_OFFSCREEN_REDIRECT:
4399       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4400       break;
4401
4402     case PROP_NAME:
4403       clutter_actor_set_name (actor, g_value_get_string (value));
4404       break;
4405
4406     case PROP_VISIBLE:
4407       if (g_value_get_boolean (value) == TRUE)
4408         clutter_actor_show (actor);
4409       else
4410         clutter_actor_hide (actor);
4411       break;
4412
4413     case PROP_SCALE_X:
4414       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4415                                       g_value_get_double (value));
4416       break;
4417
4418     case PROP_SCALE_Y:
4419       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4420                                       g_value_get_double (value));
4421       break;
4422
4423     case PROP_SCALE_CENTER_X:
4424       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4425                                       g_value_get_float (value));
4426       break;
4427
4428     case PROP_SCALE_CENTER_Y:
4429       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4430                                       g_value_get_float (value));
4431       break;
4432
4433     case PROP_SCALE_GRAVITY:
4434       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4435       break;
4436
4437     case PROP_CLIP:
4438       {
4439         const ClutterGeometry *geom = g_value_get_boxed (value);
4440
4441         clutter_actor_set_clip (actor,
4442                                 geom->x, geom->y,
4443                                 geom->width, geom->height);
4444       }
4445       break;
4446
4447     case PROP_CLIP_TO_ALLOCATION:
4448       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4449       break;
4450
4451     case PROP_REACTIVE:
4452       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4453       break;
4454
4455     case PROP_ROTATION_ANGLE_X:
4456       clutter_actor_set_rotation_angle (actor,
4457                                         CLUTTER_X_AXIS,
4458                                         g_value_get_double (value));
4459       break;
4460
4461     case PROP_ROTATION_ANGLE_Y:
4462       clutter_actor_set_rotation_angle (actor,
4463                                         CLUTTER_Y_AXIS,
4464                                         g_value_get_double (value));
4465       break;
4466
4467     case PROP_ROTATION_ANGLE_Z:
4468       clutter_actor_set_rotation_angle (actor,
4469                                         CLUTTER_Z_AXIS,
4470                                         g_value_get_double (value));
4471       break;
4472
4473     case PROP_ROTATION_CENTER_X:
4474       clutter_actor_set_rotation_center_internal (actor,
4475                                                   CLUTTER_X_AXIS,
4476                                                   g_value_get_boxed (value));
4477       break;
4478
4479     case PROP_ROTATION_CENTER_Y:
4480       clutter_actor_set_rotation_center_internal (actor,
4481                                                   CLUTTER_Y_AXIS,
4482                                                   g_value_get_boxed (value));
4483       break;
4484
4485     case PROP_ROTATION_CENTER_Z:
4486       clutter_actor_set_rotation_center_internal (actor,
4487                                                   CLUTTER_Z_AXIS,
4488                                                   g_value_get_boxed (value));
4489       break;
4490
4491     case PROP_ROTATION_CENTER_Z_GRAVITY:
4492       {
4493         const ClutterTransformInfo *info;
4494
4495         info = _clutter_actor_get_transform_info_or_defaults (actor);
4496         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4497                                                    g_value_get_enum (value));
4498       }
4499       break;
4500
4501     case PROP_ANCHOR_X:
4502       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4503                                       g_value_get_float (value));
4504       break;
4505
4506     case PROP_ANCHOR_Y:
4507       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4508                                       g_value_get_float (value));
4509       break;
4510
4511     case PROP_ANCHOR_GRAVITY:
4512       clutter_actor_set_anchor_point_from_gravity (actor,
4513                                                    g_value_get_enum (value));
4514       break;
4515
4516     case PROP_SHOW_ON_SET_PARENT:
4517       priv->show_on_set_parent = g_value_get_boolean (value);
4518       break;
4519
4520     case PROP_TEXT_DIRECTION:
4521       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4522       break;
4523
4524     case PROP_ACTIONS:
4525       clutter_actor_add_action (actor, g_value_get_object (value));
4526       break;
4527
4528     case PROP_CONSTRAINTS:
4529       clutter_actor_add_constraint (actor, g_value_get_object (value));
4530       break;
4531
4532     case PROP_EFFECT:
4533       clutter_actor_add_effect (actor, g_value_get_object (value));
4534       break;
4535
4536     case PROP_LAYOUT_MANAGER:
4537       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4538       break;
4539
4540     case PROP_X_ALIGN:
4541       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4542       break;
4543
4544     case PROP_Y_ALIGN:
4545       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4546       break;
4547
4548     case PROP_MARGIN_TOP:
4549       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4550       break;
4551
4552     case PROP_MARGIN_BOTTOM:
4553       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4554       break;
4555
4556     case PROP_MARGIN_LEFT:
4557       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4558       break;
4559
4560     case PROP_MARGIN_RIGHT:
4561       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4562       break;
4563
4564     case PROP_BACKGROUND_COLOR:
4565       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4566       break;
4567
4568     case PROP_CONTENT:
4569       clutter_actor_set_content (actor, g_value_get_object (value));
4570       break;
4571
4572     case PROP_CONTENT_GRAVITY:
4573       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4574       break;
4575
4576     case PROP_MINIFICATION_FILTER:
4577       clutter_actor_set_content_scaling_filters (actor,
4578                                                  g_value_get_enum (value),
4579                                                  actor->priv->mag_filter);
4580       break;
4581
4582     case PROP_MAGNIFICATION_FILTER:
4583       clutter_actor_set_content_scaling_filters (actor,
4584                                                  actor->priv->min_filter,
4585                                                  g_value_get_enum (value));
4586       break;
4587
4588     default:
4589       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4590       break;
4591     }
4592 }
4593
4594 static void
4595 clutter_actor_get_property (GObject    *object,
4596                             guint       prop_id,
4597                             GValue     *value,
4598                             GParamSpec *pspec)
4599 {
4600   ClutterActor *actor = CLUTTER_ACTOR (object);
4601   ClutterActorPrivate *priv = actor->priv;
4602
4603   switch (prop_id)
4604     {
4605     case PROP_X:
4606       g_value_set_float (value, clutter_actor_get_x (actor));
4607       break;
4608
4609     case PROP_Y:
4610       g_value_set_float (value, clutter_actor_get_y (actor));
4611       break;
4612
4613     case PROP_WIDTH:
4614       g_value_set_float (value, clutter_actor_get_width (actor));
4615       break;
4616
4617     case PROP_HEIGHT:
4618       g_value_set_float (value, clutter_actor_get_height (actor));
4619       break;
4620
4621     case PROP_FIXED_X:
4622       {
4623         const ClutterLayoutInfo *info;
4624
4625         info = _clutter_actor_get_layout_info_or_defaults (actor);
4626         g_value_set_float (value, info->fixed_x);
4627       }
4628       break;
4629
4630     case PROP_FIXED_Y:
4631       {
4632         const ClutterLayoutInfo *info;
4633
4634         info = _clutter_actor_get_layout_info_or_defaults (actor);
4635         g_value_set_float (value, info->fixed_y);
4636       }
4637       break;
4638
4639     case PROP_FIXED_POSITION_SET:
4640       g_value_set_boolean (value, priv->position_set);
4641       break;
4642
4643     case PROP_MIN_WIDTH:
4644       {
4645         const ClutterLayoutInfo *info;
4646
4647         info = _clutter_actor_get_layout_info_or_defaults (actor);
4648         g_value_set_float (value, info->min_width);
4649       }
4650       break;
4651
4652     case PROP_MIN_HEIGHT:
4653       {
4654         const ClutterLayoutInfo *info;
4655
4656         info = _clutter_actor_get_layout_info_or_defaults (actor);
4657         g_value_set_float (value, info->min_height);
4658       }
4659       break;
4660
4661     case PROP_NATURAL_WIDTH:
4662       {
4663         const ClutterLayoutInfo *info;
4664
4665         info = _clutter_actor_get_layout_info_or_defaults (actor);
4666         g_value_set_float (value, info->natural_width);
4667       }
4668       break;
4669
4670     case PROP_NATURAL_HEIGHT:
4671       {
4672         const ClutterLayoutInfo *info;
4673
4674         info = _clutter_actor_get_layout_info_or_defaults (actor);
4675         g_value_set_float (value, info->natural_height);
4676       }
4677       break;
4678
4679     case PROP_MIN_WIDTH_SET:
4680       g_value_set_boolean (value, priv->min_width_set);
4681       break;
4682
4683     case PROP_MIN_HEIGHT_SET:
4684       g_value_set_boolean (value, priv->min_height_set);
4685       break;
4686
4687     case PROP_NATURAL_WIDTH_SET:
4688       g_value_set_boolean (value, priv->natural_width_set);
4689       break;
4690
4691     case PROP_NATURAL_HEIGHT_SET:
4692       g_value_set_boolean (value, priv->natural_height_set);
4693       break;
4694
4695     case PROP_REQUEST_MODE:
4696       g_value_set_enum (value, priv->request_mode);
4697       break;
4698
4699     case PROP_ALLOCATION:
4700       g_value_set_boxed (value, &priv->allocation);
4701       break;
4702
4703     case PROP_DEPTH:
4704       g_value_set_float (value, clutter_actor_get_depth (actor));
4705       break;
4706
4707     case PROP_OPACITY:
4708       g_value_set_uint (value, priv->opacity);
4709       break;
4710
4711     case PROP_OFFSCREEN_REDIRECT:
4712       g_value_set_enum (value, priv->offscreen_redirect);
4713       break;
4714
4715     case PROP_NAME:
4716       g_value_set_string (value, priv->name);
4717       break;
4718
4719     case PROP_VISIBLE:
4720       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4721       break;
4722
4723     case PROP_MAPPED:
4724       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4725       break;
4726
4727     case PROP_REALIZED:
4728       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4729       break;
4730
4731     case PROP_HAS_CLIP:
4732       g_value_set_boolean (value, priv->has_clip);
4733       break;
4734
4735     case PROP_CLIP:
4736       {
4737         ClutterGeometry clip;
4738
4739         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4740         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4741         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4742         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4743
4744         g_value_set_boxed (value, &clip);
4745       }
4746       break;
4747
4748     case PROP_CLIP_TO_ALLOCATION:
4749       g_value_set_boolean (value, priv->clip_to_allocation);
4750       break;
4751
4752     case PROP_SCALE_X:
4753       {
4754         const ClutterTransformInfo *info;
4755
4756         info = _clutter_actor_get_transform_info_or_defaults (actor);
4757         g_value_set_double (value, info->scale_x);
4758       }
4759       break;
4760
4761     case PROP_SCALE_Y:
4762       {
4763         const ClutterTransformInfo *info;
4764
4765         info = _clutter_actor_get_transform_info_or_defaults (actor);
4766         g_value_set_double (value, info->scale_y);
4767       }
4768       break;
4769
4770     case PROP_SCALE_CENTER_X:
4771       {
4772         gfloat center;
4773
4774         clutter_actor_get_scale_center (actor, &center, NULL);
4775
4776         g_value_set_float (value, center);
4777       }
4778       break;
4779
4780     case PROP_SCALE_CENTER_Y:
4781       {
4782         gfloat center;
4783
4784         clutter_actor_get_scale_center (actor, NULL, &center);
4785
4786         g_value_set_float (value, center);
4787       }
4788       break;
4789
4790     case PROP_SCALE_GRAVITY:
4791       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4792       break;
4793
4794     case PROP_REACTIVE:
4795       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4796       break;
4797
4798     case PROP_ROTATION_ANGLE_X:
4799       {
4800         const ClutterTransformInfo *info;
4801
4802         info = _clutter_actor_get_transform_info_or_defaults (actor);
4803         g_value_set_double (value, info->rx_angle);
4804       }
4805       break;
4806
4807     case PROP_ROTATION_ANGLE_Y:
4808       {
4809         const ClutterTransformInfo *info;
4810
4811         info = _clutter_actor_get_transform_info_or_defaults (actor);
4812         g_value_set_double (value, info->ry_angle);
4813       }
4814       break;
4815
4816     case PROP_ROTATION_ANGLE_Z:
4817       {
4818         const ClutterTransformInfo *info;
4819
4820         info = _clutter_actor_get_transform_info_or_defaults (actor);
4821         g_value_set_double (value, info->rz_angle);
4822       }
4823       break;
4824
4825     case PROP_ROTATION_CENTER_X:
4826       {
4827         ClutterVertex center;
4828
4829         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4830                                     &center.x,
4831                                     &center.y,
4832                                     &center.z);
4833
4834         g_value_set_boxed (value, &center);
4835       }
4836       break;
4837
4838     case PROP_ROTATION_CENTER_Y:
4839       {
4840         ClutterVertex center;
4841
4842         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4843                                     &center.x,
4844                                     &center.y,
4845                                     &center.z);
4846
4847         g_value_set_boxed (value, &center);
4848       }
4849       break;
4850
4851     case PROP_ROTATION_CENTER_Z:
4852       {
4853         ClutterVertex center;
4854
4855         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4856                                     &center.x,
4857                                     &center.y,
4858                                     &center.z);
4859
4860         g_value_set_boxed (value, &center);
4861       }
4862       break;
4863
4864     case PROP_ROTATION_CENTER_Z_GRAVITY:
4865       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4866       break;
4867
4868     case PROP_ANCHOR_X:
4869       {
4870         const ClutterTransformInfo *info;
4871         gfloat anchor_x;
4872
4873         info = _clutter_actor_get_transform_info_or_defaults (actor);
4874         clutter_anchor_coord_get_units (actor, &info->anchor,
4875                                         &anchor_x,
4876                                         NULL,
4877                                         NULL);
4878         g_value_set_float (value, anchor_x);
4879       }
4880       break;
4881
4882     case PROP_ANCHOR_Y:
4883       {
4884         const ClutterTransformInfo *info;
4885         gfloat anchor_y;
4886
4887         info = _clutter_actor_get_transform_info_or_defaults (actor);
4888         clutter_anchor_coord_get_units (actor, &info->anchor,
4889                                         NULL,
4890                                         &anchor_y,
4891                                         NULL);
4892         g_value_set_float (value, anchor_y);
4893       }
4894       break;
4895
4896     case PROP_ANCHOR_GRAVITY:
4897       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4898       break;
4899
4900     case PROP_SHOW_ON_SET_PARENT:
4901       g_value_set_boolean (value, priv->show_on_set_parent);
4902       break;
4903
4904     case PROP_TEXT_DIRECTION:
4905       g_value_set_enum (value, priv->text_direction);
4906       break;
4907
4908     case PROP_HAS_POINTER:
4909       g_value_set_boolean (value, priv->has_pointer);
4910       break;
4911
4912     case PROP_LAYOUT_MANAGER:
4913       g_value_set_object (value, priv->layout_manager);
4914       break;
4915
4916     case PROP_X_ALIGN:
4917       {
4918         const ClutterLayoutInfo *info;
4919
4920         info = _clutter_actor_get_layout_info_or_defaults (actor);
4921         g_value_set_enum (value, info->x_align);
4922       }
4923       break;
4924
4925     case PROP_Y_ALIGN:
4926       {
4927         const ClutterLayoutInfo *info;
4928
4929         info = _clutter_actor_get_layout_info_or_defaults (actor);
4930         g_value_set_enum (value, info->y_align);
4931       }
4932       break;
4933
4934     case PROP_MARGIN_TOP:
4935       {
4936         const ClutterLayoutInfo *info;
4937
4938         info = _clutter_actor_get_layout_info_or_defaults (actor);
4939         g_value_set_float (value, info->margin.top);
4940       }
4941       break;
4942
4943     case PROP_MARGIN_BOTTOM:
4944       {
4945         const ClutterLayoutInfo *info;
4946
4947         info = _clutter_actor_get_layout_info_or_defaults (actor);
4948         g_value_set_float (value, info->margin.bottom);
4949       }
4950       break;
4951
4952     case PROP_MARGIN_LEFT:
4953       {
4954         const ClutterLayoutInfo *info;
4955
4956         info = _clutter_actor_get_layout_info_or_defaults (actor);
4957         g_value_set_float (value, info->margin.left);
4958       }
4959       break;
4960
4961     case PROP_MARGIN_RIGHT:
4962       {
4963         const ClutterLayoutInfo *info;
4964
4965         info = _clutter_actor_get_layout_info_or_defaults (actor);
4966         g_value_set_float (value, info->margin.right);
4967       }
4968       break;
4969
4970     case PROP_BACKGROUND_COLOR_SET:
4971       g_value_set_boolean (value, priv->bg_color_set);
4972       break;
4973
4974     case PROP_BACKGROUND_COLOR:
4975       g_value_set_boxed (value, &priv->bg_color);
4976       break;
4977
4978     case PROP_FIRST_CHILD:
4979       g_value_set_object (value, priv->first_child);
4980       break;
4981
4982     case PROP_LAST_CHILD:
4983       g_value_set_object (value, priv->last_child);
4984       break;
4985
4986     case PROP_CONTENT:
4987       g_value_set_object (value, priv->content);
4988       break;
4989
4990     case PROP_CONTENT_GRAVITY:
4991       g_value_set_enum (value, priv->content_gravity);
4992       break;
4993
4994     case PROP_CONTENT_BOX:
4995       {
4996         ClutterActorBox box = { 0, };
4997
4998         clutter_actor_get_content_box (actor, &box);
4999         g_value_set_boxed (value, &box);
5000       }
5001       break;
5002
5003     case PROP_MINIFICATION_FILTER:
5004       g_value_set_enum (value, priv->min_filter);
5005       break;
5006
5007     case PROP_MAGNIFICATION_FILTER:
5008       g_value_set_enum (value, priv->mag_filter);
5009       break;
5010
5011     default:
5012       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5013       break;
5014     }
5015 }
5016
5017 static void
5018 clutter_actor_dispose (GObject *object)
5019 {
5020   ClutterActor *self = CLUTTER_ACTOR (object);
5021   ClutterActorPrivate *priv = self->priv;
5022
5023   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5024                 priv->id,
5025                 g_type_name (G_OBJECT_TYPE (self)),
5026                 object->ref_count);
5027
5028   g_signal_emit (self, actor_signals[DESTROY], 0);
5029
5030   /* avoid recursing when called from clutter_actor_destroy() */
5031   if (priv->parent != NULL)
5032     {
5033       ClutterActor *parent = priv->parent;
5034
5035       /* go through the Container implementation unless this
5036        * is an internal child and has been marked as such.
5037        *
5038        * removing the actor from its parent will reset the
5039        * realized and mapped states.
5040        */
5041       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5042         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5043       else
5044         clutter_actor_remove_child_internal (parent, self,
5045                                              REMOVE_CHILD_LEGACY_FLAGS);
5046     }
5047
5048   /* parent must be gone at this point */
5049   g_assert (priv->parent == NULL);
5050
5051   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5052     {
5053       /* can't be mapped or realized with no parent */
5054       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5055       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5056     }
5057
5058   g_clear_object (&priv->pango_context);
5059   g_clear_object (&priv->actions);
5060   g_clear_object (&priv->constraints);
5061   g_clear_object (&priv->effects);
5062   g_clear_object (&priv->flatten_effect);
5063
5064   if (priv->layout_manager != NULL)
5065     {
5066       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5067       g_clear_object (&priv->layout_manager);
5068     }
5069
5070   if (priv->content != NULL)
5071     {
5072       _clutter_content_detached (priv->content, self);
5073       g_clear_object (&priv->content);
5074     }
5075
5076   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5077 }
5078
5079 static void
5080 clutter_actor_finalize (GObject *object)
5081 {
5082   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5083
5084   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5085                 priv->name != NULL ? priv->name : "<none>",
5086                 priv->id,
5087                 g_type_name (G_OBJECT_TYPE (object)));
5088
5089   _clutter_context_release_id (priv->id);
5090
5091   g_free (priv->name);
5092
5093   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5094 }
5095
5096
5097 /**
5098  * clutter_actor_get_accessible:
5099  * @self: a #ClutterActor
5100  *
5101  * Returns the accessible object that describes the actor to an
5102  * assistive technology.
5103  *
5104  * If no class-specific #AtkObject implementation is available for the
5105  * actor instance in question, it will inherit an #AtkObject
5106  * implementation from the first ancestor class for which such an
5107  * implementation is defined.
5108  *
5109  * The documentation of the <ulink
5110  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5111  * library contains more information about accessible objects and
5112  * their uses.
5113  *
5114  * Returns: (transfer none): the #AtkObject associated with @actor
5115  */
5116 AtkObject *
5117 clutter_actor_get_accessible (ClutterActor *self)
5118 {
5119   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5120
5121   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5122 }
5123
5124 static AtkObject *
5125 clutter_actor_real_get_accessible (ClutterActor *actor)
5126 {
5127   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5128 }
5129
5130 static AtkObject *
5131 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5132 {
5133   AtkObject *accessible;
5134
5135   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5136   if (accessible != NULL)
5137     g_object_ref (accessible);
5138
5139   return accessible;
5140 }
5141
5142 static void
5143 atk_implementor_iface_init (AtkImplementorIface *iface)
5144 {
5145   iface->ref_accessible = _clutter_actor_ref_accessible;
5146 }
5147
5148 static gboolean
5149 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5150                                            ClutterPaintVolume *volume)
5151 {
5152   ClutterActorPrivate *priv = self->priv;
5153   gboolean res = TRUE;
5154
5155   /* we start from the allocation */
5156   clutter_paint_volume_set_width (volume,
5157                                   priv->allocation.x2 - priv->allocation.x1);
5158   clutter_paint_volume_set_height (volume,
5159                                    priv->allocation.y2 - priv->allocation.y1);
5160
5161   /* if the actor has a clip set then we have a pretty definite
5162    * size for the paint volume: the actor cannot possibly paint
5163    * outside the clip region.
5164    */
5165   if (priv->clip_to_allocation)
5166     {
5167       /* the allocation has already been set, so we just flip the
5168        * return value
5169        */
5170       res = TRUE;
5171     }
5172   else
5173     {
5174       ClutterActor *child;
5175
5176       if (priv->has_clip &&
5177           priv->clip.width >= 0 &&
5178           priv->clip.height >= 0)
5179         {
5180           ClutterVertex origin;
5181
5182           origin.x = priv->clip.x;
5183           origin.y = priv->clip.y;
5184           origin.z = 0;
5185
5186           clutter_paint_volume_set_origin (volume, &origin);
5187           clutter_paint_volume_set_width (volume, priv->clip.width);
5188           clutter_paint_volume_set_height (volume, priv->clip.height);
5189
5190           res = TRUE;
5191         }
5192
5193       /* if we don't have children we just bail out here... */
5194       if (priv->n_children == 0)
5195         return res;
5196
5197       /* ...but if we have children then we ask for their paint volume in
5198        * our coordinates. if any of our children replies that it doesn't
5199        * have a paint volume, we bail out
5200        */
5201       for (child = priv->first_child;
5202            child != NULL;
5203            child = child->priv->next_sibling)
5204         {
5205           const ClutterPaintVolume *child_volume;
5206
5207           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5208             continue;
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   /* update_default_paint_volume() should only fail if one of the children
5254    * reported an invalid, or no, paint volume
5255    */
5256   if (!clutter_actor_update_default_paint_volume (self, volume))
5257     return FALSE;
5258
5259   return res;
5260 }
5261
5262 /**
5263  * clutter_actor_get_default_paint_volume:
5264  * @self: a #ClutterActor
5265  *
5266  * Retrieves the default paint volume for @self.
5267  *
5268  * This function provides the same #ClutterPaintVolume that would be
5269  * computed by the default implementation inside #ClutterActor of the
5270  * #ClutterActorClass.get_paint_volume() virtual function.
5271  *
5272  * This function should only be used by #ClutterActor subclasses that
5273  * cannot chain up to the parent implementation when computing their
5274  * paint volume.
5275  *
5276  * Return value: (transfer none): a pointer to the default
5277  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5278  *   the actor could not compute a valid paint volume. The returned value
5279  *   is not guaranteed to be stable across multiple frames, so if you
5280  *   want to retain it, you will need to copy it using
5281  *   clutter_paint_volume_copy().
5282  *
5283  * Since: 1.10
5284  */
5285 const ClutterPaintVolume *
5286 clutter_actor_get_default_paint_volume (ClutterActor *self)
5287 {
5288   ClutterPaintVolume volume;
5289   ClutterPaintVolume *res;
5290
5291   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5292
5293   res = NULL;
5294   _clutter_paint_volume_init_static (&volume, self);
5295   if (clutter_actor_update_default_paint_volume (self, &volume))
5296     {
5297       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5298
5299       if (stage != NULL)
5300         {
5301           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5302           _clutter_paint_volume_copy_static (&volume, res);
5303         }
5304     }
5305
5306   clutter_paint_volume_free (&volume);
5307
5308   return res;
5309 }
5310
5311 static gboolean
5312 clutter_actor_real_has_overlaps (ClutterActor *self)
5313 {
5314   /* By default we'll assume that all actors need an offscreen redirect to get
5315    * the correct opacity. Actors such as ClutterTexture that would never need
5316    * an offscreen redirect can override this to return FALSE. */
5317   return TRUE;
5318 }
5319
5320 static void
5321 clutter_actor_real_destroy (ClutterActor *actor)
5322 {
5323   ClutterActorIter iter;
5324
5325   g_object_freeze_notify (G_OBJECT (actor));
5326
5327   clutter_actor_iter_init (&iter, actor);
5328   while (clutter_actor_iter_next (&iter, NULL))
5329     clutter_actor_iter_destroy (&iter);
5330
5331   g_object_thaw_notify (G_OBJECT (actor));
5332 }
5333
5334 static GObject *
5335 clutter_actor_constructor (GType gtype,
5336                            guint n_props,
5337                            GObjectConstructParam *props)
5338 {
5339   GObjectClass *gobject_class;
5340   ClutterActor *self;
5341   GObject *retval;
5342
5343   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5344   retval = gobject_class->constructor (gtype, n_props, props);
5345   self = CLUTTER_ACTOR (retval);
5346
5347   if (self->priv->layout_manager == NULL)
5348     {
5349       ClutterLayoutManager *default_layout;
5350
5351       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5352
5353       default_layout = clutter_fixed_layout_new ();
5354       clutter_actor_set_layout_manager (self, default_layout);
5355     }
5356
5357   return retval;
5358 }
5359
5360 static void
5361 clutter_actor_class_init (ClutterActorClass *klass)
5362 {
5363   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5364
5365   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5366   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5367   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5368   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5369
5370   object_class->constructor = clutter_actor_constructor;
5371   object_class->set_property = clutter_actor_set_property;
5372   object_class->get_property = clutter_actor_get_property;
5373   object_class->dispose = clutter_actor_dispose;
5374   object_class->finalize = clutter_actor_finalize;
5375
5376   klass->show = clutter_actor_real_show;
5377   klass->show_all = clutter_actor_show;
5378   klass->hide = clutter_actor_real_hide;
5379   klass->hide_all = clutter_actor_hide;
5380   klass->map = clutter_actor_real_map;
5381   klass->unmap = clutter_actor_real_unmap;
5382   klass->unrealize = clutter_actor_real_unrealize;
5383   klass->pick = clutter_actor_real_pick;
5384   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5385   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5386   klass->allocate = clutter_actor_real_allocate;
5387   klass->queue_redraw = clutter_actor_real_queue_redraw;
5388   klass->queue_relayout = clutter_actor_real_queue_relayout;
5389   klass->apply_transform = clutter_actor_real_apply_transform;
5390   klass->get_accessible = clutter_actor_real_get_accessible;
5391   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5392   klass->has_overlaps = clutter_actor_real_has_overlaps;
5393   klass->paint = clutter_actor_real_paint;
5394   klass->destroy = clutter_actor_real_destroy;
5395
5396   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5397
5398   /**
5399    * ClutterActor:x:
5400    *
5401    * X coordinate of the actor in pixels. If written, forces a fixed
5402    * position for the actor. If read, returns the fixed position if any,
5403    * otherwise the allocation if available, otherwise 0.
5404    *
5405    * The #ClutterActor:x property is animatable.
5406    */
5407   obj_props[PROP_X] =
5408     g_param_spec_float ("x",
5409                         P_("X coordinate"),
5410                         P_("X coordinate of the actor"),
5411                         -G_MAXFLOAT, G_MAXFLOAT,
5412                         0.0,
5413                         G_PARAM_READWRITE |
5414                         G_PARAM_STATIC_STRINGS |
5415                         CLUTTER_PARAM_ANIMATABLE);
5416
5417   /**
5418    * ClutterActor:y:
5419    *
5420    * Y coordinate of the actor in pixels. If written, forces a fixed
5421    * position for the actor.  If read, returns the fixed position if
5422    * any, otherwise the allocation if available, otherwise 0.
5423    *
5424    * The #ClutterActor:y property is animatable.
5425    */
5426   obj_props[PROP_Y] =
5427     g_param_spec_float ("y",
5428                         P_("Y coordinate"),
5429                         P_("Y coordinate of the actor"),
5430                         -G_MAXFLOAT, G_MAXFLOAT,
5431                         0.0,
5432                         G_PARAM_READWRITE |
5433                         G_PARAM_STATIC_STRINGS |
5434                         CLUTTER_PARAM_ANIMATABLE);
5435
5436   /**
5437    * ClutterActor:width:
5438    *
5439    * Width of the actor (in pixels). If written, forces the minimum and
5440    * natural size request of the actor to the given width. If read, returns
5441    * the allocated width if available, otherwise the width request.
5442    *
5443    * The #ClutterActor:width property is animatable.
5444    */
5445   obj_props[PROP_WIDTH] =
5446     g_param_spec_float ("width",
5447                         P_("Width"),
5448                         P_("Width of the actor"),
5449                         0.0, G_MAXFLOAT,
5450                         0.0,
5451                         G_PARAM_READWRITE |
5452                         G_PARAM_STATIC_STRINGS |
5453                         CLUTTER_PARAM_ANIMATABLE);
5454
5455   /**
5456    * ClutterActor:height:
5457    *
5458    * Height of the actor (in pixels).  If written, forces the minimum and
5459    * natural size request of the actor to the given height. If read, returns
5460    * the allocated height if available, otherwise the height request.
5461    *
5462    * The #ClutterActor:height property is animatable.
5463    */
5464   obj_props[PROP_HEIGHT] =
5465     g_param_spec_float ("height",
5466                         P_("Height"),
5467                         P_("Height of the actor"),
5468                         0.0, G_MAXFLOAT,
5469                         0.0,
5470                         G_PARAM_READWRITE |
5471                         G_PARAM_STATIC_STRINGS |
5472                         CLUTTER_PARAM_ANIMATABLE);
5473
5474   /**
5475    * ClutterActor:fixed-x:
5476    *
5477    * The fixed X position of the actor in pixels.
5478    *
5479    * Writing this property sets #ClutterActor:fixed-position-set
5480    * property as well, as a side effect
5481    *
5482    * Since: 0.8
5483    */
5484   obj_props[PROP_FIXED_X] =
5485     g_param_spec_float ("fixed-x",
5486                         P_("Fixed X"),
5487                         P_("Forced X position of the actor"),
5488                         -G_MAXFLOAT, G_MAXFLOAT,
5489                         0.0,
5490                         CLUTTER_PARAM_READWRITE);
5491
5492   /**
5493    * ClutterActor:fixed-y:
5494    *
5495    * The fixed Y position of the actor in pixels.
5496    *
5497    * Writing this property sets the #ClutterActor:fixed-position-set
5498    * property as well, as a side effect
5499    *
5500    * Since: 0.8
5501    */
5502   obj_props[PROP_FIXED_Y] =
5503     g_param_spec_float ("fixed-y",
5504                         P_("Fixed Y"),
5505                         P_("Forced Y position of the actor"),
5506                         -G_MAXFLOAT, G_MAXFLOAT,
5507                         0,
5508                         CLUTTER_PARAM_READWRITE);
5509
5510   /**
5511    * ClutterActor:fixed-position-set:
5512    *
5513    * This flag controls whether the #ClutterActor:fixed-x and
5514    * #ClutterActor:fixed-y properties are used
5515    *
5516    * Since: 0.8
5517    */
5518   obj_props[PROP_FIXED_POSITION_SET] =
5519     g_param_spec_boolean ("fixed-position-set",
5520                           P_("Fixed position set"),
5521                           P_("Whether to use fixed positioning for the actor"),
5522                           FALSE,
5523                           CLUTTER_PARAM_READWRITE);
5524
5525   /**
5526    * ClutterActor:min-width:
5527    *
5528    * A forced minimum width request for the actor, in pixels
5529    *
5530    * Writing this property sets the #ClutterActor:min-width-set property
5531    * as well, as a side effect.
5532    *
5533    *This property overrides the usual width request of the actor.
5534    *
5535    * Since: 0.8
5536    */
5537   obj_props[PROP_MIN_WIDTH] =
5538     g_param_spec_float ("min-width",
5539                         P_("Min Width"),
5540                         P_("Forced minimum width request for the actor"),
5541                         0.0, G_MAXFLOAT,
5542                         0.0,
5543                         CLUTTER_PARAM_READWRITE);
5544
5545   /**
5546    * ClutterActor:min-height:
5547    *
5548    * A forced minimum height request for the actor, in pixels
5549    *
5550    * Writing this property sets the #ClutterActor:min-height-set property
5551    * as well, as a side effect. This property overrides the usual height
5552    * request of the actor.
5553    *
5554    * Since: 0.8
5555    */
5556   obj_props[PROP_MIN_HEIGHT] =
5557     g_param_spec_float ("min-height",
5558                         P_("Min Height"),
5559                         P_("Forced minimum height request for the actor"),
5560                         0.0, G_MAXFLOAT,
5561                         0.0,
5562                         CLUTTER_PARAM_READWRITE);
5563
5564   /**
5565    * ClutterActor:natural-width:
5566    *
5567    * A forced natural width request for the actor, in pixels
5568    *
5569    * Writing this property sets the #ClutterActor:natural-width-set
5570    * property as well, as a side effect. This property overrides the
5571    * usual width request of the actor
5572    *
5573    * Since: 0.8
5574    */
5575   obj_props[PROP_NATURAL_WIDTH] =
5576     g_param_spec_float ("natural-width",
5577                         P_("Natural Width"),
5578                         P_("Forced natural width request for the actor"),
5579                         0.0, G_MAXFLOAT,
5580                         0.0,
5581                         CLUTTER_PARAM_READWRITE);
5582
5583   /**
5584    * ClutterActor:natural-height:
5585    *
5586    * A forced natural height request for the actor, in pixels
5587    *
5588    * Writing this property sets the #ClutterActor:natural-height-set
5589    * property as well, as a side effect. This property overrides the
5590    * usual height request of the actor
5591    *
5592    * Since: 0.8
5593    */
5594   obj_props[PROP_NATURAL_HEIGHT] =
5595     g_param_spec_float ("natural-height",
5596                         P_("Natural Height"),
5597                         P_("Forced natural height request for the actor"),
5598                         0.0, G_MAXFLOAT,
5599                         0.0,
5600                         CLUTTER_PARAM_READWRITE);
5601
5602   /**
5603    * ClutterActor:min-width-set:
5604    *
5605    * This flag controls whether the #ClutterActor:min-width property
5606    * is used
5607    *
5608    * Since: 0.8
5609    */
5610   obj_props[PROP_MIN_WIDTH_SET] =
5611     g_param_spec_boolean ("min-width-set",
5612                           P_("Minimum width set"),
5613                           P_("Whether to use the min-width property"),
5614                           FALSE,
5615                           CLUTTER_PARAM_READWRITE);
5616
5617   /**
5618    * ClutterActor:min-height-set:
5619    *
5620    * This flag controls whether the #ClutterActor:min-height property
5621    * is used
5622    *
5623    * Since: 0.8
5624    */
5625   obj_props[PROP_MIN_HEIGHT_SET] =
5626     g_param_spec_boolean ("min-height-set",
5627                           P_("Minimum height set"),
5628                           P_("Whether to use the min-height property"),
5629                           FALSE,
5630                           CLUTTER_PARAM_READWRITE);
5631
5632   /**
5633    * ClutterActor:natural-width-set:
5634    *
5635    * This flag controls whether the #ClutterActor:natural-width property
5636    * is used
5637    *
5638    * Since: 0.8
5639    */
5640   obj_props[PROP_NATURAL_WIDTH_SET] =
5641     g_param_spec_boolean ("natural-width-set",
5642                           P_("Natural width set"),
5643                           P_("Whether to use the natural-width property"),
5644                           FALSE,
5645                           CLUTTER_PARAM_READWRITE);
5646
5647   /**
5648    * ClutterActor:natural-height-set:
5649    *
5650    * This flag controls whether the #ClutterActor:natural-height property
5651    * is used
5652    *
5653    * Since: 0.8
5654    */
5655   obj_props[PROP_NATURAL_HEIGHT_SET] =
5656     g_param_spec_boolean ("natural-height-set",
5657                           P_("Natural height set"),
5658                           P_("Whether to use the natural-height property"),
5659                           FALSE,
5660                           CLUTTER_PARAM_READWRITE);
5661
5662   /**
5663    * ClutterActor:allocation:
5664    *
5665    * The allocation for the actor, in pixels
5666    *
5667    * This is property is read-only, but you might monitor it to know when an
5668    * actor moves or resizes
5669    *
5670    * Since: 0.8
5671    */
5672   obj_props[PROP_ALLOCATION] =
5673     g_param_spec_boxed ("allocation",
5674                         P_("Allocation"),
5675                         P_("The actor's allocation"),
5676                         CLUTTER_TYPE_ACTOR_BOX,
5677                         CLUTTER_PARAM_READABLE);
5678
5679   /**
5680    * ClutterActor:request-mode:
5681    *
5682    * Request mode for the #ClutterActor. The request mode determines the
5683    * type of geometry management used by the actor, either height for width
5684    * (the default) or width for height.
5685    *
5686    * For actors implementing height for width, the parent container should get
5687    * the preferred width first, and then the preferred height for that width.
5688    *
5689    * For actors implementing width for height, the parent container should get
5690    * the preferred height first, and then the preferred width for that height.
5691    *
5692    * For instance:
5693    *
5694    * |[
5695    *   ClutterRequestMode mode;
5696    *   gfloat natural_width, min_width;
5697    *   gfloat natural_height, min_height;
5698    *
5699    *   mode = clutter_actor_get_request_mode (child);
5700    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5701    *     {
5702    *       clutter_actor_get_preferred_width (child, -1,
5703    *                                          &amp;min_width,
5704    *                                          &amp;natural_width);
5705    *       clutter_actor_get_preferred_height (child, natural_width,
5706    *                                           &amp;min_height,
5707    *                                           &amp;natural_height);
5708    *     }
5709    *   else
5710    *     {
5711    *       clutter_actor_get_preferred_height (child, -1,
5712    *                                           &amp;min_height,
5713    *                                           &amp;natural_height);
5714    *       clutter_actor_get_preferred_width (child, natural_height,
5715    *                                          &amp;min_width,
5716    *                                          &amp;natural_width);
5717    *     }
5718    * ]|
5719    *
5720    * will retrieve the minimum and natural width and height depending on the
5721    * preferred request mode of the #ClutterActor "child".
5722    *
5723    * The clutter_actor_get_preferred_size() function will implement this
5724    * check for you.
5725    *
5726    * Since: 0.8
5727    */
5728   obj_props[PROP_REQUEST_MODE] =
5729     g_param_spec_enum ("request-mode",
5730                        P_("Request Mode"),
5731                        P_("The actor's request mode"),
5732                        CLUTTER_TYPE_REQUEST_MODE,
5733                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5734                        CLUTTER_PARAM_READWRITE);
5735
5736   /**
5737    * ClutterActor:depth:
5738    *
5739    * The position of the actor on the Z axis.
5740    *
5741    * The #ClutterActor:depth property is relative to the parent's
5742    * modelview matrix.
5743    *
5744    * The #ClutterActor:depth property is animatable.
5745    *
5746    * Since: 0.6
5747    */
5748   obj_props[PROP_DEPTH] =
5749     g_param_spec_float ("depth",
5750                         P_("Depth"),
5751                         P_("Position on the Z axis"),
5752                         -G_MAXFLOAT, G_MAXFLOAT,
5753                         0.0,
5754                         G_PARAM_READWRITE |
5755                         G_PARAM_STATIC_STRINGS |
5756                         CLUTTER_PARAM_ANIMATABLE);
5757
5758   /**
5759    * ClutterActor:opacity:
5760    *
5761    * Opacity of an actor, between 0 (fully transparent) and
5762    * 255 (fully opaque)
5763    *
5764    * The #ClutterActor:opacity property is animatable.
5765    */
5766   obj_props[PROP_OPACITY] =
5767     g_param_spec_uint ("opacity",
5768                        P_("Opacity"),
5769                        P_("Opacity of an actor"),
5770                        0, 255,
5771                        255,
5772                        G_PARAM_READWRITE |
5773                        G_PARAM_STATIC_STRINGS |
5774                        CLUTTER_PARAM_ANIMATABLE);
5775
5776   /**
5777    * ClutterActor:offscreen-redirect:
5778    *
5779    * Determines the conditions in which the actor will be redirected
5780    * to an offscreen framebuffer while being painted. For example this
5781    * can be used to cache an actor in a framebuffer or for improved
5782    * handling of transparent actors. See
5783    * clutter_actor_set_offscreen_redirect() for details.
5784    *
5785    * Since: 1.8
5786    */
5787   obj_props[PROP_OFFSCREEN_REDIRECT] =
5788     g_param_spec_flags ("offscreen-redirect",
5789                         P_("Offscreen redirect"),
5790                         P_("Flags controlling when to flatten the actor into a single image"),
5791                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5792                         0,
5793                         CLUTTER_PARAM_READWRITE);
5794
5795   /**
5796    * ClutterActor:visible:
5797    *
5798    * Whether the actor is set to be visible or not
5799    *
5800    * See also #ClutterActor:mapped
5801    */
5802   obj_props[PROP_VISIBLE] =
5803     g_param_spec_boolean ("visible",
5804                           P_("Visible"),
5805                           P_("Whether the actor is visible or not"),
5806                           FALSE,
5807                           CLUTTER_PARAM_READWRITE);
5808
5809   /**
5810    * ClutterActor:mapped:
5811    *
5812    * Whether the actor is mapped (will be painted when the stage
5813    * to which it belongs is mapped)
5814    *
5815    * Since: 1.0
5816    */
5817   obj_props[PROP_MAPPED] =
5818     g_param_spec_boolean ("mapped",
5819                           P_("Mapped"),
5820                           P_("Whether the actor will be painted"),
5821                           FALSE,
5822                           CLUTTER_PARAM_READABLE);
5823
5824   /**
5825    * ClutterActor:realized:
5826    *
5827    * Whether the actor has been realized
5828    *
5829    * Since: 1.0
5830    */
5831   obj_props[PROP_REALIZED] =
5832     g_param_spec_boolean ("realized",
5833                           P_("Realized"),
5834                           P_("Whether the actor has been realized"),
5835                           FALSE,
5836                           CLUTTER_PARAM_READABLE);
5837
5838   /**
5839    * ClutterActor:reactive:
5840    *
5841    * Whether the actor is reactive to events or not
5842    *
5843    * Only reactive actors will emit event-related signals
5844    *
5845    * Since: 0.6
5846    */
5847   obj_props[PROP_REACTIVE] =
5848     g_param_spec_boolean ("reactive",
5849                           P_("Reactive"),
5850                           P_("Whether the actor is reactive to events"),
5851                           FALSE,
5852                           CLUTTER_PARAM_READWRITE);
5853
5854   /**
5855    * ClutterActor:has-clip:
5856    *
5857    * Whether the actor has the #ClutterActor:clip property set or not
5858    */
5859   obj_props[PROP_HAS_CLIP] =
5860     g_param_spec_boolean ("has-clip",
5861                           P_("Has Clip"),
5862                           P_("Whether the actor has a clip set"),
5863                           FALSE,
5864                           CLUTTER_PARAM_READABLE);
5865
5866   /**
5867    * ClutterActor:clip:
5868    *
5869    * The clip region for the actor, in actor-relative coordinates
5870    *
5871    * Every part of the actor outside the clip region will not be
5872    * painted
5873    */
5874   obj_props[PROP_CLIP] =
5875     g_param_spec_boxed ("clip",
5876                         P_("Clip"),
5877                         P_("The clip region for the actor"),
5878                         CLUTTER_TYPE_GEOMETRY,
5879                         CLUTTER_PARAM_READWRITE);
5880
5881   /**
5882    * ClutterActor:name:
5883    *
5884    * The name of the actor
5885    *
5886    * Since: 0.2
5887    */
5888   obj_props[PROP_NAME] =
5889     g_param_spec_string ("name",
5890                          P_("Name"),
5891                          P_("Name of the actor"),
5892                          NULL,
5893                          CLUTTER_PARAM_READWRITE);
5894
5895   /**
5896    * ClutterActor:scale-x:
5897    *
5898    * The horizontal scale of the actor.
5899    *
5900    * The #ClutterActor:scale-x property is animatable.
5901    *
5902    * Since: 0.6
5903    */
5904   obj_props[PROP_SCALE_X] =
5905     g_param_spec_double ("scale-x",
5906                          P_("Scale X"),
5907                          P_("Scale factor on the X axis"),
5908                          0.0, G_MAXDOUBLE,
5909                          1.0,
5910                          G_PARAM_READWRITE |
5911                          G_PARAM_STATIC_STRINGS |
5912                          CLUTTER_PARAM_ANIMATABLE);
5913
5914   /**
5915    * ClutterActor:scale-y:
5916    *
5917    * The vertical scale of the actor.
5918    *
5919    * The #ClutterActor:scale-y property is animatable.
5920    *
5921    * Since: 0.6
5922    */
5923   obj_props[PROP_SCALE_Y] =
5924     g_param_spec_double ("scale-y",
5925                          P_("Scale Y"),
5926                          P_("Scale factor on the Y axis"),
5927                          0.0, G_MAXDOUBLE,
5928                          1.0,
5929                          G_PARAM_READWRITE |
5930                          G_PARAM_STATIC_STRINGS |
5931                          CLUTTER_PARAM_ANIMATABLE);
5932
5933   /**
5934    * ClutterActor:scale-center-x:
5935    *
5936    * The horizontal center point for scaling
5937    *
5938    * Since: 1.0
5939    */
5940   obj_props[PROP_SCALE_CENTER_X] =
5941     g_param_spec_float ("scale-center-x",
5942                         P_("Scale Center X"),
5943                         P_("Horizontal scale center"),
5944                         -G_MAXFLOAT, G_MAXFLOAT,
5945                         0.0,
5946                         CLUTTER_PARAM_READWRITE);
5947
5948   /**
5949    * ClutterActor:scale-center-y:
5950    *
5951    * The vertical center point for scaling
5952    *
5953    * Since: 1.0
5954    */
5955   obj_props[PROP_SCALE_CENTER_Y] =
5956     g_param_spec_float ("scale-center-y",
5957                         P_("Scale Center Y"),
5958                         P_("Vertical scale center"),
5959                         -G_MAXFLOAT, G_MAXFLOAT,
5960                         0.0,
5961                         CLUTTER_PARAM_READWRITE);
5962
5963   /**
5964    * ClutterActor:scale-gravity:
5965    *
5966    * The center point for scaling expressed as a #ClutterGravity
5967    *
5968    * Since: 1.0
5969    */
5970   obj_props[PROP_SCALE_GRAVITY] =
5971     g_param_spec_enum ("scale-gravity",
5972                        P_("Scale Gravity"),
5973                        P_("The center of scaling"),
5974                        CLUTTER_TYPE_GRAVITY,
5975                        CLUTTER_GRAVITY_NONE,
5976                        CLUTTER_PARAM_READWRITE);
5977
5978   /**
5979    * ClutterActor:rotation-angle-x:
5980    *
5981    * The rotation angle on the X axis.
5982    *
5983    * The #ClutterActor:rotation-angle-x property is animatable.
5984    *
5985    * Since: 0.6
5986    */
5987   obj_props[PROP_ROTATION_ANGLE_X] =
5988     g_param_spec_double ("rotation-angle-x",
5989                          P_("Rotation Angle X"),
5990                          P_("The rotation angle on the X axis"),
5991                          -G_MAXDOUBLE, G_MAXDOUBLE,
5992                          0.0,
5993                          G_PARAM_READWRITE |
5994                          G_PARAM_STATIC_STRINGS |
5995                          CLUTTER_PARAM_ANIMATABLE);
5996
5997   /**
5998    * ClutterActor:rotation-angle-y:
5999    *
6000    * The rotation angle on the Y axis
6001    *
6002    * The #ClutterActor:rotation-angle-y property is animatable.
6003    *
6004    * Since: 0.6
6005    */
6006   obj_props[PROP_ROTATION_ANGLE_Y] =
6007     g_param_spec_double ("rotation-angle-y",
6008                          P_("Rotation Angle Y"),
6009                          P_("The rotation angle on the Y axis"),
6010                          -G_MAXDOUBLE, G_MAXDOUBLE,
6011                          0.0,
6012                          G_PARAM_READWRITE |
6013                          G_PARAM_STATIC_STRINGS |
6014                          CLUTTER_PARAM_ANIMATABLE);
6015
6016   /**
6017    * ClutterActor:rotation-angle-z:
6018    *
6019    * The rotation angle on the Z axis
6020    *
6021    * The #ClutterActor:rotation-angle-z property is animatable.
6022    *
6023    * Since: 0.6
6024    */
6025   obj_props[PROP_ROTATION_ANGLE_Z] =
6026     g_param_spec_double ("rotation-angle-z",
6027                          P_("Rotation Angle Z"),
6028                          P_("The rotation angle on the Z axis"),
6029                          -G_MAXDOUBLE, G_MAXDOUBLE,
6030                          0.0,
6031                          G_PARAM_READWRITE |
6032                          G_PARAM_STATIC_STRINGS |
6033                          CLUTTER_PARAM_ANIMATABLE);
6034
6035   /**
6036    * ClutterActor:rotation-center-x:
6037    *
6038    * The rotation center on the X axis.
6039    *
6040    * Since: 0.6
6041    */
6042   obj_props[PROP_ROTATION_CENTER_X] =
6043     g_param_spec_boxed ("rotation-center-x",
6044                         P_("Rotation Center X"),
6045                         P_("The rotation center on the X axis"),
6046                         CLUTTER_TYPE_VERTEX,
6047                         CLUTTER_PARAM_READWRITE);
6048
6049   /**
6050    * ClutterActor:rotation-center-y:
6051    *
6052    * The rotation center on the Y axis.
6053    *
6054    * Since: 0.6
6055    */
6056   obj_props[PROP_ROTATION_CENTER_Y] =
6057     g_param_spec_boxed ("rotation-center-y",
6058                         P_("Rotation Center Y"),
6059                         P_("The rotation center on the Y axis"),
6060                         CLUTTER_TYPE_VERTEX,
6061                         CLUTTER_PARAM_READWRITE);
6062
6063   /**
6064    * ClutterActor:rotation-center-z:
6065    *
6066    * The rotation center on the Z axis.
6067    *
6068    * Since: 0.6
6069    */
6070   obj_props[PROP_ROTATION_CENTER_Z] =
6071     g_param_spec_boxed ("rotation-center-z",
6072                         P_("Rotation Center Z"),
6073                         P_("The rotation center on the Z axis"),
6074                         CLUTTER_TYPE_VERTEX,
6075                         CLUTTER_PARAM_READWRITE);
6076
6077   /**
6078    * ClutterActor:rotation-center-z-gravity:
6079    *
6080    * The rotation center on the Z axis expressed as a #ClutterGravity.
6081    *
6082    * Since: 1.0
6083    */
6084   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6085     g_param_spec_enum ("rotation-center-z-gravity",
6086                        P_("Rotation Center Z Gravity"),
6087                        P_("Center point for rotation around the Z axis"),
6088                        CLUTTER_TYPE_GRAVITY,
6089                        CLUTTER_GRAVITY_NONE,
6090                        CLUTTER_PARAM_READWRITE);
6091
6092   /**
6093    * ClutterActor:anchor-x:
6094    *
6095    * The X coordinate of an actor's anchor point, relative to
6096    * the actor coordinate space, in pixels
6097    *
6098    * Since: 0.8
6099    */
6100   obj_props[PROP_ANCHOR_X] =
6101     g_param_spec_float ("anchor-x",
6102                         P_("Anchor X"),
6103                         P_("X coordinate of the anchor point"),
6104                         -G_MAXFLOAT, G_MAXFLOAT,
6105                         0,
6106                         CLUTTER_PARAM_READWRITE);
6107
6108   /**
6109    * ClutterActor:anchor-y:
6110    *
6111    * The Y coordinate of an actor's anchor point, relative to
6112    * the actor coordinate space, in pixels
6113    *
6114    * Since: 0.8
6115    */
6116   obj_props[PROP_ANCHOR_Y] =
6117     g_param_spec_float ("anchor-y",
6118                         P_("Anchor Y"),
6119                         P_("Y coordinate of the anchor point"),
6120                         -G_MAXFLOAT, G_MAXFLOAT,
6121                         0,
6122                         CLUTTER_PARAM_READWRITE);
6123
6124   /**
6125    * ClutterActor:anchor-gravity:
6126    *
6127    * The anchor point expressed as a #ClutterGravity
6128    *
6129    * Since: 1.0
6130    */
6131   obj_props[PROP_ANCHOR_GRAVITY] =
6132     g_param_spec_enum ("anchor-gravity",
6133                        P_("Anchor Gravity"),
6134                        P_("The anchor point as a ClutterGravity"),
6135                        CLUTTER_TYPE_GRAVITY,
6136                        CLUTTER_GRAVITY_NONE,
6137                        CLUTTER_PARAM_READWRITE);
6138
6139   /**
6140    * ClutterActor:show-on-set-parent:
6141    *
6142    * If %TRUE, the actor is automatically shown when parented.
6143    *
6144    * Calling clutter_actor_hide() on an actor which has not been
6145    * parented will set this property to %FALSE as a side effect.
6146    *
6147    * Since: 0.8
6148    */
6149   obj_props[PROP_SHOW_ON_SET_PARENT] =
6150     g_param_spec_boolean ("show-on-set-parent",
6151                           P_("Show on set parent"),
6152                           P_("Whether the actor is shown when parented"),
6153                           TRUE,
6154                           CLUTTER_PARAM_READWRITE);
6155
6156   /**
6157    * ClutterActor:clip-to-allocation:
6158    *
6159    * Whether the clip region should track the allocated area
6160    * of the actor.
6161    *
6162    * This property is ignored if a clip area has been explicitly
6163    * set using clutter_actor_set_clip().
6164    *
6165    * Since: 1.0
6166    */
6167   obj_props[PROP_CLIP_TO_ALLOCATION] =
6168     g_param_spec_boolean ("clip-to-allocation",
6169                           P_("Clip to Allocation"),
6170                           P_("Sets the clip region to track the actor's allocation"),
6171                           FALSE,
6172                           CLUTTER_PARAM_READWRITE);
6173
6174   /**
6175    * ClutterActor:text-direction:
6176    *
6177    * The direction of the text inside a #ClutterActor.
6178    *
6179    * Since: 1.0
6180    */
6181   obj_props[PROP_TEXT_DIRECTION] =
6182     g_param_spec_enum ("text-direction",
6183                        P_("Text Direction"),
6184                        P_("Direction of the text"),
6185                        CLUTTER_TYPE_TEXT_DIRECTION,
6186                        CLUTTER_TEXT_DIRECTION_LTR,
6187                        CLUTTER_PARAM_READWRITE);
6188
6189   /**
6190    * ClutterActor:has-pointer:
6191    *
6192    * Whether the actor contains the pointer of a #ClutterInputDevice
6193    * or not.
6194    *
6195    * Since: 1.2
6196    */
6197   obj_props[PROP_HAS_POINTER] =
6198     g_param_spec_boolean ("has-pointer",
6199                           P_("Has Pointer"),
6200                           P_("Whether the actor contains the pointer of an input device"),
6201                           FALSE,
6202                           CLUTTER_PARAM_READABLE);
6203
6204   /**
6205    * ClutterActor:actions:
6206    *
6207    * Adds a #ClutterAction to the actor
6208    *
6209    * Since: 1.4
6210    */
6211   obj_props[PROP_ACTIONS] =
6212     g_param_spec_object ("actions",
6213                          P_("Actions"),
6214                          P_("Adds an action to the actor"),
6215                          CLUTTER_TYPE_ACTION,
6216                          CLUTTER_PARAM_WRITABLE);
6217
6218   /**
6219    * ClutterActor:constraints:
6220    *
6221    * Adds a #ClutterConstraint to the actor
6222    *
6223    * Since: 1.4
6224    */
6225   obj_props[PROP_CONSTRAINTS] =
6226     g_param_spec_object ("constraints",
6227                          P_("Constraints"),
6228                          P_("Adds a constraint to the actor"),
6229                          CLUTTER_TYPE_CONSTRAINT,
6230                          CLUTTER_PARAM_WRITABLE);
6231
6232   /**
6233    * ClutterActor:effect:
6234    *
6235    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6236    *
6237    * Since: 1.4
6238    */
6239   obj_props[PROP_EFFECT] =
6240     g_param_spec_object ("effect",
6241                          P_("Effect"),
6242                          P_("Add an effect to be applied on the actor"),
6243                          CLUTTER_TYPE_EFFECT,
6244                          CLUTTER_PARAM_WRITABLE);
6245
6246   /**
6247    * ClutterActor:layout-manager:
6248    *
6249    * A delegate object for controlling the layout of the children of
6250    * an actor.
6251    *
6252    * Since: 1.10
6253    */
6254   obj_props[PROP_LAYOUT_MANAGER] =
6255     g_param_spec_object ("layout-manager",
6256                          P_("Layout Manager"),
6257                          P_("The object controlling the layout of an actor's children"),
6258                          CLUTTER_TYPE_LAYOUT_MANAGER,
6259                          CLUTTER_PARAM_READWRITE);
6260
6261
6262   /**
6263    * ClutterActor:x-align:
6264    *
6265    * The alignment of an actor on the X axis, if the actor has been given
6266    * extra space for its allocation.
6267    *
6268    * Since: 1.10
6269    */
6270   obj_props[PROP_X_ALIGN] =
6271     g_param_spec_enum ("x-align",
6272                        P_("X Alignment"),
6273                        P_("The alignment of the actor on the X axis within its allocation"),
6274                        CLUTTER_TYPE_ACTOR_ALIGN,
6275                        CLUTTER_ACTOR_ALIGN_FILL,
6276                        CLUTTER_PARAM_READWRITE);
6277
6278   /**
6279    * ClutterActor:y-align:
6280    *
6281    * The alignment of an actor on the Y axis, if the actor has been given
6282    * extra space for its allocation.
6283    *
6284    * Since: 1.10
6285    */
6286   obj_props[PROP_Y_ALIGN] =
6287     g_param_spec_enum ("y-align",
6288                        P_("Y Alignment"),
6289                        P_("The alignment of the actor on the Y axis within its allocation"),
6290                        CLUTTER_TYPE_ACTOR_ALIGN,
6291                        CLUTTER_ACTOR_ALIGN_FILL,
6292                        CLUTTER_PARAM_READWRITE);
6293
6294   /**
6295    * ClutterActor:margin-top:
6296    *
6297    * The margin (in pixels) from the top of the actor.
6298    *
6299    * This property adds a margin to the actor's preferred size; the margin
6300    * will be automatically taken into account when allocating the actor.
6301    *
6302    * Since: 1.10
6303    */
6304   obj_props[PROP_MARGIN_TOP] =
6305     g_param_spec_float ("margin-top",
6306                         P_("Margin Top"),
6307                         P_("Extra space at the top"),
6308                         0.0, G_MAXFLOAT,
6309                         0.0,
6310                         CLUTTER_PARAM_READWRITE);
6311
6312   /**
6313    * ClutterActor:margin-bottom:
6314    *
6315    * The margin (in pixels) from the bottom of the actor.
6316    *
6317    * This property adds a margin to the actor's preferred size; the margin
6318    * will be automatically taken into account when allocating the actor.
6319    *
6320    * Since: 1.10
6321    */
6322   obj_props[PROP_MARGIN_BOTTOM] =
6323     g_param_spec_float ("margin-bottom",
6324                         P_("Margin Bottom"),
6325                         P_("Extra space at the bottom"),
6326                         0.0, G_MAXFLOAT,
6327                         0.0,
6328                         CLUTTER_PARAM_READWRITE);
6329
6330   /**
6331    * ClutterActor:margin-left:
6332    *
6333    * The margin (in pixels) from the left of the actor.
6334    *
6335    * This property adds a margin to the actor's preferred size; the margin
6336    * will be automatically taken into account when allocating the actor.
6337    *
6338    * Since: 1.10
6339    */
6340   obj_props[PROP_MARGIN_LEFT] =
6341     g_param_spec_float ("margin-left",
6342                         P_("Margin Left"),
6343                         P_("Extra space at the left"),
6344                         0.0, G_MAXFLOAT,
6345                         0.0,
6346                         CLUTTER_PARAM_READWRITE);
6347
6348   /**
6349    * ClutterActor:margin-right:
6350    *
6351    * The margin (in pixels) from the right of the actor.
6352    *
6353    * This property adds a margin to the actor's preferred size; the margin
6354    * will be automatically taken into account when allocating the actor.
6355    *
6356    * Since: 1.10
6357    */
6358   obj_props[PROP_MARGIN_RIGHT] =
6359     g_param_spec_float ("margin-right",
6360                         P_("Margin Right"),
6361                         P_("Extra space at the right"),
6362                         0.0, G_MAXFLOAT,
6363                         0.0,
6364                         CLUTTER_PARAM_READWRITE);
6365
6366   /**
6367    * ClutterActor:background-color-set:
6368    *
6369    * Whether the #ClutterActor:background-color property has been set.
6370    *
6371    * Since: 1.10
6372    */
6373   obj_props[PROP_BACKGROUND_COLOR_SET] =
6374     g_param_spec_boolean ("background-color-set",
6375                           P_("Background Color Set"),
6376                           P_("Whether the background color is set"),
6377                           FALSE,
6378                           CLUTTER_PARAM_READABLE);
6379
6380   /**
6381    * ClutterActor:background-color:
6382    *
6383    * Paints a solid fill of the actor's allocation using the specified
6384    * color.
6385    *
6386    * The #ClutterActor:background-color property is animatable.
6387    *
6388    * Since: 1.10
6389    */
6390   obj_props[PROP_BACKGROUND_COLOR] =
6391     clutter_param_spec_color ("background-color",
6392                               P_("Background color"),
6393                               P_("The actor's background color"),
6394                               CLUTTER_COLOR_Transparent,
6395                               G_PARAM_READWRITE |
6396                               G_PARAM_STATIC_STRINGS |
6397                               CLUTTER_PARAM_ANIMATABLE);
6398
6399   /**
6400    * ClutterActor:first-child:
6401    *
6402    * The actor's first child.
6403    *
6404    * Since: 1.10
6405    */
6406   obj_props[PROP_FIRST_CHILD] =
6407     g_param_spec_object ("first-child",
6408                          P_("First Child"),
6409                          P_("The actor's first child"),
6410                          CLUTTER_TYPE_ACTOR,
6411                          CLUTTER_PARAM_READABLE);
6412
6413   /**
6414    * ClutterActor:last-child:
6415    *
6416    * The actor's last child.
6417    *
6418    * Since: 1.10
6419    */
6420   obj_props[PROP_LAST_CHILD] =
6421     g_param_spec_object ("last-child",
6422                          P_("Last Child"),
6423                          P_("The actor's last child"),
6424                          CLUTTER_TYPE_ACTOR,
6425                          CLUTTER_PARAM_READABLE);
6426
6427   /**
6428    * ClutterActor:content:
6429    *
6430    * The #ClutterContent implementation that controls the content
6431    * of the actor.
6432    *
6433    * Since: 1.10
6434    */
6435   obj_props[PROP_CONTENT] =
6436     g_param_spec_object ("content",
6437                          P_("Content"),
6438                          P_("Delegate object for painting the actor's content"),
6439                          CLUTTER_TYPE_CONTENT,
6440                          CLUTTER_PARAM_READWRITE);
6441
6442   /**
6443    * ClutterActor:content-gravity:
6444    *
6445    * The alignment that should be honoured by the #ClutterContent
6446    * set with the #ClutterActor:content property.
6447    *
6448    * Changing the value of this property will change the bounding box of
6449    * the content; you can use the #ClutterActor:content-box property to
6450    * get the position and size of the content within the actor's
6451    * allocation.
6452    *
6453    * This property is meaningful only for #ClutterContent implementations
6454    * that have a preferred size, and if the preferred size is smaller than
6455    * the actor's allocation.
6456    *
6457    * The #ClutterActor:content-gravity property is animatable.
6458    *
6459    * Since: 1.10
6460    */
6461   obj_props[PROP_CONTENT_GRAVITY] =
6462     g_param_spec_enum ("content-gravity",
6463                        P_("Content Gravity"),
6464                        P_("Alignment of the actor's content"),
6465                        CLUTTER_TYPE_CONTENT_GRAVITY,
6466                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6467                        CLUTTER_PARAM_READWRITE);
6468
6469   /**
6470    * ClutterActor:content-box:
6471    *
6472    * The bounding box for the #ClutterContent used by the actor.
6473    *
6474    * The value of this property is controlled by the #ClutterActor:allocation
6475    * and #ClutterActor:content-gravity properties of #ClutterActor.
6476    *
6477    * The bounding box for the content is guaranteed to never exceed the
6478    * allocation's of the actor.
6479    *
6480    * Since: 1.10
6481    */
6482   obj_props[PROP_CONTENT_BOX] =
6483     g_param_spec_boxed ("content-box",
6484                         P_("Content Box"),
6485                         P_("The bounding box of the actor's content"),
6486                         CLUTTER_TYPE_ACTOR_BOX,
6487                         G_PARAM_READABLE |
6488                         G_PARAM_STATIC_STRINGS |
6489                         CLUTTER_PARAM_ANIMATABLE);
6490
6491   obj_props[PROP_MINIFICATION_FILTER] =
6492     g_param_spec_enum ("minification-filter",
6493                        P_("Minification Filter"),
6494                        P_("The filter used when reducing the size of the content"),
6495                        CLUTTER_TYPE_SCALING_FILTER,
6496                        CLUTTER_SCALING_FILTER_LINEAR,
6497                        CLUTTER_PARAM_READWRITE);
6498
6499   obj_props[PROP_MAGNIFICATION_FILTER] =
6500     g_param_spec_enum ("magnification-filter",
6501                        P_("Magnification Filter"),
6502                        P_("The filter used when increasing the size of the content"),
6503                        CLUTTER_TYPE_SCALING_FILTER,
6504                        CLUTTER_SCALING_FILTER_LINEAR,
6505                        CLUTTER_PARAM_READWRITE);
6506
6507   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6508
6509   /**
6510    * ClutterActor::destroy:
6511    * @actor: the #ClutterActor which emitted the signal
6512    *
6513    * The ::destroy signal notifies that all references held on the
6514    * actor which emitted it should be released.
6515    *
6516    * The ::destroy signal should be used by all holders of a reference
6517    * on @actor.
6518    *
6519    * This signal might result in the finalization of the #ClutterActor
6520    * if all references are released.
6521    *
6522    * Composite actors and actors implementing the #ClutterContainer
6523    * interface should override the default implementation of the
6524    * class handler of this signal and call clutter_actor_destroy() on
6525    * their children. When overriding the default class handler, it is
6526    * required to chain up to the parent's implementation.
6527    *
6528    * Since: 0.2
6529    */
6530   actor_signals[DESTROY] =
6531     g_signal_new (I_("destroy"),
6532                   G_TYPE_FROM_CLASS (object_class),
6533                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6534                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6535                   NULL, NULL,
6536                   _clutter_marshal_VOID__VOID,
6537                   G_TYPE_NONE, 0);
6538   /**
6539    * ClutterActor::show:
6540    * @actor: the object which received the signal
6541    *
6542    * The ::show signal is emitted when an actor is visible and
6543    * rendered on the stage.
6544    *
6545    * Since: 0.2
6546    */
6547   actor_signals[SHOW] =
6548     g_signal_new (I_("show"),
6549                   G_TYPE_FROM_CLASS (object_class),
6550                   G_SIGNAL_RUN_FIRST,
6551                   G_STRUCT_OFFSET (ClutterActorClass, show),
6552                   NULL, NULL,
6553                   _clutter_marshal_VOID__VOID,
6554                   G_TYPE_NONE, 0);
6555   /**
6556    * ClutterActor::hide:
6557    * @actor: the object which received the signal
6558    *
6559    * The ::hide signal is emitted when an actor is no longer rendered
6560    * on the stage.
6561    *
6562    * Since: 0.2
6563    */
6564   actor_signals[HIDE] =
6565     g_signal_new (I_("hide"),
6566                   G_TYPE_FROM_CLASS (object_class),
6567                   G_SIGNAL_RUN_FIRST,
6568                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6569                   NULL, NULL,
6570                   _clutter_marshal_VOID__VOID,
6571                   G_TYPE_NONE, 0);
6572   /**
6573    * ClutterActor::parent-set:
6574    * @actor: the object which received the signal
6575    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6576    *
6577    * This signal is emitted when the parent of the actor changes.
6578    *
6579    * Since: 0.2
6580    */
6581   actor_signals[PARENT_SET] =
6582     g_signal_new (I_("parent-set"),
6583                   G_TYPE_FROM_CLASS (object_class),
6584                   G_SIGNAL_RUN_LAST,
6585                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6586                   NULL, NULL,
6587                   _clutter_marshal_VOID__OBJECT,
6588                   G_TYPE_NONE, 1,
6589                   CLUTTER_TYPE_ACTOR);
6590
6591   /**
6592    * ClutterActor::queue-redraw:
6593    * @actor: the actor we're bubbling the redraw request through
6594    * @origin: the actor which initiated the redraw request
6595    *
6596    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6597    * is called on @origin.
6598    *
6599    * The default implementation for #ClutterActor chains up to the
6600    * parent actor and queues a redraw on the parent, thus "bubbling"
6601    * the redraw queue up through the actor graph. The default
6602    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6603    * in a main loop idle handler.
6604    *
6605    * Note that the @origin actor may be the stage, or a container; it
6606    * does not have to be a leaf node in the actor graph.
6607    *
6608    * Toolkits embedding a #ClutterStage which require a redraw and
6609    * relayout cycle can stop the emission of this signal using the
6610    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6611    * themselves, like:
6612    *
6613    * |[
6614    *   static void
6615    *   on_redraw_complete (gpointer data)
6616    *   {
6617    *     ClutterStage *stage = data;
6618    *
6619    *     /&ast; execute the Clutter drawing pipeline &ast;/
6620    *     clutter_stage_ensure_redraw (stage);
6621    *   }
6622    *
6623    *   static void
6624    *   on_stage_queue_redraw (ClutterStage *stage)
6625    *   {
6626    *     /&ast; this prevents the default handler to run &ast;/
6627    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6628    *
6629    *     /&ast; queue a redraw with the host toolkit and call
6630    *      &ast; a function when the redraw has been completed
6631    *      &ast;/
6632    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6633    *   }
6634    * ]|
6635    *
6636    * <note><para>This signal is emitted before the Clutter paint
6637    * pipeline is executed. If you want to know when the pipeline has
6638    * been completed you should connect to the ::paint signal on the
6639    * Stage with g_signal_connect_after().</para></note>
6640    *
6641    * Since: 1.0
6642    */
6643   actor_signals[QUEUE_REDRAW] =
6644     g_signal_new (I_("queue-redraw"),
6645                   G_TYPE_FROM_CLASS (object_class),
6646                   G_SIGNAL_RUN_LAST |
6647                   G_SIGNAL_NO_HOOKS,
6648                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6649                   NULL, NULL,
6650                   _clutter_marshal_VOID__OBJECT,
6651                   G_TYPE_NONE, 1,
6652                   CLUTTER_TYPE_ACTOR);
6653
6654   /**
6655    * ClutterActor::queue-relayout
6656    * @actor: the actor being queued for relayout
6657    *
6658    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6659    * is called on an actor.
6660    *
6661    * The default implementation for #ClutterActor chains up to the
6662    * parent actor and queues a relayout on the parent, thus "bubbling"
6663    * the relayout queue up through the actor graph.
6664    *
6665    * The main purpose of this signal is to allow relayout to be propagated
6666    * properly in the procense of #ClutterClone actors. Applications will
6667    * not normally need to connect to this signal.
6668    *
6669    * Since: 1.2
6670    */
6671   actor_signals[QUEUE_RELAYOUT] =
6672     g_signal_new (I_("queue-relayout"),
6673                   G_TYPE_FROM_CLASS (object_class),
6674                   G_SIGNAL_RUN_LAST |
6675                   G_SIGNAL_NO_HOOKS,
6676                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6677                   NULL, NULL,
6678                   _clutter_marshal_VOID__VOID,
6679                   G_TYPE_NONE, 0);
6680
6681   /**
6682    * ClutterActor::event:
6683    * @actor: the actor which received the event
6684    * @event: a #ClutterEvent
6685    *
6686    * The ::event signal is emitted each time an event is received
6687    * by the @actor. This signal will be emitted on every actor,
6688    * following the hierarchy chain, until it reaches the top-level
6689    * container (the #ClutterStage).
6690    *
6691    * Return value: %TRUE if the event has been handled by the actor,
6692    *   or %FALSE to continue the emission.
6693    *
6694    * Since: 0.6
6695    */
6696   actor_signals[EVENT] =
6697     g_signal_new (I_("event"),
6698                   G_TYPE_FROM_CLASS (object_class),
6699                   G_SIGNAL_RUN_LAST,
6700                   G_STRUCT_OFFSET (ClutterActorClass, event),
6701                   _clutter_boolean_handled_accumulator, NULL,
6702                   _clutter_marshal_BOOLEAN__BOXED,
6703                   G_TYPE_BOOLEAN, 1,
6704                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6705   /**
6706    * ClutterActor::button-press-event:
6707    * @actor: the actor which received the event
6708    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6709    *
6710    * The ::button-press-event signal is emitted each time a mouse button
6711    * is pressed on @actor.
6712    *
6713    * Return value: %TRUE if the event has been handled by the actor,
6714    *   or %FALSE to continue the emission.
6715    *
6716    * Since: 0.6
6717    */
6718   actor_signals[BUTTON_PRESS_EVENT] =
6719     g_signal_new (I_("button-press-event"),
6720                   G_TYPE_FROM_CLASS (object_class),
6721                   G_SIGNAL_RUN_LAST,
6722                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6723                   _clutter_boolean_handled_accumulator, NULL,
6724                   _clutter_marshal_BOOLEAN__BOXED,
6725                   G_TYPE_BOOLEAN, 1,
6726                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6727   /**
6728    * ClutterActor::button-release-event:
6729    * @actor: the actor which received the event
6730    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6731    *
6732    * The ::button-release-event signal is emitted each time a mouse button
6733    * is released on @actor.
6734    *
6735    * Return value: %TRUE if the event has been handled by the actor,
6736    *   or %FALSE to continue the emission.
6737    *
6738    * Since: 0.6
6739    */
6740   actor_signals[BUTTON_RELEASE_EVENT] =
6741     g_signal_new (I_("button-release-event"),
6742                   G_TYPE_FROM_CLASS (object_class),
6743                   G_SIGNAL_RUN_LAST,
6744                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6745                   _clutter_boolean_handled_accumulator, NULL,
6746                   _clutter_marshal_BOOLEAN__BOXED,
6747                   G_TYPE_BOOLEAN, 1,
6748                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6749   /**
6750    * ClutterActor::scroll-event:
6751    * @actor: the actor which received the event
6752    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6753    *
6754    * The ::scroll-event signal is emitted each time the mouse is
6755    * scrolled on @actor
6756    *
6757    * Return value: %TRUE if the event has been handled by the actor,
6758    *   or %FALSE to continue the emission.
6759    *
6760    * Since: 0.6
6761    */
6762   actor_signals[SCROLL_EVENT] =
6763     g_signal_new (I_("scroll-event"),
6764                   G_TYPE_FROM_CLASS (object_class),
6765                   G_SIGNAL_RUN_LAST,
6766                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6767                   _clutter_boolean_handled_accumulator, NULL,
6768                   _clutter_marshal_BOOLEAN__BOXED,
6769                   G_TYPE_BOOLEAN, 1,
6770                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6771   /**
6772    * ClutterActor::key-press-event:
6773    * @actor: the actor which received the event
6774    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6775    *
6776    * The ::key-press-event signal is emitted each time a keyboard button
6777    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6778    *
6779    * Return value: %TRUE if the event has been handled by the actor,
6780    *   or %FALSE to continue the emission.
6781    *
6782    * Since: 0.6
6783    */
6784   actor_signals[KEY_PRESS_EVENT] =
6785     g_signal_new (I_("key-press-event"),
6786                   G_TYPE_FROM_CLASS (object_class),
6787                   G_SIGNAL_RUN_LAST,
6788                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6789                   _clutter_boolean_handled_accumulator, NULL,
6790                   _clutter_marshal_BOOLEAN__BOXED,
6791                   G_TYPE_BOOLEAN, 1,
6792                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6793   /**
6794    * ClutterActor::key-release-event:
6795    * @actor: the actor which received the event
6796    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6797    *
6798    * The ::key-release-event signal is emitted each time a keyboard button
6799    * is released while @actor has key focus (see
6800    * clutter_stage_set_key_focus()).
6801    *
6802    * Return value: %TRUE if the event has been handled by the actor,
6803    *   or %FALSE to continue the emission.
6804    *
6805    * Since: 0.6
6806    */
6807   actor_signals[KEY_RELEASE_EVENT] =
6808     g_signal_new (I_("key-release-event"),
6809                   G_TYPE_FROM_CLASS (object_class),
6810                   G_SIGNAL_RUN_LAST,
6811                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6812                   _clutter_boolean_handled_accumulator, NULL,
6813                   _clutter_marshal_BOOLEAN__BOXED,
6814                   G_TYPE_BOOLEAN, 1,
6815                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6816   /**
6817    * ClutterActor::motion-event:
6818    * @actor: the actor which received the event
6819    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6820    *
6821    * The ::motion-event signal is emitted each time the mouse pointer is
6822    * moved over @actor.
6823    *
6824    * Return value: %TRUE if the event has been handled by the actor,
6825    *   or %FALSE to continue the emission.
6826    *
6827    * Since: 0.6
6828    */
6829   actor_signals[MOTION_EVENT] =
6830     g_signal_new (I_("motion-event"),
6831                   G_TYPE_FROM_CLASS (object_class),
6832                   G_SIGNAL_RUN_LAST,
6833                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6834                   _clutter_boolean_handled_accumulator, NULL,
6835                   _clutter_marshal_BOOLEAN__BOXED,
6836                   G_TYPE_BOOLEAN, 1,
6837                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6838
6839   /**
6840    * ClutterActor::key-focus-in:
6841    * @actor: the actor which now has key focus
6842    *
6843    * The ::key-focus-in signal is emitted when @actor receives key focus.
6844    *
6845    * Since: 0.6
6846    */
6847   actor_signals[KEY_FOCUS_IN] =
6848     g_signal_new (I_("key-focus-in"),
6849                   G_TYPE_FROM_CLASS (object_class),
6850                   G_SIGNAL_RUN_LAST,
6851                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6852                   NULL, NULL,
6853                   _clutter_marshal_VOID__VOID,
6854                   G_TYPE_NONE, 0);
6855
6856   /**
6857    * ClutterActor::key-focus-out:
6858    * @actor: the actor which now has key focus
6859    *
6860    * The ::key-focus-out signal is emitted when @actor loses key focus.
6861    *
6862    * Since: 0.6
6863    */
6864   actor_signals[KEY_FOCUS_OUT] =
6865     g_signal_new (I_("key-focus-out"),
6866                   G_TYPE_FROM_CLASS (object_class),
6867                   G_SIGNAL_RUN_LAST,
6868                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6869                   NULL, NULL,
6870                   _clutter_marshal_VOID__VOID,
6871                   G_TYPE_NONE, 0);
6872
6873   /**
6874    * ClutterActor::enter-event:
6875    * @actor: the actor which the pointer has entered.
6876    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6877    *
6878    * The ::enter-event signal is emitted when the pointer enters the @actor
6879    *
6880    * Return value: %TRUE if the event has been handled by the actor,
6881    *   or %FALSE to continue the emission.
6882    *
6883    * Since: 0.6
6884    */
6885   actor_signals[ENTER_EVENT] =
6886     g_signal_new (I_("enter-event"),
6887                   G_TYPE_FROM_CLASS (object_class),
6888                   G_SIGNAL_RUN_LAST,
6889                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6890                   _clutter_boolean_handled_accumulator, NULL,
6891                   _clutter_marshal_BOOLEAN__BOXED,
6892                   G_TYPE_BOOLEAN, 1,
6893                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6894
6895   /**
6896    * ClutterActor::leave-event:
6897    * @actor: the actor which the pointer has left
6898    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6899    *
6900    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6901    *
6902    * Return value: %TRUE if the event has been handled by the actor,
6903    *   or %FALSE to continue the emission.
6904    *
6905    * Since: 0.6
6906    */
6907   actor_signals[LEAVE_EVENT] =
6908     g_signal_new (I_("leave-event"),
6909                   G_TYPE_FROM_CLASS (object_class),
6910                   G_SIGNAL_RUN_LAST,
6911                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6912                   _clutter_boolean_handled_accumulator, NULL,
6913                   _clutter_marshal_BOOLEAN__BOXED,
6914                   G_TYPE_BOOLEAN, 1,
6915                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6916
6917   /**
6918    * ClutterActor::captured-event:
6919    * @actor: the actor which received the signal
6920    * @event: a #ClutterEvent
6921    *
6922    * The ::captured-event signal is emitted when an event is captured
6923    * by Clutter. This signal will be emitted starting from the top-level
6924    * container (the #ClutterStage) to the actor which received the event
6925    * going down the hierarchy. This signal can be used to intercept every
6926    * event before the specialized events (like
6927    * ClutterActor::button-press-event or ::key-released-event) are
6928    * emitted.
6929    *
6930    * Return value: %TRUE if the event has been handled by the actor,
6931    *   or %FALSE to continue the emission.
6932    *
6933    * Since: 0.6
6934    */
6935   actor_signals[CAPTURED_EVENT] =
6936     g_signal_new (I_("captured-event"),
6937                   G_TYPE_FROM_CLASS (object_class),
6938                   G_SIGNAL_RUN_LAST,
6939                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6940                   _clutter_boolean_handled_accumulator, NULL,
6941                   _clutter_marshal_BOOLEAN__BOXED,
6942                   G_TYPE_BOOLEAN, 1,
6943                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6944
6945   /**
6946    * ClutterActor::paint:
6947    * @actor: the #ClutterActor that received the signal
6948    *
6949    * The ::paint signal is emitted each time an actor is being painted.
6950    *
6951    * Subclasses of #ClutterActor should override the class signal handler
6952    * and paint themselves in that function.
6953    *
6954    * It is possible to connect a handler to the ::paint signal in order
6955    * to set up some custom aspect of a paint.
6956    *
6957    * Since: 0.8
6958    */
6959   actor_signals[PAINT] =
6960     g_signal_new (I_("paint"),
6961                   G_TYPE_FROM_CLASS (object_class),
6962                   G_SIGNAL_RUN_LAST |
6963                   G_SIGNAL_NO_HOOKS,
6964                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6965                   NULL, NULL,
6966                   _clutter_marshal_VOID__VOID,
6967                   G_TYPE_NONE, 0);
6968   /**
6969    * ClutterActor::realize:
6970    * @actor: the #ClutterActor that received the signal
6971    *
6972    * The ::realize signal is emitted each time an actor is being
6973    * realized.
6974    *
6975    * Since: 0.8
6976    */
6977   actor_signals[REALIZE] =
6978     g_signal_new (I_("realize"),
6979                   G_TYPE_FROM_CLASS (object_class),
6980                   G_SIGNAL_RUN_LAST,
6981                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6982                   NULL, NULL,
6983                   _clutter_marshal_VOID__VOID,
6984                   G_TYPE_NONE, 0);
6985   /**
6986    * ClutterActor::unrealize:
6987    * @actor: the #ClutterActor that received the signal
6988    *
6989    * The ::unrealize signal is emitted each time an actor is being
6990    * unrealized.
6991    *
6992    * Since: 0.8
6993    */
6994   actor_signals[UNREALIZE] =
6995     g_signal_new (I_("unrealize"),
6996                   G_TYPE_FROM_CLASS (object_class),
6997                   G_SIGNAL_RUN_LAST,
6998                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6999                   NULL, NULL,
7000                   _clutter_marshal_VOID__VOID,
7001                   G_TYPE_NONE, 0);
7002
7003   /**
7004    * ClutterActor::pick:
7005    * @actor: the #ClutterActor that received the signal
7006    * @color: the #ClutterColor to be used when picking
7007    *
7008    * The ::pick signal is emitted each time an actor is being painted
7009    * in "pick mode". The pick mode is used to identify the actor during
7010    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7011    * The actor should paint its shape using the passed @pick_color.
7012    *
7013    * Subclasses of #ClutterActor should override the class signal handler
7014    * and paint themselves in that function.
7015    *
7016    * It is possible to connect a handler to the ::pick signal in order
7017    * to set up some custom aspect of a paint in pick mode.
7018    *
7019    * Since: 1.0
7020    */
7021   actor_signals[PICK] =
7022     g_signal_new (I_("pick"),
7023                   G_TYPE_FROM_CLASS (object_class),
7024                   G_SIGNAL_RUN_LAST,
7025                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7026                   NULL, NULL,
7027                   _clutter_marshal_VOID__BOXED,
7028                   G_TYPE_NONE, 1,
7029                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7030
7031   /**
7032    * ClutterActor::allocation-changed:
7033    * @actor: the #ClutterActor that emitted the signal
7034    * @box: a #ClutterActorBox with the new allocation
7035    * @flags: #ClutterAllocationFlags for the allocation
7036    *
7037    * The ::allocation-changed signal is emitted when the
7038    * #ClutterActor:allocation property changes. Usually, application
7039    * code should just use the notifications for the :allocation property
7040    * but if you want to track the allocation flags as well, for instance
7041    * to know whether the absolute origin of @actor changed, then you might
7042    * want use this signal instead.
7043    *
7044    * Since: 1.0
7045    */
7046   actor_signals[ALLOCATION_CHANGED] =
7047     g_signal_new (I_("allocation-changed"),
7048                   G_TYPE_FROM_CLASS (object_class),
7049                   G_SIGNAL_RUN_LAST,
7050                   0,
7051                   NULL, NULL,
7052                   _clutter_marshal_VOID__BOXED_FLAGS,
7053                   G_TYPE_NONE, 2,
7054                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7055                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7056
7057   /**
7058    * ClutterActor::transitions-completed:
7059    * @actor: a #ClutterActor
7060    *
7061    * The ::transitions-completed signal is emitted once all transitions
7062    * involving @actor are complete.
7063    *
7064    * Since: 1.10
7065    */
7066   actor_signals[TRANSITIONS_COMPLETED] =
7067     g_signal_new (I_("transitions-completed"),
7068                   G_TYPE_FROM_CLASS (object_class),
7069                   G_SIGNAL_RUN_LAST,
7070                   0,
7071                   NULL, NULL,
7072                   _clutter_marshal_VOID__VOID,
7073                   G_TYPE_NONE, 0);
7074 }
7075
7076 static void
7077 clutter_actor_init (ClutterActor *self)
7078 {
7079   ClutterActorPrivate *priv;
7080
7081   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7082
7083   priv->id = _clutter_context_acquire_id (self);
7084   priv->pick_id = -1;
7085
7086   priv->opacity = 0xff;
7087   priv->show_on_set_parent = TRUE;
7088
7089   priv->needs_width_request = TRUE;
7090   priv->needs_height_request = TRUE;
7091   priv->needs_allocation = TRUE;
7092
7093   priv->cached_width_age = 1;
7094   priv->cached_height_age = 1;
7095
7096   priv->opacity_override = -1;
7097   priv->enable_model_view_transform = TRUE;
7098
7099   /* Initialize an empty paint volume to start with */
7100   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7101   priv->last_paint_volume_valid = TRUE;
7102
7103   priv->transform_valid = FALSE;
7104
7105   /* the default is to stretch the content, to match the
7106    * current behaviour of basically all actors. also, it's
7107    * the easiest thing to compute.
7108    */
7109   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7110   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7111   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7112 }
7113
7114 /**
7115  * clutter_actor_new:
7116  *
7117  * Creates a new #ClutterActor.
7118  *
7119  * A newly created actor has a floating reference, which will be sunk
7120  * when it is added to another actor.
7121  *
7122  * Return value: (transfer full): the newly created #ClutterActor
7123  *
7124  * Since: 1.10
7125  */
7126 ClutterActor *
7127 clutter_actor_new (void)
7128 {
7129   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7130 }
7131
7132 /**
7133  * clutter_actor_destroy:
7134  * @self: a #ClutterActor
7135  *
7136  * Destroys an actor.  When an actor is destroyed, it will break any
7137  * references it holds to other objects.  If the actor is inside a
7138  * container, the actor will be removed.
7139  *
7140  * When you destroy a container, its children will be destroyed as well.
7141  *
7142  * Note: you cannot destroy the #ClutterStage returned by
7143  * clutter_stage_get_default().
7144  */
7145 void
7146 clutter_actor_destroy (ClutterActor *self)
7147 {
7148   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7149
7150   g_object_ref (self);
7151
7152   /* avoid recursion while destroying */
7153   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7154     {
7155       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7156
7157       g_object_run_dispose (G_OBJECT (self));
7158
7159       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7160     }
7161
7162   g_object_unref (self);
7163 }
7164
7165 void
7166 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7167                                     ClutterPaintVolume *clip)
7168 {
7169   ClutterActorPrivate *priv = self->priv;
7170   ClutterPaintVolume *pv;
7171   gboolean clipped;
7172
7173   /* Remove queue entry early in the process, otherwise a new
7174      queue_redraw() during signal handling could put back this
7175      object in the stage redraw list (but the entry is freed as
7176      soon as we return from this function, causing a segfault
7177      later)
7178   */
7179   priv->queue_redraw_entry = NULL;
7180
7181   /* If we've been explicitly passed a clip volume then there's
7182    * nothing more to calculate, but otherwise the only thing we know
7183    * is that the change is constrained to the given actor.
7184    *
7185    * The idea is that if we know the paint volume for where the actor
7186    * was last drawn (in eye coordinates) and we also have the paint
7187    * volume for where it will be drawn next (in actor coordinates)
7188    * then if we queue a redraw for both these volumes that will cover
7189    * everything that needs to be redrawn to clear the old view and
7190    * show the latest view of the actor.
7191    *
7192    * Don't clip this redraw if we don't know what position we had for
7193    * the previous redraw since we don't know where to set the clip so
7194    * it will clear the actor as it is currently.
7195    */
7196   if (clip)
7197     {
7198       _clutter_actor_set_queue_redraw_clip (self, clip);
7199       clipped = TRUE;
7200     }
7201   else if (G_LIKELY (priv->last_paint_volume_valid))
7202     {
7203       pv = _clutter_actor_get_paint_volume_mutable (self);
7204       if (pv)
7205         {
7206           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7207
7208           /* make sure we redraw the actors old position... */
7209           _clutter_actor_set_queue_redraw_clip (stage,
7210                                                 &priv->last_paint_volume);
7211           _clutter_actor_signal_queue_redraw (stage, stage);
7212           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7213
7214           /* XXX: Ideally the redraw signal would take a clip volume
7215            * argument, but that would be an ABI break. Until we can
7216            * break the ABI we pass the argument out-of-band
7217            */
7218
7219           /* setup the clip for the actors new position... */
7220           _clutter_actor_set_queue_redraw_clip (self, pv);
7221           clipped = TRUE;
7222         }
7223       else
7224         clipped = FALSE;
7225     }
7226   else
7227     clipped = FALSE;
7228
7229   _clutter_actor_signal_queue_redraw (self, self);
7230
7231   /* Just in case anyone is manually firing redraw signals without
7232    * using the public queue_redraw() API we are careful to ensure that
7233    * our out-of-band clip member is cleared before returning...
7234    *
7235    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7236    */
7237   if (G_LIKELY (clipped))
7238     _clutter_actor_set_queue_redraw_clip (self, NULL);
7239 }
7240
7241 static void
7242 _clutter_actor_get_allocation_clip (ClutterActor *self,
7243                                     ClutterActorBox *clip)
7244 {
7245   ClutterActorBox allocation;
7246
7247   /* XXX: we don't care if we get an out of date allocation here
7248    * because clutter_actor_queue_redraw_with_clip knows to ignore
7249    * the clip if the actor's allocation is invalid.
7250    *
7251    * This is noted because clutter_actor_get_allocation_box does some
7252    * unnecessary work to support buggy code with a comment suggesting
7253    * that it could be changed later which would be good for this use
7254    * case!
7255    */
7256   clutter_actor_get_allocation_box (self, &allocation);
7257
7258   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7259    * actor's own coordinate space but the allocation is in parent
7260    * coordinates */
7261   clip->x1 = 0;
7262   clip->y1 = 0;
7263   clip->x2 = allocation.x2 - allocation.x1;
7264   clip->y2 = allocation.y2 - allocation.y1;
7265 }
7266
7267 void
7268 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7269                                   ClutterRedrawFlags  flags,
7270                                   ClutterPaintVolume *volume,
7271                                   ClutterEffect      *effect)
7272 {
7273   ClutterActorPrivate *priv = self->priv;
7274   ClutterPaintVolume allocation_pv;
7275   ClutterPaintVolume *pv;
7276   gboolean should_free_pv;
7277   ClutterActor *stage;
7278
7279   /* Here's an outline of the actor queue redraw mechanism:
7280    *
7281    * The process starts in one of the following two functions which
7282    * are wrappers for this function:
7283    * clutter_actor_queue_redraw
7284    * _clutter_actor_queue_redraw_with_clip
7285    *
7286    * additionally, an effect can queue a redraw by wrapping this
7287    * function in clutter_effect_queue_rerun
7288    *
7289    * This functions queues an entry in a list associated with the
7290    * stage which is a list of actors that queued a redraw while
7291    * updating the timelines, performing layouting and processing other
7292    * mainloop sources before the next paint starts.
7293    *
7294    * We aim to minimize the processing done at this point because
7295    * there is a good chance other events will happen while updating
7296    * the scenegraph that would invalidate any expensive work we might
7297    * otherwise try to do here. For example we don't try and resolve
7298    * the screen space bounding box of an actor at this stage so as to
7299    * minimize how much of the screen redraw because it's possible
7300    * something else will happen which will force a full redraw anyway.
7301    *
7302    * When all updates are complete and we come to paint the stage then
7303    * we iterate this list and actually emit the "queue-redraw" signals
7304    * for each of the listed actors which will bubble up to the stage
7305    * for each actor and at that point we will transform the actors
7306    * paint volume into screen coordinates to determine the clip region
7307    * for what needs to be redrawn in the next paint.
7308    *
7309    * Besides minimizing redundant work another reason for this
7310    * deferred design is that it's more likely we will be able to
7311    * determine the paint volume of an actor once we've finished
7312    * updating the scenegraph because its allocation should be up to
7313    * date. NB: If we can't determine an actors paint volume then we
7314    * can't automatically queue a clipped redraw which can make a big
7315    * difference to performance.
7316    *
7317    * So the control flow goes like this:
7318    * One of clutter_actor_queue_redraw,
7319    *        _clutter_actor_queue_redraw_with_clip
7320    *     or clutter_effect_queue_rerun
7321    *
7322    * then control moves to:
7323    *   _clutter_stage_queue_actor_redraw
7324    *
7325    * later during _clutter_stage_do_update, once relayouting is done
7326    * and the scenegraph has been updated we will call:
7327    * _clutter_stage_finish_queue_redraws
7328    *
7329    * _clutter_stage_finish_queue_redraws will call
7330    * _clutter_actor_finish_queue_redraw for each listed actor.
7331    * Note: actors *are* allowed to queue further redraws during this
7332    * process (considering clone actors or texture_new_from_actor which
7333    * respond to their source queueing a redraw by queuing a redraw
7334    * themselves). We repeat the process until the list is empty.
7335    *
7336    * This will result in the "queue-redraw" signal being fired for
7337    * each actor which will pass control to the default signal handler:
7338    * clutter_actor_real_queue_redraw
7339    *
7340    * This will bubble up to the stages handler:
7341    * clutter_stage_real_queue_redraw
7342    *
7343    * clutter_stage_real_queue_redraw will transform the actors paint
7344    * volume into screen space and add it as a clip region for the next
7345    * paint.
7346    */
7347
7348   /* ignore queueing a redraw for actors being destroyed */
7349   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7350     return;
7351
7352   stage = _clutter_actor_get_stage_internal (self);
7353
7354   /* Ignore queueing a redraw for actors not descended from a stage */
7355   if (stage == NULL)
7356     return;
7357
7358   /* ignore queueing a redraw on stages that are being destroyed */
7359   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7360     return;
7361
7362   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7363     {
7364       ClutterActorBox allocation_clip;
7365       ClutterVertex origin;
7366
7367       /* If the actor doesn't have a valid allocation then we will
7368        * queue a full stage redraw. */
7369       if (priv->needs_allocation)
7370         {
7371           /* NB: NULL denotes an undefined clip which will result in a
7372            * full redraw... */
7373           _clutter_actor_set_queue_redraw_clip (self, NULL);
7374           _clutter_actor_signal_queue_redraw (self, self);
7375           return;
7376         }
7377
7378       _clutter_paint_volume_init_static (&allocation_pv, self);
7379       pv = &allocation_pv;
7380
7381       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7382
7383       origin.x = allocation_clip.x1;
7384       origin.y = allocation_clip.y1;
7385       origin.z = 0;
7386       clutter_paint_volume_set_origin (pv, &origin);
7387       clutter_paint_volume_set_width (pv,
7388                                       allocation_clip.x2 - allocation_clip.x1);
7389       clutter_paint_volume_set_height (pv,
7390                                        allocation_clip.y2 -
7391                                        allocation_clip.y1);
7392       should_free_pv = TRUE;
7393     }
7394   else
7395     {
7396       pv = volume;
7397       should_free_pv = FALSE;
7398     }
7399
7400   self->priv->queue_redraw_entry =
7401     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7402                                        priv->queue_redraw_entry,
7403                                        self,
7404                                        pv);
7405
7406   if (should_free_pv)
7407     clutter_paint_volume_free (pv);
7408
7409   /* If this is the first redraw queued then we can directly use the
7410      effect parameter */
7411   if (!priv->is_dirty)
7412     priv->effect_to_redraw = effect;
7413   /* Otherwise we need to merge it with the existing effect parameter */
7414   else if (effect != NULL)
7415     {
7416       /* If there's already an effect then we need to use whichever is
7417          later in the chain of actors. Otherwise a full redraw has
7418          already been queued on the actor so we need to ignore the
7419          effect parameter */
7420       if (priv->effect_to_redraw != NULL)
7421         {
7422           if (priv->effects == NULL)
7423             g_warning ("Redraw queued with an effect that is "
7424                        "not applied to the actor");
7425           else
7426             {
7427               const GList *l;
7428
7429               for (l = _clutter_meta_group_peek_metas (priv->effects);
7430                    l != NULL;
7431                    l = l->next)
7432                 {
7433                   if (l->data == priv->effect_to_redraw ||
7434                       l->data == effect)
7435                     priv->effect_to_redraw = l->data;
7436                 }
7437             }
7438         }
7439     }
7440   else
7441     {
7442       /* If no effect is specified then we need to redraw the whole
7443          actor */
7444       priv->effect_to_redraw = NULL;
7445     }
7446
7447   priv->is_dirty = TRUE;
7448 }
7449
7450 /**
7451  * clutter_actor_queue_redraw:
7452  * @self: A #ClutterActor
7453  *
7454  * Queues up a redraw of an actor and any children. The redraw occurs
7455  * once the main loop becomes idle (after the current batch of events
7456  * has been processed, roughly).
7457  *
7458  * Applications rarely need to call this, as redraws are handled
7459  * automatically by modification functions.
7460  *
7461  * This function will not do anything if @self is not visible, or
7462  * if the actor is inside an invisible part of the scenegraph.
7463  *
7464  * Also be aware that painting is a NOP for actors with an opacity of
7465  * 0
7466  *
7467  * When you are implementing a custom actor you must queue a redraw
7468  * whenever some private state changes that will affect painting or
7469  * picking of your actor.
7470  */
7471 void
7472 clutter_actor_queue_redraw (ClutterActor *self)
7473 {
7474   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7475
7476   _clutter_actor_queue_redraw_full (self,
7477                                     0, /* flags */
7478                                     NULL, /* clip volume */
7479                                     NULL /* effect */);
7480 }
7481
7482 /*< private >
7483  * _clutter_actor_queue_redraw_with_clip:
7484  * @self: A #ClutterActor
7485  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7486  *   this queue redraw.
7487  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7488  *   redrawn or %NULL if you are just using a @flag to state your
7489  *   desired clipping.
7490  *
7491  * Queues up a clipped redraw of an actor and any children. The redraw
7492  * occurs once the main loop becomes idle (after the current batch of
7493  * events has been processed, roughly).
7494  *
7495  * If no flags are given the clip volume is defined by @volume
7496  * specified in actor coordinates and tells Clutter that only content
7497  * within this volume has been changed so Clutter can optionally
7498  * optimize the redraw.
7499  *
7500  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7501  * should be %NULL and this tells Clutter to use the actor's current
7502  * allocation as a clip box. This flag can only be used for 2D actors,
7503  * because any actor with depth may be projected outside its
7504  * allocation.
7505  *
7506  * Applications rarely need to call this, as redraws are handled
7507  * automatically by modification functions.
7508  *
7509  * This function will not do anything if @self is not visible, or if
7510  * the actor is inside an invisible part of the scenegraph.
7511  *
7512  * Also be aware that painting is a NOP for actors with an opacity of
7513  * 0
7514  *
7515  * When you are implementing a custom actor you must queue a redraw
7516  * whenever some private state changes that will affect painting or
7517  * picking of your actor.
7518  */
7519 void
7520 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7521                                        ClutterRedrawFlags  flags,
7522                                        ClutterPaintVolume *volume)
7523 {
7524   _clutter_actor_queue_redraw_full (self,
7525                                     flags, /* flags */
7526                                     volume, /* clip volume */
7527                                     NULL /* effect */);
7528 }
7529
7530 static void
7531 _clutter_actor_queue_only_relayout (ClutterActor *self)
7532 {
7533   ClutterActorPrivate *priv = self->priv;
7534
7535   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7536     return;
7537
7538   if (priv->needs_width_request &&
7539       priv->needs_height_request &&
7540       priv->needs_allocation)
7541     return; /* save some cpu cycles */
7542
7543 #if CLUTTER_ENABLE_DEBUG
7544   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7545     {
7546       g_warning ("The actor '%s' is currently inside an allocation "
7547                  "cycle; calling clutter_actor_queue_relayout() is "
7548                  "not recommended",
7549                  _clutter_actor_get_debug_name (self));
7550     }
7551 #endif /* CLUTTER_ENABLE_DEBUG */
7552
7553   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7554 }
7555
7556 /**
7557  * clutter_actor_queue_redraw_with_clip:
7558  * @self: a #ClutterActor
7559  * @clip: (allow-none): a rectangular clip region, or %NULL
7560  *
7561  * Queues a redraw on @self limited to a specific, actor-relative
7562  * rectangular area.
7563  *
7564  * If @clip is %NULL this function is equivalent to
7565  * clutter_actor_queue_redraw().
7566  *
7567  * Since: 1.10
7568  */
7569 void
7570 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7571                                       const cairo_rectangle_int_t *clip)
7572 {
7573   ClutterPaintVolume volume;
7574   ClutterVertex origin;
7575
7576   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7577
7578   if (clip == NULL)
7579     {
7580       clutter_actor_queue_redraw (self);
7581       return;
7582     }
7583
7584   _clutter_paint_volume_init_static (&volume, self);
7585
7586   origin.x = clip->x;
7587   origin.y = clip->y;
7588   origin.z = 0.0f;
7589
7590   clutter_paint_volume_set_origin (&volume, &origin);
7591   clutter_paint_volume_set_width (&volume, clip->width);
7592   clutter_paint_volume_set_height (&volume, clip->height);
7593
7594   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7595
7596   clutter_paint_volume_free (&volume);
7597 }
7598
7599 /**
7600  * clutter_actor_queue_relayout:
7601  * @self: A #ClutterActor
7602  *
7603  * Indicates that the actor's size request or other layout-affecting
7604  * properties may have changed. This function is used inside #ClutterActor
7605  * subclass implementations, not by applications directly.
7606  *
7607  * Queueing a new layout automatically queues a redraw as well.
7608  *
7609  * Since: 0.8
7610  */
7611 void
7612 clutter_actor_queue_relayout (ClutterActor *self)
7613 {
7614   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7615
7616   _clutter_actor_queue_only_relayout (self);
7617   clutter_actor_queue_redraw (self);
7618 }
7619
7620 /**
7621  * clutter_actor_get_preferred_size:
7622  * @self: a #ClutterActor
7623  * @min_width_p: (out) (allow-none): return location for the minimum
7624  *   width, or %NULL
7625  * @min_height_p: (out) (allow-none): return location for the minimum
7626  *   height, or %NULL
7627  * @natural_width_p: (out) (allow-none): return location for the natural
7628  *   width, or %NULL
7629  * @natural_height_p: (out) (allow-none): return location for the natural
7630  *   height, or %NULL
7631  *
7632  * Computes the preferred minimum and natural size of an actor, taking into
7633  * account the actor's geometry management (either height-for-width
7634  * or width-for-height).
7635  *
7636  * The width and height used to compute the preferred height and preferred
7637  * width are the actor's natural ones.
7638  *
7639  * If you need to control the height for the preferred width, or the width for
7640  * the preferred height, you should use clutter_actor_get_preferred_width()
7641  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7642  * geometry management using the #ClutterActor:request-mode property.
7643  *
7644  * Since: 0.8
7645  */
7646 void
7647 clutter_actor_get_preferred_size (ClutterActor *self,
7648                                   gfloat       *min_width_p,
7649                                   gfloat       *min_height_p,
7650                                   gfloat       *natural_width_p,
7651                                   gfloat       *natural_height_p)
7652 {
7653   ClutterActorPrivate *priv;
7654   gfloat min_width, min_height;
7655   gfloat natural_width, natural_height;
7656
7657   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7658
7659   priv = self->priv;
7660
7661   min_width = min_height = 0;
7662   natural_width = natural_height = 0;
7663
7664   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7665     {
7666       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7667       clutter_actor_get_preferred_width (self, -1,
7668                                          &min_width,
7669                                          &natural_width);
7670       clutter_actor_get_preferred_height (self, natural_width,
7671                                           &min_height,
7672                                           &natural_height);
7673     }
7674   else
7675     {
7676       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7677       clutter_actor_get_preferred_height (self, -1,
7678                                           &min_height,
7679                                           &natural_height);
7680       clutter_actor_get_preferred_width (self, natural_height,
7681                                          &min_width,
7682                                          &natural_width);
7683     }
7684
7685   if (min_width_p)
7686     *min_width_p = min_width;
7687
7688   if (min_height_p)
7689     *min_height_p = min_height;
7690
7691   if (natural_width_p)
7692     *natural_width_p = natural_width;
7693
7694   if (natural_height_p)
7695     *natural_height_p = natural_height;
7696 }
7697
7698 /*< private >
7699  * effective_align:
7700  * @align: a #ClutterActorAlign
7701  * @direction: a #ClutterTextDirection
7702  *
7703  * Retrieves the correct alignment depending on the text direction
7704  *
7705  * Return value: the effective alignment
7706  */
7707 static ClutterActorAlign
7708 effective_align (ClutterActorAlign    align,
7709                  ClutterTextDirection direction)
7710 {
7711   ClutterActorAlign res;
7712
7713   switch (align)
7714     {
7715     case CLUTTER_ACTOR_ALIGN_START:
7716       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7717           ? CLUTTER_ACTOR_ALIGN_END
7718           : CLUTTER_ACTOR_ALIGN_START;
7719       break;
7720
7721     case CLUTTER_ACTOR_ALIGN_END:
7722       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7723           ? CLUTTER_ACTOR_ALIGN_START
7724           : CLUTTER_ACTOR_ALIGN_END;
7725       break;
7726
7727     default:
7728       res = align;
7729       break;
7730     }
7731
7732   return res;
7733 }
7734
7735 static inline void
7736 adjust_for_margin (float  margin_start,
7737                    float  margin_end,
7738                    float *minimum_size,
7739                    float *natural_size,
7740                    float *allocated_start,
7741                    float *allocated_end)
7742 {
7743   *minimum_size -= (margin_start + margin_end);
7744   *natural_size -= (margin_start + margin_end);
7745   *allocated_start += margin_start;
7746   *allocated_end -= margin_end;
7747 }
7748
7749 static inline void
7750 adjust_for_alignment (ClutterActorAlign  alignment,
7751                       float              natural_size,
7752                       float             *allocated_start,
7753                       float             *allocated_end)
7754 {
7755   float allocated_size = *allocated_end - *allocated_start;
7756
7757   switch (alignment)
7758     {
7759     case CLUTTER_ACTOR_ALIGN_FILL:
7760       /* do nothing */
7761       break;
7762
7763     case CLUTTER_ACTOR_ALIGN_START:
7764       /* keep start */
7765       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7766       break;
7767
7768     case CLUTTER_ACTOR_ALIGN_END:
7769       if (allocated_size > natural_size)
7770         {
7771           *allocated_start += (allocated_size - natural_size);
7772           *allocated_end = *allocated_start + natural_size;
7773         }
7774       break;
7775
7776     case CLUTTER_ACTOR_ALIGN_CENTER:
7777       if (allocated_size > natural_size)
7778         {
7779           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7780           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7781         }
7782       break;
7783     }
7784 }
7785
7786 /*< private >
7787  * clutter_actor_adjust_width:
7788  * @self: a #ClutterActor
7789  * @minimum_width: (inout): the actor's preferred minimum width, which
7790  *   will be adjusted depending on the margin
7791  * @natural_width: (inout): the actor's preferred natural width, which
7792  *   will be adjusted depending on the margin
7793  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7794  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7795  *
7796  * Adjusts the preferred and allocated position and size of an actor,
7797  * depending on the margin and alignment properties.
7798  */
7799 static void
7800 clutter_actor_adjust_width (ClutterActor *self,
7801                             gfloat       *minimum_width,
7802                             gfloat       *natural_width,
7803                             gfloat       *adjusted_x1,
7804                             gfloat       *adjusted_x2)
7805 {
7806   ClutterTextDirection text_dir;
7807   const ClutterLayoutInfo *info;
7808
7809   info = _clutter_actor_get_layout_info_or_defaults (self);
7810   text_dir = clutter_actor_get_text_direction (self);
7811
7812   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7813
7814   /* this will tweak natural_width to remove the margin, so that
7815    * adjust_for_alignment() will use the correct size
7816    */
7817   adjust_for_margin (info->margin.left, info->margin.right,
7818                      minimum_width, natural_width,
7819                      adjusted_x1, adjusted_x2);
7820
7821   adjust_for_alignment (effective_align (info->x_align, text_dir),
7822                         *natural_width,
7823                         adjusted_x1, adjusted_x2);
7824 }
7825
7826 /*< private >
7827  * clutter_actor_adjust_height:
7828  * @self: a #ClutterActor
7829  * @minimum_height: (inout): the actor's preferred minimum height, which
7830  *   will be adjusted depending on the margin
7831  * @natural_height: (inout): the actor's preferred natural height, which
7832  *   will be adjusted depending on the margin
7833  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7834  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7835  *
7836  * Adjusts the preferred and allocated position and size of an actor,
7837  * depending on the margin and alignment properties.
7838  */
7839 static void
7840 clutter_actor_adjust_height (ClutterActor *self,
7841                              gfloat       *minimum_height,
7842                              gfloat       *natural_height,
7843                              gfloat       *adjusted_y1,
7844                              gfloat       *adjusted_y2)
7845 {
7846   const ClutterLayoutInfo *info;
7847
7848   info = _clutter_actor_get_layout_info_or_defaults (self);
7849
7850   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7851
7852   /* this will tweak natural_height to remove the margin, so that
7853    * adjust_for_alignment() will use the correct size
7854    */
7855   adjust_for_margin (info->margin.top, info->margin.bottom,
7856                      minimum_height, natural_height,
7857                      adjusted_y1,
7858                      adjusted_y2);
7859
7860   /* we don't use effective_align() here, because text direction
7861    * only affects the horizontal axis
7862    */
7863   adjust_for_alignment (info->y_align,
7864                         *natural_height,
7865                         adjusted_y1,
7866                         adjusted_y2);
7867
7868 }
7869
7870 /* looks for a cached size request for this for_size. If not
7871  * found, returns the oldest entry so it can be overwritten */
7872 static gboolean
7873 _clutter_actor_get_cached_size_request (gfloat         for_size,
7874                                         SizeRequest   *cached_size_requests,
7875                                         SizeRequest  **result)
7876 {
7877   guint i;
7878
7879   *result = &cached_size_requests[0];
7880
7881   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7882     {
7883       SizeRequest *sr;
7884
7885       sr = &cached_size_requests[i];
7886
7887       if (sr->age > 0 &&
7888           sr->for_size == for_size)
7889         {
7890           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7891           *result = sr;
7892           return TRUE;
7893         }
7894       else if (sr->age < (*result)->age)
7895         {
7896           *result = sr;
7897         }
7898     }
7899
7900   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7901
7902   return FALSE;
7903 }
7904
7905 /**
7906  * clutter_actor_get_preferred_width:
7907  * @self: A #ClutterActor
7908  * @for_height: available height when computing the preferred width,
7909  *   or a negative value to indicate that no height is defined
7910  * @min_width_p: (out) (allow-none): return location for minimum width,
7911  *   or %NULL
7912  * @natural_width_p: (out) (allow-none): return location for the natural
7913  *   width, or %NULL
7914  *
7915  * Computes the requested minimum and natural widths for an actor,
7916  * optionally depending on the specified height, or if they are
7917  * already computed, returns the cached values.
7918  *
7919  * An actor may not get its request - depending on the layout
7920  * manager that's in effect.
7921  *
7922  * A request should not incorporate the actor's scale or anchor point;
7923  * those transformations do not affect layout, only rendering.
7924  *
7925  * Since: 0.8
7926  */
7927 void
7928 clutter_actor_get_preferred_width (ClutterActor *self,
7929                                    gfloat        for_height,
7930                                    gfloat       *min_width_p,
7931                                    gfloat       *natural_width_p)
7932 {
7933   float request_min_width, request_natural_width;
7934   SizeRequest *cached_size_request;
7935   const ClutterLayoutInfo *info;
7936   ClutterActorPrivate *priv;
7937   gboolean found_in_cache;
7938
7939   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7940
7941   priv = self->priv;
7942
7943   info = _clutter_actor_get_layout_info_or_defaults (self);
7944
7945   /* we shortcircuit the case of a fixed size set using set_width() */
7946   if (priv->min_width_set && priv->natural_width_set)
7947     {
7948       if (min_width_p != NULL)
7949         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7950
7951       if (natural_width_p != NULL)
7952         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7953
7954       return;
7955     }
7956
7957   /* the remaining cases are:
7958    *
7959    *   - either min_width or natural_width have been set
7960    *   - neither min_width or natural_width have been set
7961    *
7962    * in both cases, we go through the cache (and through the actor in case
7963    * of cache misses) and determine the authoritative value depending on
7964    * the *_set flags.
7965    */
7966
7967   if (!priv->needs_width_request)
7968     {
7969       found_in_cache =
7970         _clutter_actor_get_cached_size_request (for_height,
7971                                                 priv->width_requests,
7972                                                 &cached_size_request);
7973     }
7974   else
7975     {
7976       /* if the actor needs a width request we use the first slot */
7977       found_in_cache = FALSE;
7978       cached_size_request = &priv->width_requests[0];
7979     }
7980
7981   if (!found_in_cache)
7982     {
7983       gfloat minimum_width, natural_width;
7984       ClutterActorClass *klass;
7985
7986       minimum_width = natural_width = 0;
7987
7988       /* adjust for the margin */
7989       if (for_height >= 0)
7990         {
7991           for_height -= (info->margin.top + info->margin.bottom);
7992           if (for_height < 0)
7993             for_height = 0;
7994         }
7995
7996       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7997
7998       klass = CLUTTER_ACTOR_GET_CLASS (self);
7999       klass->get_preferred_width (self, for_height,
8000                                   &minimum_width,
8001                                   &natural_width);
8002
8003       /* adjust for the margin */
8004       minimum_width += (info->margin.left + info->margin.right);
8005       natural_width += (info->margin.left + info->margin.right);
8006
8007       /* Due to accumulated float errors, it's better not to warn
8008        * on this, but just fix it.
8009        */
8010       if (natural_width < minimum_width)
8011         natural_width = minimum_width;
8012
8013       cached_size_request->min_size = minimum_width;
8014       cached_size_request->natural_size = natural_width;
8015       cached_size_request->for_size = for_height;
8016       cached_size_request->age = priv->cached_width_age;
8017
8018       priv->cached_width_age += 1;
8019       priv->needs_width_request = FALSE;
8020     }
8021
8022   if (!priv->min_width_set)
8023     request_min_width = cached_size_request->min_size;
8024   else
8025     request_min_width = info->min_width;
8026
8027   if (!priv->natural_width_set)
8028     request_natural_width = cached_size_request->natural_size;
8029   else
8030     request_natural_width = info->natural_width;
8031
8032   if (min_width_p)
8033     *min_width_p = request_min_width;
8034
8035   if (natural_width_p)
8036     *natural_width_p = request_natural_width;
8037 }
8038
8039 /**
8040  * clutter_actor_get_preferred_height:
8041  * @self: A #ClutterActor
8042  * @for_width: available width to assume in computing desired height,
8043  *   or a negative value to indicate that no width is defined
8044  * @min_height_p: (out) (allow-none): return location for minimum height,
8045  *   or %NULL
8046  * @natural_height_p: (out) (allow-none): return location for natural
8047  *   height, or %NULL
8048  *
8049  * Computes the requested minimum and natural heights for an actor,
8050  * or if they are already computed, returns the cached values.
8051  *
8052  * An actor may not get its request - depending on the layout
8053  * manager that's in effect.
8054  *
8055  * A request should not incorporate the actor's scale or anchor point;
8056  * those transformations do not affect layout, only rendering.
8057  *
8058  * Since: 0.8
8059  */
8060 void
8061 clutter_actor_get_preferred_height (ClutterActor *self,
8062                                     gfloat        for_width,
8063                                     gfloat       *min_height_p,
8064                                     gfloat       *natural_height_p)
8065 {
8066   float request_min_height, request_natural_height;
8067   SizeRequest *cached_size_request;
8068   const ClutterLayoutInfo *info;
8069   ClutterActorPrivate *priv;
8070   gboolean found_in_cache;
8071
8072   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8073
8074   priv = self->priv;
8075
8076   info = _clutter_actor_get_layout_info_or_defaults (self);
8077
8078   /* we shortcircuit the case of a fixed size set using set_height() */
8079   if (priv->min_height_set && priv->natural_height_set)
8080     {
8081       if (min_height_p != NULL)
8082         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8083
8084       if (natural_height_p != NULL)
8085         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8086
8087       return;
8088     }
8089
8090   /* the remaining cases are:
8091    *
8092    *   - either min_height or natural_height have been set
8093    *   - neither min_height or natural_height have been set
8094    *
8095    * in both cases, we go through the cache (and through the actor in case
8096    * of cache misses) and determine the authoritative value depending on
8097    * the *_set flags.
8098    */
8099
8100   if (!priv->needs_height_request)
8101     {
8102       found_in_cache =
8103         _clutter_actor_get_cached_size_request (for_width,
8104                                                 priv->height_requests,
8105                                                 &cached_size_request);
8106     }
8107   else
8108     {
8109       found_in_cache = FALSE;
8110       cached_size_request = &priv->height_requests[0];
8111     }
8112
8113   if (!found_in_cache)
8114     {
8115       gfloat minimum_height, natural_height;
8116       ClutterActorClass *klass;
8117
8118       minimum_height = natural_height = 0;
8119
8120       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8121
8122       /* adjust for margin */
8123       if (for_width >= 0)
8124         {
8125           for_width -= (info->margin.left + info->margin.right);
8126           if (for_width < 0)
8127             for_width = 0;
8128         }
8129
8130       klass = CLUTTER_ACTOR_GET_CLASS (self);
8131       klass->get_preferred_height (self, for_width,
8132                                    &minimum_height,
8133                                    &natural_height);
8134
8135       /* adjust for margin */
8136       minimum_height += (info->margin.top + info->margin.bottom);
8137       natural_height += (info->margin.top + info->margin.bottom);
8138
8139       /* Due to accumulated float errors, it's better not to warn
8140        * on this, but just fix it.
8141        */
8142       if (natural_height < minimum_height)
8143         natural_height = minimum_height;
8144
8145       cached_size_request->min_size = minimum_height;
8146       cached_size_request->natural_size = natural_height;
8147       cached_size_request->for_size = for_width;
8148       cached_size_request->age = priv->cached_height_age;
8149
8150       priv->cached_height_age += 1;
8151       priv->needs_height_request = FALSE;
8152     }
8153
8154   if (!priv->min_height_set)
8155     request_min_height = cached_size_request->min_size;
8156   else
8157     request_min_height = info->min_height;
8158
8159   if (!priv->natural_height_set)
8160     request_natural_height = cached_size_request->natural_size;
8161   else
8162     request_natural_height = info->natural_height;
8163
8164   if (min_height_p)
8165     *min_height_p = request_min_height;
8166
8167   if (natural_height_p)
8168     *natural_height_p = request_natural_height;
8169 }
8170
8171 /**
8172  * clutter_actor_get_allocation_box:
8173  * @self: A #ClutterActor
8174  * @box: (out): the function fills this in with the actor's allocation
8175  *
8176  * Gets the layout box an actor has been assigned. The allocation can
8177  * only be assumed valid inside a paint() method; anywhere else, it
8178  * may be out-of-date.
8179  *
8180  * An allocation does not incorporate the actor's scale or anchor point;
8181  * those transformations do not affect layout, only rendering.
8182  *
8183  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8184  * of functions inside the implementation of the get_preferred_width()
8185  * or get_preferred_height() virtual functions.</note>
8186  *
8187  * Since: 0.8
8188  */
8189 void
8190 clutter_actor_get_allocation_box (ClutterActor    *self,
8191                                   ClutterActorBox *box)
8192 {
8193   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8194
8195   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8196    * which limits calling get_allocation to inside paint() basically; or
8197    * we can 2) force a layout, which could be expensive if someone calls
8198    * get_allocation somewhere silly; or we can 3) just return the latest
8199    * value, allowing it to be out-of-date, and assume people know what
8200    * they are doing.
8201    *
8202    * The least-surprises approach that keeps existing code working is
8203    * likely to be 2). People can end up doing some inefficient things,
8204    * though, and in general code that requires 2) is probably broken.
8205    */
8206
8207   /* this implements 2) */
8208   if (G_UNLIKELY (self->priv->needs_allocation))
8209     {
8210       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8211
8212       /* do not queue a relayout on an unparented actor */
8213       if (stage)
8214         _clutter_stage_maybe_relayout (stage);
8215     }
8216
8217   /* commenting out the code above and just keeping this assigment
8218    * implements 3)
8219    */
8220   *box = self->priv->allocation;
8221 }
8222
8223 /**
8224  * clutter_actor_get_allocation_geometry:
8225  * @self: A #ClutterActor
8226  * @geom: (out): allocation geometry in pixels
8227  *
8228  * Gets the layout box an actor has been assigned.  The allocation can
8229  * only be assumed valid inside a paint() method; anywhere else, it
8230  * may be out-of-date.
8231  *
8232  * An allocation does not incorporate the actor's scale or anchor point;
8233  * those transformations do not affect layout, only rendering.
8234  *
8235  * The returned rectangle is in pixels.
8236  *
8237  * Since: 0.8
8238  */
8239 void
8240 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8241                                        ClutterGeometry *geom)
8242 {
8243   ClutterActorBox box;
8244
8245   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8246   g_return_if_fail (geom != NULL);
8247
8248   clutter_actor_get_allocation_box (self, &box);
8249
8250   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8251   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8252   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8253   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8254 }
8255
8256 static void
8257 clutter_actor_update_constraints (ClutterActor    *self,
8258                                   ClutterActorBox *allocation)
8259 {
8260   ClutterActorPrivate *priv = self->priv;
8261   const GList *constraints, *l;
8262
8263   if (priv->constraints == NULL)
8264     return;
8265
8266   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8267   for (l = constraints; l != NULL; l = l->next)
8268     {
8269       ClutterConstraint *constraint = l->data;
8270       ClutterActorMeta *meta = l->data;
8271
8272       if (clutter_actor_meta_get_enabled (meta))
8273         {
8274           _clutter_constraint_update_allocation (constraint,
8275                                                  self,
8276                                                  allocation);
8277
8278           CLUTTER_NOTE (LAYOUT,
8279                         "Allocation of '%s' after constraint '%s': "
8280                         "{ %.2f, %.2f, %.2f, %.2f }",
8281                         _clutter_actor_get_debug_name (self),
8282                         _clutter_actor_meta_get_debug_name (meta),
8283                         allocation->x1,
8284                         allocation->y1,
8285                         allocation->x2,
8286                         allocation->y2);
8287         }
8288     }
8289 }
8290
8291 /*< private >
8292  * clutter_actor_adjust_allocation:
8293  * @self: a #ClutterActor
8294  * @allocation: (inout): the allocation to adjust
8295  *
8296  * Adjusts the passed allocation box taking into account the actor's
8297  * layout information, like alignment, expansion, and margin.
8298  */
8299 static void
8300 clutter_actor_adjust_allocation (ClutterActor    *self,
8301                                  ClutterActorBox *allocation)
8302 {
8303   ClutterActorBox adj_allocation;
8304   float alloc_width, alloc_height;
8305   float min_width, min_height;
8306   float nat_width, nat_height;
8307   ClutterRequestMode req_mode;
8308
8309   adj_allocation = *allocation;
8310
8311   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8312
8313   /* we want to hit the cache, so we use the public API */
8314   req_mode = clutter_actor_get_request_mode (self);
8315
8316   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8317     {
8318       clutter_actor_get_preferred_width (self, -1,
8319                                          &min_width,
8320                                          &nat_width);
8321       clutter_actor_get_preferred_height (self, alloc_width,
8322                                           &min_height,
8323                                           &nat_height);
8324     }
8325   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8326     {
8327       clutter_actor_get_preferred_height (self, -1,
8328                                           &min_height,
8329                                           &nat_height);
8330       clutter_actor_get_preferred_height (self, alloc_height,
8331                                           &min_width,
8332                                           &nat_width);
8333     }
8334
8335 #ifdef CLUTTER_ENABLE_DEBUG
8336   /* warn about underallocations */
8337   if (_clutter_diagnostic_enabled () &&
8338       (floorf (min_width - alloc_width) > 0 ||
8339        floorf (min_height - alloc_height) > 0))
8340     {
8341       ClutterActor *parent = clutter_actor_get_parent (self);
8342
8343       /* the only actors that are allowed to be underallocated are the Stage,
8344        * as it doesn't have an implicit size, and Actors that specifically
8345        * told us that they want to opt-out from layout control mechanisms
8346        * through the NO_LAYOUT escape hatch.
8347        */
8348       if (parent != NULL &&
8349           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8350         {
8351           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8352                      "of %.2f x %.2f from its parent actor '%s', but its "
8353                      "requested minimum size is of %.2f x %.2f",
8354                      _clutter_actor_get_debug_name (self),
8355                      alloc_width, alloc_height,
8356                      _clutter_actor_get_debug_name (parent),
8357                      min_width, min_height);
8358         }
8359     }
8360 #endif
8361
8362   clutter_actor_adjust_width (self,
8363                               &min_width,
8364                               &nat_width,
8365                               &adj_allocation.x1,
8366                               &adj_allocation.x2);
8367
8368   clutter_actor_adjust_height (self,
8369                                &min_height,
8370                                &nat_height,
8371                                &adj_allocation.y1,
8372                                &adj_allocation.y2);
8373
8374   /* we maintain the invariant that an allocation cannot be adjusted
8375    * to be outside the parent-given box
8376    */
8377   if (adj_allocation.x1 < allocation->x1 ||
8378       adj_allocation.y1 < allocation->y1 ||
8379       adj_allocation.x2 > allocation->x2 ||
8380       adj_allocation.y2 > allocation->y2)
8381     {
8382       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8383                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8384                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8385                  _clutter_actor_get_debug_name (self),
8386                  adj_allocation.x1, adj_allocation.y1,
8387                  adj_allocation.x2 - adj_allocation.x1,
8388                  adj_allocation.y2 - adj_allocation.y1,
8389                  allocation->x1, allocation->y1,
8390                  allocation->x2 - allocation->x1,
8391                  allocation->y2 - allocation->y1);
8392       return;
8393     }
8394
8395   *allocation = adj_allocation;
8396 }
8397
8398 /**
8399  * clutter_actor_allocate:
8400  * @self: A #ClutterActor
8401  * @box: new allocation of the actor, in parent-relative coordinates
8402  * @flags: flags that control the allocation
8403  *
8404  * Called by the parent of an actor to assign the actor its size.
8405  * Should never be called by applications (except when implementing
8406  * a container or layout manager).
8407  *
8408  * Actors can know from their allocation box whether they have moved
8409  * with respect to their parent actor. The @flags parameter describes
8410  * additional information about the allocation, for instance whether
8411  * the parent has moved with respect to the stage, for example because
8412  * a grandparent's origin has moved.
8413  *
8414  * Since: 0.8
8415  */
8416 void
8417 clutter_actor_allocate (ClutterActor           *self,
8418                         const ClutterActorBox  *box,
8419                         ClutterAllocationFlags  flags)
8420 {
8421   ClutterActorPrivate *priv;
8422   ClutterActorClass *klass;
8423   ClutterActorBox old_allocation, real_allocation;
8424   gboolean origin_changed, child_moved, size_changed;
8425   gboolean stage_allocation_changed;
8426
8427   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8428   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8429     {
8430       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8431                  "which isn't a descendent of the stage!\n",
8432                  self, _clutter_actor_get_debug_name (self));
8433       return;
8434     }
8435
8436   priv = self->priv;
8437
8438   old_allocation = priv->allocation;
8439   real_allocation = *box;
8440
8441   /* constraints are allowed to modify the allocation only here; we do
8442    * this prior to all the other checks so that we can bail out if the
8443    * allocation did not change
8444    */
8445   clutter_actor_update_constraints (self, &real_allocation);
8446
8447   /* adjust the allocation depending on the align/margin properties */
8448   clutter_actor_adjust_allocation (self, &real_allocation);
8449
8450   if (real_allocation.x2 < real_allocation.x1 ||
8451       real_allocation.y2 < real_allocation.y1)
8452     {
8453       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8454                  _clutter_actor_get_debug_name (self),
8455                  real_allocation.x2 - real_allocation.x1,
8456                  real_allocation.y2 - real_allocation.y1);
8457     }
8458
8459   /* we allow 0-sized actors, but not negative-sized ones */
8460   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8461   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8462
8463   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8464
8465   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8466                  real_allocation.y1 != old_allocation.y1);
8467
8468   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8469                   real_allocation.y2 != old_allocation.y2);
8470
8471   if (origin_changed || child_moved || size_changed)
8472     stage_allocation_changed = TRUE;
8473   else
8474     stage_allocation_changed = FALSE;
8475
8476   /* If we get an allocation "out of the blue"
8477    * (we did not queue relayout), then we want to
8478    * ignore it. But if we have needs_allocation set,
8479    * we want to guarantee that allocate() virtual
8480    * method is always called, i.e. that queue_relayout()
8481    * always results in an allocate() invocation on
8482    * an actor.
8483    *
8484    * The optimization here is to avoid re-allocating
8485    * actors that did not queue relayout and were
8486    * not moved.
8487    */
8488   if (!priv->needs_allocation && !stage_allocation_changed)
8489     {
8490       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8491       return;
8492     }
8493
8494   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8495    * clutter_actor_allocate(), it indicates whether the parent has its
8496    * absolute origin moved; when passed in to ClutterActor::allocate()
8497    * virtual method though, it indicates whether the child has its
8498    * absolute origin moved.  So we set it when child_moved is TRUE
8499    */
8500   if (child_moved)
8501     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8502
8503   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8504
8505   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8506                 _clutter_actor_get_debug_name (self));
8507
8508   klass = CLUTTER_ACTOR_GET_CLASS (self);
8509   klass->allocate (self, &real_allocation, flags);
8510
8511   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8512
8513   if (stage_allocation_changed)
8514     clutter_actor_queue_redraw (self);
8515 }
8516
8517 /**
8518  * clutter_actor_set_allocation:
8519  * @self: a #ClutterActor
8520  * @box: a #ClutterActorBox
8521  * @flags: allocation flags
8522  *
8523  * Stores the allocation of @self as defined by @box.
8524  *
8525  * This function can only be called from within the implementation of
8526  * the #ClutterActorClass.allocate() virtual function.
8527  *
8528  * The allocation should have been adjusted to take into account constraints,
8529  * alignment, and margin properties. If you are implementing a #ClutterActor
8530  * subclass that provides its own layout management policy for its children
8531  * instead of using a #ClutterLayoutManager delegate, you should not call
8532  * this function on the children of @self; instead, you should call
8533  * clutter_actor_allocate(), which will adjust the allocation box for
8534  * you.
8535  *
8536  * This function should only be used by subclasses of #ClutterActor
8537  * that wish to store their allocation but cannot chain up to the
8538  * parent's implementation; the default implementation of the
8539  * #ClutterActorClass.allocate() virtual function will call this
8540  * function.
8541  *
8542  * It is important to note that, while chaining up was the recommended
8543  * behaviour for #ClutterActor subclasses prior to the introduction of
8544  * this function, it is recommended to call clutter_actor_set_allocation()
8545  * instead.
8546  *
8547  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8548  * to handle the allocation of its children, this function will call
8549  * the clutter_layout_manager_allocate() function only if the
8550  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8551  * expected that the subclass will call clutter_layout_manager_allocate()
8552  * by itself. For instance, the following code:
8553  *
8554  * |[
8555  * static void
8556  * my_actor_allocate (ClutterActor *actor,
8557  *                    const ClutterActorBox *allocation,
8558  *                    ClutterAllocationFlags flags)
8559  * {
8560  *   ClutterActorBox new_alloc;
8561  *   ClutterAllocationFlags new_flags;
8562  *
8563  *   adjust_allocation (allocation, &amp;new_alloc);
8564  *
8565  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8566  *
8567  *   /&ast; this will use the layout manager set on the actor &ast;/
8568  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8569  * }
8570  * ]|
8571  *
8572  * is equivalent to this:
8573  *
8574  * |[
8575  * static void
8576  * my_actor_allocate (ClutterActor *actor,
8577  *                    const ClutterActorBox *allocation,
8578  *                    ClutterAllocationFlags flags)
8579  * {
8580  *   ClutterLayoutManager *layout;
8581  *   ClutterActorBox new_alloc;
8582  *
8583  *   adjust_allocation (allocation, &amp;new_alloc);
8584  *
8585  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8586  *
8587  *   layout = clutter_actor_get_layout_manager (actor);
8588  *   clutter_layout_manager_allocate (layout,
8589  *                                    CLUTTER_CONTAINER (actor),
8590  *                                    &amp;new_alloc,
8591  *                                    flags);
8592  * }
8593  * ]|
8594  *
8595  * Since: 1.10
8596  */
8597 void
8598 clutter_actor_set_allocation (ClutterActor           *self,
8599                               const ClutterActorBox  *box,
8600                               ClutterAllocationFlags  flags)
8601 {
8602   ClutterActorPrivate *priv;
8603   gboolean changed;
8604
8605   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8606   g_return_if_fail (box != NULL);
8607
8608   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8609     {
8610       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8611                   "can only be called from within the implementation of "
8612                   "the ClutterActor::allocate() virtual function.");
8613       return;
8614     }
8615
8616   priv = self->priv;
8617
8618   g_object_freeze_notify (G_OBJECT (self));
8619
8620   changed = clutter_actor_set_allocation_internal (self, box, flags);
8621
8622   /* we allocate our children before we notify changes in our geometry,
8623    * so that people connecting to properties will be able to get valid
8624    * data out of the sub-tree of the scene graph that has this actor at
8625    * the root.
8626    */
8627   clutter_actor_maybe_layout_children (self, box, flags);
8628
8629   if (changed)
8630     {
8631       ClutterActorBox signal_box = priv->allocation;
8632       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8633
8634       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8635                      &signal_box,
8636                      signal_flags);
8637     }
8638
8639   g_object_thaw_notify (G_OBJECT (self));
8640 }
8641
8642 /**
8643  * clutter_actor_set_geometry:
8644  * @self: A #ClutterActor
8645  * @geometry: A #ClutterGeometry
8646  *
8647  * Sets the actor's fixed position and forces its minimum and natural
8648  * size, in pixels. This means the untransformed actor will have the
8649  * given geometry. This is the same as calling clutter_actor_set_position()
8650  * and clutter_actor_set_size().
8651  *
8652  * Deprecated: 1.10: Use clutter_actor_set_position() and
8653  *   clutter_actor_set_size() instead.
8654  */
8655 void
8656 clutter_actor_set_geometry (ClutterActor          *self,
8657                             const ClutterGeometry *geometry)
8658 {
8659   g_object_freeze_notify (G_OBJECT (self));
8660
8661   clutter_actor_set_position (self, geometry->x, geometry->y);
8662   clutter_actor_set_size (self, geometry->width, geometry->height);
8663
8664   g_object_thaw_notify (G_OBJECT (self));
8665 }
8666
8667 /**
8668  * clutter_actor_get_geometry:
8669  * @self: A #ClutterActor
8670  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8671  *
8672  * Gets the size and position of an actor relative to its parent
8673  * actor. This is the same as calling clutter_actor_get_position() and
8674  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8675  * requested size and position if the actor's allocation is invalid.
8676  *
8677  * Deprecated: 1.10: Use clutter_actor_get_position() and
8678  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8679  *   instead.
8680  */
8681 void
8682 clutter_actor_get_geometry (ClutterActor    *self,
8683                             ClutterGeometry *geometry)
8684 {
8685   gfloat x, y, width, height;
8686
8687   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8688   g_return_if_fail (geometry != NULL);
8689
8690   clutter_actor_get_position (self, &x, &y);
8691   clutter_actor_get_size (self, &width, &height);
8692
8693   geometry->x = (int) x;
8694   geometry->y = (int) y;
8695   geometry->width = (int) width;
8696   geometry->height = (int) height;
8697 }
8698
8699 /**
8700  * clutter_actor_set_position:
8701  * @self: A #ClutterActor
8702  * @x: New left position of actor in pixels.
8703  * @y: New top position of actor in pixels.
8704  *
8705  * Sets the actor's fixed position in pixels relative to any parent
8706  * actor.
8707  *
8708  * If a layout manager is in use, this position will override the
8709  * layout manager and force a fixed position.
8710  */
8711 void
8712 clutter_actor_set_position (ClutterActor *self,
8713                             gfloat        x,
8714                             gfloat        y)
8715 {
8716   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8717
8718   g_object_freeze_notify (G_OBJECT (self));
8719
8720   clutter_actor_set_x (self, x);
8721   clutter_actor_set_y (self, y);
8722
8723   g_object_thaw_notify (G_OBJECT (self));
8724 }
8725
8726 /**
8727  * clutter_actor_get_fixed_position_set:
8728  * @self: A #ClutterActor
8729  *
8730  * Checks whether an actor has a fixed position set (and will thus be
8731  * unaffected by any layout manager).
8732  *
8733  * Return value: %TRUE if the fixed position is set on the actor
8734  *
8735  * Since: 0.8
8736  */
8737 gboolean
8738 clutter_actor_get_fixed_position_set (ClutterActor *self)
8739 {
8740   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8741
8742   return self->priv->position_set;
8743 }
8744
8745 /**
8746  * clutter_actor_set_fixed_position_set:
8747  * @self: A #ClutterActor
8748  * @is_set: whether to use fixed position
8749  *
8750  * Sets whether an actor has a fixed position set (and will thus be
8751  * unaffected by any layout manager).
8752  *
8753  * Since: 0.8
8754  */
8755 void
8756 clutter_actor_set_fixed_position_set (ClutterActor *self,
8757                                       gboolean      is_set)
8758 {
8759   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8760
8761   if (self->priv->position_set == (is_set != FALSE))
8762     return;
8763
8764   self->priv->position_set = is_set != FALSE;
8765   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8766
8767   clutter_actor_queue_relayout (self);
8768 }
8769
8770 /**
8771  * clutter_actor_move_by:
8772  * @self: A #ClutterActor
8773  * @dx: Distance to move Actor on X axis.
8774  * @dy: Distance to move Actor on Y axis.
8775  *
8776  * Moves an actor by the specified distance relative to its current
8777  * position in pixels.
8778  *
8779  * This function modifies the fixed position of an actor and thus removes
8780  * it from any layout management. Another way to move an actor is with an
8781  * anchor point, see clutter_actor_set_anchor_point().
8782  *
8783  * Since: 0.2
8784  */
8785 void
8786 clutter_actor_move_by (ClutterActor *self,
8787                        gfloat        dx,
8788                        gfloat        dy)
8789 {
8790   const ClutterLayoutInfo *info;
8791   gfloat x, y;
8792
8793   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8794
8795   info = _clutter_actor_get_layout_info_or_defaults (self);
8796   x = info->fixed_x;
8797   y = info->fixed_y;
8798
8799   clutter_actor_set_position (self, x + dx, y + dy);
8800 }
8801
8802 static void
8803 clutter_actor_set_min_width (ClutterActor *self,
8804                              gfloat        min_width)
8805 {
8806   ClutterActorPrivate *priv = self->priv;
8807   ClutterActorBox old = { 0, };
8808   ClutterLayoutInfo *info;
8809
8810   /* if we are setting the size on a top-level actor and the
8811    * backend only supports static top-levels (e.g. framebuffers)
8812    * then we ignore the passed value and we override it with
8813    * the stage implementation's preferred size.
8814    */
8815   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8816       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8817     return;
8818
8819   info = _clutter_actor_get_layout_info (self);
8820
8821   if (priv->min_width_set && min_width == info->min_width)
8822     return;
8823
8824   g_object_freeze_notify (G_OBJECT (self));
8825
8826   clutter_actor_store_old_geometry (self, &old);
8827
8828   info->min_width = min_width;
8829   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8830   clutter_actor_set_min_width_set (self, TRUE);
8831
8832   clutter_actor_notify_if_geometry_changed (self, &old);
8833
8834   g_object_thaw_notify (G_OBJECT (self));
8835
8836   clutter_actor_queue_relayout (self);
8837 }
8838
8839 static void
8840 clutter_actor_set_min_height (ClutterActor *self,
8841                               gfloat        min_height)
8842
8843 {
8844   ClutterActorPrivate *priv = self->priv;
8845   ClutterActorBox old = { 0, };
8846   ClutterLayoutInfo *info;
8847
8848   /* if we are setting the size on a top-level actor and the
8849    * backend only supports static top-levels (e.g. framebuffers)
8850    * then we ignore the passed value and we override it with
8851    * the stage implementation's preferred size.
8852    */
8853   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8854       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8855     return;
8856
8857   info = _clutter_actor_get_layout_info (self);
8858
8859   if (priv->min_height_set && min_height == info->min_height)
8860     return;
8861
8862   g_object_freeze_notify (G_OBJECT (self));
8863
8864   clutter_actor_store_old_geometry (self, &old);
8865
8866   info->min_height = min_height;
8867   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8868   clutter_actor_set_min_height_set (self, TRUE);
8869
8870   clutter_actor_notify_if_geometry_changed (self, &old);
8871
8872   g_object_thaw_notify (G_OBJECT (self));
8873
8874   clutter_actor_queue_relayout (self);
8875 }
8876
8877 static void
8878 clutter_actor_set_natural_width (ClutterActor *self,
8879                                  gfloat        natural_width)
8880 {
8881   ClutterActorPrivate *priv = self->priv;
8882   ClutterActorBox old = { 0, };
8883   ClutterLayoutInfo *info;
8884
8885   /* if we are setting the size on a top-level actor and the
8886    * backend only supports static top-levels (e.g. framebuffers)
8887    * then we ignore the passed value and we override it with
8888    * the stage implementation's preferred size.
8889    */
8890   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8891       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8892     return;
8893
8894   info = _clutter_actor_get_layout_info (self);
8895
8896   if (priv->natural_width_set && natural_width == info->natural_width)
8897     return;
8898
8899   g_object_freeze_notify (G_OBJECT (self));
8900
8901   clutter_actor_store_old_geometry (self, &old);
8902
8903   info->natural_width = natural_width;
8904   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8905   clutter_actor_set_natural_width_set (self, TRUE);
8906
8907   clutter_actor_notify_if_geometry_changed (self, &old);
8908
8909   g_object_thaw_notify (G_OBJECT (self));
8910
8911   clutter_actor_queue_relayout (self);
8912 }
8913
8914 static void
8915 clutter_actor_set_natural_height (ClutterActor *self,
8916                                   gfloat        natural_height)
8917 {
8918   ClutterActorPrivate *priv = self->priv;
8919   ClutterActorBox old = { 0, };
8920   ClutterLayoutInfo *info;
8921
8922   /* if we are setting the size on a top-level actor and the
8923    * backend only supports static top-levels (e.g. framebuffers)
8924    * then we ignore the passed value and we override it with
8925    * the stage implementation's preferred size.
8926    */
8927   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8928       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8929     return;
8930
8931   info = _clutter_actor_get_layout_info (self);
8932
8933   if (priv->natural_height_set && natural_height == info->natural_height)
8934     return;
8935
8936   g_object_freeze_notify (G_OBJECT (self));
8937
8938   clutter_actor_store_old_geometry (self, &old);
8939
8940   info->natural_height = natural_height;
8941   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8942   clutter_actor_set_natural_height_set (self, TRUE);
8943
8944   clutter_actor_notify_if_geometry_changed (self, &old);
8945
8946   g_object_thaw_notify (G_OBJECT (self));
8947
8948   clutter_actor_queue_relayout (self);
8949 }
8950
8951 static void
8952 clutter_actor_set_min_width_set (ClutterActor *self,
8953                                  gboolean      use_min_width)
8954 {
8955   ClutterActorPrivate *priv = self->priv;
8956   ClutterActorBox old = { 0, };
8957
8958   if (priv->min_width_set == (use_min_width != FALSE))
8959     return;
8960
8961   clutter_actor_store_old_geometry (self, &old);
8962
8963   priv->min_width_set = use_min_width != FALSE;
8964   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8965
8966   clutter_actor_notify_if_geometry_changed (self, &old);
8967
8968   clutter_actor_queue_relayout (self);
8969 }
8970
8971 static void
8972 clutter_actor_set_min_height_set (ClutterActor *self,
8973                                   gboolean      use_min_height)
8974 {
8975   ClutterActorPrivate *priv = self->priv;
8976   ClutterActorBox old = { 0, };
8977
8978   if (priv->min_height_set == (use_min_height != FALSE))
8979     return;
8980
8981   clutter_actor_store_old_geometry (self, &old);
8982
8983   priv->min_height_set = use_min_height != FALSE;
8984   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8985
8986   clutter_actor_notify_if_geometry_changed (self, &old);
8987
8988   clutter_actor_queue_relayout (self);
8989 }
8990
8991 static void
8992 clutter_actor_set_natural_width_set (ClutterActor *self,
8993                                      gboolean      use_natural_width)
8994 {
8995   ClutterActorPrivate *priv = self->priv;
8996   ClutterActorBox old = { 0, };
8997
8998   if (priv->natural_width_set == (use_natural_width != FALSE))
8999     return;
9000
9001   clutter_actor_store_old_geometry (self, &old);
9002
9003   priv->natural_width_set = use_natural_width != FALSE;
9004   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9005
9006   clutter_actor_notify_if_geometry_changed (self, &old);
9007
9008   clutter_actor_queue_relayout (self);
9009 }
9010
9011 static void
9012 clutter_actor_set_natural_height_set (ClutterActor *self,
9013                                       gboolean      use_natural_height)
9014 {
9015   ClutterActorPrivate *priv = self->priv;
9016   ClutterActorBox old = { 0, };
9017
9018   if (priv->natural_height_set == (use_natural_height != FALSE))
9019     return;
9020
9021   clutter_actor_store_old_geometry (self, &old);
9022
9023   priv->natural_height_set = use_natural_height != FALSE;
9024   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9025
9026   clutter_actor_notify_if_geometry_changed (self, &old);
9027
9028   clutter_actor_queue_relayout (self);
9029 }
9030
9031 /**
9032  * clutter_actor_set_request_mode:
9033  * @self: a #ClutterActor
9034  * @mode: the request mode
9035  *
9036  * Sets the geometry request mode of @self.
9037  *
9038  * The @mode determines the order for invoking
9039  * clutter_actor_get_preferred_width() and
9040  * clutter_actor_get_preferred_height()
9041  *
9042  * Since: 1.2
9043  */
9044 void
9045 clutter_actor_set_request_mode (ClutterActor       *self,
9046                                 ClutterRequestMode  mode)
9047 {
9048   ClutterActorPrivate *priv;
9049
9050   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9051
9052   priv = self->priv;
9053
9054   if (priv->request_mode == mode)
9055     return;
9056
9057   priv->request_mode = mode;
9058
9059   priv->needs_width_request = TRUE;
9060   priv->needs_height_request = TRUE;
9061
9062   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9063
9064   clutter_actor_queue_relayout (self);
9065 }
9066
9067 /**
9068  * clutter_actor_get_request_mode:
9069  * @self: a #ClutterActor
9070  *
9071  * Retrieves the geometry request mode of @self
9072  *
9073  * Return value: the request mode for the actor
9074  *
9075  * Since: 1.2
9076  */
9077 ClutterRequestMode
9078 clutter_actor_get_request_mode (ClutterActor *self)
9079 {
9080   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9081                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9082
9083   return self->priv->request_mode;
9084 }
9085
9086 /* variant of set_width() without checks and without notification
9087  * freeze+thaw, for internal usage only
9088  */
9089 static inline void
9090 clutter_actor_set_width_internal (ClutterActor *self,
9091                                   gfloat        width)
9092 {
9093   if (width >= 0)
9094     {
9095       /* the Stage will use the :min-width to control the minimum
9096        * width to be resized to, so we should not be setting it
9097        * along with the :natural-width
9098        */
9099       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9100         clutter_actor_set_min_width (self, width);
9101
9102       clutter_actor_set_natural_width (self, width);
9103     }
9104   else
9105     {
9106       /* we only unset the :natural-width for the Stage */
9107       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9108         clutter_actor_set_min_width_set (self, FALSE);
9109
9110       clutter_actor_set_natural_width_set (self, FALSE);
9111     }
9112 }
9113
9114 /* variant of set_height() without checks and without notification
9115  * freeze+thaw, for internal usage only
9116  */
9117 static inline void
9118 clutter_actor_set_height_internal (ClutterActor *self,
9119                                    gfloat        height)
9120 {
9121   if (height >= 0)
9122     {
9123       /* see the comment above in set_width_internal() */
9124       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9125         clutter_actor_set_min_height (self, height);
9126
9127       clutter_actor_set_natural_height (self, height);
9128     }
9129   else
9130     {
9131       /* see the comment above in set_width_internal() */
9132       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9133         clutter_actor_set_min_height_set (self, FALSE);
9134
9135       clutter_actor_set_natural_height_set (self, FALSE);
9136     }
9137 }
9138
9139 /**
9140  * clutter_actor_set_size:
9141  * @self: A #ClutterActor
9142  * @width: New width of actor in pixels, or -1
9143  * @height: New height of actor in pixels, or -1
9144  *
9145  * Sets the actor's size request in pixels. This overrides any
9146  * "normal" size request the actor would have. For example
9147  * a text actor might normally request the size of the text;
9148  * this function would force a specific size instead.
9149  *
9150  * If @width and/or @height are -1 the actor will use its
9151  * "normal" size request instead of overriding it, i.e.
9152  * you can "unset" the size with -1.
9153  *
9154  * This function sets or unsets both the minimum and natural size.
9155  */
9156 void
9157 clutter_actor_set_size (ClutterActor *self,
9158                         gfloat        width,
9159                         gfloat        height)
9160 {
9161   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9162
9163   g_object_freeze_notify (G_OBJECT (self));
9164
9165   clutter_actor_set_width (self, width);
9166   clutter_actor_set_height (self, height);
9167
9168   g_object_thaw_notify (G_OBJECT (self));
9169 }
9170
9171 /**
9172  * clutter_actor_get_size:
9173  * @self: A #ClutterActor
9174  * @width: (out) (allow-none): return location for the width, or %NULL.
9175  * @height: (out) (allow-none): return location for the height, or %NULL.
9176  *
9177  * This function tries to "do what you mean" and return
9178  * the size an actor will have. If the actor has a valid
9179  * allocation, the allocation will be returned; otherwise,
9180  * the actors natural size request will be returned.
9181  *
9182  * If you care whether you get the request vs. the allocation, you
9183  * should probably call a different function like
9184  * clutter_actor_get_allocation_box() or
9185  * clutter_actor_get_preferred_width().
9186  *
9187  * Since: 0.2
9188  */
9189 void
9190 clutter_actor_get_size (ClutterActor *self,
9191                         gfloat       *width,
9192                         gfloat       *height)
9193 {
9194   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9195
9196   if (width)
9197     *width = clutter_actor_get_width (self);
9198
9199   if (height)
9200     *height = clutter_actor_get_height (self);
9201 }
9202
9203 /**
9204  * clutter_actor_get_position:
9205  * @self: a #ClutterActor
9206  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9207  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9208  *
9209  * This function tries to "do what you mean" and tell you where the
9210  * actor is, prior to any transformations. Retrieves the fixed
9211  * position of an actor in pixels, if one has been set; otherwise, if
9212  * the allocation is valid, returns the actor's allocated position;
9213  * otherwise, returns 0,0.
9214  *
9215  * The returned position is in pixels.
9216  *
9217  * Since: 0.6
9218  */
9219 void
9220 clutter_actor_get_position (ClutterActor *self,
9221                             gfloat       *x,
9222                             gfloat       *y)
9223 {
9224   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9225
9226   if (x)
9227     *x = clutter_actor_get_x (self);
9228
9229   if (y)
9230     *y = clutter_actor_get_y (self);
9231 }
9232
9233 /**
9234  * clutter_actor_get_transformed_position:
9235  * @self: A #ClutterActor
9236  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9237  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9238  *
9239  * Gets the absolute position of an actor, in pixels relative to the stage.
9240  *
9241  * Since: 0.8
9242  */
9243 void
9244 clutter_actor_get_transformed_position (ClutterActor *self,
9245                                         gfloat       *x,
9246                                         gfloat       *y)
9247 {
9248   ClutterVertex v1;
9249   ClutterVertex v2;
9250
9251   v1.x = v1.y = v1.z = 0;
9252   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9253
9254   if (x)
9255     *x = v2.x;
9256
9257   if (y)
9258     *y = v2.y;
9259 }
9260
9261 /**
9262  * clutter_actor_get_transformed_size:
9263  * @self: A #ClutterActor
9264  * @width: (out) (allow-none): return location for the width, or %NULL
9265  * @height: (out) (allow-none): return location for the height, or %NULL
9266  *
9267  * Gets the absolute size of an actor in pixels, taking into account the
9268  * scaling factors.
9269  *
9270  * If the actor has a valid allocation, the allocated size will be used.
9271  * If the actor has not a valid allocation then the preferred size will
9272  * be transformed and returned.
9273  *
9274  * If you want the transformed allocation, see
9275  * clutter_actor_get_abs_allocation_vertices() instead.
9276  *
9277  * <note>When the actor (or one of its ancestors) is rotated around the
9278  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9279  * as a generic quadrangle; in that case this function returns the size
9280  * of the smallest rectangle that encapsulates the entire quad. Please
9281  * note that in this case no assumptions can be made about the relative
9282  * position of this envelope to the absolute position of the actor, as
9283  * returned by clutter_actor_get_transformed_position(); if you need this
9284  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9285  * to get the coords of the actual quadrangle.</note>
9286  *
9287  * Since: 0.8
9288  */
9289 void
9290 clutter_actor_get_transformed_size (ClutterActor *self,
9291                                     gfloat       *width,
9292                                     gfloat       *height)
9293 {
9294   ClutterActorPrivate *priv;
9295   ClutterVertex v[4];
9296   gfloat x_min, x_max, y_min, y_max;
9297   gint i;
9298
9299   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9300
9301   priv = self->priv;
9302
9303   /* if the actor hasn't been allocated yet, get the preferred
9304    * size and transform that
9305    */
9306   if (priv->needs_allocation)
9307     {
9308       gfloat natural_width, natural_height;
9309       ClutterActorBox box;
9310
9311       /* Make a fake allocation to transform.
9312        *
9313        * NB: _clutter_actor_transform_and_project_box expects a box in
9314        * the actor's coordinate space... */
9315
9316       box.x1 = 0;
9317       box.y1 = 0;
9318
9319       natural_width = natural_height = 0;
9320       clutter_actor_get_preferred_size (self, NULL, NULL,
9321                                         &natural_width,
9322                                         &natural_height);
9323
9324       box.x2 = natural_width;
9325       box.y2 = natural_height;
9326
9327       _clutter_actor_transform_and_project_box (self, &box, v);
9328     }
9329   else
9330     clutter_actor_get_abs_allocation_vertices (self, v);
9331
9332   x_min = x_max = v[0].x;
9333   y_min = y_max = v[0].y;
9334
9335   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9336     {
9337       if (v[i].x < x_min)
9338         x_min = v[i].x;
9339
9340       if (v[i].x > x_max)
9341         x_max = v[i].x;
9342
9343       if (v[i].y < y_min)
9344         y_min = v[i].y;
9345
9346       if (v[i].y > y_max)
9347         y_max = v[i].y;
9348     }
9349
9350   if (width)
9351     *width  = x_max - x_min;
9352
9353   if (height)
9354     *height = y_max - y_min;
9355 }
9356
9357 /**
9358  * clutter_actor_get_width:
9359  * @self: A #ClutterActor
9360  *
9361  * Retrieves the width of a #ClutterActor.
9362  *
9363  * If the actor has a valid allocation, this function will return the
9364  * width of the allocated area given to the actor.
9365  *
9366  * If the actor does not have a valid allocation, this function will
9367  * return the actor's natural width, that is the preferred width of
9368  * the actor.
9369  *
9370  * If you care whether you get the preferred width or the width that
9371  * has been assigned to the actor, you should probably call a different
9372  * function like clutter_actor_get_allocation_box() to retrieve the
9373  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9374  * preferred width.
9375  *
9376  * If an actor has a fixed width, for instance a width that has been
9377  * assigned using clutter_actor_set_width(), the width returned will
9378  * be the same value.
9379  *
9380  * Return value: the width of the actor, in pixels
9381  */
9382 gfloat
9383 clutter_actor_get_width (ClutterActor *self)
9384 {
9385   ClutterActorPrivate *priv;
9386
9387   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9388
9389   priv = self->priv;
9390
9391   if (priv->needs_allocation)
9392     {
9393       gfloat natural_width = 0;
9394
9395       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9396         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9397       else
9398         {
9399           gfloat natural_height = 0;
9400
9401           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9402           clutter_actor_get_preferred_width (self, natural_height,
9403                                              NULL,
9404                                              &natural_width);
9405         }
9406
9407       return natural_width;
9408     }
9409   else
9410     return priv->allocation.x2 - priv->allocation.x1;
9411 }
9412
9413 /**
9414  * clutter_actor_get_height:
9415  * @self: A #ClutterActor
9416  *
9417  * Retrieves the height of a #ClutterActor.
9418  *
9419  * If the actor has a valid allocation, this function will return the
9420  * height of the allocated area given to the actor.
9421  *
9422  * If the actor does not have a valid allocation, this function will
9423  * return the actor's natural height, that is the preferred height of
9424  * the actor.
9425  *
9426  * If you care whether you get the preferred height or the height that
9427  * has been assigned to the actor, you should probably call a different
9428  * function like clutter_actor_get_allocation_box() to retrieve the
9429  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9430  * preferred height.
9431  *
9432  * If an actor has a fixed height, for instance a height that has been
9433  * assigned using clutter_actor_set_height(), the height returned will
9434  * be the same value.
9435  *
9436  * Return value: the height of the actor, in pixels
9437  */
9438 gfloat
9439 clutter_actor_get_height (ClutterActor *self)
9440 {
9441   ClutterActorPrivate *priv;
9442
9443   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9444
9445   priv = self->priv;
9446
9447   if (priv->needs_allocation)
9448     {
9449       gfloat natural_height = 0;
9450
9451       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9452         {
9453           gfloat natural_width = 0;
9454
9455           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9456           clutter_actor_get_preferred_height (self, natural_width,
9457                                               NULL, &natural_height);
9458         }
9459       else
9460         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9461
9462       return natural_height;
9463     }
9464   else
9465     return priv->allocation.y2 - priv->allocation.y1;
9466 }
9467
9468 /**
9469  * clutter_actor_set_width:
9470  * @self: A #ClutterActor
9471  * @width: Requested new width for the actor, in pixels, or -1
9472  *
9473  * Forces a width on an actor, causing the actor's preferred width
9474  * and height (if any) to be ignored.
9475  *
9476  * If @width is -1 the actor will use its preferred width request
9477  * instead of overriding it, i.e. you can "unset" the width with -1.
9478  *
9479  * This function sets both the minimum and natural size of the actor.
9480  *
9481  * since: 0.2
9482  */
9483 void
9484 clutter_actor_set_width (ClutterActor *self,
9485                          gfloat        width)
9486 {
9487   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9488
9489   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9490     {
9491       float cur_size;
9492
9493       /* minor optimization: if we don't have a duration
9494        * then we can skip the get_width() below, to avoid
9495        * the chance of going through get_preferred_width()
9496        * just to jump to a new desired width.
9497        */
9498       if (clutter_actor_get_easing_duration (self) == 0)
9499         {
9500           g_object_freeze_notify (G_OBJECT (self));
9501
9502           clutter_actor_set_width_internal (self, width);
9503
9504           g_object_thaw_notify (G_OBJECT (self));
9505
9506           return;
9507         }
9508       else
9509         cur_size = clutter_actor_get_width (self);
9510
9511       _clutter_actor_create_transition (self,
9512                                         obj_props[PROP_WIDTH],
9513                                         cur_size,
9514                                         width);
9515     }
9516   else
9517     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9518 }
9519
9520 /**
9521  * clutter_actor_set_height:
9522  * @self: A #ClutterActor
9523  * @height: Requested new height for the actor, in pixels, or -1
9524  *
9525  * Forces a height on an actor, causing the actor's preferred width
9526  * and height (if any) to be ignored.
9527  *
9528  * If @height is -1 the actor will use its preferred height instead of
9529  * overriding it, i.e. you can "unset" the height with -1.
9530  *
9531  * This function sets both the minimum and natural size of the actor.
9532  *
9533  * since: 0.2
9534  */
9535 void
9536 clutter_actor_set_height (ClutterActor *self,
9537                           gfloat        height)
9538 {
9539   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9540
9541   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9542     {
9543       float cur_size;
9544
9545       /* see the comment in clutter_actor_set_width() above */
9546       if (clutter_actor_get_easing_duration (self) == 0)
9547         {
9548           g_object_freeze_notify (G_OBJECT (self));
9549
9550           clutter_actor_set_height_internal (self, height);
9551
9552           g_object_thaw_notify (G_OBJECT (self));
9553
9554           return;
9555         }
9556       else
9557         cur_size = clutter_actor_get_height (self);
9558
9559       _clutter_actor_create_transition (self,
9560                                         obj_props[PROP_HEIGHT],
9561                                         cur_size,
9562                                         height);
9563     }
9564   else
9565     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9566 }
9567
9568 static inline void
9569 clutter_actor_set_x_internal (ClutterActor *self,
9570                               float         x)
9571 {
9572   ClutterActorPrivate *priv = self->priv;
9573   ClutterLayoutInfo *linfo;
9574   ClutterActorBox old = { 0, };
9575
9576   linfo = _clutter_actor_get_layout_info (self);
9577
9578   if (priv->position_set && linfo->fixed_x == x)
9579     return;
9580
9581   clutter_actor_store_old_geometry (self, &old);
9582
9583   linfo->fixed_x = x;
9584   clutter_actor_set_fixed_position_set (self, TRUE);
9585
9586   clutter_actor_notify_if_geometry_changed (self, &old);
9587
9588   clutter_actor_queue_relayout (self);
9589 }
9590
9591 static inline void
9592 clutter_actor_set_y_internal (ClutterActor *self,
9593                               float         y)
9594 {
9595   ClutterActorPrivate *priv = self->priv;
9596   ClutterLayoutInfo *linfo;
9597   ClutterActorBox old = { 0, };
9598
9599   linfo = _clutter_actor_get_layout_info (self);
9600
9601   if (priv->position_set && linfo->fixed_y == y)
9602     return;
9603
9604   clutter_actor_store_old_geometry (self, &old);
9605
9606   linfo->fixed_y = y;
9607   clutter_actor_set_fixed_position_set (self, TRUE);
9608
9609   clutter_actor_notify_if_geometry_changed (self, &old);
9610
9611   clutter_actor_queue_relayout (self);
9612 }
9613
9614 /**
9615  * clutter_actor_set_x:
9616  * @self: a #ClutterActor
9617  * @x: the actor's position on the X axis
9618  *
9619  * Sets the actor's X coordinate, relative to its parent, in pixels.
9620  *
9621  * Overrides any layout manager and forces a fixed position for
9622  * the actor.
9623  *
9624  * The #ClutterActor:x property is animatable.
9625  *
9626  * Since: 0.6
9627  */
9628 void
9629 clutter_actor_set_x (ClutterActor *self,
9630                      gfloat        x)
9631 {
9632   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9633
9634   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9635     {
9636       float cur_position = clutter_actor_get_x (self);
9637
9638       _clutter_actor_create_transition (self, obj_props[PROP_X],
9639                                         cur_position,
9640                                         x);
9641     }
9642   else
9643     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9644 }
9645
9646 /**
9647  * clutter_actor_set_y:
9648  * @self: a #ClutterActor
9649  * @y: the actor's position on the Y axis
9650  *
9651  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9652  *
9653  * Overrides any layout manager and forces a fixed position for
9654  * the actor.
9655  *
9656  * The #ClutterActor:y property is animatable.
9657  *
9658  * Since: 0.6
9659  */
9660 void
9661 clutter_actor_set_y (ClutterActor *self,
9662                      gfloat        y)
9663 {
9664   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9665
9666   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9667     {
9668       float cur_position = clutter_actor_get_y (self);
9669
9670       _clutter_actor_create_transition (self, obj_props[PROP_Y],
9671                                         cur_position,
9672                                         y);
9673     }
9674   else
9675     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9676 }
9677
9678 /**
9679  * clutter_actor_get_x:
9680  * @self: A #ClutterActor
9681  *
9682  * Retrieves the X coordinate of a #ClutterActor.
9683  *
9684  * This function tries to "do what you mean", by returning the
9685  * correct value depending on the actor's state.
9686  *
9687  * If the actor has a valid allocation, this function will return
9688  * the X coordinate of the origin of the allocation box.
9689  *
9690  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9691  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9692  * function will return that coordinate.
9693  *
9694  * If both the allocation and a fixed position are missing, this function
9695  * will return 0.
9696  *
9697  * Return value: the X coordinate, in pixels, ignoring any
9698  *   transformation (i.e. scaling, rotation)
9699  */
9700 gfloat
9701 clutter_actor_get_x (ClutterActor *self)
9702 {
9703   ClutterActorPrivate *priv;
9704
9705   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9706
9707   priv = self->priv;
9708
9709   if (priv->needs_allocation)
9710     {
9711       if (priv->position_set)
9712         {
9713           const ClutterLayoutInfo *info;
9714
9715           info = _clutter_actor_get_layout_info_or_defaults (self);
9716
9717           return info->fixed_x;
9718         }
9719       else
9720         return 0;
9721     }
9722   else
9723     return priv->allocation.x1;
9724 }
9725
9726 /**
9727  * clutter_actor_get_y:
9728  * @self: A #ClutterActor
9729  *
9730  * Retrieves the Y coordinate of a #ClutterActor.
9731  *
9732  * This function tries to "do what you mean", by returning the
9733  * correct value depending on the actor's state.
9734  *
9735  * If the actor has a valid allocation, this function will return
9736  * the Y coordinate of the origin of the allocation box.
9737  *
9738  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9739  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9740  * function will return that coordinate.
9741  *
9742  * If both the allocation and a fixed position are missing, this function
9743  * will return 0.
9744  *
9745  * Return value: the Y coordinate, in pixels, ignoring any
9746  *   transformation (i.e. scaling, rotation)
9747  */
9748 gfloat
9749 clutter_actor_get_y (ClutterActor *self)
9750 {
9751   ClutterActorPrivate *priv;
9752
9753   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9754
9755   priv = self->priv;
9756
9757   if (priv->needs_allocation)
9758     {
9759       if (priv->position_set)
9760         {
9761           const ClutterLayoutInfo *info;
9762
9763           info = _clutter_actor_get_layout_info_or_defaults (self);
9764
9765           return info->fixed_y;
9766         }
9767       else
9768         return 0;
9769     }
9770   else
9771     return priv->allocation.y1;
9772 }
9773
9774 /**
9775  * clutter_actor_set_scale:
9776  * @self: A #ClutterActor
9777  * @scale_x: double factor to scale actor by horizontally.
9778  * @scale_y: double factor to scale actor by vertically.
9779  *
9780  * Scales an actor with the given factors. The scaling is relative to
9781  * the scale center and the anchor point. The scale center is
9782  * unchanged by this function and defaults to 0,0.
9783  *
9784  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9785  * animatable.
9786  *
9787  * Since: 0.2
9788  */
9789 void
9790 clutter_actor_set_scale (ClutterActor *self,
9791                          gdouble       scale_x,
9792                          gdouble       scale_y)
9793 {
9794   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9795
9796   g_object_freeze_notify (G_OBJECT (self));
9797
9798   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9799   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9800
9801   g_object_thaw_notify (G_OBJECT (self));
9802 }
9803
9804 /**
9805  * clutter_actor_set_scale_full:
9806  * @self: A #ClutterActor
9807  * @scale_x: double factor to scale actor by horizontally.
9808  * @scale_y: double factor to scale actor by vertically.
9809  * @center_x: X coordinate of the center of the scale.
9810  * @center_y: Y coordinate of the center of the scale
9811  *
9812  * Scales an actor with the given factors around the given center
9813  * point. The center point is specified in pixels relative to the
9814  * anchor point (usually the top left corner of the actor).
9815  *
9816  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9817  * are animatable.
9818  *
9819  * Since: 1.0
9820  */
9821 void
9822 clutter_actor_set_scale_full (ClutterActor *self,
9823                               gdouble       scale_x,
9824                               gdouble       scale_y,
9825                               gfloat        center_x,
9826                               gfloat        center_y)
9827 {
9828   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9829
9830   g_object_freeze_notify (G_OBJECT (self));
9831
9832   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9833   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9834   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9835   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9836
9837   g_object_thaw_notify (G_OBJECT (self));
9838 }
9839
9840 /**
9841  * clutter_actor_set_scale_with_gravity:
9842  * @self: A #ClutterActor
9843  * @scale_x: double factor to scale actor by horizontally.
9844  * @scale_y: double factor to scale actor by vertically.
9845  * @gravity: the location of the scale center expressed as a compass
9846  * direction.
9847  *
9848  * Scales an actor with the given factors around the given
9849  * center point. The center point is specified as one of the compass
9850  * directions in #ClutterGravity. For example, setting it to north
9851  * will cause the top of the actor to remain unchanged and the rest of
9852  * the actor to expand left, right and downwards.
9853  *
9854  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9855  * animatable.
9856  *
9857  * Since: 1.0
9858  */
9859 void
9860 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9861                                       gdouble         scale_x,
9862                                       gdouble         scale_y,
9863                                       ClutterGravity  gravity)
9864 {
9865   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9866
9867   g_object_freeze_notify (G_OBJECT (self));
9868
9869   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9870   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9871   clutter_actor_set_scale_gravity (self, gravity);
9872
9873   g_object_thaw_notify (G_OBJECT (self));
9874 }
9875
9876 /**
9877  * clutter_actor_get_scale:
9878  * @self: A #ClutterActor
9879  * @scale_x: (out) (allow-none): Location to store horizonal
9880  *   scale factor, or %NULL.
9881  * @scale_y: (out) (allow-none): Location to store vertical
9882  *   scale factor, or %NULL.
9883  *
9884  * Retrieves an actors scale factors.
9885  *
9886  * Since: 0.2
9887  */
9888 void
9889 clutter_actor_get_scale (ClutterActor *self,
9890                          gdouble      *scale_x,
9891                          gdouble      *scale_y)
9892 {
9893   const ClutterTransformInfo *info;
9894
9895   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9896
9897   info = _clutter_actor_get_transform_info_or_defaults (self);
9898
9899   if (scale_x)
9900     *scale_x = info->scale_x;
9901
9902   if (scale_y)
9903     *scale_y = info->scale_y;
9904 }
9905
9906 /**
9907  * clutter_actor_get_scale_center:
9908  * @self: A #ClutterActor
9909  * @center_x: (out) (allow-none): Location to store the X position
9910  *   of the scale center, or %NULL.
9911  * @center_y: (out) (allow-none): Location to store the Y position
9912  *   of the scale center, or %NULL.
9913  *
9914  * Retrieves the scale center coordinate in pixels relative to the top
9915  * left corner of the actor. If the scale center was specified using a
9916  * #ClutterGravity this will calculate the pixel offset using the
9917  * current size of the actor.
9918  *
9919  * Since: 1.0
9920  */
9921 void
9922 clutter_actor_get_scale_center (ClutterActor *self,
9923                                 gfloat       *center_x,
9924                                 gfloat       *center_y)
9925 {
9926   const ClutterTransformInfo *info;
9927
9928   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9929
9930   info = _clutter_actor_get_transform_info_or_defaults (self);
9931
9932   clutter_anchor_coord_get_units (self, &info->scale_center,
9933                                   center_x,
9934                                   center_y,
9935                                   NULL);
9936 }
9937
9938 /**
9939  * clutter_actor_get_scale_gravity:
9940  * @self: A #ClutterActor
9941  *
9942  * Retrieves the scale center as a compass direction. If the scale
9943  * center was specified in pixels or units this will return
9944  * %CLUTTER_GRAVITY_NONE.
9945  *
9946  * Return value: the scale gravity
9947  *
9948  * Since: 1.0
9949  */
9950 ClutterGravity
9951 clutter_actor_get_scale_gravity (ClutterActor *self)
9952 {
9953   const ClutterTransformInfo *info;
9954
9955   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9956
9957   info = _clutter_actor_get_transform_info_or_defaults (self);
9958
9959   return clutter_anchor_coord_get_gravity (&info->scale_center);
9960 }
9961
9962 static inline void
9963 clutter_actor_set_opacity_internal (ClutterActor *self,
9964                                     guint8        opacity)
9965 {
9966   ClutterActorPrivate *priv = self->priv;
9967
9968   if (priv->opacity != opacity)
9969     {
9970       priv->opacity = opacity;
9971
9972       /* Queue a redraw from the flatten effect so that it can use
9973          its cached image if available instead of having to redraw the
9974          actual actor. If it doesn't end up using the FBO then the
9975          effect is still able to continue the paint anyway. If there
9976          is no flatten effect yet then this is equivalent to queueing
9977          a full redraw */
9978       _clutter_actor_queue_redraw_full (self,
9979                                         0, /* flags */
9980                                         NULL, /* clip */
9981                                         priv->flatten_effect);
9982
9983       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9984     }
9985 }
9986
9987 /**
9988  * clutter_actor_set_opacity:
9989  * @self: A #ClutterActor
9990  * @opacity: New opacity value for the actor.
9991  *
9992  * Sets the actor's opacity, with zero being completely transparent and
9993  * 255 (0xff) being fully opaque.
9994  *
9995  * The #ClutterActor:opacity property is animatable.
9996  */
9997 void
9998 clutter_actor_set_opacity (ClutterActor *self,
9999                            guint8        opacity)
10000 {
10001   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10002
10003   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10004     {
10005       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10006                                         self->priv->opacity,
10007                                         opacity);
10008     }
10009   else
10010     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10011 }
10012
10013 /*
10014  * clutter_actor_get_paint_opacity_internal:
10015  * @self: a #ClutterActor
10016  *
10017  * Retrieves the absolute opacity of the actor, as it appears on the stage
10018  *
10019  * This function does not do type checks
10020  *
10021  * Return value: the absolute opacity of the actor
10022  */
10023 static guint8
10024 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10025 {
10026   ClutterActorPrivate *priv = self->priv;
10027   ClutterActor *parent;
10028
10029   /* override the top-level opacity to always be 255; even in
10030    * case of ClutterStage:use-alpha being TRUE we want the rest
10031    * of the scene to be painted
10032    */
10033   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10034     return 255;
10035
10036   if (priv->opacity_override >= 0)
10037     return priv->opacity_override;
10038
10039   parent = priv->parent;
10040
10041   /* Factor in the actual actors opacity with parents */
10042   if (parent != NULL)
10043     {
10044       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10045
10046       if (opacity != 0xff)
10047         return (opacity * priv->opacity) / 0xff;
10048     }
10049
10050   return priv->opacity;
10051
10052 }
10053
10054 /**
10055  * clutter_actor_get_paint_opacity:
10056  * @self: A #ClutterActor
10057  *
10058  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10059  *
10060  * This function traverses the hierarchy chain and composites the opacity of
10061  * the actor with that of its parents.
10062  *
10063  * This function is intended for subclasses to use in the paint virtual
10064  * function, to paint themselves with the correct opacity.
10065  *
10066  * Return value: The actor opacity value.
10067  *
10068  * Since: 0.8
10069  */
10070 guint8
10071 clutter_actor_get_paint_opacity (ClutterActor *self)
10072 {
10073   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10074
10075   return clutter_actor_get_paint_opacity_internal (self);
10076 }
10077
10078 /**
10079  * clutter_actor_get_opacity:
10080  * @self: a #ClutterActor
10081  *
10082  * Retrieves the opacity value of an actor, as set by
10083  * clutter_actor_set_opacity().
10084  *
10085  * For retrieving the absolute opacity of the actor inside a paint
10086  * virtual function, see clutter_actor_get_paint_opacity().
10087  *
10088  * Return value: the opacity of the actor
10089  */
10090 guint8
10091 clutter_actor_get_opacity (ClutterActor *self)
10092 {
10093   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10094
10095   return self->priv->opacity;
10096 }
10097
10098 /**
10099  * clutter_actor_set_offscreen_redirect:
10100  * @self: A #ClutterActor
10101  * @redirect: New offscreen redirect flags for the actor.
10102  *
10103  * Defines the circumstances where the actor should be redirected into
10104  * an offscreen image. The offscreen image is used to flatten the
10105  * actor into a single image while painting for two main reasons.
10106  * Firstly, when the actor is painted a second time without any of its
10107  * contents changing it can simply repaint the cached image without
10108  * descending further down the actor hierarchy. Secondly, it will make
10109  * the opacity look correct even if there are overlapping primitives
10110  * in the actor.
10111  *
10112  * Caching the actor could in some cases be a performance win and in
10113  * some cases be a performance lose so it is important to determine
10114  * which value is right for an actor before modifying this value. For
10115  * example, there is never any reason to flatten an actor that is just
10116  * a single texture (such as a #ClutterTexture) because it is
10117  * effectively already cached in an image so the offscreen would be
10118  * redundant. Also if the actor contains primitives that are far apart
10119  * with a large transparent area in the middle (such as a large
10120  * CluterGroup with a small actor in the top left and a small actor in
10121  * the bottom right) then the cached image will contain the entire
10122  * image of the large area and the paint will waste time blending all
10123  * of the transparent pixels in the middle.
10124  *
10125  * The default method of implementing opacity on a container simply
10126  * forwards on the opacity to all of the children. If the children are
10127  * overlapping then it will appear as if they are two separate glassy
10128  * objects and there will be a break in the color where they
10129  * overlap. By redirecting to an offscreen buffer it will be as if the
10130  * two opaque objects are combined into one and then made transparent
10131  * which is usually what is expected.
10132  *
10133  * The image below demonstrates the difference between redirecting and
10134  * not. The image shows two Clutter groups, each containing a red and
10135  * a green rectangle which overlap. The opacity on the group is set to
10136  * 128 (which is 50%). When the offscreen redirect is not used, the
10137  * red rectangle can be seen through the blue rectangle as if the two
10138  * rectangles were separately transparent. When the redirect is used
10139  * the group as a whole is transparent instead so the red rectangle is
10140  * not visible where they overlap.
10141  *
10142  * <figure id="offscreen-redirect">
10143  *   <title>Sample of using an offscreen redirect for transparency</title>
10144  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10145  * </figure>
10146  *
10147  * The default value for this property is 0, so we effectively will
10148  * never redirect an actor offscreen by default. This means that there
10149  * are times that transparent actors may look glassy as described
10150  * above. The reason this is the default is because there is a
10151  * performance trade off between quality and performance here. In many
10152  * cases the default form of glassy opacity looks good enough, but if
10153  * it's not you will need to set the
10154  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10155  * redirection for opacity.
10156  *
10157  * Custom actors that don't contain any overlapping primitives are
10158  * recommended to override the has_overlaps() virtual to return %FALSE
10159  * for maximum efficiency.
10160  *
10161  * Since: 1.8
10162  */
10163 void
10164 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10165                                       ClutterOffscreenRedirect redirect)
10166 {
10167   ClutterActorPrivate *priv;
10168
10169   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10170
10171   priv = self->priv;
10172
10173   if (priv->offscreen_redirect != redirect)
10174     {
10175       priv->offscreen_redirect = redirect;
10176
10177       /* Queue a redraw from the effect so that it can use its cached
10178          image if available instead of having to redraw the actual
10179          actor. If it doesn't end up using the FBO then the effect is
10180          still able to continue the paint anyway. If there is no
10181          effect then this is equivalent to queuing a full redraw */
10182       _clutter_actor_queue_redraw_full (self,
10183                                         0, /* flags */
10184                                         NULL, /* clip */
10185                                         priv->flatten_effect);
10186
10187       g_object_notify_by_pspec (G_OBJECT (self),
10188                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10189     }
10190 }
10191
10192 /**
10193  * clutter_actor_get_offscreen_redirect:
10194  * @self: a #ClutterActor
10195  *
10196  * Retrieves whether to redirect the actor to an offscreen buffer, as
10197  * set by clutter_actor_set_offscreen_redirect().
10198  *
10199  * Return value: the value of the offscreen-redirect property of the actor
10200  *
10201  * Since: 1.8
10202  */
10203 ClutterOffscreenRedirect
10204 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10205 {
10206   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10207
10208   return self->priv->offscreen_redirect;
10209 }
10210
10211 /**
10212  * clutter_actor_set_name:
10213  * @self: A #ClutterActor
10214  * @name: Textual tag to apply to actor
10215  *
10216  * Sets the given name to @self. The name can be used to identify
10217  * a #ClutterActor.
10218  */
10219 void
10220 clutter_actor_set_name (ClutterActor *self,
10221                         const gchar  *name)
10222 {
10223   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10224
10225   g_free (self->priv->name);
10226   self->priv->name = g_strdup (name);
10227
10228   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10229 }
10230
10231 /**
10232  * clutter_actor_get_name:
10233  * @self: A #ClutterActor
10234  *
10235  * Retrieves the name of @self.
10236  *
10237  * Return value: the name of the actor, or %NULL. The returned string is
10238  *   owned by the actor and should not be modified or freed.
10239  */
10240 const gchar *
10241 clutter_actor_get_name (ClutterActor *self)
10242 {
10243   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10244
10245   return self->priv->name;
10246 }
10247
10248 /**
10249  * clutter_actor_get_gid:
10250  * @self: A #ClutterActor
10251  *
10252  * Retrieves the unique id for @self.
10253  *
10254  * Return value: Globally unique value for this object instance.
10255  *
10256  * Since: 0.6
10257  *
10258  * Deprecated: 1.8: The id is not used any longer.
10259  */
10260 guint32
10261 clutter_actor_get_gid (ClutterActor *self)
10262 {
10263   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10264
10265   return self->priv->id;
10266 }
10267
10268 static inline void
10269 clutter_actor_set_depth_internal (ClutterActor *self,
10270                                   float         depth)
10271 {
10272   ClutterTransformInfo *info;
10273
10274   info = _clutter_actor_get_transform_info (self);
10275
10276   if (info->depth != depth)
10277     {
10278       /* Sets Z value - XXX 2.0: should we invert? */
10279       info->depth = depth;
10280
10281       self->priv->transform_valid = FALSE;
10282
10283       /* FIXME - remove this crap; sadly, there are still containers
10284        * in Clutter that depend on this utter brain damage
10285        */
10286       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10287
10288       clutter_actor_queue_redraw (self);
10289
10290       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10291     }
10292 }
10293
10294 /**
10295  * clutter_actor_set_depth:
10296  * @self: a #ClutterActor
10297  * @depth: Z co-ord
10298  *
10299  * Sets the Z coordinate of @self to @depth.
10300  *
10301  * The unit used by @depth is dependant on the perspective setup. See
10302  * also clutter_stage_set_perspective().
10303  */
10304 void
10305 clutter_actor_set_depth (ClutterActor *self,
10306                          gfloat        depth)
10307 {
10308   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10309
10310   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10311     {
10312       const ClutterTransformInfo *info;
10313
10314       info = _clutter_actor_get_transform_info_or_defaults (self);
10315
10316       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10317                                         info->depth,
10318                                         depth);
10319     }
10320   else
10321     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10322
10323   clutter_actor_queue_redraw (self);
10324 }
10325
10326 /**
10327  * clutter_actor_get_depth:
10328  * @self: a #ClutterActor
10329  *
10330  * Retrieves the depth of @self.
10331  *
10332  * Return value: the depth of the actor
10333  */
10334 gfloat
10335 clutter_actor_get_depth (ClutterActor *self)
10336 {
10337   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10338
10339   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10340 }
10341
10342 /**
10343  * clutter_actor_set_rotation:
10344  * @self: a #ClutterActor
10345  * @axis: the axis of rotation
10346  * @angle: the angle of rotation
10347  * @x: X coordinate of the rotation center
10348  * @y: Y coordinate of the rotation center
10349  * @z: Z coordinate of the rotation center
10350  *
10351  * Sets the rotation angle of @self around the given axis.
10352  *
10353  * The rotation center coordinates used depend on the value of @axis:
10354  * <itemizedlist>
10355  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10356  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10357  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10358  * </itemizedlist>
10359  *
10360  * The rotation coordinates are relative to the anchor point of the
10361  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10362  * point is set, the upper left corner is assumed as the origin.
10363  *
10364  * Since: 0.8
10365  */
10366 void
10367 clutter_actor_set_rotation (ClutterActor      *self,
10368                             ClutterRotateAxis  axis,
10369                             gdouble            angle,
10370                             gfloat             x,
10371                             gfloat             y,
10372                             gfloat             z)
10373 {
10374   ClutterVertex v;
10375
10376   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10377
10378   v.x = x;
10379   v.y = y;
10380   v.z = z;
10381
10382   g_object_freeze_notify (G_OBJECT (self));
10383
10384   clutter_actor_set_rotation_angle (self, axis, angle);
10385   clutter_actor_set_rotation_center_internal (self, axis, &v);
10386
10387   g_object_thaw_notify (G_OBJECT (self));
10388 }
10389
10390 /**
10391  * clutter_actor_set_z_rotation_from_gravity:
10392  * @self: a #ClutterActor
10393  * @angle: the angle of rotation
10394  * @gravity: the center point of the rotation
10395  *
10396  * Sets the rotation angle of @self around the Z axis using the center
10397  * point specified as a compass point. For example to rotate such that
10398  * the center of the actor remains static you can use
10399  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10400  * will move accordingly.
10401  *
10402  * Since: 1.0
10403  */
10404 void
10405 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10406                                            gdouble         angle,
10407                                            ClutterGravity  gravity)
10408 {
10409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10410
10411   if (gravity == CLUTTER_GRAVITY_NONE)
10412     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10413   else
10414     {
10415       GObject *obj = G_OBJECT (self);
10416       ClutterTransformInfo *info;
10417
10418       info = _clutter_actor_get_transform_info (self);
10419
10420       g_object_freeze_notify (obj);
10421
10422       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10423
10424       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10425       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10426       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10427
10428       g_object_thaw_notify (obj);
10429     }
10430 }
10431
10432 /**
10433  * clutter_actor_get_rotation:
10434  * @self: a #ClutterActor
10435  * @axis: the axis of rotation
10436  * @x: (out): return value for the X coordinate of the center of rotation
10437  * @y: (out): return value for the Y coordinate of the center of rotation
10438  * @z: (out): return value for the Z coordinate of the center of rotation
10439  *
10440  * Retrieves the angle and center of rotation on the given axis,
10441  * set using clutter_actor_set_rotation().
10442  *
10443  * Return value: the angle of rotation
10444  *
10445  * Since: 0.8
10446  */
10447 gdouble
10448 clutter_actor_get_rotation (ClutterActor      *self,
10449                             ClutterRotateAxis  axis,
10450                             gfloat            *x,
10451                             gfloat            *y,
10452                             gfloat            *z)
10453 {
10454   const ClutterTransformInfo *info;
10455   const AnchorCoord *anchor_coord;
10456   gdouble retval = 0;
10457
10458   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10459
10460   info = _clutter_actor_get_transform_info_or_defaults (self);
10461
10462   switch (axis)
10463     {
10464     case CLUTTER_X_AXIS:
10465       anchor_coord = &info->rx_center;
10466       retval = info->rx_angle;
10467       break;
10468
10469     case CLUTTER_Y_AXIS:
10470       anchor_coord = &info->ry_center;
10471       retval = info->ry_angle;
10472       break;
10473
10474     case CLUTTER_Z_AXIS:
10475       anchor_coord = &info->rz_center;
10476       retval = info->rz_angle;
10477       break;
10478
10479     default:
10480       anchor_coord = NULL;
10481       retval = 0.0;
10482       break;
10483     }
10484
10485   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10486
10487   return retval;
10488 }
10489
10490 /**
10491  * clutter_actor_get_z_rotation_gravity:
10492  * @self: A #ClutterActor
10493  *
10494  * Retrieves the center for the rotation around the Z axis as a
10495  * compass direction. If the center was specified in pixels or units
10496  * this will return %CLUTTER_GRAVITY_NONE.
10497  *
10498  * Return value: the Z rotation center
10499  *
10500  * Since: 1.0
10501  */
10502 ClutterGravity
10503 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10504 {
10505   const ClutterTransformInfo *info;
10506
10507   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10508
10509   info = _clutter_actor_get_transform_info_or_defaults (self);
10510
10511   return clutter_anchor_coord_get_gravity (&info->rz_center);
10512 }
10513
10514 /**
10515  * clutter_actor_set_clip:
10516  * @self: A #ClutterActor
10517  * @xoff: X offset of the clip rectangle
10518  * @yoff: Y offset of the clip rectangle
10519  * @width: Width of the clip rectangle
10520  * @height: Height of the clip rectangle
10521  *
10522  * Sets clip area for @self. The clip area is always computed from the
10523  * upper left corner of the actor, even if the anchor point is set
10524  * otherwise.
10525  *
10526  * Since: 0.6
10527  */
10528 void
10529 clutter_actor_set_clip (ClutterActor *self,
10530                         gfloat        xoff,
10531                         gfloat        yoff,
10532                         gfloat        width,
10533                         gfloat        height)
10534 {
10535   ClutterActorPrivate *priv;
10536
10537   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10538
10539   priv = self->priv;
10540
10541   if (priv->has_clip &&
10542       priv->clip.x == xoff &&
10543       priv->clip.y == yoff &&
10544       priv->clip.width == width &&
10545       priv->clip.height == height)
10546     return;
10547
10548   priv->clip.x = xoff;
10549   priv->clip.y = yoff;
10550   priv->clip.width = width;
10551   priv->clip.height = height;
10552
10553   priv->has_clip = TRUE;
10554
10555   clutter_actor_queue_redraw (self);
10556
10557   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10558   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10559 }
10560
10561 /**
10562  * clutter_actor_remove_clip:
10563  * @self: A #ClutterActor
10564  *
10565  * Removes clip area from @self.
10566  */
10567 void
10568 clutter_actor_remove_clip (ClutterActor *self)
10569 {
10570   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10571
10572   if (!self->priv->has_clip)
10573     return;
10574
10575   self->priv->has_clip = FALSE;
10576
10577   clutter_actor_queue_redraw (self);
10578
10579   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10580 }
10581
10582 /**
10583  * clutter_actor_has_clip:
10584  * @self: a #ClutterActor
10585  *
10586  * Determines whether the actor has a clip area set or not.
10587  *
10588  * Return value: %TRUE if the actor has a clip area set.
10589  *
10590  * Since: 0.1.1
10591  */
10592 gboolean
10593 clutter_actor_has_clip (ClutterActor *self)
10594 {
10595   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10596
10597   return self->priv->has_clip;
10598 }
10599
10600 /**
10601  * clutter_actor_get_clip:
10602  * @self: a #ClutterActor
10603  * @xoff: (out) (allow-none): return location for the X offset of
10604  *   the clip rectangle, or %NULL
10605  * @yoff: (out) (allow-none): return location for the Y offset of
10606  *   the clip rectangle, or %NULL
10607  * @width: (out) (allow-none): return location for the width of
10608  *   the clip rectangle, or %NULL
10609  * @height: (out) (allow-none): return location for the height of
10610  *   the clip rectangle, or %NULL
10611  *
10612  * Gets the clip area for @self, if any is set
10613  *
10614  * Since: 0.6
10615  */
10616 void
10617 clutter_actor_get_clip (ClutterActor *self,
10618                         gfloat       *xoff,
10619                         gfloat       *yoff,
10620                         gfloat       *width,
10621                         gfloat       *height)
10622 {
10623   ClutterActorPrivate *priv;
10624
10625   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10626
10627   priv = self->priv;
10628
10629   if (!priv->has_clip)
10630     return;
10631
10632   if (xoff != NULL)
10633     *xoff = priv->clip.x;
10634
10635   if (yoff != NULL)
10636     *yoff = priv->clip.y;
10637
10638   if (width != NULL)
10639     *width = priv->clip.width;
10640
10641   if (height != NULL)
10642     *height = priv->clip.height;
10643 }
10644
10645 /**
10646  * clutter_actor_get_children:
10647  * @self: a #ClutterActor
10648  *
10649  * Retrieves the list of children of @self.
10650  *
10651  * Return value: (transfer container) (element-type ClutterActor): A newly
10652  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10653  *   done.
10654  *
10655  * Since: 1.10
10656  */
10657 GList *
10658 clutter_actor_get_children (ClutterActor *self)
10659 {
10660   ClutterActor *iter;
10661   GList *res;
10662
10663   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10664
10665   /* we walk the list backward so that we can use prepend(),
10666    * which is O(1)
10667    */
10668   for (iter = self->priv->last_child, res = NULL;
10669        iter != NULL;
10670        iter = iter->priv->prev_sibling)
10671     {
10672       res = g_list_prepend (res, iter);
10673     }
10674
10675   return res;
10676 }
10677
10678 /*< private >
10679  * insert_child_at_depth:
10680  * @self: a #ClutterActor
10681  * @child: a #ClutterActor
10682  *
10683  * Inserts @child inside the list of children held by @self, using
10684  * the depth as the insertion criteria.
10685  *
10686  * This sadly makes the insertion not O(1), but we can keep the
10687  * list sorted so that the painters algorithm we use for painting
10688  * the children will work correctly.
10689  */
10690 static void
10691 insert_child_at_depth (ClutterActor *self,
10692                        ClutterActor *child,
10693                        gpointer      dummy G_GNUC_UNUSED)
10694 {
10695   ClutterActor *iter;
10696   float child_depth;
10697
10698   child->priv->parent = self;
10699
10700   child_depth =
10701     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10702
10703   /* special-case the first child */
10704   if (self->priv->n_children == 0)
10705     {
10706       self->priv->first_child = child;
10707       self->priv->last_child = child;
10708
10709       child->priv->next_sibling = NULL;
10710       child->priv->prev_sibling = NULL;
10711
10712       return;
10713     }
10714
10715   /* Find the right place to insert the child so that it will still be
10716      sorted and the child will be after all of the actors at the same
10717      dept */
10718   for (iter = self->priv->first_child;
10719        iter != NULL;
10720        iter = iter->priv->next_sibling)
10721     {
10722       float iter_depth;
10723
10724       iter_depth =
10725         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10726
10727       if (iter_depth > child_depth)
10728         break;
10729     }
10730
10731   if (iter != NULL)
10732     {
10733       ClutterActor *tmp = iter->priv->prev_sibling;
10734
10735       if (tmp != NULL)
10736         tmp->priv->next_sibling = child;
10737
10738       /* Insert the node before the found one */
10739       child->priv->prev_sibling = iter->priv->prev_sibling;
10740       child->priv->next_sibling = iter;
10741       iter->priv->prev_sibling = child;
10742     }
10743   else
10744     {
10745       ClutterActor *tmp = self->priv->last_child;
10746
10747       if (tmp != NULL)
10748         tmp->priv->next_sibling = child;
10749
10750       /* insert the node at the end of the list */
10751       child->priv->prev_sibling = self->priv->last_child;
10752       child->priv->next_sibling = NULL;
10753     }
10754
10755   if (child->priv->prev_sibling == NULL)
10756     self->priv->first_child = child;
10757
10758   if (child->priv->next_sibling == NULL)
10759     self->priv->last_child = child;
10760 }
10761
10762 static void
10763 insert_child_at_index (ClutterActor *self,
10764                        ClutterActor *child,
10765                        gpointer      data_)
10766 {
10767   gint index_ = GPOINTER_TO_INT (data_);
10768
10769   child->priv->parent = self;
10770
10771   if (index_ == 0)
10772     {
10773       ClutterActor *tmp = self->priv->first_child;
10774
10775       if (tmp != NULL)
10776         tmp->priv->prev_sibling = child;
10777
10778       child->priv->prev_sibling = NULL;
10779       child->priv->next_sibling = tmp;
10780     }
10781   else if (index_ < 0 || index_ >= self->priv->n_children)
10782     {
10783       ClutterActor *tmp = self->priv->last_child;
10784
10785       if (tmp != NULL)
10786         tmp->priv->next_sibling = child;
10787
10788       child->priv->prev_sibling = tmp;
10789       child->priv->next_sibling = NULL;
10790     }
10791   else
10792     {
10793       ClutterActor *iter;
10794       int i;
10795
10796       for (iter = self->priv->first_child, i = 0;
10797            iter != NULL;
10798            iter = iter->priv->next_sibling, i += 1)
10799         {
10800           if (index_ == i)
10801             {
10802               ClutterActor *tmp = iter->priv->prev_sibling;
10803
10804               child->priv->prev_sibling = tmp;
10805               child->priv->next_sibling = iter;
10806
10807               iter->priv->prev_sibling = child;
10808
10809               if (tmp != NULL)
10810                 tmp->priv->next_sibling = child;
10811
10812               break;
10813             }
10814         }
10815     }
10816
10817   if (child->priv->prev_sibling == NULL)
10818     self->priv->first_child = child;
10819
10820   if (child->priv->next_sibling == NULL)
10821     self->priv->last_child = child;
10822 }
10823
10824 static void
10825 insert_child_above (ClutterActor *self,
10826                     ClutterActor *child,
10827                     gpointer      data)
10828 {
10829   ClutterActor *sibling = data;
10830
10831   child->priv->parent = self;
10832
10833   if (sibling == NULL)
10834     sibling = self->priv->last_child;
10835
10836   child->priv->prev_sibling = sibling;
10837
10838   if (sibling != NULL)
10839     {
10840       ClutterActor *tmp = sibling->priv->next_sibling;
10841
10842       child->priv->next_sibling = tmp;
10843
10844       if (tmp != NULL)
10845         tmp->priv->prev_sibling = child;
10846
10847       sibling->priv->next_sibling = child;
10848     }
10849   else
10850     child->priv->next_sibling = NULL;
10851
10852   if (child->priv->prev_sibling == NULL)
10853     self->priv->first_child = child;
10854
10855   if (child->priv->next_sibling == NULL)
10856     self->priv->last_child = child;
10857 }
10858
10859 static void
10860 insert_child_below (ClutterActor *self,
10861                     ClutterActor *child,
10862                     gpointer      data)
10863 {
10864   ClutterActor *sibling = data;
10865
10866   child->priv->parent = self;
10867
10868   if (sibling == NULL)
10869     sibling = self->priv->first_child;
10870
10871   child->priv->next_sibling = sibling;
10872
10873   if (sibling != NULL)
10874     {
10875       ClutterActor *tmp = sibling->priv->prev_sibling;
10876
10877       child->priv->prev_sibling = tmp;
10878
10879       if (tmp != NULL)
10880         tmp->priv->next_sibling = child;
10881
10882       sibling->priv->prev_sibling = child;
10883     }
10884   else
10885     child->priv->prev_sibling = NULL;
10886
10887   if (child->priv->prev_sibling == NULL)
10888     self->priv->first_child = child;
10889
10890   if (child->priv->next_sibling == NULL)
10891     self->priv->last_child = child;
10892 }
10893
10894 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10895                                            ClutterActor *child,
10896                                            gpointer      data);
10897
10898 typedef enum {
10899   ADD_CHILD_CREATE_META       = 1 << 0,
10900   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10901   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10902   ADD_CHILD_CHECK_STATE       = 1 << 3,
10903   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10904
10905   /* default flags for public API */
10906   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10907                                ADD_CHILD_EMIT_PARENT_SET |
10908                                ADD_CHILD_EMIT_ACTOR_ADDED |
10909                                ADD_CHILD_CHECK_STATE |
10910                                ADD_CHILD_NOTIFY_FIRST_LAST,
10911
10912   /* flags for legacy/deprecated API */
10913   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10914                                ADD_CHILD_CHECK_STATE |
10915                                ADD_CHILD_NOTIFY_FIRST_LAST
10916 } ClutterActorAddChildFlags;
10917
10918 /*< private >
10919  * clutter_actor_add_child_internal:
10920  * @self: a #ClutterActor
10921  * @child: a #ClutterActor
10922  * @flags: control flags for actions
10923  * @add_func: delegate function
10924  * @data: (closure): data to pass to @add_func
10925  *
10926  * Adds @child to the list of children of @self.
10927  *
10928  * The actual insertion inside the list is delegated to @add_func: this
10929  * function will just set up the state, perform basic checks, and emit
10930  * signals.
10931  *
10932  * The @flags argument is used to perform additional operations.
10933  */
10934 static inline void
10935 clutter_actor_add_child_internal (ClutterActor              *self,
10936                                   ClutterActor              *child,
10937                                   ClutterActorAddChildFlags  flags,
10938                                   ClutterActorAddChildFunc   add_func,
10939                                   gpointer                   data)
10940 {
10941   ClutterTextDirection text_dir;
10942   gboolean create_meta;
10943   gboolean emit_parent_set, emit_actor_added;
10944   gboolean check_state;
10945   gboolean notify_first_last;
10946   ClutterActor *old_first_child, *old_last_child;
10947
10948   if (child->priv->parent != NULL)
10949     {
10950       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10951                  "use clutter_actor_remove_child() first.",
10952                  _clutter_actor_get_debug_name (child),
10953                  _clutter_actor_get_debug_name (child->priv->parent));
10954       return;
10955     }
10956
10957   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10958     {
10959       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10960                  "a child of another actor.",
10961                  _clutter_actor_get_debug_name (child));
10962       return;
10963     }
10964
10965 #if 0
10966   /* XXX - this check disallows calling methods that change the stacking
10967    * order within the destruction sequence, by triggering a critical
10968    * warning first, and leaving the actor in an undefined state, which
10969    * then ends up being caught by an assertion.
10970    *
10971    * the reproducible sequence is:
10972    *
10973    *   - actor gets destroyed;
10974    *   - another actor, linked to the first, will try to change the
10975    *     stacking order of the first actor;
10976    *   - changing the stacking order is a composite operation composed
10977    *     by the following steps:
10978    *     1. ref() the child;
10979    *     2. remove_child_internal(), which removes the reference;
10980    *     3. add_child_internal(), which adds a reference;
10981    *   - the state of the actor is not changed between (2) and (3), as
10982    *     it could be an expensive recomputation;
10983    *   - if (3) bails out, then the actor is in an undefined state, but
10984    *     still alive;
10985    *   - the destruction sequence terminates, but the actor is unparented
10986    *     while its state indicates being parented instead.
10987    *   - assertion failure.
10988    *
10989    * the obvious fix would be to decompose each set_child_*_sibling()
10990    * method into proper remove_child()/add_child(), with state validation;
10991    * this may cause excessive work, though, and trigger a cascade of other
10992    * bugs in code that assumes that a change in the stacking order is an
10993    * atomic operation.
10994    *
10995    * another potential fix is to just remove this check here, and let
10996    * code doing stacking order changes inside the destruction sequence
10997    * of an actor continue doing the work.
10998    *
10999    * the third fix is to silently bail out early from every
11000    * set_child_*_sibling() and set_child_at_index() method, and avoid
11001    * doing work.
11002    *
11003    * I have a preference for the second solution, since it involves the
11004    * least amount of work, and the least amount of code duplication.
11005    *
11006    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11007    */
11008   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11009     {
11010       g_warning ("The actor '%s' is currently being destroyed, and "
11011                  "cannot be added as a child of another actor.",
11012                  _clutter_actor_get_debug_name (child));
11013       return;
11014     }
11015 #endif
11016
11017   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11018   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11019   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11020   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11021   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11022
11023   old_first_child = self->priv->first_child;
11024   old_last_child = self->priv->last_child;
11025
11026   g_object_freeze_notify (G_OBJECT (self));
11027
11028   if (create_meta)
11029     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11030
11031   g_object_ref_sink (child);
11032   child->priv->parent = NULL;
11033   child->priv->next_sibling = NULL;
11034   child->priv->prev_sibling = NULL;
11035
11036   /* delegate the actual insertion */
11037   add_func (self, child, data);
11038
11039   g_assert (child->priv->parent == self);
11040
11041   self->priv->n_children += 1;
11042
11043   self->priv->age += 1;
11044
11045   /* if push_internal() has been called then we automatically set
11046    * the flag on the actor
11047    */
11048   if (self->priv->internal_child)
11049     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11050
11051   /* clutter_actor_reparent() will emit ::parent-set for us */
11052   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11053     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11054
11055   if (check_state)
11056     {
11057       /* If parent is mapped or realized, we need to also be mapped or
11058        * realized once we're inside the parent.
11059        */
11060       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11061
11062       /* propagate the parent's text direction to the child */
11063       text_dir = clutter_actor_get_text_direction (self);
11064       clutter_actor_set_text_direction (child, text_dir);
11065     }
11066
11067   if (child->priv->show_on_set_parent)
11068     clutter_actor_show (child);
11069
11070   if (CLUTTER_ACTOR_IS_MAPPED (child))
11071     clutter_actor_queue_redraw (child);
11072
11073   /* maintain the invariant that if an actor needs layout,
11074    * its parents do as well
11075    */
11076   if (child->priv->needs_width_request ||
11077       child->priv->needs_height_request ||
11078       child->priv->needs_allocation)
11079     {
11080       /* we work around the short-circuiting we do
11081        * in clutter_actor_queue_relayout() since we
11082        * want to force a relayout
11083        */
11084       child->priv->needs_width_request = TRUE;
11085       child->priv->needs_height_request = TRUE;
11086       child->priv->needs_allocation = TRUE;
11087
11088       clutter_actor_queue_relayout (child->priv->parent);
11089     }
11090
11091   if (emit_actor_added)
11092     g_signal_emit_by_name (self, "actor-added", child);
11093
11094   if (notify_first_last)
11095     {
11096       if (old_first_child != self->priv->first_child)
11097         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11098
11099       if (old_last_child != self->priv->last_child)
11100         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11101     }
11102
11103   g_object_thaw_notify (G_OBJECT (self));
11104 }
11105
11106 /**
11107  * clutter_actor_add_child:
11108  * @self: a #ClutterActor
11109  * @child: a #ClutterActor
11110  *
11111  * Adds @child to the children of @self.
11112  *
11113  * This function will acquire a reference on @child that will only
11114  * be released when calling clutter_actor_remove_child().
11115  *
11116  * This function will take into consideration the #ClutterActor:depth
11117  * of @child, and will keep the list of children sorted.
11118  *
11119  * This function will emit the #ClutterContainer::actor-added signal
11120  * on @self.
11121  *
11122  * Since: 1.10
11123  */
11124 void
11125 clutter_actor_add_child (ClutterActor *self,
11126                          ClutterActor *child)
11127 {
11128   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11129   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11130   g_return_if_fail (self != child);
11131   g_return_if_fail (child->priv->parent == NULL);
11132
11133   clutter_actor_add_child_internal (self, child,
11134                                     ADD_CHILD_DEFAULT_FLAGS,
11135                                     insert_child_at_depth,
11136                                     NULL);
11137 }
11138
11139 /**
11140  * clutter_actor_insert_child_at_index:
11141  * @self: a #ClutterActor
11142  * @child: a #ClutterActor
11143  * @index_: the index
11144  *
11145  * Inserts @child into the list of children of @self, using the
11146  * given @index_. If @index_ is greater than the number of children
11147  * in @self, or is less than 0, then the new child is added at the end.
11148  *
11149  * This function will acquire a reference on @child that will only
11150  * be released when calling clutter_actor_remove_child().
11151  *
11152  * This function will not take into consideration the #ClutterActor:depth
11153  * of @child.
11154  *
11155  * This function will emit the #ClutterContainer::actor-added signal
11156  * on @self.
11157  *
11158  * Since: 1.10
11159  */
11160 void
11161 clutter_actor_insert_child_at_index (ClutterActor *self,
11162                                      ClutterActor *child,
11163                                      gint          index_)
11164 {
11165   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11166   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11167   g_return_if_fail (self != child);
11168   g_return_if_fail (child->priv->parent == NULL);
11169
11170   clutter_actor_add_child_internal (self, child,
11171                                     ADD_CHILD_DEFAULT_FLAGS,
11172                                     insert_child_at_index,
11173                                     GINT_TO_POINTER (index_));
11174 }
11175
11176 /**
11177  * clutter_actor_insert_child_above:
11178  * @self: a #ClutterActor
11179  * @child: a #ClutterActor
11180  * @sibling: (allow-none): a child of @self, or %NULL
11181  *
11182  * Inserts @child into the list of children of @self, above another
11183  * child of @self or, if @sibling is %NULL, above all the children
11184  * of @self.
11185  *
11186  * This function will acquire a reference on @child that will only
11187  * be released when calling clutter_actor_remove_child().
11188  *
11189  * This function will not take into consideration the #ClutterActor:depth
11190  * of @child.
11191  *
11192  * This function will emit the #ClutterContainer::actor-added signal
11193  * on @self.
11194  *
11195  * Since: 1.10
11196  */
11197 void
11198 clutter_actor_insert_child_above (ClutterActor *self,
11199                                   ClutterActor *child,
11200                                   ClutterActor *sibling)
11201 {
11202   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11203   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11204   g_return_if_fail (self != child);
11205   g_return_if_fail (child != sibling);
11206   g_return_if_fail (child->priv->parent == NULL);
11207   g_return_if_fail (sibling == NULL ||
11208                     (CLUTTER_IS_ACTOR (sibling) &&
11209                      sibling->priv->parent == self));
11210
11211   clutter_actor_add_child_internal (self, child,
11212                                     ADD_CHILD_DEFAULT_FLAGS,
11213                                     insert_child_above,
11214                                     sibling);
11215 }
11216
11217 /**
11218  * clutter_actor_insert_child_below:
11219  * @self: a #ClutterActor
11220  * @child: a #ClutterActor
11221  * @sibling: (allow-none): a child of @self, or %NULL
11222  *
11223  * Inserts @child into the list of children of @self, below another
11224  * child of @self or, if @sibling is %NULL, below all the children
11225  * of @self.
11226  *
11227  * This function will acquire a reference on @child that will only
11228  * be released when calling clutter_actor_remove_child().
11229  *
11230  * This function will not take into consideration the #ClutterActor:depth
11231  * of @child.
11232  *
11233  * This function will emit the #ClutterContainer::actor-added signal
11234  * on @self.
11235  *
11236  * Since: 1.10
11237  */
11238 void
11239 clutter_actor_insert_child_below (ClutterActor *self,
11240                                   ClutterActor *child,
11241                                   ClutterActor *sibling)
11242 {
11243   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11244   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11245   g_return_if_fail (self != child);
11246   g_return_if_fail (child != sibling);
11247   g_return_if_fail (child->priv->parent == NULL);
11248   g_return_if_fail (sibling == NULL ||
11249                     (CLUTTER_IS_ACTOR (sibling) &&
11250                      sibling->priv->parent == self));
11251
11252   clutter_actor_add_child_internal (self, child,
11253                                     ADD_CHILD_DEFAULT_FLAGS,
11254                                     insert_child_below,
11255                                     sibling);
11256 }
11257
11258 /**
11259  * clutter_actor_set_parent:
11260  * @self: A #ClutterActor
11261  * @parent: A new #ClutterActor parent
11262  *
11263  * Sets the parent of @self to @parent.
11264  *
11265  * This function will result in @parent acquiring a reference on @self,
11266  * eventually by sinking its floating reference first. The reference
11267  * will be released by clutter_actor_unparent().
11268  *
11269  * This function should only be called by legacy #ClutterActor<!-- -->s
11270  * implementing the #ClutterContainer interface.
11271  *
11272  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11273  */
11274 void
11275 clutter_actor_set_parent (ClutterActor *self,
11276                           ClutterActor *parent)
11277 {
11278   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11279   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11280   g_return_if_fail (self != parent);
11281   g_return_if_fail (self->priv->parent == NULL);
11282
11283   /* as this function will be called inside ClutterContainer::add
11284    * implementations or when building up a composite actor, we have
11285    * to preserve the old behaviour, and not create child meta or
11286    * emit the ::actor-added signal, to avoid recursion or double
11287    * emissions
11288    */
11289   clutter_actor_add_child_internal (parent, self,
11290                                     ADD_CHILD_LEGACY_FLAGS,
11291                                     insert_child_at_depth,
11292                                     NULL);
11293 }
11294
11295 /**
11296  * clutter_actor_get_parent:
11297  * @self: A #ClutterActor
11298  *
11299  * Retrieves the parent of @self.
11300  *
11301  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11302  *  if no parent is set
11303  */
11304 ClutterActor *
11305 clutter_actor_get_parent (ClutterActor *self)
11306 {
11307   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11308
11309   return self->priv->parent;
11310 }
11311
11312 /**
11313  * clutter_actor_get_paint_visibility:
11314  * @self: A #ClutterActor
11315  *
11316  * Retrieves the 'paint' visibility of an actor recursively checking for non
11317  * visible parents.
11318  *
11319  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11320  *
11321  * Return Value: %TRUE if the actor is visibile and will be painted.
11322  *
11323  * Since: 0.8.4
11324  */
11325 gboolean
11326 clutter_actor_get_paint_visibility (ClutterActor *actor)
11327 {
11328   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11329
11330   return CLUTTER_ACTOR_IS_MAPPED (actor);
11331 }
11332
11333 /**
11334  * clutter_actor_remove_child:
11335  * @self: a #ClutterActor
11336  * @child: a #ClutterActor
11337  *
11338  * Removes @child from the children of @self.
11339  *
11340  * This function will release the reference added by
11341  * clutter_actor_add_child(), so if you want to keep using @child
11342  * you will have to acquire a referenced on it before calling this
11343  * function.
11344  *
11345  * This function will emit the #ClutterContainer::actor-removed
11346  * signal on @self.
11347  *
11348  * Since: 1.10
11349  */
11350 void
11351 clutter_actor_remove_child (ClutterActor *self,
11352                             ClutterActor *child)
11353 {
11354   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11355   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11356   g_return_if_fail (self != child);
11357   g_return_if_fail (child->priv->parent != NULL);
11358   g_return_if_fail (child->priv->parent == self);
11359
11360   clutter_actor_remove_child_internal (self, child,
11361                                        REMOVE_CHILD_DEFAULT_FLAGS);
11362 }
11363
11364 /**
11365  * clutter_actor_remove_all_children:
11366  * @self: a #ClutterActor
11367  *
11368  * Removes all children of @self.
11369  *
11370  * This function releases the reference added by inserting a child actor
11371  * in the list of children of @self.
11372  *
11373  * If the reference count of a child drops to zero, the child will be
11374  * destroyed. If you want to ensure the destruction of all the children
11375  * of @self, use clutter_actor_destroy_all_children().
11376  *
11377  * Since: 1.10
11378  */
11379 void
11380 clutter_actor_remove_all_children (ClutterActor *self)
11381 {
11382   ClutterActorIter iter;
11383
11384   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11385
11386   if (self->priv->n_children == 0)
11387     return;
11388
11389   g_object_freeze_notify (G_OBJECT (self));
11390
11391   clutter_actor_iter_init (&iter, self);
11392   while (clutter_actor_iter_next (&iter, NULL))
11393     clutter_actor_iter_remove (&iter);
11394
11395   g_object_thaw_notify (G_OBJECT (self));
11396
11397   /* sanity check */
11398   g_assert (self->priv->first_child == NULL);
11399   g_assert (self->priv->last_child == NULL);
11400   g_assert (self->priv->n_children == 0);
11401 }
11402
11403 /**
11404  * clutter_actor_destroy_all_children:
11405  * @self: a #ClutterActor
11406  *
11407  * Destroys all children of @self.
11408  *
11409  * This function releases the reference added by inserting a child
11410  * actor in the list of children of @self, and ensures that the
11411  * #ClutterActor::destroy signal is emitted on each child of the
11412  * actor.
11413  *
11414  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11415  * when its reference count drops to 0; the default handler of the
11416  * #ClutterActor::destroy signal will destroy all the children of an
11417  * actor. This function ensures that all children are destroyed, instead
11418  * of just removed from @self, unlike clutter_actor_remove_all_children()
11419  * which will merely release the reference and remove each child.
11420  *
11421  * Unless you acquired an additional reference on each child of @self
11422  * prior to calling clutter_actor_remove_all_children() and want to reuse
11423  * the actors, you should use clutter_actor_destroy_all_children() in
11424  * order to make sure that children are destroyed and signal handlers
11425  * are disconnected even in cases where circular references prevent this
11426  * from automatically happening through reference counting alone.
11427  *
11428  * Since: 1.10
11429  */
11430 void
11431 clutter_actor_destroy_all_children (ClutterActor *self)
11432 {
11433   ClutterActorIter iter;
11434
11435   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11436
11437   if (self->priv->n_children == 0)
11438     return;
11439
11440   g_object_freeze_notify (G_OBJECT (self));
11441
11442   clutter_actor_iter_init (&iter, self);
11443   while (clutter_actor_iter_next (&iter, NULL))
11444     clutter_actor_iter_destroy (&iter);
11445
11446   g_object_thaw_notify (G_OBJECT (self));
11447
11448   /* sanity check */
11449   g_assert (self->priv->first_child == NULL);
11450   g_assert (self->priv->last_child == NULL);
11451   g_assert (self->priv->n_children == 0);
11452 }
11453
11454 typedef struct _InsertBetweenData {
11455   ClutterActor *prev_sibling;
11456   ClutterActor *next_sibling;
11457 } InsertBetweenData;
11458
11459 static void
11460 insert_child_between (ClutterActor *self,
11461                       ClutterActor *child,
11462                       gpointer      data_)
11463 {
11464   InsertBetweenData *data = data_;
11465   ClutterActor *prev_sibling = data->prev_sibling;
11466   ClutterActor *next_sibling = data->next_sibling;
11467
11468   child->priv->parent = self;
11469   child->priv->prev_sibling = prev_sibling;
11470   child->priv->next_sibling = next_sibling;
11471
11472   if (prev_sibling != NULL)
11473     prev_sibling->priv->next_sibling = child;
11474
11475   if (next_sibling != NULL)
11476     next_sibling->priv->prev_sibling = child;
11477
11478   if (child->priv->prev_sibling == NULL)
11479     self->priv->first_child = child;
11480
11481   if (child->priv->next_sibling == NULL)
11482     self->priv->last_child = child;
11483 }
11484
11485 /**
11486  * clutter_actor_replace_child:
11487  * @self: a #ClutterActor
11488  * @old_child: the child of @self to replace
11489  * @new_child: the #ClutterActor to replace @old_child
11490  *
11491  * Replaces @old_child with @new_child in the list of children of @self.
11492  *
11493  * Since: 1.10
11494  */
11495 void
11496 clutter_actor_replace_child (ClutterActor *self,
11497                              ClutterActor *old_child,
11498                              ClutterActor *new_child)
11499 {
11500   ClutterActor *prev_sibling, *next_sibling;
11501   InsertBetweenData clos;
11502
11503   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11504   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11505   g_return_if_fail (old_child->priv->parent == self);
11506   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11507   g_return_if_fail (old_child != new_child);
11508   g_return_if_fail (new_child != self);
11509   g_return_if_fail (new_child->priv->parent == NULL);
11510
11511   prev_sibling = old_child->priv->prev_sibling;
11512   next_sibling = old_child->priv->next_sibling;
11513   clutter_actor_remove_child_internal (self, old_child,
11514                                        REMOVE_CHILD_DEFAULT_FLAGS);
11515
11516   clos.prev_sibling = prev_sibling;
11517   clos.next_sibling = next_sibling;
11518   clutter_actor_add_child_internal (self, new_child,
11519                                     ADD_CHILD_DEFAULT_FLAGS,
11520                                     insert_child_between,
11521                                     &clos);
11522 }
11523
11524 /**
11525  * clutter_actor_unparent:
11526  * @self: a #ClutterActor
11527  *
11528  * Removes the parent of @self.
11529  *
11530  * This will cause the parent of @self to release the reference
11531  * acquired when calling clutter_actor_set_parent(), so if you
11532  * want to keep @self you will have to acquire a reference of
11533  * your own, through g_object_ref().
11534  *
11535  * This function should only be called by legacy #ClutterActor<!-- -->s
11536  * implementing the #ClutterContainer interface.
11537  *
11538  * Since: 0.1.1
11539  *
11540  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11541  */
11542 void
11543 clutter_actor_unparent (ClutterActor *self)
11544 {
11545   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11546
11547   if (self->priv->parent == NULL)
11548     return;
11549
11550   clutter_actor_remove_child_internal (self->priv->parent, self,
11551                                        REMOVE_CHILD_LEGACY_FLAGS);
11552 }
11553
11554 /**
11555  * clutter_actor_reparent:
11556  * @self: a #ClutterActor
11557  * @new_parent: the new #ClutterActor parent
11558  *
11559  * Resets the parent actor of @self.
11560  *
11561  * This function is logically equivalent to calling clutter_actor_unparent()
11562  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11563  * ensures the child is not finalized when unparented, and emits the
11564  * #ClutterActor::parent-set signal only once.
11565  *
11566  * In reality, calling this function is less useful than it sounds, as some
11567  * application code may rely on changes in the intermediate state between
11568  * removal and addition of the actor from its old parent to the @new_parent.
11569  * Thus, it is strongly encouraged to avoid using this function in application
11570  * code.
11571  *
11572  * Since: 0.2
11573  *
11574  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11575  *   clutter_actor_add_child() instead; remember to take a reference on
11576  *   the actor being removed before calling clutter_actor_remove_child()
11577  *   to avoid the reference count dropping to zero and the actor being
11578  *   destroyed.
11579  */
11580 void
11581 clutter_actor_reparent (ClutterActor *self,
11582                         ClutterActor *new_parent)
11583 {
11584   ClutterActorPrivate *priv;
11585
11586   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11587   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11588   g_return_if_fail (self != new_parent);
11589
11590   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11591     {
11592       g_warning ("Cannot set a parent on a toplevel actor");
11593       return;
11594     }
11595
11596   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11597     {
11598       g_warning ("Cannot set a parent currently being destroyed");
11599       return;
11600     }
11601
11602   priv = self->priv;
11603
11604   if (priv->parent != new_parent)
11605     {
11606       ClutterActor *old_parent;
11607
11608       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11609
11610       old_parent = priv->parent;
11611
11612       g_object_ref (self);
11613
11614       if (old_parent != NULL)
11615         {
11616          /* go through the Container implementation if this is a regular
11617           * child and not an internal one
11618           */
11619          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11620            {
11621              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11622
11623              /* this will have to call unparent() */
11624              clutter_container_remove_actor (parent, self);
11625            }
11626          else
11627            clutter_actor_remove_child_internal (old_parent, self,
11628                                                 REMOVE_CHILD_LEGACY_FLAGS);
11629         }
11630
11631       /* Note, will call set_parent() */
11632       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11633         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11634       else
11635         clutter_actor_add_child_internal (new_parent, self,
11636                                           ADD_CHILD_LEGACY_FLAGS,
11637                                           insert_child_at_depth,
11638                                           NULL);
11639
11640       /* we emit the ::parent-set signal once */
11641       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11642
11643       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11644
11645       /* the IN_REPARENT flag suspends state updates */
11646       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11647
11648       g_object_unref (self);
11649    }
11650 }
11651
11652 /**
11653  * clutter_actor_contains:
11654  * @self: A #ClutterActor
11655  * @descendant: A #ClutterActor, possibly contained in @self
11656  *
11657  * Determines if @descendant is contained inside @self (either as an
11658  * immediate child, or as a deeper descendant). If @self and
11659  * @descendant point to the same actor then it will also return %TRUE.
11660  *
11661  * Return value: whether @descendent is contained within @self
11662  *
11663  * Since: 1.4
11664  */
11665 gboolean
11666 clutter_actor_contains (ClutterActor *self,
11667                         ClutterActor *descendant)
11668 {
11669   ClutterActor *actor;
11670
11671   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11672   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11673
11674   for (actor = descendant; actor; actor = actor->priv->parent)
11675     if (actor == self)
11676       return TRUE;
11677
11678   return FALSE;
11679 }
11680
11681 /**
11682  * clutter_actor_set_child_above_sibling:
11683  * @self: a #ClutterActor
11684  * @child: a #ClutterActor child of @self
11685  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11686  *
11687  * Sets @child to be above @sibling in the list of children of @self.
11688  *
11689  * If @sibling is %NULL, @child will be the new last child of @self.
11690  *
11691  * This function is logically equivalent to removing @child and using
11692  * clutter_actor_insert_child_above(), but it will not emit signals
11693  * or change state on @child.
11694  *
11695  * Since: 1.10
11696  */
11697 void
11698 clutter_actor_set_child_above_sibling (ClutterActor *self,
11699                                        ClutterActor *child,
11700                                        ClutterActor *sibling)
11701 {
11702   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11703   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11704   g_return_if_fail (child->priv->parent == self);
11705   g_return_if_fail (child != sibling);
11706   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11707
11708   if (sibling != NULL)
11709     g_return_if_fail (sibling->priv->parent == self);
11710
11711   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11712       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11713       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11714     return;
11715
11716   /* we don't want to change the state of child, or emit signals, or
11717    * regenerate ChildMeta instances here, but we still want to follow
11718    * the correct sequence of steps encoded in remove_child() and
11719    * add_child(), so that correctness is ensured, and we only go
11720    * through one known code path.
11721    */
11722   g_object_ref (child);
11723   clutter_actor_remove_child_internal (self, child, 0);
11724   clutter_actor_add_child_internal (self, child,
11725                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11726                                     insert_child_above,
11727                                     sibling);
11728
11729   clutter_actor_queue_relayout (self);
11730 }
11731
11732 /**
11733  * clutter_actor_set_child_below_sibling:
11734  * @self: a #ClutterActor
11735  * @child: a #ClutterActor child of @self
11736  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11737  *
11738  * Sets @child to be below @sibling in the list of children of @self.
11739  *
11740  * If @sibling is %NULL, @child will be the new first child of @self.
11741  *
11742  * This function is logically equivalent to removing @self and using
11743  * clutter_actor_insert_child_below(), but it will not emit signals
11744  * or change state on @child.
11745  *
11746  * Since: 1.10
11747  */
11748 void
11749 clutter_actor_set_child_below_sibling (ClutterActor *self,
11750                                        ClutterActor *child,
11751                                        ClutterActor *sibling)
11752 {
11753   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11754   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11755   g_return_if_fail (child->priv->parent == self);
11756   g_return_if_fail (child != sibling);
11757   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11758
11759   if (sibling != NULL)
11760     g_return_if_fail (sibling->priv->parent == self);
11761
11762   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11763       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11764       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11765     return;
11766
11767   /* see the comment in set_child_above_sibling() */
11768   g_object_ref (child);
11769   clutter_actor_remove_child_internal (self, child, 0);
11770   clutter_actor_add_child_internal (self, child,
11771                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11772                                     insert_child_below,
11773                                     sibling);
11774
11775   clutter_actor_queue_relayout (self);
11776 }
11777
11778 /**
11779  * clutter_actor_set_child_at_index:
11780  * @self: a #ClutterActor
11781  * @child: a #ClutterActor child of @self
11782  * @index_: the new index for @child
11783  *
11784  * Changes the index of @child in the list of children of @self.
11785  *
11786  * This function is logically equivalent to removing @child and
11787  * calling clutter_actor_insert_child_at_index(), but it will not
11788  * emit signals or change state on @child.
11789  *
11790  * Since: 1.10
11791  */
11792 void
11793 clutter_actor_set_child_at_index (ClutterActor *self,
11794                                   ClutterActor *child,
11795                                   gint          index_)
11796 {
11797   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11798   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11799   g_return_if_fail (child->priv->parent == self);
11800   g_return_if_fail (index_ <= self->priv->n_children);
11801
11802   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11803       CLUTTER_ACTOR_IN_DESTRUCTION (child))
11804     return;
11805
11806   g_object_ref (child);
11807   clutter_actor_remove_child_internal (self, child, 0);
11808   clutter_actor_add_child_internal (self, child,
11809                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11810                                     insert_child_at_index,
11811                                     GINT_TO_POINTER (index_));
11812
11813   clutter_actor_queue_relayout (self);
11814 }
11815
11816 /**
11817  * clutter_actor_raise:
11818  * @self: A #ClutterActor
11819  * @below: (allow-none): A #ClutterActor to raise above.
11820  *
11821  * Puts @self above @below.
11822  *
11823  * Both actors must have the same parent, and the parent must implement
11824  * the #ClutterContainer interface
11825  *
11826  * This function calls clutter_container_raise_child() internally.
11827  *
11828  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11829  */
11830 void
11831 clutter_actor_raise (ClutterActor *self,
11832                      ClutterActor *below)
11833 {
11834   ClutterActor *parent;
11835
11836   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11837
11838   parent = clutter_actor_get_parent (self);
11839   if (parent == NULL)
11840     {
11841       g_warning ("%s: Actor '%s' is not inside a container",
11842                  G_STRFUNC,
11843                  _clutter_actor_get_debug_name (self));
11844       return;
11845     }
11846
11847   if (below != NULL)
11848     {
11849       if (parent != clutter_actor_get_parent (below))
11850         {
11851           g_warning ("%s Actor '%s' is not in the same container as "
11852                      "actor '%s'",
11853                      G_STRFUNC,
11854                      _clutter_actor_get_debug_name (self),
11855                      _clutter_actor_get_debug_name (below));
11856           return;
11857         }
11858     }
11859
11860   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11861 }
11862
11863 /**
11864  * clutter_actor_lower:
11865  * @self: A #ClutterActor
11866  * @above: (allow-none): A #ClutterActor to lower below
11867  *
11868  * Puts @self below @above.
11869  *
11870  * Both actors must have the same parent, and the parent must implement
11871  * the #ClutterContainer interface.
11872  *
11873  * This function calls clutter_container_lower_child() internally.
11874  *
11875  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11876  */
11877 void
11878 clutter_actor_lower (ClutterActor *self,
11879                      ClutterActor *above)
11880 {
11881   ClutterActor *parent;
11882
11883   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11884
11885   parent = clutter_actor_get_parent (self);
11886   if (parent == NULL)
11887     {
11888       g_warning ("%s: Actor of type %s is not inside a container",
11889                  G_STRFUNC,
11890                  _clutter_actor_get_debug_name (self));
11891       return;
11892     }
11893
11894   if (above)
11895     {
11896       if (parent != clutter_actor_get_parent (above))
11897         {
11898           g_warning ("%s: Actor '%s' is not in the same container as "
11899                      "actor '%s'",
11900                      G_STRFUNC,
11901                      _clutter_actor_get_debug_name (self),
11902                      _clutter_actor_get_debug_name (above));
11903           return;
11904         }
11905     }
11906
11907   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11908 }
11909
11910 /**
11911  * clutter_actor_raise_top:
11912  * @self: A #ClutterActor
11913  *
11914  * Raises @self to the top.
11915  *
11916  * This function calls clutter_actor_raise() internally.
11917  *
11918  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11919  *   a %NULL sibling, instead.
11920  */
11921 void
11922 clutter_actor_raise_top (ClutterActor *self)
11923 {
11924   clutter_actor_raise (self, NULL);
11925 }
11926
11927 /**
11928  * clutter_actor_lower_bottom:
11929  * @self: A #ClutterActor
11930  *
11931  * Lowers @self to the bottom.
11932  *
11933  * This function calls clutter_actor_lower() internally.
11934  *
11935  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11936  *   a %NULL sibling, instead.
11937  */
11938 void
11939 clutter_actor_lower_bottom (ClutterActor *self)
11940 {
11941   clutter_actor_lower (self, NULL);
11942 }
11943
11944 /*
11945  * Event handling
11946  */
11947
11948 /**
11949  * clutter_actor_event:
11950  * @actor: a #ClutterActor
11951  * @event: a #ClutterEvent
11952  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11953  *
11954  * This function is used to emit an event on the main stage.
11955  * You should rarely need to use this function, except for
11956  * synthetising events.
11957  *
11958  * Return value: the return value from the signal emission: %TRUE
11959  *   if the actor handled the event, or %FALSE if the event was
11960  *   not handled
11961  *
11962  * Since: 0.6
11963  */
11964 gboolean
11965 clutter_actor_event (ClutterActor *actor,
11966                      ClutterEvent *event,
11967                      gboolean      capture)
11968 {
11969   gboolean retval = FALSE;
11970   gint signal_num = -1;
11971
11972   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11973   g_return_val_if_fail (event != NULL, FALSE);
11974
11975   g_object_ref (actor);
11976
11977   if (capture)
11978     {
11979       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11980                      event,
11981                      &retval);
11982       goto out;
11983     }
11984
11985   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11986
11987   if (!retval)
11988     {
11989       switch (event->type)
11990         {
11991         case CLUTTER_NOTHING:
11992           break;
11993         case CLUTTER_BUTTON_PRESS:
11994           signal_num = BUTTON_PRESS_EVENT;
11995           break;
11996         case CLUTTER_BUTTON_RELEASE:
11997           signal_num = BUTTON_RELEASE_EVENT;
11998           break;
11999         case CLUTTER_SCROLL:
12000           signal_num = SCROLL_EVENT;
12001           break;
12002         case CLUTTER_KEY_PRESS:
12003           signal_num = KEY_PRESS_EVENT;
12004           break;
12005         case CLUTTER_KEY_RELEASE:
12006           signal_num = KEY_RELEASE_EVENT;
12007           break;
12008         case CLUTTER_MOTION:
12009           signal_num = MOTION_EVENT;
12010           break;
12011         case CLUTTER_ENTER:
12012           signal_num = ENTER_EVENT;
12013           break;
12014         case CLUTTER_LEAVE:
12015           signal_num = LEAVE_EVENT;
12016           break;
12017         case CLUTTER_DELETE:
12018         case CLUTTER_DESTROY_NOTIFY:
12019         case CLUTTER_CLIENT_MESSAGE:
12020         default:
12021           signal_num = -1;
12022           break;
12023         }
12024
12025       if (signal_num != -1)
12026         g_signal_emit (actor, actor_signals[signal_num], 0,
12027                        event, &retval);
12028     }
12029
12030 out:
12031   g_object_unref (actor);
12032
12033   return retval;
12034 }
12035
12036 /**
12037  * clutter_actor_set_reactive:
12038  * @actor: a #ClutterActor
12039  * @reactive: whether the actor should be reactive to events
12040  *
12041  * Sets @actor as reactive. Reactive actors will receive events.
12042  *
12043  * Since: 0.6
12044  */
12045 void
12046 clutter_actor_set_reactive (ClutterActor *actor,
12047                             gboolean      reactive)
12048 {
12049   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12050
12051   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12052     return;
12053
12054   if (reactive)
12055     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12056   else
12057     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12058
12059   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12060 }
12061
12062 /**
12063  * clutter_actor_get_reactive:
12064  * @actor: a #ClutterActor
12065  *
12066  * Checks whether @actor is marked as reactive.
12067  *
12068  * Return value: %TRUE if the actor is reactive
12069  *
12070  * Since: 0.6
12071  */
12072 gboolean
12073 clutter_actor_get_reactive (ClutterActor *actor)
12074 {
12075   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12076
12077   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12078 }
12079
12080 /**
12081  * clutter_actor_get_anchor_point:
12082  * @self: a #ClutterActor
12083  * @anchor_x: (out): return location for the X coordinate of the anchor point
12084  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12085  *
12086  * Gets the current anchor point of the @actor in pixels.
12087  *
12088  * Since: 0.6
12089  */
12090 void
12091 clutter_actor_get_anchor_point (ClutterActor *self,
12092                                 gfloat       *anchor_x,
12093                                 gfloat       *anchor_y)
12094 {
12095   const ClutterTransformInfo *info;
12096
12097   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12098
12099   info = _clutter_actor_get_transform_info_or_defaults (self);
12100   clutter_anchor_coord_get_units (self, &info->anchor,
12101                                   anchor_x,
12102                                   anchor_y,
12103                                   NULL);
12104 }
12105
12106 /**
12107  * clutter_actor_set_anchor_point:
12108  * @self: a #ClutterActor
12109  * @anchor_x: X coordinate of the anchor point
12110  * @anchor_y: Y coordinate of the anchor point
12111  *
12112  * Sets an anchor point for @self. The anchor point is a point in the
12113  * coordinate space of an actor to which the actor position within its
12114  * parent is relative; the default is (0, 0), i.e. the top-left corner
12115  * of the actor.
12116  *
12117  * Since: 0.6
12118  */
12119 void
12120 clutter_actor_set_anchor_point (ClutterActor *self,
12121                                 gfloat        anchor_x,
12122                                 gfloat        anchor_y)
12123 {
12124   ClutterTransformInfo *info;
12125   ClutterActorPrivate *priv;
12126   gboolean changed = FALSE;
12127   gfloat old_anchor_x, old_anchor_y;
12128   GObject *obj;
12129
12130   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12131
12132   obj = G_OBJECT (self);
12133   priv = self->priv;
12134   info = _clutter_actor_get_transform_info (self);
12135
12136   g_object_freeze_notify (obj);
12137
12138   clutter_anchor_coord_get_units (self, &info->anchor,
12139                                   &old_anchor_x,
12140                                   &old_anchor_y,
12141                                   NULL);
12142
12143   if (info->anchor.is_fractional)
12144     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12145
12146   if (old_anchor_x != anchor_x)
12147     {
12148       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12149       changed = TRUE;
12150     }
12151
12152   if (old_anchor_y != anchor_y)
12153     {
12154       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12155       changed = TRUE;
12156     }
12157
12158   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12159
12160   if (changed)
12161     {
12162       priv->transform_valid = FALSE;
12163       clutter_actor_queue_redraw (self);
12164     }
12165
12166   g_object_thaw_notify (obj);
12167 }
12168
12169 /**
12170  * clutter_actor_get_anchor_point_gravity:
12171  * @self: a #ClutterActor
12172  *
12173  * Retrieves the anchor position expressed as a #ClutterGravity. If
12174  * the anchor point was specified using pixels or units this will
12175  * return %CLUTTER_GRAVITY_NONE.
12176  *
12177  * Return value: the #ClutterGravity used by the anchor point
12178  *
12179  * Since: 1.0
12180  */
12181 ClutterGravity
12182 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12183 {
12184   const ClutterTransformInfo *info;
12185
12186   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12187
12188   info = _clutter_actor_get_transform_info_or_defaults (self);
12189
12190   return clutter_anchor_coord_get_gravity (&info->anchor);
12191 }
12192
12193 /**
12194  * clutter_actor_move_anchor_point:
12195  * @self: a #ClutterActor
12196  * @anchor_x: X coordinate of the anchor point
12197  * @anchor_y: Y coordinate of the anchor point
12198  *
12199  * Sets an anchor point for the actor, and adjusts the actor postion so that
12200  * the relative position of the actor toward its parent remains the same.
12201  *
12202  * Since: 0.6
12203  */
12204 void
12205 clutter_actor_move_anchor_point (ClutterActor *self,
12206                                  gfloat        anchor_x,
12207                                  gfloat        anchor_y)
12208 {
12209   gfloat old_anchor_x, old_anchor_y;
12210   const ClutterTransformInfo *info;
12211
12212   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12213
12214   info = _clutter_actor_get_transform_info (self);
12215   clutter_anchor_coord_get_units (self, &info->anchor,
12216                                   &old_anchor_x,
12217                                   &old_anchor_y,
12218                                   NULL);
12219
12220   g_object_freeze_notify (G_OBJECT (self));
12221
12222   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12223
12224   if (self->priv->position_set)
12225     clutter_actor_move_by (self,
12226                            anchor_x - old_anchor_x,
12227                            anchor_y - old_anchor_y);
12228
12229   g_object_thaw_notify (G_OBJECT (self));
12230 }
12231
12232 /**
12233  * clutter_actor_move_anchor_point_from_gravity:
12234  * @self: a #ClutterActor
12235  * @gravity: #ClutterGravity.
12236  *
12237  * Sets an anchor point on the actor based on the given gravity, adjusting the
12238  * actor postion so that its relative position within its parent remains
12239  * unchanged.
12240  *
12241  * Since version 1.0 the anchor point will be stored as a gravity so
12242  * that if the actor changes size then the anchor point will move. For
12243  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12244  * and later double the size of the actor, the anchor point will move
12245  * to the bottom right.
12246  *
12247  * Since: 0.6
12248  */
12249 void
12250 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12251                                               ClutterGravity  gravity)
12252 {
12253   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12254   const ClutterTransformInfo *info;
12255   ClutterActorPrivate *priv;
12256
12257   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12258
12259   priv = self->priv;
12260   info = _clutter_actor_get_transform_info (self);
12261
12262   g_object_freeze_notify (G_OBJECT (self));
12263
12264   clutter_anchor_coord_get_units (self, &info->anchor,
12265                                   &old_anchor_x,
12266                                   &old_anchor_y,
12267                                   NULL);
12268   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12269   clutter_anchor_coord_get_units (self, &info->anchor,
12270                                   &new_anchor_x,
12271                                   &new_anchor_y,
12272                                   NULL);
12273
12274   if (priv->position_set)
12275     clutter_actor_move_by (self,
12276                            new_anchor_x - old_anchor_x,
12277                            new_anchor_y - old_anchor_y);
12278
12279   g_object_thaw_notify (G_OBJECT (self));
12280 }
12281
12282 /**
12283  * clutter_actor_set_anchor_point_from_gravity:
12284  * @self: a #ClutterActor
12285  * @gravity: #ClutterGravity.
12286  *
12287  * Sets an anchor point on the actor, based on the given gravity (this is a
12288  * convenience function wrapping clutter_actor_set_anchor_point()).
12289  *
12290  * Since version 1.0 the anchor point will be stored as a gravity so
12291  * that if the actor changes size then the anchor point will move. For
12292  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12293  * and later double the size of the actor, the anchor point will move
12294  * to the bottom right.
12295  *
12296  * Since: 0.6
12297  */
12298 void
12299 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12300                                              ClutterGravity  gravity)
12301 {
12302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12303
12304   if (gravity == CLUTTER_GRAVITY_NONE)
12305     clutter_actor_set_anchor_point (self, 0, 0);
12306   else
12307     {
12308       GObject *obj = G_OBJECT (self);
12309       ClutterTransformInfo *info;
12310
12311       g_object_freeze_notify (obj);
12312
12313       info = _clutter_actor_get_transform_info (self);
12314       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12315
12316       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12317       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12318       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12319
12320       self->priv->transform_valid = FALSE;
12321
12322       clutter_actor_queue_redraw (self);
12323
12324       g_object_thaw_notify (obj);
12325     }
12326 }
12327
12328 static void
12329 clutter_actor_store_content_box (ClutterActor *self,
12330                                  const ClutterActorBox *box)
12331 {
12332   if (box != NULL)
12333     {
12334       self->priv->content_box = *box;
12335       self->priv->content_box_valid = TRUE;
12336     }
12337   else
12338     self->priv->content_box_valid = FALSE;
12339
12340   clutter_actor_queue_redraw (self);
12341
12342   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12343 }
12344
12345 static void
12346 clutter_container_iface_init (ClutterContainerIface *iface)
12347 {
12348   /* we don't override anything, as ClutterContainer already has a default
12349    * implementation that we can use, and which calls into our own API.
12350    */
12351 }
12352
12353 typedef enum
12354 {
12355   PARSE_X,
12356   PARSE_Y,
12357   PARSE_WIDTH,
12358   PARSE_HEIGHT,
12359   PARSE_ANCHOR_X,
12360   PARSE_ANCHOR_Y
12361 } ParseDimension;
12362
12363 static gfloat
12364 parse_units (ClutterActor   *self,
12365              ParseDimension  dimension,
12366              JsonNode       *node)
12367 {
12368   GValue value = G_VALUE_INIT;
12369   gfloat retval = 0;
12370
12371   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12372     return 0;
12373
12374   json_node_get_value (node, &value);
12375
12376   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12377     {
12378       retval = (gfloat) g_value_get_int64 (&value);
12379     }
12380   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12381     {
12382       retval = g_value_get_double (&value);
12383     }
12384   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12385     {
12386       ClutterUnits units;
12387       gboolean res;
12388
12389       res = clutter_units_from_string (&units, g_value_get_string (&value));
12390       if (res)
12391         retval = clutter_units_to_pixels (&units);
12392       else
12393         {
12394           g_warning ("Invalid value '%s': integers, strings or floating point "
12395                      "values can be used for the x, y, width and height "
12396                      "properties. Valid modifiers for strings are 'px', 'mm', "
12397                      "'pt' and 'em'.",
12398                      g_value_get_string (&value));
12399           retval = 0;
12400         }
12401     }
12402   else
12403     {
12404       g_warning ("Invalid value of type '%s': integers, strings of floating "
12405                  "point values can be used for the x, y, width, height "
12406                  "anchor-x and anchor-y properties.",
12407                  g_type_name (G_VALUE_TYPE (&value)));
12408     }
12409
12410   g_value_unset (&value);
12411
12412   return retval;
12413 }
12414
12415 typedef struct {
12416   ClutterRotateAxis axis;
12417
12418   gdouble angle;
12419
12420   gfloat center_x;
12421   gfloat center_y;
12422   gfloat center_z;
12423 } RotationInfo;
12424
12425 static inline gboolean
12426 parse_rotation_array (ClutterActor *actor,
12427                       JsonArray    *array,
12428                       RotationInfo *info)
12429 {
12430   JsonNode *element;
12431
12432   if (json_array_get_length (array) != 2)
12433     return FALSE;
12434
12435   /* angle */
12436   element = json_array_get_element (array, 0);
12437   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12438     info->angle = json_node_get_double (element);
12439   else
12440     return FALSE;
12441
12442   /* center */
12443   element = json_array_get_element (array, 1);
12444   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12445     {
12446       JsonArray *center = json_node_get_array (element);
12447
12448       if (json_array_get_length (center) != 2)
12449         return FALSE;
12450
12451       switch (info->axis)
12452         {
12453         case CLUTTER_X_AXIS:
12454           info->center_y = parse_units (actor, PARSE_Y,
12455                                         json_array_get_element (center, 0));
12456           info->center_z = parse_units (actor, PARSE_Y,
12457                                         json_array_get_element (center, 1));
12458           return TRUE;
12459
12460         case CLUTTER_Y_AXIS:
12461           info->center_x = parse_units (actor, PARSE_X,
12462                                         json_array_get_element (center, 0));
12463           info->center_z = parse_units (actor, PARSE_X,
12464                                         json_array_get_element (center, 1));
12465           return TRUE;
12466
12467         case CLUTTER_Z_AXIS:
12468           info->center_x = parse_units (actor, PARSE_X,
12469                                         json_array_get_element (center, 0));
12470           info->center_y = parse_units (actor, PARSE_Y,
12471                                         json_array_get_element (center, 1));
12472           return TRUE;
12473         }
12474     }
12475
12476   return FALSE;
12477 }
12478
12479 static gboolean
12480 parse_rotation (ClutterActor *actor,
12481                 JsonNode     *node,
12482                 RotationInfo *info)
12483 {
12484   JsonArray *array;
12485   guint len, i;
12486   gboolean retval = FALSE;
12487
12488   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12489     {
12490       g_warning ("Invalid node of type '%s' found, expecting an array",
12491                  json_node_type_name (node));
12492       return FALSE;
12493     }
12494
12495   array = json_node_get_array (node);
12496   len = json_array_get_length (array);
12497
12498   for (i = 0; i < len; i++)
12499     {
12500       JsonNode *element = json_array_get_element (array, i);
12501       JsonObject *object;
12502       JsonNode *member;
12503
12504       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12505         {
12506           g_warning ("Invalid node of type '%s' found, expecting an object",
12507                      json_node_type_name (element));
12508           return FALSE;
12509         }
12510
12511       object = json_node_get_object (element);
12512
12513       if (json_object_has_member (object, "x-axis"))
12514         {
12515           member = json_object_get_member (object, "x-axis");
12516
12517           info->axis = CLUTTER_X_AXIS;
12518
12519           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12520             {
12521               info->angle = json_node_get_double (member);
12522               retval = TRUE;
12523             }
12524           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12525             retval = parse_rotation_array (actor,
12526                                            json_node_get_array (member),
12527                                            info);
12528           else
12529             retval = FALSE;
12530         }
12531       else if (json_object_has_member (object, "y-axis"))
12532         {
12533           member = json_object_get_member (object, "y-axis");
12534
12535           info->axis = CLUTTER_Y_AXIS;
12536
12537           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12538             {
12539               info->angle = json_node_get_double (member);
12540               retval = TRUE;
12541             }
12542           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12543             retval = parse_rotation_array (actor,
12544                                            json_node_get_array (member),
12545                                            info);
12546           else
12547             retval = FALSE;
12548         }
12549       else if (json_object_has_member (object, "z-axis"))
12550         {
12551           member = json_object_get_member (object, "z-axis");
12552
12553           info->axis = CLUTTER_Z_AXIS;
12554
12555           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12556             {
12557               info->angle = json_node_get_double (member);
12558               retval = TRUE;
12559             }
12560           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12561             retval = parse_rotation_array (actor,
12562                                            json_node_get_array (member),
12563                                            info);
12564           else
12565             retval = FALSE;
12566         }
12567     }
12568
12569   return retval;
12570 }
12571
12572 static GSList *
12573 parse_actor_metas (ClutterScript *script,
12574                    ClutterActor  *actor,
12575                    JsonNode      *node)
12576 {
12577   GList *elements, *l;
12578   GSList *retval = NULL;
12579
12580   if (!JSON_NODE_HOLDS_ARRAY (node))
12581     return NULL;
12582
12583   elements = json_array_get_elements (json_node_get_array (node));
12584
12585   for (l = elements; l != NULL; l = l->next)
12586     {
12587       JsonNode *element = l->data;
12588       const gchar *id_ = _clutter_script_get_id_from_node (element);
12589       GObject *meta;
12590
12591       if (id_ == NULL || *id_ == '\0')
12592         continue;
12593
12594       meta = clutter_script_get_object (script, id_);
12595       if (meta == NULL)
12596         continue;
12597
12598       retval = g_slist_prepend (retval, meta);
12599     }
12600
12601   g_list_free (elements);
12602
12603   return g_slist_reverse (retval);
12604 }
12605
12606 static GSList *
12607 parse_behaviours (ClutterScript *script,
12608                   ClutterActor  *actor,
12609                   JsonNode      *node)
12610 {
12611   GList *elements, *l;
12612   GSList *retval = NULL;
12613
12614   if (!JSON_NODE_HOLDS_ARRAY (node))
12615     return NULL;
12616
12617   elements = json_array_get_elements (json_node_get_array (node));
12618
12619   for (l = elements; l != NULL; l = l->next)
12620     {
12621       JsonNode *element = l->data;
12622       const gchar *id_ = _clutter_script_get_id_from_node (element);
12623       GObject *behaviour;
12624
12625       if (id_ == NULL || *id_ == '\0')
12626         continue;
12627
12628       behaviour = clutter_script_get_object (script, id_);
12629       if (behaviour == NULL)
12630         continue;
12631
12632       retval = g_slist_prepend (retval, behaviour);
12633     }
12634
12635   g_list_free (elements);
12636
12637   return g_slist_reverse (retval);
12638 }
12639
12640 static gboolean
12641 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12642                                  ClutterScript     *script,
12643                                  GValue            *value,
12644                                  const gchar       *name,
12645                                  JsonNode          *node)
12646 {
12647   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12648   gboolean retval = FALSE;
12649
12650   if ((name[0] == 'x' && name[1] == '\0') ||
12651       (name[0] == 'y' && name[1] == '\0') ||
12652       (strcmp (name, "width") == 0) ||
12653       (strcmp (name, "height") == 0) ||
12654       (strcmp (name, "anchor_x") == 0) ||
12655       (strcmp (name, "anchor_y") == 0))
12656     {
12657       ParseDimension dimension;
12658       gfloat units;
12659
12660       if (name[0] == 'x')
12661         dimension = PARSE_X;
12662       else if (name[0] == 'y')
12663         dimension = PARSE_Y;
12664       else if (name[0] == 'w')
12665         dimension = PARSE_WIDTH;
12666       else if (name[0] == 'h')
12667         dimension = PARSE_HEIGHT;
12668       else if (name[0] == 'a' && name[7] == 'x')
12669         dimension = PARSE_ANCHOR_X;
12670       else if (name[0] == 'a' && name[7] == 'y')
12671         dimension = PARSE_ANCHOR_Y;
12672       else
12673         return FALSE;
12674
12675       units = parse_units (actor, dimension, node);
12676
12677       /* convert back to pixels: all properties are pixel-based */
12678       g_value_init (value, G_TYPE_FLOAT);
12679       g_value_set_float (value, units);
12680
12681       retval = TRUE;
12682     }
12683   else if (strcmp (name, "rotation") == 0)
12684     {
12685       RotationInfo *info;
12686
12687       info = g_slice_new0 (RotationInfo);
12688       retval = parse_rotation (actor, node, info);
12689
12690       if (retval)
12691         {
12692           g_value_init (value, G_TYPE_POINTER);
12693           g_value_set_pointer (value, info);
12694         }
12695       else
12696         g_slice_free (RotationInfo, info);
12697     }
12698   else if (strcmp (name, "behaviours") == 0)
12699     {
12700       GSList *l;
12701
12702 #ifdef CLUTTER_ENABLE_DEBUG
12703       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12704         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12705                                      "and it should not be used in newly "
12706                                      "written ClutterScript definitions.");
12707 #endif
12708
12709       l = parse_behaviours (script, actor, node);
12710
12711       g_value_init (value, G_TYPE_POINTER);
12712       g_value_set_pointer (value, l);
12713
12714       retval = TRUE;
12715     }
12716   else if (strcmp (name, "actions") == 0 ||
12717            strcmp (name, "constraints") == 0 ||
12718            strcmp (name, "effects") == 0)
12719     {
12720       GSList *l;
12721
12722       l = parse_actor_metas (script, actor, node);
12723
12724       g_value_init (value, G_TYPE_POINTER);
12725       g_value_set_pointer (value, l);
12726
12727       retval = TRUE;
12728     }
12729
12730   return retval;
12731 }
12732
12733 static void
12734 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12735                                    ClutterScript     *script,
12736                                    const gchar       *name,
12737                                    const GValue      *value)
12738 {
12739   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12740
12741 #ifdef CLUTTER_ENABLE_DEBUG
12742   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12743     {
12744       gchar *tmp = g_strdup_value_contents (value);
12745
12746       CLUTTER_NOTE (SCRIPT,
12747                     "in ClutterActor::set_custom_property('%s') = %s",
12748                     name,
12749                     tmp);
12750
12751       g_free (tmp);
12752     }
12753 #endif /* CLUTTER_ENABLE_DEBUG */
12754
12755   if (strcmp (name, "rotation") == 0)
12756     {
12757       RotationInfo *info;
12758
12759       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12760         return;
12761
12762       info = g_value_get_pointer (value);
12763
12764       clutter_actor_set_rotation (actor,
12765                                   info->axis, info->angle,
12766                                   info->center_x,
12767                                   info->center_y,
12768                                   info->center_z);
12769
12770       g_slice_free (RotationInfo, info);
12771
12772       return;
12773     }
12774
12775   if (strcmp (name, "behaviours") == 0)
12776     {
12777       GSList *behaviours, *l;
12778
12779       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12780         return;
12781
12782       behaviours = g_value_get_pointer (value);
12783       for (l = behaviours; l != NULL; l = l->next)
12784         {
12785           ClutterBehaviour *behaviour = l->data;
12786
12787           clutter_behaviour_apply (behaviour, actor);
12788         }
12789
12790       g_slist_free (behaviours);
12791
12792       return;
12793     }
12794
12795   if (strcmp (name, "actions") == 0 ||
12796       strcmp (name, "constraints") == 0 ||
12797       strcmp (name, "effects") == 0)
12798     {
12799       GSList *metas, *l;
12800
12801       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12802         return;
12803
12804       metas = g_value_get_pointer (value);
12805       for (l = metas; l != NULL; l = l->next)
12806         {
12807           if (name[0] == 'a')
12808             clutter_actor_add_action (actor, l->data);
12809
12810           if (name[0] == 'c')
12811             clutter_actor_add_constraint (actor, l->data);
12812
12813           if (name[0] == 'e')
12814             clutter_actor_add_effect (actor, l->data);
12815         }
12816
12817       g_slist_free (metas);
12818
12819       return;
12820     }
12821
12822   g_object_set_property (G_OBJECT (scriptable), name, value);
12823 }
12824
12825 static void
12826 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12827 {
12828   iface->parse_custom_node = clutter_actor_parse_custom_node;
12829   iface->set_custom_property = clutter_actor_set_custom_property;
12830 }
12831
12832 static ClutterActorMeta *
12833 get_meta_from_animation_property (ClutterActor  *actor,
12834                                   const gchar   *name,
12835                                   gchar        **name_p)
12836 {
12837   ClutterActorPrivate *priv = actor->priv;
12838   ClutterActorMeta *meta = NULL;
12839   gchar **tokens;
12840
12841   /* if this is not a special property, fall through */
12842   if (name[0] != '@')
12843     return NULL;
12844
12845   /* detect the properties named using the following spec:
12846    *
12847    *   @<section>.<meta-name>.<property-name>
12848    *
12849    * where <section> can be one of the following:
12850    *
12851    *   - actions
12852    *   - constraints
12853    *   - effects
12854    *
12855    * and <meta-name> is the name set on a specific ActorMeta
12856    */
12857
12858   tokens = g_strsplit (name + 1, ".", -1);
12859   if (tokens == NULL || g_strv_length (tokens) != 3)
12860     {
12861       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12862                     name + 1);
12863       g_strfreev (tokens);
12864       return NULL;
12865     }
12866
12867   if (strcmp (tokens[0], "actions") == 0)
12868     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12869
12870   if (strcmp (tokens[0], "constraints") == 0)
12871     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12872
12873   if (strcmp (tokens[0], "effects") == 0)
12874     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12875
12876   if (name_p != NULL)
12877     *name_p = g_strdup (tokens[2]);
12878
12879   CLUTTER_NOTE (ANIMATION,
12880                 "Looking for property '%s' of object '%s' in section '%s'",
12881                 tokens[2],
12882                 tokens[1],
12883                 tokens[0]);
12884
12885   g_strfreev (tokens);
12886
12887   return meta;
12888 }
12889
12890 static GParamSpec *
12891 clutter_actor_find_property (ClutterAnimatable *animatable,
12892                              const gchar       *property_name)
12893 {
12894   ClutterActorMeta *meta = NULL;
12895   GObjectClass *klass = NULL;
12896   GParamSpec *pspec = NULL;
12897   gchar *p_name = NULL;
12898
12899   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12900                                            property_name,
12901                                            &p_name);
12902
12903   if (meta != NULL)
12904     {
12905       klass = G_OBJECT_GET_CLASS (meta);
12906
12907       pspec = g_object_class_find_property (klass, p_name);
12908     }
12909   else
12910     {
12911       klass = G_OBJECT_GET_CLASS (animatable);
12912
12913       pspec = g_object_class_find_property (klass, property_name);
12914     }
12915
12916   g_free (p_name);
12917
12918   return pspec;
12919 }
12920
12921 static void
12922 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12923                                  const gchar       *property_name,
12924                                  GValue            *initial)
12925 {
12926   ClutterActorMeta *meta = NULL;
12927   gchar *p_name = NULL;
12928
12929   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12930                                            property_name,
12931                                            &p_name);
12932
12933   if (meta != NULL)
12934     g_object_get_property (G_OBJECT (meta), p_name, initial);
12935   else
12936     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12937
12938   g_free (p_name);
12939 }
12940
12941 /*
12942  * clutter_actor_set_animatable_property:
12943  * @actor: a #ClutterActor
12944  * @prop_id: the paramspec id
12945  * @value: the value to set
12946  * @pspec: the paramspec
12947  *
12948  * Sets values of animatable properties.
12949  *
12950  * This is a variant of clutter_actor_set_property() that gets called
12951  * by the #ClutterAnimatable implementation of #ClutterActor for the
12952  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12953  * #GParamSpec.
12954  *
12955  * Unlike the implementation of #GObjectClass.set_property(), this
12956  * function will not update the interval if a transition involving an
12957  * animatable property is in progress - this avoids cycles with the
12958  * transition API calling the public API.
12959  */
12960 static void
12961 clutter_actor_set_animatable_property (ClutterActor *actor,
12962                                        guint         prop_id,
12963                                        const GValue *value,
12964                                        GParamSpec   *pspec)
12965 {
12966   GObject *obj = G_OBJECT (actor);
12967
12968   g_object_freeze_notify (obj);
12969
12970   switch (prop_id)
12971     {
12972     case PROP_X:
12973       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12974       break;
12975
12976     case PROP_Y:
12977       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12978       break;
12979
12980     case PROP_WIDTH:
12981       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12982       break;
12983
12984     case PROP_HEIGHT:
12985       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12986       break;
12987
12988     case PROP_DEPTH:
12989       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12990       break;
12991
12992     case PROP_OPACITY:
12993       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12994       break;
12995
12996     case PROP_BACKGROUND_COLOR:
12997       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12998       break;
12999
13000     case PROP_SCALE_X:
13001       clutter_actor_set_scale_factor_internal (actor,
13002                                                g_value_get_double (value),
13003                                                pspec);
13004       break;
13005
13006     case PROP_SCALE_Y:
13007       clutter_actor_set_scale_factor_internal (actor,
13008                                                g_value_get_double (value),
13009                                                pspec);
13010       break;
13011
13012     case PROP_ROTATION_ANGLE_X:
13013       clutter_actor_set_rotation_angle_internal (actor,
13014                                                  CLUTTER_X_AXIS,
13015                                                  g_value_get_double (value));
13016       break;
13017
13018     case PROP_ROTATION_ANGLE_Y:
13019       clutter_actor_set_rotation_angle_internal (actor,
13020                                                  CLUTTER_Y_AXIS,
13021                                                  g_value_get_double (value));
13022       break;
13023
13024     case PROP_ROTATION_ANGLE_Z:
13025       clutter_actor_set_rotation_angle_internal (actor,
13026                                                  CLUTTER_Z_AXIS,
13027                                                  g_value_get_double (value));
13028       break;
13029
13030     case PROP_CONTENT_BOX:
13031       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13032       break;
13033
13034     default:
13035       g_object_set_property (obj, pspec->name, value);
13036       break;
13037     }
13038
13039   g_object_thaw_notify (obj);
13040 }
13041
13042 static void
13043 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13044                                const gchar       *property_name,
13045                                const GValue      *final)
13046 {
13047   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13048   ClutterActorMeta *meta = NULL;
13049   gchar *p_name = NULL;
13050
13051   meta = get_meta_from_animation_property (actor,
13052                                            property_name,
13053                                            &p_name);
13054   if (meta != NULL)
13055     g_object_set_property (G_OBJECT (meta), p_name, final);
13056   else
13057     {
13058       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13059       GParamSpec *pspec;
13060
13061       pspec = g_object_class_find_property (obj_class, property_name);
13062
13063       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13064         {
13065           /* XXX - I'm going to the special hell for this */
13066           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13067         }
13068       else
13069         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13070     }
13071
13072   g_free (p_name);
13073 }
13074
13075 static void
13076 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13077 {
13078   iface->find_property = clutter_actor_find_property;
13079   iface->get_initial_state = clutter_actor_get_initial_state;
13080   iface->set_final_state = clutter_actor_set_final_state;
13081 }
13082
13083 /**
13084  * clutter_actor_transform_stage_point:
13085  * @self: A #ClutterActor
13086  * @x: (in): x screen coordinate of the point to unproject
13087  * @y: (in): y screen coordinate of the point to unproject
13088  * @x_out: (out): return location for the unprojected x coordinance
13089  * @y_out: (out): return location for the unprojected y coordinance
13090  *
13091  * This function translates screen coordinates (@x, @y) to
13092  * coordinates relative to the actor. For example, it can be used to translate
13093  * screen events from global screen coordinates into actor-local coordinates.
13094  *
13095  * The conversion can fail, notably if the transform stack results in the
13096  * actor being projected on the screen as a mere line.
13097  *
13098  * The conversion should not be expected to be pixel-perfect due to the
13099  * nature of the operation. In general the error grows when the skewing
13100  * of the actor rectangle on screen increases.
13101  *
13102  * <note><para>This function can be computationally intensive.</para></note>
13103  *
13104  * <note><para>This function only works when the allocation is up-to-date,
13105  * i.e. inside of paint().</para></note>
13106  *
13107  * Return value: %TRUE if conversion was successful.
13108  *
13109  * Since: 0.6
13110  */
13111 gboolean
13112 clutter_actor_transform_stage_point (ClutterActor *self,
13113                                      gfloat        x,
13114                                      gfloat        y,
13115                                      gfloat       *x_out,
13116                                      gfloat       *y_out)
13117 {
13118   ClutterVertex v[4];
13119   float ST[3][3];
13120   float RQ[3][3];
13121   int du, dv, xi, yi;
13122   float px, py;
13123   float xf, yf, wf, det;
13124   ClutterActorPrivate *priv;
13125
13126   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13127
13128   priv = self->priv;
13129
13130   /* This implementation is based on the quad -> quad projection algorithm
13131    * described by Paul Heckbert in:
13132    *
13133    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13134    *
13135    * and the sample implementation at:
13136    *
13137    *   http://www.cs.cmu.edu/~ph/src/texfund/
13138    *
13139    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13140    * quad to rectangle only, which significantly simplifies things; the
13141    * function calls have been unrolled, and most of the math is done in fixed
13142    * point.
13143    */
13144
13145   clutter_actor_get_abs_allocation_vertices (self, v);
13146
13147   /* Keeping these as ints simplifies the multiplication (no significant
13148    * loss of precision here).
13149    */
13150   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13151   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13152
13153   if (!du || !dv)
13154     return FALSE;
13155
13156 #define UX2FP(x)        (x)
13157 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13158
13159   /* First, find mapping from unit uv square to xy quadrilateral; this
13160    * equivalent to the pmap_square_quad() functions in the sample
13161    * implementation, which we can simplify, since our target is always
13162    * a rectangle.
13163    */
13164   px = v[0].x - v[1].x + v[3].x - v[2].x;
13165   py = v[0].y - v[1].y + v[3].y - v[2].y;
13166
13167   if (!px && !py)
13168     {
13169       /* affine transform */
13170       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13171       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13172       RQ[2][0] = UX2FP (v[0].x);
13173       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13174       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13175       RQ[2][1] = UX2FP (v[0].y);
13176       RQ[0][2] = 0;
13177       RQ[1][2] = 0;
13178       RQ[2][2] = 1.0;
13179     }
13180   else
13181     {
13182       /* projective transform */
13183       double dx1, dx2, dy1, dy2, del;
13184
13185       dx1 = UX2FP (v[1].x - v[3].x);
13186       dx2 = UX2FP (v[2].x - v[3].x);
13187       dy1 = UX2FP (v[1].y - v[3].y);
13188       dy2 = UX2FP (v[2].y - v[3].y);
13189
13190       del = DET2FP (dx1, dx2, dy1, dy2);
13191       if (!del)
13192         return FALSE;
13193
13194       /*
13195        * The division here needs to be done in floating point for
13196        * precisions reasons.
13197        */
13198       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13199       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13200       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13201       RQ[2][2] = 1.0;
13202       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13203       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13204       RQ[2][0] = UX2FP (v[0].x);
13205       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13206       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13207       RQ[2][1] = UX2FP (v[0].y);
13208     }
13209
13210   /*
13211    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13212    * square. Since our rectangle is based at 0,0 we only need to scale.
13213    */
13214   RQ[0][0] /= du;
13215   RQ[1][0] /= dv;
13216   RQ[0][1] /= du;
13217   RQ[1][1] /= dv;
13218   RQ[0][2] /= du;
13219   RQ[1][2] /= dv;
13220
13221   /*
13222    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13223    * inverse of that.
13224    */
13225   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13226   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13227   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13228   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13229   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13230   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13231   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13232   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13233   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13234
13235   /*
13236    * Check the resulting matrix is OK.
13237    */
13238   det = (RQ[0][0] * ST[0][0])
13239       + (RQ[0][1] * ST[0][1])
13240       + (RQ[0][2] * ST[0][2]);
13241   if (!det)
13242     return FALSE;
13243
13244   /*
13245    * Now transform our point with the ST matrix; the notional w
13246    * coordinate is 1, hence the last part is simply added.
13247    */
13248   xi = (int) x;
13249   yi = (int) y;
13250
13251   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13252   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13253   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13254
13255   if (x_out)
13256     *x_out = xf / wf;
13257
13258   if (y_out)
13259     *y_out = yf / wf;
13260
13261 #undef UX2FP
13262 #undef DET2FP
13263
13264   return TRUE;
13265 }
13266
13267 /*
13268  * ClutterGeometry
13269  */
13270
13271 static ClutterGeometry*
13272 clutter_geometry_copy (const ClutterGeometry *geometry)
13273 {
13274   return g_slice_dup (ClutterGeometry, geometry);
13275 }
13276
13277 static void
13278 clutter_geometry_free (ClutterGeometry *geometry)
13279 {
13280   if (G_LIKELY (geometry != NULL))
13281     g_slice_free (ClutterGeometry, geometry);
13282 }
13283
13284 /**
13285  * clutter_geometry_union:
13286  * @geometry_a: a #ClutterGeometry
13287  * @geometry_b: another #ClutterGeometry
13288  * @result: (out): location to store the result
13289  *
13290  * Find the union of two rectangles represented as #ClutterGeometry.
13291  *
13292  * Since: 1.4
13293  */
13294 void
13295 clutter_geometry_union (const ClutterGeometry *geometry_a,
13296                         const ClutterGeometry *geometry_b,
13297                         ClutterGeometry       *result)
13298 {
13299   /* We don't try to handle rectangles that can't be represented
13300    * as a signed integer box */
13301   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13302   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13303   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13304                   geometry_b->x + (gint)geometry_b->width);
13305   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13306                   geometry_b->y + (gint)geometry_b->height);
13307   result->x = x_1;
13308   result->y = y_1;
13309   result->width = x_2 - x_1;
13310   result->height = y_2 - y_1;
13311 }
13312
13313 /**
13314  * clutter_geometry_intersects:
13315  * @geometry0: The first geometry to test
13316  * @geometry1: The second geometry to test
13317  *
13318  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13319  * they do else %FALSE.
13320  *
13321  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13322  * %FALSE.
13323  *
13324  * Since: 1.4
13325  */
13326 gboolean
13327 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13328                              const ClutterGeometry *geometry1)
13329 {
13330   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13331       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13332       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13333       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13334     return FALSE;
13335   else
13336     return TRUE;
13337 }
13338
13339 static gboolean
13340 clutter_geometry_progress (const GValue *a,
13341                            const GValue *b,
13342                            gdouble       progress,
13343                            GValue       *retval)
13344 {
13345   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13346   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13347   ClutterGeometry res = { 0, };
13348   gint a_width = a_geom->width;
13349   gint b_width = b_geom->width;
13350   gint a_height = a_geom->height;
13351   gint b_height = b_geom->height;
13352
13353   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13354   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13355
13356   res.width = a_width + (b_width - a_width) * progress;
13357   res.height = a_height + (b_height - a_height) * progress;
13358
13359   g_value_set_boxed (retval, &res);
13360
13361   return TRUE;
13362 }
13363
13364 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13365                                clutter_geometry_copy,
13366                                clutter_geometry_free,
13367                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13368
13369 /*
13370  * ClutterVertices
13371  */
13372
13373 /**
13374  * clutter_vertex_new:
13375  * @x: X coordinate
13376  * @y: Y coordinate
13377  * @z: Z coordinate
13378  *
13379  * Creates a new #ClutterVertex for the point in 3D space
13380  * identified by the 3 coordinates @x, @y, @z
13381  *
13382  * Return value: the newly allocate #ClutterVertex. Use
13383  *   clutter_vertex_free() to free the resources
13384  *
13385  * Since: 1.0
13386  */
13387 ClutterVertex *
13388 clutter_vertex_new (gfloat x,
13389                     gfloat y,
13390                     gfloat z)
13391 {
13392   ClutterVertex *vertex;
13393
13394   vertex = g_slice_new (ClutterVertex);
13395   clutter_vertex_init (vertex, x, y, z);
13396
13397   return vertex;
13398 }
13399
13400 /**
13401  * clutter_vertex_init:
13402  * @vertex: a #ClutterVertex
13403  * @x: X coordinate
13404  * @y: Y coordinate
13405  * @z: Z coordinate
13406  *
13407  * Initializes @vertex with the given coordinates.
13408  *
13409  * Since: 1.10
13410  */
13411 void
13412 clutter_vertex_init (ClutterVertex *vertex,
13413                      gfloat         x,
13414                      gfloat         y,
13415                      gfloat         z)
13416 {
13417   g_return_if_fail (vertex != NULL);
13418
13419   vertex->x = x;
13420   vertex->y = y;
13421   vertex->z = z;
13422 }
13423
13424 /**
13425  * clutter_vertex_copy:
13426  * @vertex: a #ClutterVertex
13427  *
13428  * Copies @vertex
13429  *
13430  * Return value: a newly allocated copy of #ClutterVertex. Use
13431  *   clutter_vertex_free() to free the allocated resources
13432  *
13433  * Since: 1.0
13434  */
13435 ClutterVertex *
13436 clutter_vertex_copy (const ClutterVertex *vertex)
13437 {
13438   if (G_LIKELY (vertex != NULL))
13439     return g_slice_dup (ClutterVertex, vertex);
13440
13441   return NULL;
13442 }
13443
13444 /**
13445  * clutter_vertex_free:
13446  * @vertex: a #ClutterVertex
13447  *
13448  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13449  *
13450  * Since: 1.0
13451  */
13452 void
13453 clutter_vertex_free (ClutterVertex *vertex)
13454 {
13455   if (G_UNLIKELY (vertex != NULL))
13456     g_slice_free (ClutterVertex, vertex);
13457 }
13458
13459 /**
13460  * clutter_vertex_equal:
13461  * @vertex_a: a #ClutterVertex
13462  * @vertex_b: a #ClutterVertex
13463  *
13464  * Compares @vertex_a and @vertex_b for equality
13465  *
13466  * Return value: %TRUE if the passed #ClutterVertex are equal
13467  *
13468  * Since: 1.0
13469  */
13470 gboolean
13471 clutter_vertex_equal (const ClutterVertex *vertex_a,
13472                       const ClutterVertex *vertex_b)
13473 {
13474   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13475
13476   if (vertex_a == vertex_b)
13477     return TRUE;
13478
13479   return vertex_a->x == vertex_b->x &&
13480          vertex_a->y == vertex_b->y &&
13481          vertex_a->z == vertex_b->z;
13482 }
13483
13484 static gboolean
13485 clutter_vertex_progress (const GValue *a,
13486                          const GValue *b,
13487                          gdouble       progress,
13488                          GValue       *retval)
13489 {
13490   const ClutterVertex *av = g_value_get_boxed (a);
13491   const ClutterVertex *bv = g_value_get_boxed (b);
13492   ClutterVertex res = { 0, };
13493
13494   res.x = av->x + (bv->x - av->x) * progress;
13495   res.y = av->y + (bv->y - av->y) * progress;
13496   res.z = av->z + (bv->z - av->z) * progress;
13497
13498   g_value_set_boxed (retval, &res);
13499
13500   return TRUE;
13501 }
13502
13503 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13504                                clutter_vertex_copy,
13505                                clutter_vertex_free,
13506                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13507
13508 /**
13509  * clutter_actor_is_rotated:
13510  * @self: a #ClutterActor
13511  *
13512  * Checks whether any rotation is applied to the actor.
13513  *
13514  * Return value: %TRUE if the actor is rotated.
13515  *
13516  * Since: 0.6
13517  */
13518 gboolean
13519 clutter_actor_is_rotated (ClutterActor *self)
13520 {
13521   const ClutterTransformInfo *info;
13522
13523   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13524
13525   info = _clutter_actor_get_transform_info_or_defaults (self);
13526
13527   if (info->rx_angle || info->ry_angle || info->rz_angle)
13528     return TRUE;
13529
13530   return FALSE;
13531 }
13532
13533 /**
13534  * clutter_actor_is_scaled:
13535  * @self: a #ClutterActor
13536  *
13537  * Checks whether the actor is scaled in either dimension.
13538  *
13539  * Return value: %TRUE if the actor is scaled.
13540  *
13541  * Since: 0.6
13542  */
13543 gboolean
13544 clutter_actor_is_scaled (ClutterActor *self)
13545 {
13546   const ClutterTransformInfo *info;
13547
13548   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13549
13550   info = _clutter_actor_get_transform_info_or_defaults (self);
13551
13552   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13553     return TRUE;
13554
13555   return FALSE;
13556 }
13557
13558 ClutterActor *
13559 _clutter_actor_get_stage_internal (ClutterActor *actor)
13560 {
13561   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13562     actor = actor->priv->parent;
13563
13564   return actor;
13565 }
13566
13567 /**
13568  * clutter_actor_get_stage:
13569  * @actor: a #ClutterActor
13570  *
13571  * Retrieves the #ClutterStage where @actor is contained.
13572  *
13573  * Return value: (transfer none) (type Clutter.Stage): the stage
13574  *   containing the actor, or %NULL
13575  *
13576  * Since: 0.8
13577  */
13578 ClutterActor *
13579 clutter_actor_get_stage (ClutterActor *actor)
13580 {
13581   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13582
13583   return _clutter_actor_get_stage_internal (actor);
13584 }
13585
13586 /**
13587  * clutter_actor_allocate_available_size:
13588  * @self: a #ClutterActor
13589  * @x: the actor's X coordinate
13590  * @y: the actor's Y coordinate
13591  * @available_width: the maximum available width, or -1 to use the
13592  *   actor's natural width
13593  * @available_height: the maximum available height, or -1 to use the
13594  *   actor's natural height
13595  * @flags: flags controlling the allocation
13596  *
13597  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13598  * preferred size, but limiting it to the maximum available width
13599  * and height provided.
13600  *
13601  * This function will do the right thing when dealing with the
13602  * actor's request mode.
13603  *
13604  * The implementation of this function is equivalent to:
13605  *
13606  * |[
13607  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13608  *     {
13609  *       clutter_actor_get_preferred_width (self, available_height,
13610  *                                          &amp;min_width,
13611  *                                          &amp;natural_width);
13612  *       width = CLAMP (natural_width, min_width, available_width);
13613  *
13614  *       clutter_actor_get_preferred_height (self, width,
13615  *                                           &amp;min_height,
13616  *                                           &amp;natural_height);
13617  *       height = CLAMP (natural_height, min_height, available_height);
13618  *     }
13619  *   else
13620  *     {
13621  *       clutter_actor_get_preferred_height (self, available_width,
13622  *                                           &amp;min_height,
13623  *                                           &amp;natural_height);
13624  *       height = CLAMP (natural_height, min_height, available_height);
13625  *
13626  *       clutter_actor_get_preferred_width (self, height,
13627  *                                          &amp;min_width,
13628  *                                          &amp;natural_width);
13629  *       width = CLAMP (natural_width, min_width, available_width);
13630  *     }
13631  *
13632  *   box.x1 = x; box.y1 = y;
13633  *   box.x2 = box.x1 + available_width;
13634  *   box.y2 = box.y1 + available_height;
13635  *   clutter_actor_allocate (self, &amp;box, flags);
13636  * ]|
13637  *
13638  * This function can be used by fluid layout managers to allocate
13639  * an actor's preferred size without making it bigger than the area
13640  * available for the container.
13641  *
13642  * Since: 1.0
13643  */
13644 void
13645 clutter_actor_allocate_available_size (ClutterActor           *self,
13646                                        gfloat                  x,
13647                                        gfloat                  y,
13648                                        gfloat                  available_width,
13649                                        gfloat                  available_height,
13650                                        ClutterAllocationFlags  flags)
13651 {
13652   ClutterActorPrivate *priv;
13653   gfloat width, height;
13654   gfloat min_width, min_height;
13655   gfloat natural_width, natural_height;
13656   ClutterActorBox box;
13657
13658   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13659
13660   priv = self->priv;
13661
13662   width = height = 0.0;
13663
13664   switch (priv->request_mode)
13665     {
13666     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13667       clutter_actor_get_preferred_width (self, available_height,
13668                                          &min_width,
13669                                          &natural_width);
13670       width  = CLAMP (natural_width, min_width, available_width);
13671
13672       clutter_actor_get_preferred_height (self, width,
13673                                           &min_height,
13674                                           &natural_height);
13675       height = CLAMP (natural_height, min_height, available_height);
13676       break;
13677
13678     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13679       clutter_actor_get_preferred_height (self, available_width,
13680                                           &min_height,
13681                                           &natural_height);
13682       height = CLAMP (natural_height, min_height, available_height);
13683
13684       clutter_actor_get_preferred_width (self, height,
13685                                          &min_width,
13686                                          &natural_width);
13687       width  = CLAMP (natural_width, min_width, available_width);
13688       break;
13689     }
13690
13691
13692   box.x1 = x;
13693   box.y1 = y;
13694   box.x2 = box.x1 + width;
13695   box.y2 = box.y1 + height;
13696   clutter_actor_allocate (self, &box, flags);
13697 }
13698
13699 /**
13700  * clutter_actor_allocate_preferred_size:
13701  * @self: a #ClutterActor
13702  * @flags: flags controlling the allocation
13703  *
13704  * Allocates the natural size of @self.
13705  *
13706  * This function is a utility call for #ClutterActor implementations
13707  * that allocates the actor's preferred natural size. It can be used
13708  * by fixed layout managers (like #ClutterGroup or so called
13709  * 'composite actors') inside the ClutterActor::allocate
13710  * implementation to give each child exactly how much space it
13711  * requires.
13712  *
13713  * This function is not meant to be used by applications. It is also
13714  * not meant to be used outside the implementation of the
13715  * ClutterActor::allocate virtual function.
13716  *
13717  * Since: 0.8
13718  */
13719 void
13720 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13721                                        ClutterAllocationFlags  flags)
13722 {
13723   gfloat actor_x, actor_y;
13724   gfloat natural_width, natural_height;
13725   ClutterActorBox actor_box;
13726
13727   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13728
13729   actor_x = clutter_actor_get_x (self);
13730   actor_y = clutter_actor_get_y (self);
13731
13732   clutter_actor_get_preferred_size (self,
13733                                     NULL, NULL,
13734                                     &natural_width,
13735                                     &natural_height);
13736
13737   actor_box.x1 = actor_x;
13738   actor_box.y1 = actor_y;
13739   actor_box.x2 = actor_box.x1 + natural_width;
13740   actor_box.y2 = actor_box.y1 + natural_height;
13741
13742   clutter_actor_allocate (self, &actor_box, flags);
13743 }
13744
13745 /**
13746  * clutter_actor_allocate_align_fill:
13747  * @self: a #ClutterActor
13748  * @box: a #ClutterActorBox, containing the available width and height
13749  * @x_align: the horizontal alignment, between 0 and 1
13750  * @y_align: the vertical alignment, between 0 and 1
13751  * @x_fill: whether the actor should fill horizontally
13752  * @y_fill: whether the actor should fill vertically
13753  * @flags: allocation flags to be passed to clutter_actor_allocate()
13754  *
13755  * Allocates @self by taking into consideration the available allocation
13756  * area; an alignment factor on either axis; and whether the actor should
13757  * fill the allocation on either axis.
13758  *
13759  * The @box should contain the available allocation width and height;
13760  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13761  * allocation will be offset by their value.
13762  *
13763  * This function takes into consideration the geometry request specified by
13764  * the #ClutterActor:request-mode property, and the text direction.
13765  *
13766  * This function is useful for fluid layout managers, like #ClutterBinLayout
13767  * or #ClutterTableLayout
13768  *
13769  * Since: 1.4
13770  */
13771 void
13772 clutter_actor_allocate_align_fill (ClutterActor           *self,
13773                                    const ClutterActorBox  *box,
13774                                    gdouble                 x_align,
13775                                    gdouble                 y_align,
13776                                    gboolean                x_fill,
13777                                    gboolean                y_fill,
13778                                    ClutterAllocationFlags  flags)
13779 {
13780   ClutterActorPrivate *priv;
13781   ClutterActorBox allocation = { 0, };
13782   gfloat x_offset, y_offset;
13783   gfloat available_width, available_height;
13784   gfloat child_width, child_height;
13785
13786   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13787   g_return_if_fail (box != NULL);
13788   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13789   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13790
13791   priv = self->priv;
13792
13793   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13794   clutter_actor_box_get_size (box, &available_width, &available_height);
13795
13796   if (available_width < 0)
13797     available_width = 0;
13798
13799   if (available_height < 0)
13800     available_height = 0;
13801
13802   if (x_fill)
13803     {
13804       allocation.x1 = x_offset;
13805       allocation.x2 = allocation.x1 + available_width;
13806     }
13807
13808   if (y_fill)
13809     {
13810       allocation.y1 = y_offset;
13811       allocation.y2 = allocation.y1 + available_height;
13812     }
13813
13814   /* if we are filling horizontally and vertically then we're done */
13815   if (x_fill && y_fill)
13816     goto out;
13817
13818   child_width = child_height = 0.0f;
13819
13820   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13821     {
13822       gfloat min_width, natural_width;
13823       gfloat min_height, natural_height;
13824
13825       clutter_actor_get_preferred_width (self, available_height,
13826                                          &min_width,
13827                                          &natural_width);
13828
13829       child_width = CLAMP (natural_width, min_width, available_width);
13830
13831       if (!y_fill)
13832         {
13833           clutter_actor_get_preferred_height (self, child_width,
13834                                               &min_height,
13835                                               &natural_height);
13836
13837           child_height = CLAMP (natural_height, min_height, available_height);
13838         }
13839     }
13840   else
13841     {
13842       gfloat min_width, natural_width;
13843       gfloat min_height, natural_height;
13844
13845       clutter_actor_get_preferred_height (self, available_width,
13846                                           &min_height,
13847                                           &natural_height);
13848
13849       child_height = CLAMP (natural_height, min_height, available_height);
13850
13851       if (!x_fill)
13852         {
13853           clutter_actor_get_preferred_width (self, child_height,
13854                                              &min_width,
13855                                              &natural_width);
13856
13857           child_width = CLAMP (natural_width, min_width, available_width);
13858         }
13859     }
13860
13861   /* invert the horizontal alignment for RTL languages */
13862   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13863     x_align = 1.0 - x_align;
13864
13865   if (!x_fill)
13866     {
13867       allocation.x1 = x_offset
13868                     + ((available_width - child_width) * x_align);
13869       allocation.x2 = allocation.x1 + child_width;
13870     }
13871
13872   if (!y_fill)
13873     {
13874       allocation.y1 = y_offset
13875                     + ((available_height - child_height) * y_align);
13876       allocation.y2 = allocation.y1 + child_height;
13877     }
13878
13879 out:
13880   clutter_actor_box_clamp_to_pixel (&allocation);
13881   clutter_actor_allocate (self, &allocation, flags);
13882 }
13883
13884 /**
13885  * clutter_actor_grab_key_focus:
13886  * @self: a #ClutterActor
13887  *
13888  * Sets the key focus of the #ClutterStage including @self
13889  * to this #ClutterActor.
13890  *
13891  * Since: 1.0
13892  */
13893 void
13894 clutter_actor_grab_key_focus (ClutterActor *self)
13895 {
13896   ClutterActor *stage;
13897
13898   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13899
13900   stage = _clutter_actor_get_stage_internal (self);
13901   if (stage != NULL)
13902     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13903 }
13904
13905 /**
13906  * clutter_actor_get_pango_context:
13907  * @self: a #ClutterActor
13908  *
13909  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13910  * is already configured using the appropriate font map, resolution
13911  * and font options.
13912  *
13913  * Unlike clutter_actor_create_pango_context(), this context is owend
13914  * by the #ClutterActor and it will be updated each time the options
13915  * stored by the #ClutterBackend change.
13916  *
13917  * You can use the returned #PangoContext to create a #PangoLayout
13918  * and render text using cogl_pango_render_layout() to reuse the
13919  * glyphs cache also used by Clutter.
13920  *
13921  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13922  *   The returned #PangoContext is owned by the actor and should not be
13923  *   unreferenced by the application code
13924  *
13925  * Since: 1.0
13926  */
13927 PangoContext *
13928 clutter_actor_get_pango_context (ClutterActor *self)
13929 {
13930   ClutterActorPrivate *priv;
13931
13932   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13933
13934   priv = self->priv;
13935
13936   if (priv->pango_context != NULL)
13937     return priv->pango_context;
13938
13939   priv->pango_context = _clutter_context_get_pango_context ();
13940   g_object_ref (priv->pango_context);
13941
13942   return priv->pango_context;
13943 }
13944
13945 /**
13946  * clutter_actor_create_pango_context:
13947  * @self: a #ClutterActor
13948  *
13949  * Creates a #PangoContext for the given actor. The #PangoContext
13950  * is already configured using the appropriate font map, resolution
13951  * and font options.
13952  *
13953  * See also clutter_actor_get_pango_context().
13954  *
13955  * Return value: (transfer full): the newly created #PangoContext.
13956  *   Use g_object_unref() on the returned value to deallocate its
13957  *   resources
13958  *
13959  * Since: 1.0
13960  */
13961 PangoContext *
13962 clutter_actor_create_pango_context (ClutterActor *self)
13963 {
13964   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13965
13966   return _clutter_context_create_pango_context ();
13967 }
13968
13969 /**
13970  * clutter_actor_create_pango_layout:
13971  * @self: a #ClutterActor
13972  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13973  *
13974  * Creates a new #PangoLayout from the same #PangoContext used
13975  * by the #ClutterActor. The #PangoLayout is already configured
13976  * with the font map, resolution and font options, and the
13977  * given @text.
13978  *
13979  * If you want to keep around a #PangoLayout created by this
13980  * function you will have to connect to the #ClutterBackend::font-changed
13981  * and #ClutterBackend::resolution-changed signals, and call
13982  * pango_layout_context_changed() in response to them.
13983  *
13984  * Return value: (transfer full): the newly created #PangoLayout.
13985  *   Use g_object_unref() when done
13986  *
13987  * Since: 1.0
13988  */
13989 PangoLayout *
13990 clutter_actor_create_pango_layout (ClutterActor *self,
13991                                    const gchar  *text)
13992 {
13993   PangoContext *context;
13994   PangoLayout *layout;
13995
13996   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13997
13998   context = clutter_actor_get_pango_context (self);
13999   layout = pango_layout_new (context);
14000
14001   if (text)
14002     pango_layout_set_text (layout, text, -1);
14003
14004   return layout;
14005 }
14006
14007 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14008  * ClutterOffscreenEffect.
14009  */
14010 void
14011 _clutter_actor_set_opacity_override (ClutterActor *self,
14012                                      gint          opacity)
14013 {
14014   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14015
14016   self->priv->opacity_override = opacity;
14017 }
14018
14019 gint
14020 _clutter_actor_get_opacity_override (ClutterActor *self)
14021 {
14022   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14023
14024   return self->priv->opacity_override;
14025 }
14026
14027 /* Allows you to disable applying the actors model view transform during
14028  * a paint. Used by ClutterClone. */
14029 void
14030 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14031                                                 gboolean      enable)
14032 {
14033   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14034
14035   self->priv->enable_model_view_transform = enable;
14036 }
14037
14038 void
14039 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14040                                           gboolean      enable)
14041 {
14042   ClutterActorPrivate *priv;
14043
14044   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14045
14046   priv = self->priv;
14047
14048   priv->enable_paint_unmapped = enable;
14049
14050   if (priv->enable_paint_unmapped)
14051     {
14052       /* Make sure that the parents of the widget are realized first;
14053        * otherwise checks in clutter_actor_update_map_state() will
14054        * fail.
14055        */
14056       clutter_actor_realize (self);
14057
14058       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14059     }
14060   else
14061     {
14062       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14063     }
14064 }
14065
14066 static void
14067 clutter_anchor_coord_get_units (ClutterActor      *self,
14068                                 const AnchorCoord *coord,
14069                                 gfloat            *x,
14070                                 gfloat            *y,
14071                                 gfloat            *z)
14072 {
14073   if (coord->is_fractional)
14074     {
14075       gfloat actor_width, actor_height;
14076
14077       clutter_actor_get_size (self, &actor_width, &actor_height);
14078
14079       if (x)
14080         *x = actor_width * coord->v.fraction.x;
14081
14082       if (y)
14083         *y = actor_height * coord->v.fraction.y;
14084
14085       if (z)
14086         *z = 0;
14087     }
14088   else
14089     {
14090       if (x)
14091         *x = coord->v.units.x;
14092
14093       if (y)
14094         *y = coord->v.units.y;
14095
14096       if (z)
14097         *z = coord->v.units.z;
14098     }
14099 }
14100
14101 static void
14102 clutter_anchor_coord_set_units (AnchorCoord *coord,
14103                                 gfloat       x,
14104                                 gfloat       y,
14105                                 gfloat       z)
14106 {
14107   coord->is_fractional = FALSE;
14108   coord->v.units.x = x;
14109   coord->v.units.y = y;
14110   coord->v.units.z = z;
14111 }
14112
14113 static ClutterGravity
14114 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14115 {
14116   if (coord->is_fractional)
14117     {
14118       if (coord->v.fraction.x == 0.0)
14119         {
14120           if (coord->v.fraction.y == 0.0)
14121             return CLUTTER_GRAVITY_NORTH_WEST;
14122           else if (coord->v.fraction.y == 0.5)
14123             return CLUTTER_GRAVITY_WEST;
14124           else if (coord->v.fraction.y == 1.0)
14125             return CLUTTER_GRAVITY_SOUTH_WEST;
14126           else
14127             return CLUTTER_GRAVITY_NONE;
14128         }
14129       else if (coord->v.fraction.x == 0.5)
14130         {
14131           if (coord->v.fraction.y == 0.0)
14132             return CLUTTER_GRAVITY_NORTH;
14133           else if (coord->v.fraction.y == 0.5)
14134             return CLUTTER_GRAVITY_CENTER;
14135           else if (coord->v.fraction.y == 1.0)
14136             return CLUTTER_GRAVITY_SOUTH;
14137           else
14138             return CLUTTER_GRAVITY_NONE;
14139         }
14140       else if (coord->v.fraction.x == 1.0)
14141         {
14142           if (coord->v.fraction.y == 0.0)
14143             return CLUTTER_GRAVITY_NORTH_EAST;
14144           else if (coord->v.fraction.y == 0.5)
14145             return CLUTTER_GRAVITY_EAST;
14146           else if (coord->v.fraction.y == 1.0)
14147             return CLUTTER_GRAVITY_SOUTH_EAST;
14148           else
14149             return CLUTTER_GRAVITY_NONE;
14150         }
14151       else
14152         return CLUTTER_GRAVITY_NONE;
14153     }
14154   else
14155     return CLUTTER_GRAVITY_NONE;
14156 }
14157
14158 static void
14159 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14160                                   ClutterGravity  gravity)
14161 {
14162   switch (gravity)
14163     {
14164     case CLUTTER_GRAVITY_NORTH:
14165       coord->v.fraction.x = 0.5;
14166       coord->v.fraction.y = 0.0;
14167       break;
14168
14169     case CLUTTER_GRAVITY_NORTH_EAST:
14170       coord->v.fraction.x = 1.0;
14171       coord->v.fraction.y = 0.0;
14172       break;
14173
14174     case CLUTTER_GRAVITY_EAST:
14175       coord->v.fraction.x = 1.0;
14176       coord->v.fraction.y = 0.5;
14177       break;
14178
14179     case CLUTTER_GRAVITY_SOUTH_EAST:
14180       coord->v.fraction.x = 1.0;
14181       coord->v.fraction.y = 1.0;
14182       break;
14183
14184     case CLUTTER_GRAVITY_SOUTH:
14185       coord->v.fraction.x = 0.5;
14186       coord->v.fraction.y = 1.0;
14187       break;
14188
14189     case CLUTTER_GRAVITY_SOUTH_WEST:
14190       coord->v.fraction.x = 0.0;
14191       coord->v.fraction.y = 1.0;
14192       break;
14193
14194     case CLUTTER_GRAVITY_WEST:
14195       coord->v.fraction.x = 0.0;
14196       coord->v.fraction.y = 0.5;
14197       break;
14198
14199     case CLUTTER_GRAVITY_NORTH_WEST:
14200       coord->v.fraction.x = 0.0;
14201       coord->v.fraction.y = 0.0;
14202       break;
14203
14204     case CLUTTER_GRAVITY_CENTER:
14205       coord->v.fraction.x = 0.5;
14206       coord->v.fraction.y = 0.5;
14207       break;
14208
14209     default:
14210       coord->v.fraction.x = 0.0;
14211       coord->v.fraction.y = 0.0;
14212       break;
14213     }
14214
14215   coord->is_fractional = TRUE;
14216 }
14217
14218 static gboolean
14219 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14220 {
14221   if (coord->is_fractional)
14222     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14223   else
14224     return (coord->v.units.x == 0.0
14225             && coord->v.units.y == 0.0
14226             && coord->v.units.z == 0.0);
14227 }
14228
14229 /**
14230  * clutter_actor_get_flags:
14231  * @self: a #ClutterActor
14232  *
14233  * Retrieves the flags set on @self
14234  *
14235  * Return value: a bitwise or of #ClutterActorFlags or 0
14236  *
14237  * Since: 1.0
14238  */
14239 ClutterActorFlags
14240 clutter_actor_get_flags (ClutterActor *self)
14241 {
14242   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14243
14244   return self->flags;
14245 }
14246
14247 /**
14248  * clutter_actor_set_flags:
14249  * @self: a #ClutterActor
14250  * @flags: the flags to set
14251  *
14252  * Sets @flags on @self
14253  *
14254  * This function will emit notifications for the changed properties
14255  *
14256  * Since: 1.0
14257  */
14258 void
14259 clutter_actor_set_flags (ClutterActor      *self,
14260                          ClutterActorFlags  flags)
14261 {
14262   ClutterActorFlags old_flags;
14263   GObject *obj;
14264   gboolean was_reactive_set, reactive_set;
14265   gboolean was_realized_set, realized_set;
14266   gboolean was_mapped_set, mapped_set;
14267   gboolean was_visible_set, visible_set;
14268
14269   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14270
14271   if (self->flags == flags)
14272     return;
14273
14274   obj = G_OBJECT (self);
14275   g_object_ref (obj);
14276   g_object_freeze_notify (obj);
14277
14278   old_flags = self->flags;
14279
14280   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14281   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14282   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14283   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14284
14285   self->flags |= flags;
14286
14287   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14288   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14289   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14290   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14291
14292   if (reactive_set != was_reactive_set)
14293     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14294
14295   if (realized_set != was_realized_set)
14296     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14297
14298   if (mapped_set != was_mapped_set)
14299     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14300
14301   if (visible_set != was_visible_set)
14302     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14303
14304   g_object_thaw_notify (obj);
14305   g_object_unref (obj);
14306 }
14307
14308 /**
14309  * clutter_actor_unset_flags:
14310  * @self: a #ClutterActor
14311  * @flags: the flags to unset
14312  *
14313  * Unsets @flags on @self
14314  *
14315  * This function will emit notifications for the changed properties
14316  *
14317  * Since: 1.0
14318  */
14319 void
14320 clutter_actor_unset_flags (ClutterActor      *self,
14321                            ClutterActorFlags  flags)
14322 {
14323   ClutterActorFlags old_flags;
14324   GObject *obj;
14325   gboolean was_reactive_set, reactive_set;
14326   gboolean was_realized_set, realized_set;
14327   gboolean was_mapped_set, mapped_set;
14328   gboolean was_visible_set, visible_set;
14329
14330   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14331
14332   obj = G_OBJECT (self);
14333   g_object_freeze_notify (obj);
14334
14335   old_flags = self->flags;
14336
14337   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14338   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14339   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14340   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14341
14342   self->flags &= ~flags;
14343
14344   if (self->flags == old_flags)
14345     return;
14346
14347   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14348   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14349   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14350   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14351
14352   if (reactive_set != was_reactive_set)
14353     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14354
14355   if (realized_set != was_realized_set)
14356     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14357
14358   if (mapped_set != was_mapped_set)
14359     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14360
14361   if (visible_set != was_visible_set)
14362     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14363
14364   g_object_thaw_notify (obj);
14365 }
14366
14367 /**
14368  * clutter_actor_get_transformation_matrix:
14369  * @self: a #ClutterActor
14370  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14371  *
14372  * Retrieves the transformations applied to @self relative to its
14373  * parent.
14374  *
14375  * Since: 1.0
14376  */
14377 void
14378 clutter_actor_get_transformation_matrix (ClutterActor *self,
14379                                          CoglMatrix   *matrix)
14380 {
14381   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14382
14383   cogl_matrix_init_identity (matrix);
14384
14385   _clutter_actor_apply_modelview_transform (self, matrix);
14386 }
14387
14388 void
14389 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14390                                    gboolean      is_in_clone_paint)
14391 {
14392   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14393   self->priv->in_clone_paint = is_in_clone_paint;
14394 }
14395
14396 /**
14397  * clutter_actor_is_in_clone_paint:
14398  * @self: a #ClutterActor
14399  *
14400  * Checks whether @self is being currently painted by a #ClutterClone
14401  *
14402  * This function is useful only inside the ::paint virtual function
14403  * implementations or within handlers for the #ClutterActor::paint
14404  * signal
14405  *
14406  * This function should not be used by applications
14407  *
14408  * Return value: %TRUE if the #ClutterActor is currently being painted
14409  *   by a #ClutterClone, and %FALSE otherwise
14410  *
14411  * Since: 1.0
14412  */
14413 gboolean
14414 clutter_actor_is_in_clone_paint (ClutterActor *self)
14415 {
14416   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14417
14418   return self->priv->in_clone_paint;
14419 }
14420
14421 static gboolean
14422 set_direction_recursive (ClutterActor *actor,
14423                          gpointer      user_data)
14424 {
14425   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14426
14427   clutter_actor_set_text_direction (actor, text_dir);
14428
14429   return TRUE;
14430 }
14431
14432 /**
14433  * clutter_actor_set_text_direction:
14434  * @self: a #ClutterActor
14435  * @text_dir: the text direction for @self
14436  *
14437  * Sets the #ClutterTextDirection for an actor
14438  *
14439  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14440  *
14441  * If @self implements #ClutterContainer then this function will recurse
14442  * inside all the children of @self (including the internal ones).
14443  *
14444  * Composite actors not implementing #ClutterContainer, or actors requiring
14445  * special handling when the text direction changes, should connect to
14446  * the #GObject::notify signal for the #ClutterActor:text-direction property
14447  *
14448  * Since: 1.2
14449  */
14450 void
14451 clutter_actor_set_text_direction (ClutterActor         *self,
14452                                   ClutterTextDirection  text_dir)
14453 {
14454   ClutterActorPrivate *priv;
14455
14456   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14457   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14458
14459   priv = self->priv;
14460
14461   if (priv->text_direction != text_dir)
14462     {
14463       priv->text_direction = text_dir;
14464
14465       /* we need to emit the notify::text-direction first, so that
14466        * the sub-classes can catch that and do specific handling of
14467        * the text direction; see clutter_text_direction_changed_cb()
14468        * inside clutter-text.c
14469        */
14470       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14471
14472       _clutter_actor_foreach_child (self, set_direction_recursive,
14473                                     GINT_TO_POINTER (text_dir));
14474
14475       clutter_actor_queue_relayout (self);
14476     }
14477 }
14478
14479 void
14480 _clutter_actor_set_has_pointer (ClutterActor *self,
14481                                 gboolean      has_pointer)
14482 {
14483   ClutterActorPrivate *priv = self->priv;
14484
14485   if (priv->has_pointer != has_pointer)
14486     {
14487       priv->has_pointer = has_pointer;
14488
14489       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14490     }
14491 }
14492
14493 /**
14494  * clutter_actor_get_text_direction:
14495  * @self: a #ClutterActor
14496  *
14497  * Retrieves the value set using clutter_actor_set_text_direction()
14498  *
14499  * If no text direction has been previously set, the default text
14500  * direction, as returned by clutter_get_default_text_direction(), will
14501  * be returned instead
14502  *
14503  * Return value: the #ClutterTextDirection for the actor
14504  *
14505  * Since: 1.2
14506  */
14507 ClutterTextDirection
14508 clutter_actor_get_text_direction (ClutterActor *self)
14509 {
14510   ClutterActorPrivate *priv;
14511
14512   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14513                         CLUTTER_TEXT_DIRECTION_LTR);
14514
14515   priv = self->priv;
14516
14517   /* if no direction has been set yet use the default */
14518   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14519     priv->text_direction = clutter_get_default_text_direction ();
14520
14521   return priv->text_direction;
14522 }
14523
14524 /**
14525  * clutter_actor_push_internal:
14526  * @self: a #ClutterActor
14527  *
14528  * Should be used by actors implementing the #ClutterContainer and with
14529  * internal children added through clutter_actor_set_parent(), for instance:
14530  *
14531  * |[
14532  *   static void
14533  *   my_actor_init (MyActor *self)
14534  *   {
14535  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14536  *
14537  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14538  *
14539  *     /&ast; calling clutter_actor_set_parent() now will result in
14540  *      &ast; the internal flag being set on a child of MyActor
14541  *      &ast;/
14542  *
14543  *     /&ast; internal child - a background texture &ast;/
14544  *     self->priv->background_tex = clutter_texture_new ();
14545  *     clutter_actor_set_parent (self->priv->background_tex,
14546  *                               CLUTTER_ACTOR (self));
14547  *
14548  *     /&ast; internal child - a label &ast;/
14549  *     self->priv->label = clutter_text_new ();
14550  *     clutter_actor_set_parent (self->priv->label,
14551  *                               CLUTTER_ACTOR (self));
14552  *
14553  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14554  *
14555  *     /&ast; calling clutter_actor_set_parent() now will not result in
14556  *      &ast; the internal flag being set on a child of MyActor
14557  *      &ast;/
14558  *   }
14559  * ]|
14560  *
14561  * This function will be used by Clutter to toggle an "internal child"
14562  * flag whenever clutter_actor_set_parent() is called; internal children
14563  * are handled differently by Clutter, specifically when destroying their
14564  * parent.
14565  *
14566  * Call clutter_actor_pop_internal() when you finished adding internal
14567  * children.
14568  *
14569  * Nested calls to clutter_actor_push_internal() are allowed, but each
14570  * one must by followed by a clutter_actor_pop_internal() call.
14571  *
14572  * Since: 1.2
14573  *
14574  * Deprecated: 1.10: All children of an actor are accessible through
14575  *   the #ClutterActor API, and #ClutterActor implements the
14576  *   #ClutterContainer interface, so this function is only useful
14577  *   for legacy containers overriding the default implementation.
14578  */
14579 void
14580 clutter_actor_push_internal (ClutterActor *self)
14581 {
14582   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14583
14584   self->priv->internal_child += 1;
14585 }
14586
14587 /**
14588  * clutter_actor_pop_internal:
14589  * @self: a #ClutterActor
14590  *
14591  * Disables the effects of clutter_actor_push_internal().
14592  *
14593  * Since: 1.2
14594  *
14595  * Deprecated: 1.10: All children of an actor are accessible through
14596  *   the #ClutterActor API. This function is only useful for legacy
14597  *   containers overriding the default implementation of the
14598  *   #ClutterContainer interface.
14599  */
14600 void
14601 clutter_actor_pop_internal (ClutterActor *self)
14602 {
14603   ClutterActorPrivate *priv;
14604
14605   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14606
14607   priv = self->priv;
14608
14609   if (priv->internal_child == 0)
14610     {
14611       g_warning ("Mismatched %s: you need to call "
14612                  "clutter_actor_push_composite() at least once before "
14613                  "calling this function", G_STRFUNC);
14614       return;
14615     }
14616
14617   priv->internal_child -= 1;
14618 }
14619
14620 /**
14621  * clutter_actor_has_pointer:
14622  * @self: a #ClutterActor
14623  *
14624  * Checks whether an actor contains the pointer of a
14625  * #ClutterInputDevice
14626  *
14627  * Return value: %TRUE if the actor contains the pointer, and
14628  *   %FALSE otherwise
14629  *
14630  * Since: 1.2
14631  */
14632 gboolean
14633 clutter_actor_has_pointer (ClutterActor *self)
14634 {
14635   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14636
14637   return self->priv->has_pointer;
14638 }
14639
14640 /* XXX: This is a workaround for not being able to break the ABI of
14641  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14642  * clutter_actor_queue_clipped_redraw() for details.
14643  */
14644 ClutterPaintVolume *
14645 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14646 {
14647   return g_object_get_data (G_OBJECT (self),
14648                             "-clutter-actor-queue-redraw-clip");
14649 }
14650
14651 void
14652 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14653                                       ClutterPaintVolume *clip)
14654 {
14655   g_object_set_data (G_OBJECT (self),
14656                      "-clutter-actor-queue-redraw-clip",
14657                      clip);
14658 }
14659
14660 /**
14661  * clutter_actor_has_allocation:
14662  * @self: a #ClutterActor
14663  *
14664  * Checks if the actor has an up-to-date allocation assigned to
14665  * it. This means that the actor should have an allocation: it's
14666  * visible and has a parent. It also means that there is no
14667  * outstanding relayout request in progress for the actor or its
14668  * children (There might be other outstanding layout requests in
14669  * progress that will cause the actor to get a new allocation
14670  * when the stage is laid out, however).
14671  *
14672  * If this function returns %FALSE, then the actor will normally
14673  * be allocated before it is next drawn on the screen.
14674  *
14675  * Return value: %TRUE if the actor has an up-to-date allocation
14676  *
14677  * Since: 1.4
14678  */
14679 gboolean
14680 clutter_actor_has_allocation (ClutterActor *self)
14681 {
14682   ClutterActorPrivate *priv;
14683
14684   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14685
14686   priv = self->priv;
14687
14688   return priv->parent != NULL &&
14689          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14690          !priv->needs_allocation;
14691 }
14692
14693 /**
14694  * clutter_actor_add_action:
14695  * @self: a #ClutterActor
14696  * @action: a #ClutterAction
14697  *
14698  * Adds @action to the list of actions applied to @self
14699  *
14700  * A #ClutterAction can only belong to one actor at a time
14701  *
14702  * The #ClutterActor will hold a reference on @action until either
14703  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14704  * is called
14705  *
14706  * Since: 1.4
14707  */
14708 void
14709 clutter_actor_add_action (ClutterActor  *self,
14710                           ClutterAction *action)
14711 {
14712   ClutterActorPrivate *priv;
14713
14714   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14715   g_return_if_fail (CLUTTER_IS_ACTION (action));
14716
14717   priv = self->priv;
14718
14719   if (priv->actions == NULL)
14720     {
14721       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14722       priv->actions->actor = self;
14723     }
14724
14725   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14726
14727   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14728 }
14729
14730 /**
14731  * clutter_actor_add_action_with_name:
14732  * @self: a #ClutterActor
14733  * @name: the name to set on the action
14734  * @action: a #ClutterAction
14735  *
14736  * A convenience function for setting the name of a #ClutterAction
14737  * while adding it to the list of actions applied to @self
14738  *
14739  * This function is the logical equivalent of:
14740  *
14741  * |[
14742  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14743  *   clutter_actor_add_action (self, action);
14744  * ]|
14745  *
14746  * Since: 1.4
14747  */
14748 void
14749 clutter_actor_add_action_with_name (ClutterActor  *self,
14750                                     const gchar   *name,
14751                                     ClutterAction *action)
14752 {
14753   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14754   g_return_if_fail (name != NULL);
14755   g_return_if_fail (CLUTTER_IS_ACTION (action));
14756
14757   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14758   clutter_actor_add_action (self, action);
14759 }
14760
14761 /**
14762  * clutter_actor_remove_action:
14763  * @self: a #ClutterActor
14764  * @action: a #ClutterAction
14765  *
14766  * Removes @action from the list of actions applied to @self
14767  *
14768  * The reference held by @self on the #ClutterAction will be released
14769  *
14770  * Since: 1.4
14771  */
14772 void
14773 clutter_actor_remove_action (ClutterActor  *self,
14774                              ClutterAction *action)
14775 {
14776   ClutterActorPrivate *priv;
14777
14778   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14779   g_return_if_fail (CLUTTER_IS_ACTION (action));
14780
14781   priv = self->priv;
14782
14783   if (priv->actions == NULL)
14784     return;
14785
14786   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14787
14788   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14789     g_clear_object (&priv->actions);
14790
14791   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14792 }
14793
14794 /**
14795  * clutter_actor_remove_action_by_name:
14796  * @self: a #ClutterActor
14797  * @name: the name of the action to remove
14798  *
14799  * Removes the #ClutterAction with the given name from the list
14800  * of actions applied to @self
14801  *
14802  * Since: 1.4
14803  */
14804 void
14805 clutter_actor_remove_action_by_name (ClutterActor *self,
14806                                      const gchar  *name)
14807 {
14808   ClutterActorPrivate *priv;
14809   ClutterActorMeta *meta;
14810
14811   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14812   g_return_if_fail (name != NULL);
14813
14814   priv = self->priv;
14815
14816   if (priv->actions == NULL)
14817     return;
14818
14819   meta = _clutter_meta_group_get_meta (priv->actions, name);
14820   if (meta == NULL)
14821     return;
14822
14823   _clutter_meta_group_remove_meta (priv->actions, meta);
14824
14825   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14826 }
14827
14828 /**
14829  * clutter_actor_get_actions:
14830  * @self: a #ClutterActor
14831  *
14832  * Retrieves the list of actions applied to @self
14833  *
14834  * Return value: (transfer container) (element-type Clutter.Action): a copy
14835  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14836  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14837  *   allocated by the returned #GList
14838  *
14839  * Since: 1.4
14840  */
14841 GList *
14842 clutter_actor_get_actions (ClutterActor *self)
14843 {
14844   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14845
14846   if (self->priv->actions == NULL)
14847     return NULL;
14848
14849   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14850 }
14851
14852 /**
14853  * clutter_actor_get_action:
14854  * @self: a #ClutterActor
14855  * @name: the name of the action to retrieve
14856  *
14857  * Retrieves the #ClutterAction with the given name in the list
14858  * of actions applied to @self
14859  *
14860  * Return value: (transfer none): a #ClutterAction for the given
14861  *   name, or %NULL. The returned #ClutterAction is owned by the
14862  *   actor and it should not be unreferenced directly
14863  *
14864  * Since: 1.4
14865  */
14866 ClutterAction *
14867 clutter_actor_get_action (ClutterActor *self,
14868                           const gchar  *name)
14869 {
14870   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14871   g_return_val_if_fail (name != NULL, NULL);
14872
14873   if (self->priv->actions == NULL)
14874     return NULL;
14875
14876   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14877 }
14878
14879 /**
14880  * clutter_actor_clear_actions:
14881  * @self: a #ClutterActor
14882  *
14883  * Clears the list of actions applied to @self
14884  *
14885  * Since: 1.4
14886  */
14887 void
14888 clutter_actor_clear_actions (ClutterActor *self)
14889 {
14890   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14891
14892   if (self->priv->actions == NULL)
14893     return;
14894
14895   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14896 }
14897
14898 /**
14899  * clutter_actor_add_constraint:
14900  * @self: a #ClutterActor
14901  * @constraint: a #ClutterConstraint
14902  *
14903  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14904  * to @self
14905  *
14906  * The #ClutterActor will hold a reference on the @constraint until
14907  * either clutter_actor_remove_constraint() or
14908  * clutter_actor_clear_constraints() is called.
14909  *
14910  * Since: 1.4
14911  */
14912 void
14913 clutter_actor_add_constraint (ClutterActor      *self,
14914                               ClutterConstraint *constraint)
14915 {
14916   ClutterActorPrivate *priv;
14917
14918   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14919   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14920
14921   priv = self->priv;
14922
14923   if (priv->constraints == NULL)
14924     {
14925       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14926       priv->constraints->actor = self;
14927     }
14928
14929   _clutter_meta_group_add_meta (priv->constraints,
14930                                 CLUTTER_ACTOR_META (constraint));
14931   clutter_actor_queue_relayout (self);
14932
14933   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14934 }
14935
14936 /**
14937  * clutter_actor_add_constraint_with_name:
14938  * @self: a #ClutterActor
14939  * @name: the name to set on the constraint
14940  * @constraint: a #ClutterConstraint
14941  *
14942  * A convenience function for setting the name of a #ClutterConstraint
14943  * while adding it to the list of constraints applied to @self
14944  *
14945  * This function is the logical equivalent of:
14946  *
14947  * |[
14948  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14949  *   clutter_actor_add_constraint (self, constraint);
14950  * ]|
14951  *
14952  * Since: 1.4
14953  */
14954 void
14955 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14956                                         const gchar       *name,
14957                                         ClutterConstraint *constraint)
14958 {
14959   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14960   g_return_if_fail (name != NULL);
14961   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14962
14963   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14964   clutter_actor_add_constraint (self, constraint);
14965 }
14966
14967 /**
14968  * clutter_actor_remove_constraint:
14969  * @self: a #ClutterActor
14970  * @constraint: a #ClutterConstraint
14971  *
14972  * Removes @constraint from the list of constraints applied to @self
14973  *
14974  * The reference held by @self on the #ClutterConstraint will be released
14975  *
14976  * Since: 1.4
14977  */
14978 void
14979 clutter_actor_remove_constraint (ClutterActor      *self,
14980                                  ClutterConstraint *constraint)
14981 {
14982   ClutterActorPrivate *priv;
14983
14984   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14985   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14986
14987   priv = self->priv;
14988
14989   if (priv->constraints == NULL)
14990     return;
14991
14992   _clutter_meta_group_remove_meta (priv->constraints,
14993                                    CLUTTER_ACTOR_META (constraint));
14994
14995   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
14996     g_clear_object (&priv->constraints);
14997
14998   clutter_actor_queue_relayout (self);
14999
15000   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15001 }
15002
15003 /**
15004  * clutter_actor_remove_constraint_by_name:
15005  * @self: a #ClutterActor
15006  * @name: the name of the constraint to remove
15007  *
15008  * Removes the #ClutterConstraint with the given name from the list
15009  * of constraints applied to @self
15010  *
15011  * Since: 1.4
15012  */
15013 void
15014 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15015                                          const gchar  *name)
15016 {
15017   ClutterActorPrivate *priv;
15018   ClutterActorMeta *meta;
15019
15020   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15021   g_return_if_fail (name != NULL);
15022
15023   priv = self->priv;
15024
15025   if (priv->constraints == NULL)
15026     return;
15027
15028   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15029   if (meta == NULL)
15030     return;
15031
15032   _clutter_meta_group_remove_meta (priv->constraints, meta);
15033   clutter_actor_queue_relayout (self);
15034 }
15035
15036 /**
15037  * clutter_actor_get_constraints:
15038  * @self: a #ClutterActor
15039  *
15040  * Retrieves the list of constraints applied to @self
15041  *
15042  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15043  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15044  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15045  *   allocated by the returned #GList
15046  *
15047  * Since: 1.4
15048  */
15049 GList *
15050 clutter_actor_get_constraints (ClutterActor *self)
15051 {
15052   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15053
15054   if (self->priv->constraints == NULL)
15055     return NULL;
15056
15057   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15058 }
15059
15060 /**
15061  * clutter_actor_get_constraint:
15062  * @self: a #ClutterActor
15063  * @name: the name of the constraint to retrieve
15064  *
15065  * Retrieves the #ClutterConstraint with the given name in the list
15066  * of constraints applied to @self
15067  *
15068  * Return value: (transfer none): a #ClutterConstraint for the given
15069  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15070  *   actor and it should not be unreferenced directly
15071  *
15072  * Since: 1.4
15073  */
15074 ClutterConstraint *
15075 clutter_actor_get_constraint (ClutterActor *self,
15076                               const gchar  *name)
15077 {
15078   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15079   g_return_val_if_fail (name != NULL, NULL);
15080
15081   if (self->priv->constraints == NULL)
15082     return NULL;
15083
15084   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15085 }
15086
15087 /**
15088  * clutter_actor_clear_constraints:
15089  * @self: a #ClutterActor
15090  *
15091  * Clears the list of constraints applied to @self
15092  *
15093  * Since: 1.4
15094  */
15095 void
15096 clutter_actor_clear_constraints (ClutterActor *self)
15097 {
15098   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15099
15100   if (self->priv->constraints == NULL)
15101     return;
15102
15103   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15104
15105   clutter_actor_queue_relayout (self);
15106 }
15107
15108 /**
15109  * clutter_actor_set_clip_to_allocation:
15110  * @self: a #ClutterActor
15111  * @clip_set: %TRUE to apply a clip tracking the allocation
15112  *
15113  * Sets whether @self should be clipped to the same size as its
15114  * allocation
15115  *
15116  * Since: 1.4
15117  */
15118 void
15119 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15120                                       gboolean      clip_set)
15121 {
15122   ClutterActorPrivate *priv;
15123
15124   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15125
15126   clip_set = !!clip_set;
15127
15128   priv = self->priv;
15129
15130   if (priv->clip_to_allocation != clip_set)
15131     {
15132       priv->clip_to_allocation = clip_set;
15133
15134       clutter_actor_queue_redraw (self);
15135
15136       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15137     }
15138 }
15139
15140 /**
15141  * clutter_actor_get_clip_to_allocation:
15142  * @self: a #ClutterActor
15143  *
15144  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15145  *
15146  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15147  *
15148  * Since: 1.4
15149  */
15150 gboolean
15151 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15152 {
15153   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15154
15155   return self->priv->clip_to_allocation;
15156 }
15157
15158 /**
15159  * clutter_actor_add_effect:
15160  * @self: a #ClutterActor
15161  * @effect: a #ClutterEffect
15162  *
15163  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15164  *
15165  * The #ClutterActor will hold a reference on the @effect until either
15166  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15167  * called.
15168  *
15169  * Since: 1.4
15170  */
15171 void
15172 clutter_actor_add_effect (ClutterActor  *self,
15173                           ClutterEffect *effect)
15174 {
15175   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15176   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15177
15178   _clutter_actor_add_effect_internal (self, effect);
15179
15180   clutter_actor_queue_redraw (self);
15181
15182   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15183 }
15184
15185 /**
15186  * clutter_actor_add_effect_with_name:
15187  * @self: a #ClutterActor
15188  * @name: the name to set on the effect
15189  * @effect: a #ClutterEffect
15190  *
15191  * A convenience function for setting the name of a #ClutterEffect
15192  * while adding it to the list of effectss applied to @self
15193  *
15194  * This function is the logical equivalent of:
15195  *
15196  * |[
15197  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15198  *   clutter_actor_add_effect (self, effect);
15199  * ]|
15200  *
15201  * Since: 1.4
15202  */
15203 void
15204 clutter_actor_add_effect_with_name (ClutterActor  *self,
15205                                     const gchar   *name,
15206                                     ClutterEffect *effect)
15207 {
15208   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15209   g_return_if_fail (name != NULL);
15210   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15211
15212   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15213   clutter_actor_add_effect (self, effect);
15214 }
15215
15216 /**
15217  * clutter_actor_remove_effect:
15218  * @self: a #ClutterActor
15219  * @effect: a #ClutterEffect
15220  *
15221  * Removes @effect from the list of effects applied to @self
15222  *
15223  * The reference held by @self on the #ClutterEffect will be released
15224  *
15225  * Since: 1.4
15226  */
15227 void
15228 clutter_actor_remove_effect (ClutterActor  *self,
15229                              ClutterEffect *effect)
15230 {
15231   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15232   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15233
15234   _clutter_actor_remove_effect_internal (self, effect);
15235
15236   clutter_actor_queue_redraw (self);
15237
15238   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15239 }
15240
15241 /**
15242  * clutter_actor_remove_effect_by_name:
15243  * @self: a #ClutterActor
15244  * @name: the name of the effect to remove
15245  *
15246  * Removes the #ClutterEffect with the given name from the list
15247  * of effects applied to @self
15248  *
15249  * Since: 1.4
15250  */
15251 void
15252 clutter_actor_remove_effect_by_name (ClutterActor *self,
15253                                      const gchar  *name)
15254 {
15255   ClutterActorPrivate *priv;
15256   ClutterActorMeta *meta;
15257
15258   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15259   g_return_if_fail (name != NULL);
15260
15261   priv = self->priv;
15262
15263   if (priv->effects == NULL)
15264     return;
15265
15266   meta = _clutter_meta_group_get_meta (priv->effects, name);
15267   if (meta == NULL)
15268     return;
15269
15270   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15271 }
15272
15273 /**
15274  * clutter_actor_get_effects:
15275  * @self: a #ClutterActor
15276  *
15277  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15278  *
15279  * Return value: (transfer container) (element-type Clutter.Effect): a list
15280  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15281  *   list are owned by Clutter and they should not be freed. You should
15282  *   free the returned list using g_list_free() when done
15283  *
15284  * Since: 1.4
15285  */
15286 GList *
15287 clutter_actor_get_effects (ClutterActor *self)
15288 {
15289   ClutterActorPrivate *priv;
15290
15291   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15292
15293   priv = self->priv;
15294
15295   if (priv->effects == NULL)
15296     return NULL;
15297
15298   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15299 }
15300
15301 /**
15302  * clutter_actor_get_effect:
15303  * @self: a #ClutterActor
15304  * @name: the name of the effect to retrieve
15305  *
15306  * Retrieves the #ClutterEffect with the given name in the list
15307  * of effects applied to @self
15308  *
15309  * Return value: (transfer none): a #ClutterEffect for the given
15310  *   name, or %NULL. The returned #ClutterEffect is owned by the
15311  *   actor and it should not be unreferenced directly
15312  *
15313  * Since: 1.4
15314  */
15315 ClutterEffect *
15316 clutter_actor_get_effect (ClutterActor *self,
15317                           const gchar  *name)
15318 {
15319   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15320   g_return_val_if_fail (name != NULL, NULL);
15321
15322   if (self->priv->effects == NULL)
15323     return NULL;
15324
15325   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15326 }
15327
15328 /**
15329  * clutter_actor_clear_effects:
15330  * @self: a #ClutterActor
15331  *
15332  * Clears the list of effects applied to @self
15333  *
15334  * Since: 1.4
15335  */
15336 void
15337 clutter_actor_clear_effects (ClutterActor *self)
15338 {
15339   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15340
15341   if (self->priv->effects == NULL)
15342     return;
15343
15344   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15345
15346   clutter_actor_queue_redraw (self);
15347 }
15348
15349 /**
15350  * clutter_actor_has_key_focus:
15351  * @self: a #ClutterActor
15352  *
15353  * Checks whether @self is the #ClutterActor that has key focus
15354  *
15355  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15356  *
15357  * Since: 1.4
15358  */
15359 gboolean
15360 clutter_actor_has_key_focus (ClutterActor *self)
15361 {
15362   ClutterActor *stage;
15363
15364   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15365
15366   stage = _clutter_actor_get_stage_internal (self);
15367   if (stage == NULL)
15368     return FALSE;
15369
15370   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15371 }
15372
15373 static gboolean
15374 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15375                                       ClutterPaintVolume *pv)
15376 {
15377   ClutterActorPrivate *priv = self->priv;
15378
15379   /* Actors are only expected to report a valid paint volume
15380    * while they have a valid allocation. */
15381   if (G_UNLIKELY (priv->needs_allocation))
15382     {
15383       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15384                     "Actor needs allocation",
15385                     _clutter_actor_get_debug_name (self));
15386       return FALSE;
15387     }
15388
15389   /* Check if there are any handlers connected to the paint
15390    * signal. If there are then all bets are off for what the paint
15391    * volume for this actor might possibly be!
15392    *
15393    * XXX: It's expected that this is going to end up being quite a
15394    * costly check to have to do here, but we haven't come up with
15395    * another solution that can reliably catch paint signal handlers at
15396    * the right time to either avoid artefacts due to invalid stage
15397    * clipping or due to incorrect culling.
15398    *
15399    * Previously we checked in clutter_actor_paint(), but at that time
15400    * we may already be using a stage clip that could be derived from
15401    * an invalid paint-volume. We used to try and handle that by
15402    * queuing a follow up, unclipped, redraw but still the previous
15403    * checking wasn't enough to catch invalid volumes involved in
15404    * culling (considering that containers may derive their volume from
15405    * children that haven't yet been painted)
15406    *
15407    * Longer term, improved solutions could be:
15408    * - Disallow painting in the paint signal, only allow using it
15409    *   for tracking when paints happen. We can add another API that
15410    *   allows monkey patching the paint of arbitrary actors but in a
15411    *   more controlled way and that also supports modifying the
15412    *   paint-volume.
15413    * - If we could be notified somehow when signal handlers are
15414    *   connected we wouldn't have to poll for handlers like this.
15415    */
15416   if (g_signal_has_handler_pending (self,
15417                                     actor_signals[PAINT],
15418                                     0,
15419                                     TRUE))
15420     {
15421       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15422                     "Actor has \"paint\" signal handlers",
15423                     _clutter_actor_get_debug_name (self));
15424       return FALSE;
15425     }
15426
15427   _clutter_paint_volume_init_static (pv, self);
15428
15429   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15430     {
15431       clutter_paint_volume_free (pv);
15432       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15433                     "Actor failed to report a volume",
15434                     _clutter_actor_get_debug_name (self));
15435       return FALSE;
15436     }
15437
15438   /* since effects can modify the paint volume, we allow them to actually
15439    * do this by making get_paint_volume() "context sensitive"
15440    */
15441   if (priv->effects != NULL)
15442     {
15443       if (priv->current_effect != NULL)
15444         {
15445           const GList *effects, *l;
15446
15447           /* if we are being called from within the paint sequence of
15448            * an actor, get the paint volume up to the current effect
15449            */
15450           effects = _clutter_meta_group_peek_metas (priv->effects);
15451           for (l = effects;
15452                l != NULL || (l != NULL && l->data != priv->current_effect);
15453                l = l->next)
15454             {
15455               if (!_clutter_effect_get_paint_volume (l->data, pv))
15456                 {
15457                   clutter_paint_volume_free (pv);
15458                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15459                                 "Effect (%s) failed to report a volume",
15460                                 _clutter_actor_get_debug_name (self),
15461                                 _clutter_actor_meta_get_debug_name (l->data));
15462                   return FALSE;
15463                 }
15464             }
15465         }
15466       else
15467         {
15468           const GList *effects, *l;
15469
15470           /* otherwise, get the cumulative volume */
15471           effects = _clutter_meta_group_peek_metas (priv->effects);
15472           for (l = effects; l != NULL; l = l->next)
15473             if (!_clutter_effect_get_paint_volume (l->data, pv))
15474               {
15475                 clutter_paint_volume_free (pv);
15476                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15477                               "Effect (%s) failed to report a volume",
15478                               _clutter_actor_get_debug_name (self),
15479                               _clutter_actor_meta_get_debug_name (l->data));
15480                 return FALSE;
15481               }
15482         }
15483     }
15484
15485   return TRUE;
15486 }
15487
15488 /* The public clutter_actor_get_paint_volume API returns a const
15489  * pointer since we return a pointer directly to the cached
15490  * PaintVolume associated with the actor and don't want the user to
15491  * inadvertently modify it, but for internal uses we sometimes need
15492  * access to the same PaintVolume but need to apply some book-keeping
15493  * modifications to it so we don't want a const pointer.
15494  */
15495 static ClutterPaintVolume *
15496 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15497 {
15498   ClutterActorPrivate *priv;
15499
15500   priv = self->priv;
15501
15502   if (priv->paint_volume_valid)
15503     clutter_paint_volume_free (&priv->paint_volume);
15504
15505   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15506     {
15507       priv->paint_volume_valid = TRUE;
15508       return &priv->paint_volume;
15509     }
15510   else
15511     {
15512       priv->paint_volume_valid = FALSE;
15513       return NULL;
15514     }
15515 }
15516
15517 /**
15518  * clutter_actor_get_paint_volume:
15519  * @self: a #ClutterActor
15520  *
15521  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15522  * when a paint volume can't be determined.
15523  *
15524  * The paint volume is defined as the 3D space occupied by an actor
15525  * when being painted.
15526  *
15527  * This function will call the <function>get_paint_volume()</function>
15528  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15529  * should not usually care about overriding the default implementation,
15530  * unless they are, for instance: painting outside their allocation, or
15531  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15532  * 3D depth).
15533  *
15534  * <note>2D actors overriding <function>get_paint_volume()</function>
15535  * ensure their volume has a depth of 0. (This will be true so long as
15536  * you don't call clutter_paint_volume_set_depth().)</note>
15537  *
15538  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15539  *   or %NULL if no volume could be determined. The returned pointer
15540  *   is not guaranteed to be valid across multiple frames; if you want
15541  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15542  *
15543  * Since: 1.6
15544  */
15545 const ClutterPaintVolume *
15546 clutter_actor_get_paint_volume (ClutterActor *self)
15547 {
15548   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15549
15550   return _clutter_actor_get_paint_volume_mutable (self);
15551 }
15552
15553 /**
15554  * clutter_actor_get_transformed_paint_volume:
15555  * @self: a #ClutterActor
15556  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15557  *    (or %NULL for the stage)
15558  *
15559  * Retrieves the 3D paint volume of an actor like
15560  * clutter_actor_get_paint_volume() does (Please refer to the
15561  * documentation of clutter_actor_get_paint_volume() for more
15562  * details.) and it additionally transforms the paint volume into the
15563  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15564  * is passed for @relative_to_ancestor)
15565  *
15566  * This can be used by containers that base their paint volume on
15567  * the volume of their children. Such containers can query the
15568  * transformed paint volume of all of its children and union them
15569  * together using clutter_paint_volume_union().
15570  *
15571  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15572  *   or %NULL if no volume could be determined. The returned pointer is
15573  *   not guaranteed to be valid across multiple frames; if you wish to
15574  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15575  *
15576  * Since: 1.6
15577  */
15578 const ClutterPaintVolume *
15579 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15580                                             ClutterActor *relative_to_ancestor)
15581 {
15582   const ClutterPaintVolume *volume;
15583   ClutterActor *stage;
15584   ClutterPaintVolume *transformed_volume;
15585
15586   stage = _clutter_actor_get_stage_internal (self);
15587   if (G_UNLIKELY (stage == NULL))
15588     return NULL;
15589
15590   if (relative_to_ancestor == NULL)
15591     relative_to_ancestor = stage;
15592
15593   volume = clutter_actor_get_paint_volume (self);
15594   if (volume == NULL)
15595     return NULL;
15596
15597   transformed_volume =
15598     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15599
15600   _clutter_paint_volume_copy_static (volume, transformed_volume);
15601
15602   _clutter_paint_volume_transform_relative (transformed_volume,
15603                                             relative_to_ancestor);
15604
15605   return transformed_volume;
15606 }
15607
15608 /**
15609  * clutter_actor_get_paint_box:
15610  * @self: a #ClutterActor
15611  * @box: (out): return location for a #ClutterActorBox
15612  *
15613  * Retrieves the paint volume of the passed #ClutterActor, and
15614  * transforms it into a 2D bounding box in stage coordinates.
15615  *
15616  * This function is useful to determine the on screen area occupied by
15617  * the actor. The box is only an approximation and may often be
15618  * considerably larger due to the optimizations used to calculate the
15619  * box. The box is never smaller though, so it can reliably be used
15620  * for culling.
15621  *
15622  * There are times when a 2D paint box can't be determined, e.g.
15623  * because the actor isn't yet parented under a stage or because
15624  * the actor is unable to determine a paint volume.
15625  *
15626  * Return value: %TRUE if a 2D paint box could be determined, else
15627  * %FALSE.
15628  *
15629  * Since: 1.6
15630  */
15631 gboolean
15632 clutter_actor_get_paint_box (ClutterActor    *self,
15633                              ClutterActorBox *box)
15634 {
15635   ClutterActor *stage;
15636   ClutterPaintVolume *pv;
15637
15638   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15639   g_return_val_if_fail (box != NULL, FALSE);
15640
15641   stage = _clutter_actor_get_stage_internal (self);
15642   if (G_UNLIKELY (!stage))
15643     return FALSE;
15644
15645   pv = _clutter_actor_get_paint_volume_mutable (self);
15646   if (G_UNLIKELY (!pv))
15647     return FALSE;
15648
15649   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15650
15651   return TRUE;
15652 }
15653
15654 /**
15655  * clutter_actor_has_overlaps:
15656  * @self: A #ClutterActor
15657  *
15658  * Asks the actor's implementation whether it may contain overlapping
15659  * primitives.
15660  *
15661  * For example; Clutter may use this to determine whether the painting
15662  * should be redirected to an offscreen buffer to correctly implement
15663  * the opacity property.
15664  *
15665  * Custom actors can override the default response by implementing the
15666  * #ClutterActor <function>has_overlaps</function> virtual function. See
15667  * clutter_actor_set_offscreen_redirect() for more information.
15668  *
15669  * Return value: %TRUE if the actor may have overlapping primitives, and
15670  *   %FALSE otherwise
15671  *
15672  * Since: 1.8
15673  */
15674 gboolean
15675 clutter_actor_has_overlaps (ClutterActor *self)
15676 {
15677   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15678
15679   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15680 }
15681
15682 /**
15683  * clutter_actor_has_effects:
15684  * @self: A #ClutterActor
15685  *
15686  * Returns whether the actor has any effects applied.
15687  *
15688  * Return value: %TRUE if the actor has any effects,
15689  *   %FALSE otherwise
15690  *
15691  * Since: 1.10
15692  */
15693 gboolean
15694 clutter_actor_has_effects (ClutterActor *self)
15695 {
15696   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15697
15698   if (self->priv->effects == NULL)
15699     return FALSE;
15700
15701   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15702 }
15703
15704 /**
15705  * clutter_actor_has_constraints:
15706  * @self: A #ClutterActor
15707  *
15708  * Returns whether the actor has any constraints applied.
15709  *
15710  * Return value: %TRUE if the actor has any constraints,
15711  *   %FALSE otherwise
15712  *
15713  * Since: 1.10
15714  */
15715 gboolean
15716 clutter_actor_has_constraints (ClutterActor *self)
15717 {
15718   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15719
15720   return self->priv->constraints != NULL;
15721 }
15722
15723 /**
15724  * clutter_actor_has_actions:
15725  * @self: A #ClutterActor
15726  *
15727  * Returns whether the actor has any actions applied.
15728  *
15729  * Return value: %TRUE if the actor has any actions,
15730  *   %FALSE otherwise
15731  *
15732  * Since: 1.10
15733  */
15734 gboolean
15735 clutter_actor_has_actions (ClutterActor *self)
15736 {
15737   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15738
15739   return self->priv->actions != NULL;
15740 }
15741
15742 /**
15743  * clutter_actor_get_n_children:
15744  * @self: a #ClutterActor
15745  *
15746  * Retrieves the number of children of @self.
15747  *
15748  * Return value: the number of children of an actor
15749  *
15750  * Since: 1.10
15751  */
15752 gint
15753 clutter_actor_get_n_children (ClutterActor *self)
15754 {
15755   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15756
15757   return self->priv->n_children;
15758 }
15759
15760 /**
15761  * clutter_actor_get_child_at_index:
15762  * @self: a #ClutterActor
15763  * @index_: the position in the list of children
15764  *
15765  * Retrieves the actor at the given @index_ inside the list of
15766  * children of @self.
15767  *
15768  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15769  *
15770  * Since: 1.10
15771  */
15772 ClutterActor *
15773 clutter_actor_get_child_at_index (ClutterActor *self,
15774                                   gint          index_)
15775 {
15776   ClutterActor *iter;
15777   int i;
15778
15779   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15780   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15781
15782   for (iter = self->priv->first_child, i = 0;
15783        iter != NULL && i < index_;
15784        iter = iter->priv->next_sibling, i += 1)
15785     ;
15786
15787   return iter;
15788 }
15789
15790 /*< private >
15791  * _clutter_actor_foreach_child:
15792  * @actor: The actor whos children you want to iterate
15793  * @callback: The function to call for each child
15794  * @user_data: Private data to pass to @callback
15795  *
15796  * Calls a given @callback once for each child of the specified @actor and
15797  * passing the @user_data pointer each time.
15798  *
15799  * Return value: returns %TRUE if all children were iterated, else
15800  *    %FALSE if a callback broke out of iteration early.
15801  */
15802 gboolean
15803 _clutter_actor_foreach_child (ClutterActor           *self,
15804                               ClutterForeachCallback  callback,
15805                               gpointer                user_data)
15806 {
15807   ClutterActor *iter;
15808   gboolean cont;
15809
15810   if (self->priv->first_child == NULL)
15811     return TRUE;
15812
15813   cont = TRUE;
15814   iter = self->priv->first_child;
15815
15816   /* we use this form so that it's safe to change the children
15817    * list while iterating it
15818    */
15819   while (cont && iter != NULL)
15820     {
15821       ClutterActor *next = iter->priv->next_sibling;
15822
15823       cont = callback (iter, user_data);
15824
15825       iter = next;
15826     }
15827
15828   return cont;
15829 }
15830
15831 #if 0
15832 /* For debugging purposes this gives us a simple way to print out
15833  * the scenegraph e.g in gdb using:
15834  * [|
15835  *   _clutter_actor_traverse (stage,
15836  *                            0,
15837  *                            clutter_debug_print_actor_cb,
15838  *                            NULL,
15839  *                            NULL);
15840  * |]
15841  */
15842 static ClutterActorTraverseVisitFlags
15843 clutter_debug_print_actor_cb (ClutterActor *actor,
15844                               int depth,
15845                               void *user_data)
15846 {
15847   g_print ("%*s%s:%p\n",
15848            depth * 2, "",
15849            _clutter_actor_get_debug_name (actor),
15850            actor);
15851
15852   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15853 }
15854 #endif
15855
15856 static void
15857 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15858                                  ClutterTraverseCallback callback,
15859                                  gpointer                user_data)
15860 {
15861   GQueue *queue = g_queue_new ();
15862   ClutterActor dummy;
15863   int current_depth = 0;
15864
15865   g_queue_push_tail (queue, actor);
15866   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15867
15868   while ((actor = g_queue_pop_head (queue)))
15869     {
15870       ClutterActorTraverseVisitFlags flags;
15871
15872       if (actor == &dummy)
15873         {
15874           current_depth++;
15875           g_queue_push_tail (queue, &dummy);
15876           continue;
15877         }
15878
15879       flags = callback (actor, current_depth, user_data);
15880       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15881         break;
15882       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15883         {
15884           ClutterActor *iter;
15885
15886           for (iter = actor->priv->first_child;
15887                iter != NULL;
15888                iter = iter->priv->next_sibling)
15889             {
15890               g_queue_push_tail (queue, iter);
15891             }
15892         }
15893     }
15894
15895   g_queue_free (queue);
15896 }
15897
15898 static ClutterActorTraverseVisitFlags
15899 _clutter_actor_traverse_depth (ClutterActor           *actor,
15900                                ClutterTraverseCallback before_children_callback,
15901                                ClutterTraverseCallback after_children_callback,
15902                                int                     current_depth,
15903                                gpointer                user_data)
15904 {
15905   ClutterActorTraverseVisitFlags flags;
15906
15907   flags = before_children_callback (actor, current_depth, user_data);
15908   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15909     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15910
15911   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15912     {
15913       ClutterActor *iter;
15914
15915       for (iter = actor->priv->first_child;
15916            iter != NULL;
15917            iter = iter->priv->next_sibling)
15918         {
15919           flags = _clutter_actor_traverse_depth (iter,
15920                                                  before_children_callback,
15921                                                  after_children_callback,
15922                                                  current_depth + 1,
15923                                                  user_data);
15924
15925           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15926             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15927         }
15928     }
15929
15930   if (after_children_callback)
15931     return after_children_callback (actor, current_depth, user_data);
15932   else
15933     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15934 }
15935
15936 /* _clutter_actor_traverse:
15937  * @actor: The actor to start traversing the graph from
15938  * @flags: These flags may affect how the traversal is done
15939  * @before_children_callback: A function to call before visiting the
15940  *   children of the current actor.
15941  * @after_children_callback: A function to call after visiting the
15942  *   children of the current actor. (Ignored if
15943  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15944  * @user_data: The private data to pass to the callbacks
15945  *
15946  * Traverses the scenegraph starting at the specified @actor and
15947  * descending through all its children and its children's children.
15948  * For each actor traversed @before_children_callback and
15949  * @after_children_callback are called with the specified
15950  * @user_data, before and after visiting that actor's children.
15951  *
15952  * The callbacks can return flags that affect the ongoing traversal
15953  * such as by skipping over an actors children or bailing out of
15954  * any further traversing.
15955  */
15956 void
15957 _clutter_actor_traverse (ClutterActor              *actor,
15958                          ClutterActorTraverseFlags  flags,
15959                          ClutterTraverseCallback    before_children_callback,
15960                          ClutterTraverseCallback    after_children_callback,
15961                          gpointer                   user_data)
15962 {
15963   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15964     _clutter_actor_traverse_breadth (actor,
15965                                      before_children_callback,
15966                                      user_data);
15967   else /* DEPTH_FIRST */
15968     _clutter_actor_traverse_depth (actor,
15969                                    before_children_callback,
15970                                    after_children_callback,
15971                                    0, /* start depth */
15972                                    user_data);
15973 }
15974
15975 static void
15976 on_layout_manager_changed (ClutterLayoutManager *manager,
15977                            ClutterActor         *self)
15978 {
15979   clutter_actor_queue_relayout (self);
15980 }
15981
15982 /**
15983  * clutter_actor_set_layout_manager:
15984  * @self: a #ClutterActor
15985  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15986  *
15987  * Sets the #ClutterLayoutManager delegate object that will be used to
15988  * lay out the children of @self.
15989  *
15990  * The #ClutterActor will take a reference on the passed @manager which
15991  * will be released either when the layout manager is removed, or when
15992  * the actor is destroyed.
15993  *
15994  * Since: 1.10
15995  */
15996 void
15997 clutter_actor_set_layout_manager (ClutterActor         *self,
15998                                   ClutterLayoutManager *manager)
15999 {
16000   ClutterActorPrivate *priv;
16001
16002   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16003   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16004
16005   priv = self->priv;
16006
16007   if (priv->layout_manager != NULL)
16008     {
16009       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16010                                             G_CALLBACK (on_layout_manager_changed),
16011                                             self);
16012       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16013       g_clear_object (&priv->layout_manager);
16014     }
16015
16016   priv->layout_manager = manager;
16017
16018   if (priv->layout_manager != NULL)
16019     {
16020       g_object_ref_sink (priv->layout_manager);
16021       clutter_layout_manager_set_container (priv->layout_manager,
16022                                             CLUTTER_CONTAINER (self));
16023       g_signal_connect (priv->layout_manager, "layout-changed",
16024                         G_CALLBACK (on_layout_manager_changed),
16025                         self);
16026     }
16027
16028   clutter_actor_queue_relayout (self);
16029
16030   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16031 }
16032
16033 /**
16034  * clutter_actor_get_layout_manager:
16035  * @self: a #ClutterActor
16036  *
16037  * Retrieves the #ClutterLayoutManager used by @self.
16038  *
16039  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16040  *   or %NULL
16041  *
16042  * Since: 1.10
16043  */
16044 ClutterLayoutManager *
16045 clutter_actor_get_layout_manager (ClutterActor *self)
16046 {
16047   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16048
16049   return self->priv->layout_manager;
16050 }
16051
16052 static const ClutterLayoutInfo default_layout_info = {
16053   0.f,                          /* fixed-x */
16054   0.f,                          /* fixed-y */
16055   { 0, 0, 0, 0 },               /* margin */
16056   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16057   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16058   0.f, 0.f,                     /* min_width, natural_width */
16059   0.f, 0.f,                     /* natual_width, natural_height */
16060 };
16061
16062 static void
16063 layout_info_free (gpointer data)
16064 {
16065   if (G_LIKELY (data != NULL))
16066     g_slice_free (ClutterLayoutInfo, data);
16067 }
16068
16069 /*< private >
16070  * _clutter_actor_get_layout_info:
16071  * @self: a #ClutterActor
16072  *
16073  * Retrieves a pointer to the ClutterLayoutInfo structure.
16074  *
16075  * If the actor does not have a ClutterLayoutInfo associated to it, one
16076  * will be created and initialized to the default values.
16077  *
16078  * This function should be used for setters.
16079  *
16080  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16081  * instead.
16082  *
16083  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16084  */
16085 ClutterLayoutInfo *
16086 _clutter_actor_get_layout_info (ClutterActor *self)
16087 {
16088   ClutterLayoutInfo *retval;
16089
16090   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16091   if (retval == NULL)
16092     {
16093       retval = g_slice_new (ClutterLayoutInfo);
16094
16095       *retval = default_layout_info;
16096
16097       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16098                                retval,
16099                                layout_info_free);
16100     }
16101
16102   return retval;
16103 }
16104
16105 /*< private >
16106  * _clutter_actor_get_layout_info_or_defaults:
16107  * @self: a #ClutterActor
16108  *
16109  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16110  *
16111  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16112  * then the default structure will be returned.
16113  *
16114  * This function should only be used for getters.
16115  *
16116  * Return value: a const pointer to the ClutterLayoutInfo structure
16117  */
16118 const ClutterLayoutInfo *
16119 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16120 {
16121   const ClutterLayoutInfo *info;
16122
16123   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16124   if (info == NULL)
16125     return &default_layout_info;
16126
16127   return info;
16128 }
16129
16130 /**
16131  * clutter_actor_set_x_align:
16132  * @self: a #ClutterActor
16133  * @x_align: the horizontal alignment policy
16134  *
16135  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16136  * actor received extra horizontal space.
16137  *
16138  * See also the #ClutterActor:x-align property.
16139  *
16140  * Since: 1.10
16141  */
16142 void
16143 clutter_actor_set_x_align (ClutterActor      *self,
16144                            ClutterActorAlign  x_align)
16145 {
16146   ClutterLayoutInfo *info;
16147
16148   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16149
16150   info = _clutter_actor_get_layout_info (self);
16151
16152   if (info->x_align != x_align)
16153     {
16154       info->x_align = x_align;
16155
16156       clutter_actor_queue_relayout (self);
16157
16158       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16159     }
16160 }
16161
16162 /**
16163  * clutter_actor_get_x_align:
16164  * @self: a #ClutterActor
16165  *
16166  * Retrieves the horizontal alignment policy set using
16167  * clutter_actor_set_x_align().
16168  *
16169  * Return value: the horizontal alignment policy.
16170  *
16171  * Since: 1.10
16172  */
16173 ClutterActorAlign
16174 clutter_actor_get_x_align (ClutterActor *self)
16175 {
16176   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16177
16178   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16179 }
16180
16181 /**
16182  * clutter_actor_set_y_align:
16183  * @self: a #ClutterActor
16184  * @y_align: the vertical alignment policy
16185  *
16186  * Sets the vertical alignment policy of a #ClutterActor, in case the
16187  * actor received extra vertical space.
16188  *
16189  * See also the #ClutterActor:y-align property.
16190  *
16191  * Since: 1.10
16192  */
16193 void
16194 clutter_actor_set_y_align (ClutterActor      *self,
16195                            ClutterActorAlign  y_align)
16196 {
16197   ClutterLayoutInfo *info;
16198
16199   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16200
16201   info = _clutter_actor_get_layout_info (self);
16202
16203   if (info->y_align != y_align)
16204     {
16205       info->y_align = y_align;
16206
16207       clutter_actor_queue_relayout (self);
16208
16209       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16210     }
16211 }
16212
16213 /**
16214  * clutter_actor_get_y_align:
16215  * @self: a #ClutterActor
16216  *
16217  * Retrieves the vertical alignment policy set using
16218  * clutter_actor_set_y_align().
16219  *
16220  * Return value: the vertical alignment policy.
16221  *
16222  * Since: 1.10
16223  */
16224 ClutterActorAlign
16225 clutter_actor_get_y_align (ClutterActor *self)
16226 {
16227   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16228
16229   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16230 }
16231
16232
16233 /**
16234  * clutter_margin_new:
16235  *
16236  * Creates a new #ClutterMargin.
16237  *
16238  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16239  *   clutter_margin_free() to free the resources associated with it when
16240  *   done.
16241  *
16242  * Since: 1.10
16243  */
16244 ClutterMargin *
16245 clutter_margin_new (void)
16246 {
16247   return g_slice_new0 (ClutterMargin);
16248 }
16249
16250 /**
16251  * clutter_margin_copy:
16252  * @margin_: a #ClutterMargin
16253  *
16254  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16255  * the newly created structure.
16256  *
16257  * Return value: (transfer full): a copy of the #ClutterMargin.
16258  *
16259  * Since: 1.10
16260  */
16261 ClutterMargin *
16262 clutter_margin_copy (const ClutterMargin *margin_)
16263 {
16264   if (G_LIKELY (margin_ != NULL))
16265     return g_slice_dup (ClutterMargin, margin_);
16266
16267   return NULL;
16268 }
16269
16270 /**
16271  * clutter_margin_free:
16272  * @margin_: a #ClutterMargin
16273  *
16274  * Frees the resources allocated by clutter_margin_new() and
16275  * clutter_margin_copy().
16276  *
16277  * Since: 1.10
16278  */
16279 void
16280 clutter_margin_free (ClutterMargin *margin_)
16281 {
16282   if (G_LIKELY (margin_ != NULL))
16283     g_slice_free (ClutterMargin, margin_);
16284 }
16285
16286 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16287                      clutter_margin_copy,
16288                      clutter_margin_free)
16289
16290 /**
16291  * clutter_actor_set_margin:
16292  * @self: a #ClutterActor
16293  * @margin: a #ClutterMargin
16294  *
16295  * Sets all the components of the margin of a #ClutterActor.
16296  *
16297  * Since: 1.10
16298  */
16299 void
16300 clutter_actor_set_margin (ClutterActor        *self,
16301                           const ClutterMargin *margin)
16302 {
16303   ClutterLayoutInfo *info;
16304   gboolean changed;
16305   GObject *obj;
16306
16307   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16308   g_return_if_fail (margin != NULL);
16309
16310   obj = G_OBJECT (self);
16311   changed = FALSE;
16312
16313   g_object_freeze_notify (obj);
16314
16315   info = _clutter_actor_get_layout_info (self);
16316
16317   if (info->margin.top != margin->top)
16318     {
16319       info->margin.top = margin->top;
16320       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16321       changed = TRUE;
16322     }
16323
16324   if (info->margin.right != margin->right)
16325     {
16326       info->margin.right = margin->right;
16327       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16328       changed = TRUE;
16329     }
16330
16331   if (info->margin.bottom != margin->bottom)
16332     {
16333       info->margin.bottom = margin->bottom;
16334       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16335       changed = TRUE;
16336     }
16337
16338   if (info->margin.left != margin->left)
16339     {
16340       info->margin.left = margin->left;
16341       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16342       changed = TRUE;
16343     }
16344
16345   if (changed)
16346     clutter_actor_queue_relayout (self);
16347
16348   g_object_thaw_notify (obj);
16349 }
16350
16351 /**
16352  * clutter_actor_get_margin:
16353  * @self: a #ClutterActor
16354  * @margin: (out caller-allocates): return location for a #ClutterMargin
16355  *
16356  * Retrieves all the components of the margin of a #ClutterActor.
16357  *
16358  * Since: 1.10
16359  */
16360 void
16361 clutter_actor_get_margin (ClutterActor  *self,
16362                           ClutterMargin *margin)
16363 {
16364   const ClutterLayoutInfo *info;
16365
16366   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16367   g_return_if_fail (margin != NULL);
16368
16369   info = _clutter_actor_get_layout_info_or_defaults (self);
16370
16371   *margin = info->margin;
16372 }
16373
16374 /**
16375  * clutter_actor_set_margin_top:
16376  * @self: a #ClutterActor
16377  * @margin: the top margin
16378  *
16379  * Sets the margin from the top of a #ClutterActor.
16380  *
16381  * Since: 1.10
16382  */
16383 void
16384 clutter_actor_set_margin_top (ClutterActor *self,
16385                               gfloat        margin)
16386 {
16387   ClutterLayoutInfo *info;
16388
16389   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16390   g_return_if_fail (margin >= 0.f);
16391
16392   info = _clutter_actor_get_layout_info (self);
16393
16394   if (info->margin.top == margin)
16395     return;
16396
16397   info->margin.top = margin;
16398
16399   clutter_actor_queue_relayout (self);
16400
16401   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16402 }
16403
16404 /**
16405  * clutter_actor_get_margin_top:
16406  * @self: a #ClutterActor
16407  *
16408  * Retrieves the top margin of a #ClutterActor.
16409  *
16410  * Return value: the top margin
16411  *
16412  * Since: 1.10
16413  */
16414 gfloat
16415 clutter_actor_get_margin_top (ClutterActor *self)
16416 {
16417   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16418
16419   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16420 }
16421
16422 /**
16423  * clutter_actor_set_margin_bottom:
16424  * @self: a #ClutterActor
16425  * @margin: the bottom margin
16426  *
16427  * Sets the margin from the bottom of a #ClutterActor.
16428  *
16429  * Since: 1.10
16430  */
16431 void
16432 clutter_actor_set_margin_bottom (ClutterActor *self,
16433                                  gfloat        margin)
16434 {
16435   ClutterLayoutInfo *info;
16436
16437   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16438   g_return_if_fail (margin >= 0.f);
16439
16440   info = _clutter_actor_get_layout_info (self);
16441
16442   if (info->margin.bottom == margin)
16443     return;
16444
16445   info->margin.bottom = margin;
16446
16447   clutter_actor_queue_relayout (self);
16448
16449   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16450 }
16451
16452 /**
16453  * clutter_actor_get_margin_bottom:
16454  * @self: a #ClutterActor
16455  *
16456  * Retrieves the bottom margin of a #ClutterActor.
16457  *
16458  * Return value: the bottom margin
16459  *
16460  * Since: 1.10
16461  */
16462 gfloat
16463 clutter_actor_get_margin_bottom (ClutterActor *self)
16464 {
16465   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16466
16467   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16468 }
16469
16470 /**
16471  * clutter_actor_set_margin_left:
16472  * @self: a #ClutterActor
16473  * @margin: the left margin
16474  *
16475  * Sets the margin from the left of a #ClutterActor.
16476  *
16477  * Since: 1.10
16478  */
16479 void
16480 clutter_actor_set_margin_left (ClutterActor *self,
16481                                gfloat        margin)
16482 {
16483   ClutterLayoutInfo *info;
16484
16485   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16486   g_return_if_fail (margin >= 0.f);
16487
16488   info = _clutter_actor_get_layout_info (self);
16489
16490   if (info->margin.left == margin)
16491     return;
16492
16493   info->margin.left = margin;
16494
16495   clutter_actor_queue_relayout (self);
16496
16497   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16498 }
16499
16500 /**
16501  * clutter_actor_get_margin_left:
16502  * @self: a #ClutterActor
16503  *
16504  * Retrieves the left margin of a #ClutterActor.
16505  *
16506  * Return value: the left margin
16507  *
16508  * Since: 1.10
16509  */
16510 gfloat
16511 clutter_actor_get_margin_left (ClutterActor *self)
16512 {
16513   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16514
16515   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16516 }
16517
16518 /**
16519  * clutter_actor_set_margin_right:
16520  * @self: a #ClutterActor
16521  * @margin: the right margin
16522  *
16523  * Sets the margin from the right of a #ClutterActor.
16524  *
16525  * Since: 1.10
16526  */
16527 void
16528 clutter_actor_set_margin_right (ClutterActor *self,
16529                                 gfloat        margin)
16530 {
16531   ClutterLayoutInfo *info;
16532
16533   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16534   g_return_if_fail (margin >= 0.f);
16535
16536   info = _clutter_actor_get_layout_info (self);
16537
16538   if (info->margin.right == margin)
16539     return;
16540
16541   info->margin.right = margin;
16542
16543   clutter_actor_queue_relayout (self);
16544
16545   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16546 }
16547
16548 /**
16549  * clutter_actor_get_margin_right:
16550  * @self: a #ClutterActor
16551  *
16552  * Retrieves the right margin of a #ClutterActor.
16553  *
16554  * Return value: the right margin
16555  *
16556  * Since: 1.10
16557  */
16558 gfloat
16559 clutter_actor_get_margin_right (ClutterActor *self)
16560 {
16561   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16562
16563   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16564 }
16565
16566 static inline void
16567 clutter_actor_set_background_color_internal (ClutterActor *self,
16568                                              const ClutterColor *color)
16569 {
16570   ClutterActorPrivate *priv = self->priv;
16571   GObject *obj;
16572
16573   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16574     return;
16575
16576   obj = G_OBJECT (self);
16577
16578   priv->bg_color = *color;
16579   priv->bg_color_set = TRUE;
16580
16581   clutter_actor_queue_redraw (self);
16582
16583   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16584   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16585 }
16586
16587 /**
16588  * clutter_actor_set_background_color:
16589  * @self: a #ClutterActor
16590  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16591  *  set color
16592  *
16593  * Sets the background color of a #ClutterActor.
16594  *
16595  * The background color will be used to cover the whole allocation of the
16596  * actor. The default background color of an actor is transparent.
16597  *
16598  * To check whether an actor has a background color, you can use the
16599  * #ClutterActor:background-color-set actor property.
16600  *
16601  * The #ClutterActor:background-color property is animatable.
16602  *
16603  * Since: 1.10
16604  */
16605 void
16606 clutter_actor_set_background_color (ClutterActor       *self,
16607                                     const ClutterColor *color)
16608 {
16609   ClutterActorPrivate *priv;
16610   GObject *obj;
16611   GParamSpec *bg_color_pspec;
16612
16613   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16614
16615   obj = G_OBJECT (self);
16616
16617   priv = self->priv;
16618
16619   if (color == NULL)
16620     {
16621       priv->bg_color_set = FALSE;
16622       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16623       clutter_actor_queue_redraw (self);
16624       return;
16625     }
16626
16627   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16628   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16629     {
16630       _clutter_actor_create_transition (self, bg_color_pspec,
16631                                         &priv->bg_color,
16632                                         color);
16633     }
16634   else
16635     _clutter_actor_update_transition (self, bg_color_pspec, color);
16636
16637   clutter_actor_queue_redraw (self);
16638 }
16639
16640 /**
16641  * clutter_actor_get_background_color:
16642  * @self: a #ClutterActor
16643  * @color: (out caller-allocates): return location for a #ClutterColor
16644  *
16645  * Retrieves the color set using clutter_actor_set_background_color().
16646  *
16647  * Since: 1.10
16648  */
16649 void
16650 clutter_actor_get_background_color (ClutterActor *self,
16651                                     ClutterColor *color)
16652 {
16653   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16654   g_return_if_fail (color != NULL);
16655
16656   *color = self->priv->bg_color;
16657 }
16658
16659 /**
16660  * clutter_actor_get_previous_sibling:
16661  * @self: a #ClutterActor
16662  *
16663  * Retrieves the sibling of @self that comes before it in the list
16664  * of children of @self's parent.
16665  *
16666  * The returned pointer is only valid until the scene graph changes; it
16667  * is not safe to modify the list of children of @self while iterating
16668  * it.
16669  *
16670  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16671  *
16672  * Since: 1.10
16673  */
16674 ClutterActor *
16675 clutter_actor_get_previous_sibling (ClutterActor *self)
16676 {
16677   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16678
16679   return self->priv->prev_sibling;
16680 }
16681
16682 /**
16683  * clutter_actor_get_next_sibling:
16684  * @self: a #ClutterActor
16685  *
16686  * Retrieves the sibling of @self that comes after it in the list
16687  * of children of @self's parent.
16688  *
16689  * The returned pointer is only valid until the scene graph changes; it
16690  * is not safe to modify the list of children of @self while iterating
16691  * it.
16692  *
16693  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16694  *
16695  * Since: 1.10
16696  */
16697 ClutterActor *
16698 clutter_actor_get_next_sibling (ClutterActor *self)
16699 {
16700   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16701
16702   return self->priv->next_sibling;
16703 }
16704
16705 /**
16706  * clutter_actor_get_first_child:
16707  * @self: a #ClutterActor
16708  *
16709  * Retrieves the first child of @self.
16710  *
16711  * The returned pointer is only valid until the scene graph changes; it
16712  * is not safe to modify the list of children of @self while iterating
16713  * it.
16714  *
16715  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16716  *
16717  * Since: 1.10
16718  */
16719 ClutterActor *
16720 clutter_actor_get_first_child (ClutterActor *self)
16721 {
16722   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16723
16724   return self->priv->first_child;
16725 }
16726
16727 /**
16728  * clutter_actor_get_last_child:
16729  * @self: a #ClutterActor
16730  *
16731  * Retrieves the last child of @self.
16732  *
16733  * The returned pointer is only valid until the scene graph changes; it
16734  * is not safe to modify the list of children of @self while iterating
16735  * it.
16736  *
16737  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16738  *
16739  * Since: 1.10
16740  */
16741 ClutterActor *
16742 clutter_actor_get_last_child (ClutterActor *self)
16743 {
16744   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16745
16746   return self->priv->last_child;
16747 }
16748
16749 /* easy way to have properly named fields instead of the dummy ones
16750  * we use in the public structure
16751  */
16752 typedef struct _RealActorIter
16753 {
16754   ClutterActor *root;           /* dummy1 */
16755   ClutterActor *current;        /* dummy2 */
16756   gpointer padding_1;           /* dummy3 */
16757   gint age;                     /* dummy4 */
16758   gpointer padding_2;           /* dummy5 */
16759 } RealActorIter;
16760
16761 /**
16762  * clutter_actor_iter_init:
16763  * @iter: a #ClutterActorIter
16764  * @root: a #ClutterActor
16765  *
16766  * Initializes a #ClutterActorIter, which can then be used to iterate
16767  * efficiently over a section of the scene graph, and associates it
16768  * with @root.
16769  *
16770  * Modifying the scene graph section that contains @root will invalidate
16771  * the iterator.
16772  *
16773  * |[
16774  *   ClutterActorIter iter;
16775  *   ClutterActor *child;
16776  *
16777  *   clutter_actor_iter_init (&iter, container);
16778  *   while (clutter_actor_iter_next (&iter, &child))
16779  *     {
16780  *       /&ast; do something with child &ast;/
16781  *     }
16782  * ]|
16783  *
16784  * Since: 1.10
16785  */
16786 void
16787 clutter_actor_iter_init (ClutterActorIter *iter,
16788                          ClutterActor     *root)
16789 {
16790   RealActorIter *ri = (RealActorIter *) iter;
16791
16792   g_return_if_fail (iter != NULL);
16793   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16794
16795   ri->root = root;
16796   ri->current = NULL;
16797   ri->age = root->priv->age;
16798 }
16799
16800 /**
16801  * clutter_actor_iter_next:
16802  * @iter: a #ClutterActorIter
16803  * @child: (out): return location for a #ClutterActor
16804  *
16805  * Advances the @iter and retrieves the next child of the root #ClutterActor
16806  * that was used to initialize the #ClutterActorIterator.
16807  *
16808  * If the iterator can advance, this function returns %TRUE and sets the
16809  * @child argument.
16810  *
16811  * If the iterator cannot advance, this function returns %FALSE, and
16812  * the contents of @child are undefined.
16813  *
16814  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16815  *
16816  * Since: 1.10
16817  */
16818 gboolean
16819 clutter_actor_iter_next (ClutterActorIter  *iter,
16820                          ClutterActor     **child)
16821 {
16822   RealActorIter *ri = (RealActorIter *) iter;
16823
16824   g_return_val_if_fail (iter != NULL, FALSE);
16825   g_return_val_if_fail (ri->root != NULL, FALSE);
16826 #ifndef G_DISABLE_ASSERT
16827   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16828 #endif
16829
16830   if (ri->current == NULL)
16831     ri->current = ri->root->priv->first_child;
16832   else
16833     ri->current = ri->current->priv->next_sibling;
16834
16835   if (child != NULL)
16836     *child = ri->current;
16837
16838   return ri->current != NULL;
16839 }
16840
16841 /**
16842  * clutter_actor_iter_prev:
16843  * @iter: a #ClutterActorIter
16844  * @child: (out): return location for a #ClutterActor
16845  *
16846  * Advances the @iter and retrieves the previous child of the root
16847  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16848  *
16849  * If the iterator can advance, this function returns %TRUE and sets the
16850  * @child argument.
16851  *
16852  * If the iterator cannot advance, this function returns %FALSE, and
16853  * the contents of @child are undefined.
16854  *
16855  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16856  *
16857  * Since: 1.10
16858  */
16859 gboolean
16860 clutter_actor_iter_prev (ClutterActorIter  *iter,
16861                          ClutterActor     **child)
16862 {
16863   RealActorIter *ri = (RealActorIter *) iter;
16864
16865   g_return_val_if_fail (iter != NULL, FALSE);
16866   g_return_val_if_fail (ri->root != NULL, FALSE);
16867 #ifndef G_DISABLE_ASSERT
16868   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16869 #endif
16870
16871   if (ri->current == NULL)
16872     ri->current = ri->root->priv->last_child;
16873   else
16874     ri->current = ri->current->priv->prev_sibling;
16875
16876   if (child != NULL)
16877     *child = ri->current;
16878
16879   return ri->current != NULL;
16880 }
16881
16882 /**
16883  * clutter_actor_iter_remove:
16884  * @iter: a #ClutterActorIter
16885  *
16886  * Safely removes the #ClutterActor currently pointer to by the iterator
16887  * from its parent.
16888  *
16889  * This function can only be called after clutter_actor_iter_next() or
16890  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16891  * than once for the same actor.
16892  *
16893  * This function will call clutter_actor_remove_child() internally.
16894  *
16895  * Since: 1.10
16896  */
16897 void
16898 clutter_actor_iter_remove (ClutterActorIter *iter)
16899 {
16900   RealActorIter *ri = (RealActorIter *) iter;
16901   ClutterActor *cur;
16902
16903   g_return_if_fail (iter != NULL);
16904   g_return_if_fail (ri->root != NULL);
16905 #ifndef G_DISABLE_ASSERT
16906   g_return_if_fail (ri->age == ri->root->priv->age);
16907 #endif
16908   g_return_if_fail (ri->current != NULL);
16909
16910   cur = ri->current;
16911
16912   if (cur != NULL)
16913     {
16914       ri->current = cur->priv->prev_sibling;
16915
16916       clutter_actor_remove_child_internal (ri->root, cur,
16917                                            REMOVE_CHILD_DEFAULT_FLAGS);
16918
16919       ri->age += 1;
16920     }
16921 }
16922
16923 /**
16924  * clutter_actor_iter_destroy:
16925  * @iter: a #ClutterActorIter
16926  *
16927  * Safely destroys the #ClutterActor currently pointer to by the iterator
16928  * from its parent.
16929  *
16930  * This function can only be called after clutter_actor_iter_next() or
16931  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16932  * than once for the same actor.
16933  *
16934  * This function will call clutter_actor_destroy() internally.
16935  *
16936  * Since: 1.10
16937  */
16938 void
16939 clutter_actor_iter_destroy (ClutterActorIter *iter)
16940 {
16941   RealActorIter *ri = (RealActorIter *) iter;
16942   ClutterActor *cur;
16943
16944   g_return_if_fail (iter != NULL);
16945   g_return_if_fail (ri->root != NULL);
16946 #ifndef G_DISABLE_ASSERT
16947   g_return_if_fail (ri->age == ri->root->priv->age);
16948 #endif
16949   g_return_if_fail (ri->current != NULL);
16950
16951   cur = ri->current;
16952
16953   if (cur != NULL)
16954     {
16955       ri->current = cur->priv->prev_sibling;
16956
16957       clutter_actor_destroy (cur);
16958
16959       ri->age += 1;
16960     }
16961 }
16962
16963 static const ClutterAnimationInfo default_animation_info = {
16964   NULL,         /* transitions */
16965   NULL,         /* states */
16966   NULL,         /* cur_state */
16967 };
16968
16969 static void
16970 clutter_animation_info_free (gpointer data)
16971 {
16972   if (data != NULL)
16973     {
16974       ClutterAnimationInfo *info = data;
16975
16976       if (info->transitions != NULL)
16977         g_hash_table_unref (info->transitions);
16978
16979       if (info->states != NULL)
16980         g_array_unref (info->states);
16981
16982       g_slice_free (ClutterAnimationInfo, info);
16983     }
16984 }
16985
16986 const ClutterAnimationInfo *
16987 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16988 {
16989   const ClutterAnimationInfo *res;
16990   GObject *obj = G_OBJECT (self);
16991
16992   res = g_object_get_qdata (obj, quark_actor_animation_info);
16993   if (res != NULL)
16994     return res;
16995
16996   return &default_animation_info;
16997 }
16998
16999 ClutterAnimationInfo *
17000 _clutter_actor_get_animation_info (ClutterActor *self)
17001 {
17002   GObject *obj = G_OBJECT (self);
17003   ClutterAnimationInfo *res;
17004
17005   res = g_object_get_qdata (obj, quark_actor_animation_info);
17006   if (res == NULL)
17007     {
17008       res = g_slice_new (ClutterAnimationInfo);
17009
17010       *res = default_animation_info;
17011
17012       g_object_set_qdata_full (obj, quark_actor_animation_info,
17013                                res,
17014                                clutter_animation_info_free);
17015     }
17016
17017   return res;
17018 }
17019
17020 ClutterTransition *
17021 _clutter_actor_get_transition (ClutterActor *actor,
17022                                GParamSpec   *pspec)
17023 {
17024   const ClutterAnimationInfo *info;
17025
17026   info = _clutter_actor_get_animation_info_or_defaults (actor);
17027
17028   if (info->transitions == NULL)
17029     return NULL;
17030
17031   return g_hash_table_lookup (info->transitions, pspec->name);
17032 }
17033
17034 typedef struct _TransitionClosure
17035 {
17036   ClutterActor *actor;
17037   ClutterTransition *transition;
17038   gchar *name;
17039   gulong completed_id;
17040 } TransitionClosure;
17041
17042 static void
17043 transition_closure_free (gpointer data)
17044 {
17045   if (G_LIKELY (data != NULL))
17046     {
17047       TransitionClosure *clos = data;
17048       ClutterTimeline *timeline;
17049
17050       timeline = CLUTTER_TIMELINE (clos->transition);
17051
17052       if (clutter_timeline_is_playing (timeline))
17053         clutter_timeline_stop (timeline);
17054
17055       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17056
17057       g_object_unref (clos->transition);
17058       g_free (clos->name);
17059
17060       g_slice_free (TransitionClosure, clos);
17061     }
17062 }
17063
17064 static void
17065 on_transition_completed (ClutterTransition *transition,
17066                          TransitionClosure *clos)
17067 {
17068   ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17069   ClutterActor *actor = clos->actor;
17070   ClutterAnimationInfo *info;
17071   gint n_repeats, cur_repeat;
17072
17073   info = _clutter_actor_get_animation_info (actor);
17074
17075   /* reset the caches used by animations */
17076   clutter_actor_store_content_box (actor, NULL);
17077
17078   /* ensure that we remove the transition only at the end
17079    * of its run; we emit ::completed for every repeat
17080    */
17081   n_repeats = clutter_timeline_get_repeat_count (timeline);
17082   cur_repeat = clutter_timeline_get_current_repeat (timeline);
17083
17084   if (cur_repeat == n_repeats)
17085     {
17086       if (clutter_transition_get_remove_on_complete (transition))
17087         {
17088           /* we take a reference here because removing the closure
17089            * will release the reference on the transition, and we
17090            * want the transition to survive the signal emission;
17091            * the master clock will release the last reference at
17092            * the end of the frame processing.
17093            */
17094           g_object_ref (transition);
17095           g_hash_table_remove (info->transitions, clos->name);
17096         }
17097     }
17098
17099   /* if it's the last transition then we clean up */
17100   if (g_hash_table_size (info->transitions) == 0)
17101     {
17102       g_hash_table_unref (info->transitions);
17103       info->transitions = NULL;
17104
17105       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17106                     _clutter_actor_get_debug_name (actor));
17107
17108       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17109     }
17110 }
17111
17112 void
17113 _clutter_actor_update_transition (ClutterActor *actor,
17114                                   GParamSpec   *pspec,
17115                                   ...)
17116 {
17117   TransitionClosure *clos;
17118   ClutterTimeline *timeline;
17119   ClutterInterval *interval;
17120   const ClutterAnimationInfo *info;
17121   va_list var_args;
17122   GType ptype;
17123   GValue initial = G_VALUE_INIT;
17124   GValue final = G_VALUE_INIT;
17125   char *error = NULL;
17126
17127   info = _clutter_actor_get_animation_info_or_defaults (actor);
17128
17129   if (info->transitions == NULL)
17130     return;
17131
17132   clos = g_hash_table_lookup (info->transitions, pspec->name);
17133   if (clos == NULL)
17134     return;
17135
17136   timeline = CLUTTER_TIMELINE (clos->transition);
17137
17138   va_start (var_args, pspec);
17139
17140   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17141
17142   g_value_init (&initial, ptype);
17143   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17144                                         pspec->name,
17145                                         &initial);
17146
17147   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17148   if (error != NULL)
17149     {
17150       g_critical ("%s: %s", G_STRLOC, error);
17151       g_free (error);
17152       goto out;
17153     }
17154
17155   interval = clutter_transition_get_interval (clos->transition);
17156   clutter_interval_set_initial_value (interval, &initial);
17157   clutter_interval_set_final_value (interval, &final);
17158
17159   /* if we're updating with an easing duration of zero milliseconds,
17160    * we just jump the timeline to the end and let it run its course
17161    */
17162   if (info->cur_state != NULL &&
17163       info->cur_state->easing_duration != 0)
17164     {
17165       guint cur_duration = clutter_timeline_get_duration (timeline);
17166       ClutterAnimationMode cur_mode =
17167         clutter_timeline_get_progress_mode (timeline);
17168
17169       if (cur_duration != info->cur_state->easing_duration)
17170         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17171
17172       if (cur_mode != info->cur_state->easing_mode)
17173         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17174
17175       clutter_timeline_rewind (timeline);
17176     }
17177   else
17178     {
17179       guint duration = clutter_timeline_get_duration (timeline);
17180
17181       clutter_timeline_advance (timeline, duration);
17182     }
17183
17184 out:
17185   g_value_unset (&initial);
17186   g_value_unset (&final);
17187
17188   va_end (var_args);
17189 }
17190
17191 /*< private >*
17192  * _clutter_actor_create_transition:
17193  * @actor: a #ClutterActor
17194  * @pspec: the property used for the transition
17195  * @...: initial and final state
17196  *
17197  * Creates a #ClutterTransition for the property represented by @pspec.
17198  *
17199  * Return value: a #ClutterTransition
17200  */
17201 ClutterTransition *
17202 _clutter_actor_create_transition (ClutterActor *actor,
17203                                   GParamSpec   *pspec,
17204                                   ...)
17205 {
17206   ClutterAnimationInfo *info;
17207   ClutterTransition *res = NULL;
17208   gboolean call_restore = FALSE;
17209   TransitionClosure *clos;
17210   va_list var_args;
17211
17212   info = _clutter_actor_get_animation_info (actor);
17213
17214   /* XXX - this will go away in 2.0
17215    *
17216    * if no state has been pushed, we assume that the easing state is
17217    * in "compatibility mode": all transitions have a duration of 0
17218    * msecs, which means that they happen immediately. in Clutter 2.0
17219    * this will turn into a g_assert(info->states != NULL), as every
17220    * actor will start with a predefined easing state
17221    */
17222   if (info->states == NULL)
17223     {
17224       clutter_actor_save_easing_state (actor);
17225       clutter_actor_set_easing_duration (actor, 0);
17226       call_restore = TRUE;
17227     }
17228
17229   if (info->transitions == NULL)
17230     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17231                                                NULL,
17232                                                transition_closure_free);
17233
17234   va_start (var_args, pspec);
17235
17236   clos = g_hash_table_lookup (info->transitions, pspec->name);
17237   if (clos == NULL)
17238     {
17239       ClutterInterval *interval;
17240       GValue initial = G_VALUE_INIT;
17241       GValue final = G_VALUE_INIT;
17242       GType ptype;
17243       char *error;
17244
17245       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17246
17247       G_VALUE_COLLECT_INIT (&initial, ptype,
17248                             var_args, 0,
17249                             &error);
17250       if (error != NULL)
17251         {
17252           g_critical ("%s: %s", G_STRLOC, error);
17253           g_free (error);
17254           goto out;
17255         }
17256
17257       G_VALUE_COLLECT_INIT (&final, ptype,
17258                             var_args, 0,
17259                             &error);
17260
17261       if (error != NULL)
17262         {
17263           g_critical ("%s: %s", G_STRLOC, error);
17264           g_value_unset (&initial);
17265           g_free (error);
17266           goto out;
17267         }
17268
17269       /* if the current easing state has a duration of 0, then we don't
17270        * bother to create the transition, and we just set the final value
17271        * directly on the actor; we don't go through the Animatable
17272        * interface because we know we got here through an animatable
17273        * property.
17274        */
17275       if (info->cur_state->easing_duration == 0)
17276         {
17277           clutter_actor_set_animatable_property (actor,
17278                                                  pspec->param_id,
17279                                                  &final,
17280                                                  pspec);
17281           g_value_unset (&initial);
17282           g_value_unset (&final);
17283
17284           goto out;
17285         }
17286
17287       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17288
17289       g_value_unset (&initial);
17290       g_value_unset (&final);
17291
17292       res = clutter_property_transition_new (pspec->name);
17293
17294       clutter_transition_set_interval (res, interval);
17295       clutter_transition_set_remove_on_complete (res, TRUE);
17296
17297       /* this will start the transition as well */
17298       clutter_actor_add_transition (actor, pspec->name, res);
17299
17300       /* the actor now owns the transition */
17301       g_object_unref (res);
17302     }
17303   else
17304     res = clos->transition;
17305
17306 out:
17307   if (call_restore)
17308     clutter_actor_restore_easing_state (actor);
17309
17310   va_end (var_args);
17311
17312   return res;
17313 }
17314
17315 /**
17316  * clutter_actor_add_transition:
17317  * @self: a #ClutterActor
17318  * @name: the name of the transition to add
17319  * @transition: the #ClutterTransition to add
17320  *
17321  * Adds a @transition to the #ClutterActor's list of animations.
17322  *
17323  * The @name string is a per-actor unique identifier of the @transition: only
17324  * one #ClutterTransition can be associated to the specified @name.
17325  *
17326  * The @transition will be given the easing duration, mode, and delay
17327  * associated to the actor's current easing state; it is possible to modify
17328  * these values after calling clutter_actor_add_transition().
17329  *
17330  * The @transition will be started once added.
17331  *
17332  * This function will take a reference on the @transition.
17333  *
17334  * This function is usually called implicitly when modifying an animatable
17335  * property.
17336  *
17337  * Since: 1.10
17338  */
17339 void
17340 clutter_actor_add_transition (ClutterActor      *self,
17341                               const char        *name,
17342                               ClutterTransition *transition)
17343 {
17344   ClutterTimeline *timeline;
17345   TransitionClosure *clos;
17346   ClutterAnimationInfo *info;
17347
17348   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17349   g_return_if_fail (name != NULL);
17350   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17351
17352   info = _clutter_actor_get_animation_info (self);
17353
17354   if (info->cur_state == NULL)
17355     {
17356       g_warning ("No easing state is defined for the actor '%s'; you "
17357                  "must call clutter_actor_save_easing_state() before "
17358                  "calling clutter_actor_add_transition().",
17359                  _clutter_actor_get_debug_name (self));
17360       return;
17361     }
17362
17363   if (info->transitions == NULL)
17364     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17365                                                NULL,
17366                                                transition_closure_free);
17367
17368   if (g_hash_table_lookup (info->transitions, name) != NULL)
17369     {
17370       g_warning ("A transition with name '%s' already exists for "
17371                  "the actor '%s'",
17372                  name,
17373                  _clutter_actor_get_debug_name (self));
17374       return;
17375     }
17376
17377   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17378
17379   timeline = CLUTTER_TIMELINE (transition);
17380
17381   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17382   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17383   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17384
17385   clos = g_slice_new (TransitionClosure);
17386   clos->actor = self;
17387   clos->transition = g_object_ref (transition);
17388   clos->name = g_strdup (name);
17389   clos->completed_id = g_signal_connect (timeline, "completed",
17390                                          G_CALLBACK (on_transition_completed),
17391                                          clos);
17392
17393   CLUTTER_NOTE (ANIMATION,
17394                 "Adding transition '%s' [%p] to actor '%s'",
17395                 clos->name,
17396                 clos->transition,
17397                 _clutter_actor_get_debug_name (self));
17398
17399   g_hash_table_insert (info->transitions, clos->name, clos);
17400   clutter_timeline_start (timeline);
17401 }
17402
17403 /**
17404  * clutter_actor_remove_transition:
17405  * @self: a #ClutterActor
17406  * @name: the name of the transition to remove
17407  *
17408  * Removes the transition stored inside a #ClutterActor using @name
17409  * identifier.
17410  *
17411  * If the transition is currently in progress, it will be stopped.
17412  *
17413  * This function releases the reference acquired when the transition
17414  * was added to the #ClutterActor.
17415  *
17416  * Since: 1.10
17417  */
17418 void
17419 clutter_actor_remove_transition (ClutterActor *self,
17420                                  const char   *name)
17421 {
17422   const ClutterAnimationInfo *info;
17423
17424   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17425   g_return_if_fail (name != NULL);
17426
17427   info = _clutter_actor_get_animation_info_or_defaults (self);
17428
17429   if (info->transitions == NULL)
17430     return;
17431
17432   g_hash_table_remove (info->transitions, name);
17433 }
17434
17435 /**
17436  * clutter_actor_remove_all_transitions:
17437  * @self: a #ClutterActor
17438  *
17439  * Removes all transitions associated to @self.
17440  *
17441  * Since: 1.10
17442  */
17443 void
17444 clutter_actor_remove_all_transitions (ClutterActor *self)
17445 {
17446   const ClutterAnimationInfo *info;
17447
17448   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17449
17450   info = _clutter_actor_get_animation_info_or_defaults (self);
17451   if (info->transitions == NULL)
17452     return;
17453
17454   g_hash_table_remove_all (info->transitions);
17455 }
17456
17457 /**
17458  * clutter_actor_set_easing_duration:
17459  * @self: a #ClutterActor
17460  * @msecs: the duration of the easing, or %NULL
17461  *
17462  * Sets the duration of the tweening for animatable properties
17463  * of @self for the current easing state.
17464  *
17465  * Since: 1.10
17466  */
17467 void
17468 clutter_actor_set_easing_duration (ClutterActor *self,
17469                                    guint         msecs)
17470 {
17471   ClutterAnimationInfo *info;
17472
17473   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17474
17475   info = _clutter_actor_get_animation_info (self);
17476
17477   if (info->cur_state == NULL)
17478     {
17479       g_warning ("You must call clutter_actor_save_easing_state() prior "
17480                  "to calling clutter_actor_set_easing_duration().");
17481       return;
17482     }
17483
17484   if (info->cur_state->easing_duration != msecs)
17485     info->cur_state->easing_duration = msecs;
17486 }
17487
17488 /**
17489  * clutter_actor_get_easing_duration:
17490  * @self: a #ClutterActor
17491  *
17492  * Retrieves the duration of the tweening for animatable
17493  * properties of @self for the current easing state.
17494  *
17495  * Return value: the duration of the tweening, in milliseconds
17496  *
17497  * Since: 1.10
17498  */
17499 guint
17500 clutter_actor_get_easing_duration (ClutterActor *self)
17501 {
17502   const ClutterAnimationInfo *info;
17503
17504   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17505
17506   info = _clutter_actor_get_animation_info_or_defaults (self);
17507
17508   if (info->cur_state != NULL)
17509     return info->cur_state->easing_duration;
17510
17511   return 0;
17512 }
17513
17514 /**
17515  * clutter_actor_set_easing_mode:
17516  * @self: a #ClutterActor
17517  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17518  *
17519  * Sets the easing mode for the tweening of animatable properties
17520  * of @self.
17521  *
17522  * Since: 1.10
17523  */
17524 void
17525 clutter_actor_set_easing_mode (ClutterActor         *self,
17526                                ClutterAnimationMode  mode)
17527 {
17528   ClutterAnimationInfo *info;
17529
17530   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17531   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17532   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17533
17534   info = _clutter_actor_get_animation_info (self);
17535
17536   if (info->cur_state == NULL)
17537     {
17538       g_warning ("You must call clutter_actor_save_easing_state() prior "
17539                  "to calling clutter_actor_set_easing_mode().");
17540       return;
17541     }
17542
17543   if (info->cur_state->easing_mode != mode)
17544     info->cur_state->easing_mode = mode;
17545 }
17546
17547 /**
17548  * clutter_actor_get_easing_mode:
17549  * @self: a #ClutterActor
17550  *
17551  * Retrieves the easing mode for the tweening of animatable properties
17552  * of @self for the current easing state.
17553  *
17554  * Return value: an easing mode
17555  *
17556  * Since: 1.10
17557  */
17558 ClutterAnimationMode
17559 clutter_actor_get_easing_mode (ClutterActor *self)
17560 {
17561   const ClutterAnimationInfo *info;
17562
17563   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17564
17565   info = _clutter_actor_get_animation_info_or_defaults (self);
17566
17567   if (info->cur_state != NULL)
17568     return info->cur_state->easing_mode;
17569
17570   return CLUTTER_EASE_OUT_CUBIC;
17571 }
17572
17573 /**
17574  * clutter_actor_set_easing_delay:
17575  * @self: a #ClutterActor
17576  * @msecs: the delay before the start of the tweening, in milliseconds
17577  *
17578  * Sets the delay that should be applied before tweening animatable
17579  * properties.
17580  *
17581  * Since: 1.10
17582  */
17583 void
17584 clutter_actor_set_easing_delay (ClutterActor *self,
17585                                 guint         msecs)
17586 {
17587   ClutterAnimationInfo *info;
17588
17589   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17590
17591   info = _clutter_actor_get_animation_info (self);
17592
17593   if (info->cur_state == NULL)
17594     {
17595       g_warning ("You must call clutter_actor_save_easing_state() prior "
17596                  "to calling clutter_actor_set_easing_delay().");
17597       return;
17598     }
17599
17600   if (info->cur_state->easing_delay != msecs)
17601     info->cur_state->easing_delay = msecs;
17602 }
17603
17604 /**
17605  * clutter_actor_get_easing_delay:
17606  * @self: a #ClutterActor
17607  *
17608  * Retrieves the delay that should be applied when tweening animatable
17609  * properties.
17610  *
17611  * Return value: a delay, in milliseconds
17612  *
17613  * Since: 1.10
17614  */
17615 guint
17616 clutter_actor_get_easing_delay (ClutterActor *self)
17617 {
17618   const ClutterAnimationInfo *info;
17619
17620   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17621
17622   info = _clutter_actor_get_animation_info_or_defaults (self);
17623
17624   if (info->cur_state != NULL)
17625     return info->cur_state->easing_delay;
17626
17627   return 0;
17628 }
17629
17630 /**
17631  * clutter_actor_get_transition:
17632  * @self: a #ClutterActor
17633  * @name: the name of the transition
17634  *
17635  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17636  * transition @name.
17637  *
17638  * Transitions created for animatable properties use the name of the
17639  * property itself, for instance the code below:
17640  *
17641  * |[
17642  *   clutter_actor_set_easing_duration (actor, 1000);
17643  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17644  *
17645  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17646  *   g_signal_connect (transition, "completed",
17647  *                     G_CALLBACK (on_transition_complete),
17648  *                     actor);
17649  * ]|
17650  *
17651  * will call the <function>on_transition_complete</function> callback when
17652  * the transition is complete.
17653  *
17654  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17655  *   was found to match the passed name; the returned instance is owned
17656  *   by Clutter and it should not be freed
17657  *
17658  * Since: 1.10
17659  */
17660 ClutterTransition *
17661 clutter_actor_get_transition (ClutterActor *self,
17662                               const char   *name)
17663 {
17664   TransitionClosure *clos;
17665   const ClutterAnimationInfo *info;
17666
17667   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17668   g_return_val_if_fail (name != NULL, NULL);
17669
17670   info = _clutter_actor_get_animation_info_or_defaults (self);
17671   if (info->transitions == NULL)
17672     return NULL;
17673
17674   clos = g_hash_table_lookup (info->transitions, name);
17675   if (clos == NULL)
17676     return NULL;
17677
17678   return clos->transition;
17679 }
17680
17681 /**
17682  * clutter_actor_save_easing_state:
17683  * @self: a #ClutterActor
17684  *
17685  * Saves the current easing state for animatable properties, and creates
17686  * a new state with the default values for easing mode and duration.
17687  *
17688  * Since: 1.10
17689  */
17690 void
17691 clutter_actor_save_easing_state (ClutterActor *self)
17692 {
17693   ClutterAnimationInfo *info;
17694   AState new_state;
17695
17696   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17697
17698   info = _clutter_actor_get_animation_info (self);
17699
17700   if (info->states == NULL)
17701     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17702
17703   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17704   new_state.easing_duration = 250;
17705   new_state.easing_delay = 0;
17706
17707   g_array_append_val (info->states, new_state);
17708
17709   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17710 }
17711
17712 /**
17713  * clutter_actor_restore_easing_state:
17714  * @self: a #ClutterActor
17715  *
17716  * Restores the easing state as it was prior to a call to
17717  * clutter_actor_save_easing_state().
17718  *
17719  * Since: 1.10
17720  */
17721 void
17722 clutter_actor_restore_easing_state (ClutterActor *self)
17723 {
17724   ClutterAnimationInfo *info;
17725
17726   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17727
17728   info = _clutter_actor_get_animation_info (self);
17729
17730   if (info->states == NULL)
17731     {
17732       g_critical ("The function clutter_actor_restore_easing_state() has "
17733                   "called without a previous call to "
17734                   "clutter_actor_save_easing_state().");
17735       return;
17736     }
17737
17738   g_array_remove_index (info->states, info->states->len - 1);
17739
17740   if (info->states->len > 0)
17741     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17742   else
17743     {
17744       g_array_unref (info->states);
17745       info->states = NULL;
17746       info->cur_state = NULL;
17747     }
17748 }
17749
17750 /**
17751  * clutter_actor_set_content:
17752  * @self: a #ClutterActor
17753  * @content: (allow-none): a #ClutterContent, or %NULL
17754  *
17755  * Sets the contents of a #ClutterActor.
17756  *
17757  * Since: 1.10
17758  */
17759 void
17760 clutter_actor_set_content (ClutterActor   *self,
17761                            ClutterContent *content)
17762 {
17763   ClutterActorPrivate *priv;
17764
17765   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17766   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17767
17768   priv = self->priv;
17769
17770   if (priv->content != NULL)
17771     {
17772       _clutter_content_detached (priv->content, self);
17773       g_clear_object (&priv->content);
17774     }
17775
17776   priv->content = content;
17777
17778   if (priv->content != NULL)
17779     {
17780       g_object_ref (priv->content);
17781       _clutter_content_attached (priv->content, self);
17782     }
17783
17784   /* given that the content is always painted within the allocation,
17785    * we only need to queue a redraw here
17786    */
17787   clutter_actor_queue_redraw (self);
17788
17789   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17790
17791   /* if the content gravity is not resize-fill, and the new content has a
17792    * different preferred size than the previous one, then the content box
17793    * may have been changed. since we compute that lazily, we just notify
17794    * here, and let whomever watches :content-box do whatever they need to
17795    * do.
17796    */
17797   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17798     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17799 }
17800
17801 /**
17802  * clutter_actor_get_content:
17803  * @self: a #ClutterActor
17804  *
17805  * Retrieves the contents of @self.
17806  *
17807  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17808  *   or %NULL if none was set
17809  *
17810  * Since: 1.10
17811  */
17812 ClutterContent *
17813 clutter_actor_get_content (ClutterActor *self)
17814 {
17815   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17816
17817   return self->priv->content;
17818 }
17819
17820 /**
17821  * clutter_actor_set_content_gravity:
17822  * @self: a #ClutterActor
17823  * @gravity: the #ClutterContentGravity
17824  *
17825  * Sets the gravity of the #ClutterContent used by @self.
17826  *
17827  * See the description of the #ClutterActor:content-gravity property for
17828  * more information.
17829  *
17830  * The #ClutterActor:content-gravity property is animatable.
17831  *
17832  * Since: 1.10
17833  */
17834 void
17835 clutter_actor_set_content_gravity (ClutterActor *self,
17836                                    ClutterContentGravity  gravity)
17837 {
17838   ClutterActorPrivate *priv;
17839
17840   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17841
17842   priv = self->priv;
17843
17844   if (priv->content_gravity == gravity)
17845     return;
17846
17847   priv->content_box_valid = FALSE;
17848
17849   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17850     {
17851       ClutterActorBox from_box, to_box;
17852
17853       clutter_actor_get_content_box (self, &from_box);
17854
17855       priv->content_gravity = gravity;
17856
17857       clutter_actor_get_content_box (self, &to_box);
17858
17859       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17860                                         &from_box,
17861                                         &to_box);
17862     }
17863   else
17864     {
17865       ClutterActorBox to_box;
17866
17867       priv->content_gravity = gravity;
17868
17869       clutter_actor_get_content_box (self, &to_box);
17870
17871       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17872                                         &to_box);
17873     }
17874
17875   clutter_actor_queue_redraw (self);
17876
17877   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17878 }
17879
17880 /**
17881  * clutter_actor_get_content_gravity:
17882  * @self: a #ClutterActor
17883  *
17884  * Retrieves the content gravity as set using
17885  * clutter_actor_get_content_gravity().
17886  *
17887  * Return value: the content gravity
17888  *
17889  * Since: 1.10
17890  */
17891 ClutterContentGravity
17892 clutter_actor_get_content_gravity (ClutterActor *self)
17893 {
17894   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17895                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17896
17897   return self->priv->content_gravity;
17898 }
17899
17900 /**
17901  * clutter_actor_get_content_box:
17902  * @self: a #ClutterActor
17903  * @box: (out caller-allocates): the return location for the bounding
17904  *   box for the #ClutterContent
17905  *
17906  * Retrieves the bounding box for the #ClutterContent of @self.
17907  *
17908  * The bounding box is relative to the actor's allocation.
17909  *
17910  * If no #ClutterContent is set for @self, or if @self has not been
17911  * allocated yet, then the result is undefined.
17912  *
17913  * The content box is guaranteed to be, at most, as big as the allocation
17914  * of the #ClutterActor.
17915  *
17916  * If the #ClutterContent used by the actor has a preferred size, then
17917  * it is possible to modify the content box by using the
17918  * #ClutterActor:content-gravity property.
17919  *
17920  * Since: 1.10
17921  */
17922 void
17923 clutter_actor_get_content_box (ClutterActor    *self,
17924                                ClutterActorBox *box)
17925 {
17926   ClutterActorPrivate *priv;
17927   gfloat content_w, content_h;
17928   gfloat alloc_w, alloc_h;
17929
17930   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17931   g_return_if_fail (box != NULL);
17932
17933   priv = self->priv;
17934
17935   box->x1 = 0.f;
17936   box->y1 = 0.f;
17937   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17938   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17939
17940   if (priv->content_box_valid)
17941     {
17942       *box = priv->content_box;
17943       return;
17944     }
17945
17946   /* no need to do any more work */
17947   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17948     return;
17949
17950   if (priv->content == NULL)
17951     return;
17952
17953   /* if the content does not have a preferred size then there is
17954    * no point in computing the content box
17955    */
17956   if (!clutter_content_get_preferred_size (priv->content,
17957                                            &content_w,
17958                                            &content_h))
17959     return;
17960
17961   alloc_w = box->x2;
17962   alloc_h = box->y2;
17963
17964   switch (priv->content_gravity)
17965     {
17966     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17967       box->x2 = box->x1 + MIN (content_w, alloc_w);
17968       box->y2 = box->y1 + MIN (content_h, alloc_h);
17969       break;
17970
17971     case CLUTTER_CONTENT_GRAVITY_TOP:
17972       if (alloc_w > content_w)
17973         {
17974           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17975           box->x2 = box->x1 + content_w;
17976         }
17977       box->y2 = box->y1 + MIN (content_h, alloc_h);
17978       break;
17979
17980     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17981       if (alloc_w > content_w)
17982         {
17983           box->x1 += (alloc_w - content_w);
17984           box->x2 = box->x1 + content_w;
17985         }
17986       box->y2 = box->y1 + MIN (content_h, alloc_h);
17987       break;
17988
17989     case CLUTTER_CONTENT_GRAVITY_LEFT:
17990       box->x2 = box->x1 + MIN (content_w, alloc_w);
17991       if (alloc_h > content_h)
17992         {
17993           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17994           box->y2 = box->y1 + content_h;
17995         }
17996       break;
17997
17998     case CLUTTER_CONTENT_GRAVITY_CENTER:
17999       if (alloc_w > content_w)
18000         {
18001           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18002           box->x2 = box->x1 + content_w;
18003         }
18004       if (alloc_h > content_h)
18005         {
18006           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18007           box->y2 = box->y1 + content_h;
18008         }
18009       break;
18010
18011     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18012       if (alloc_w > content_w)
18013         {
18014           box->x1 += (alloc_w - content_w);
18015           box->x2 = box->x1 + content_w;
18016         }
18017       if (alloc_h > content_h)
18018         {
18019           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18020           box->y2 = box->y1 + content_h;
18021         }
18022       break;
18023
18024     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18025       box->x2 = box->x1 + MIN (content_w, alloc_w);
18026       if (alloc_h > content_h)
18027         {
18028           box->y1 += (alloc_h - content_h);
18029           box->y2 = box->y1 + content_h;
18030         }
18031       break;
18032
18033     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18034       if (alloc_w > content_w)
18035         {
18036           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18037           box->x2 = box->x1 + content_w;
18038         }
18039       if (alloc_h > content_h)
18040         {
18041           box->y1 += (alloc_h - content_h);
18042           box->y2 = box->y1 + content_h;
18043         }
18044       break;
18045
18046     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18047       if (alloc_w > content_w)
18048         {
18049           box->x1 += (alloc_w - content_w);
18050           box->x2 = box->x1 + content_w;
18051         }
18052       if (alloc_h > content_h)
18053         {
18054           box->y1 += (alloc_h - content_h);
18055           box->y2 = box->y1 + content_h;
18056         }
18057       break;
18058
18059     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18060       g_assert_not_reached ();
18061       break;
18062
18063     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18064       {
18065         double r_c = content_w / content_h;
18066         double r_a = alloc_w / alloc_h;
18067
18068         if (r_c >= 1.0)
18069           {
18070             if (r_a >= 1.0)
18071               {
18072                 box->x1 = 0.f;
18073                 box->x2 = alloc_w;
18074
18075                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18076                 box->y2 = box->y1 + (alloc_w * r_c);
18077               }
18078             else
18079               {
18080                 box->y1 = 0.f;
18081                 box->y2 = alloc_h;
18082
18083                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18084                 box->x2 = box->x1 + (alloc_h * r_c);
18085               }
18086           }
18087         else
18088           {
18089             if (r_a >= 1.0)
18090               {
18091                 box->y1 = 0.f;
18092                 box->y2 = alloc_h;
18093
18094                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18095                 box->x2 = box->x1 + (alloc_h * r_c);
18096               }
18097             else
18098               {
18099                 box->x1 = 0.f;
18100                 box->x2 = alloc_w;
18101
18102                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18103                 box->y2 = box->y1 + (alloc_w * r_c);
18104               }
18105           }
18106       }
18107       break;
18108     }
18109 }
18110
18111 /**
18112  * clutter_actor_set_content_scaling_filters:
18113  * @self: a #ClutterActor
18114  * @min_filter: the minification filter for the content
18115  * @mag_filter: the magnification filter for the content
18116  *
18117  * Sets the minification and magnification filter to be applied when
18118  * scaling the #ClutterActor:content of a #ClutterActor.
18119  *
18120  * The #ClutterActor:minification-filter will be used when reducing
18121  * the size of the content; the #ClutterActor:magnification-filter
18122  * will be used when increasing the size of the content.
18123  *
18124  * Since: 1.10
18125  */
18126 void
18127 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18128                                            ClutterScalingFilter  min_filter,
18129                                            ClutterScalingFilter  mag_filter)
18130 {
18131   ClutterActorPrivate *priv;
18132   gboolean changed;
18133   GObject *obj;
18134
18135   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18136
18137   priv = self->priv;
18138   obj = G_OBJECT (self);
18139
18140   g_object_freeze_notify (obj);
18141
18142   changed = FALSE;
18143
18144   if (priv->min_filter != min_filter)
18145     {
18146       priv->min_filter = min_filter;
18147       changed = TRUE;
18148
18149       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18150     }
18151
18152   if (priv->mag_filter != mag_filter)
18153     {
18154       priv->mag_filter = mag_filter;
18155       changed = TRUE;
18156
18157       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18158     }
18159
18160   if (changed)
18161     clutter_actor_queue_redraw (self);
18162
18163   g_object_thaw_notify (obj);
18164 }
18165
18166 /**
18167  * clutter_actor_get_content_scaling_filters:
18168  * @self: a #ClutterActor
18169  * @min_filter: (out) (allow-none): return location for the minification
18170  *   filter, or %NULL
18171  * @mag_filter: (out) (allow-none): return location for the magnification
18172  *   filter, or %NULL
18173  *
18174  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18175  *
18176  * Since: 1.10
18177  */
18178 void
18179 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18180                                            ClutterScalingFilter *min_filter,
18181                                            ClutterScalingFilter *mag_filter)
18182 {
18183   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18184
18185   if (min_filter != NULL)
18186     *min_filter = self->priv->min_filter;
18187
18188   if (mag_filter != NULL)
18189     *mag_filter = self->priv->mag_filter;
18190 }