timeline: Add a new "stopped" signal
[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="../../../../examples/basic-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_from (transition, G_TYPE_UINT, 255);
297  * clutter_transition_set_to (transition, G_TYPE_UINT, 0);
298  *
299  * clutter_actor_add_transition (actor, "animate-opacity", transition);
300  *     </programlisting></informalexample>
301  *     <para>The example above will animate the #ClutterActor:opacity property
302  *     of an actor between fully opaque and fully transparent, and back, over
303  *     a span of 3 seconds. The animation does not begin until it is added to
304  *     the actor.</para>
305  *     <para>The explicit animation API should also be used when using custom
306  *     animatable properties for #ClutterAction, #ClutterConstraint, and
307  *     #ClutterEffect instances associated to an actor; see the section on
308  *     <ulink linkend="ClutterActor-custom-animatable-properties">custom
309  *     animatable properties below</ulink> for an example.</para>
310  *     <para>Finally, explicit animations are useful for creating animations
311  *     that run continuously, for instance:</para>
312  *     <informalexample><programlisting>
313  * /&ast; this animation will pulse the actor's opacity continuously &ast;/
314  * ClutterTransition *transition;
315  * ClutterInterval *interval;
316  *
317  * transition = clutter_property_transition_new ("opacity");
318  *
319  * /&ast; we want to animate the opacity between 0 and 255 &ast;/
320  * clutter_transition_set_from (transition, G_TYPE_UINT, 0);
321  * clutter_transition_set_to (transition, G_TYPE_UINT, 255);
322  *
323  * /&ast; over a one second duration, running an infinite amount of times &ast;/
324  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
325  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
326  *
327  * /&ast; we want to fade in and out, so we need to auto-reverse the transition &ast;/
328  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
329  *
330  * /&ast; and we want to use an easing function that eases both in and out &ast;/
331  * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
332  *                                     CLUTTER_EASE_IN_OUT_CUBIC);
333  *
334  * /&ast; add the transition to the desired actor; this will
335  *  &ast; start the animation.
336  *  &ast;/
337  * clutter_actor_add_transition (actor, "opacityAnimation", transition);
338  *     </programlisting></informalexample>
339  *   </formalpara>
340  * </refsect2>
341  *
342  * <refsect2 id="ClutterActor-subclassing">
343  *   <title>Implementing an actor</title>
344  *   <para>Careful consideration should be given when deciding to implement
345  *   a #ClutterActor sub-class. It is generally recommended to implement a
346  *   sub-class of #ClutterActor only for actors that should be used as leaf
347  *   nodes of a scene graph.</para>
348  *   <para>If your actor should be painted in a custom way, you should
349  *   override the #ClutterActor::paint signal class handler. You can either
350  *   opt to chain up to the parent class implementation or decide to fully
351  *   override the default paint implementation; Clutter will set up the
352  *   transformations and clip regions prior to emitting the #ClutterActor::paint
353  *   signal.</para>
354  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
355  *   #ClutterActorClass.get_preferred_height() virtual functions it is
356  *   possible to change or provide the preferred size of an actor; similarly,
357  *   by overriding the #ClutterActorClass.allocate() virtual function it is
358  *   possible to control the layout of the children of an actor. Make sure to
359  *   always chain up to the parent implementation of the
360  *   #ClutterActorClass.allocate() virtual function.</para>
361  *   <para>In general, it is strongly encouraged to use delegation and
362  *   composition instead of direct subclassing.</para>
363  * </refsect2>
364  *
365  * <refsect2 id="ClutterActor-script">
366  *   <title>ClutterActor custom properties for #ClutterScript</title>
367  *   <para>#ClutterActor defines a custom "rotation" property which
368  *   allows a short-hand description of the rotations to be applied
369  *   to an actor.</para>
370  *   <para>The syntax of the "rotation" property is the following:</para>
371  *   <informalexample>
372  *     <programlisting>
373  * "rotation" : [
374  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
375  * ]
376  *     </programlisting>
377  *   </informalexample>
378  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
379  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
380  *   floating point value representing the rotation angle on the given axis,
381  *   in degrees.</para>
382  *   <para>The <emphasis>center</emphasis> array is optional, and if present
383  *   it must contain the center of rotation as described by two coordinates:
384  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
385  *   "z-axis".</para>
386  *   <para>#ClutterActor also defines a scriptable "margin" property which
387  *   follows the CSS "margin" shorthand.
388  *   <informalexample>
389  *     <programlisting>
390  * // 4 values
391  * "margin" : [ &lt;top&gt;, &lt;right&gt;, &lt;bottom&gt; &lt;left&gt; ]
392  * // 3 values
393  * "margin" : [ &lt;top&gt;, &lt;left/right&gt;, &lt;bottom&gt; ]
394  * // 2 values
395  * "margin" : [ &lt;top/bottom&gt;, &lt;left/right&gt; ]
396  * // 1 value
397  * "margin" : [ &lt;top/right/bottom/left&gt; ]
398  *     </programlisting>
399  *   </informalexample>
400  *   </para>
401  *   <para>#ClutterActor will also parse every positional and dimensional
402  *   property defined as a string through clutter_units_from_string(); you
403  *   should read the documentation for the #ClutterUnits parser format for
404  *   the valid units and syntax.</para>
405  * </refsect2>
406  *
407  * <refsect2 id="ClutterActor-custom-animatable-properties">
408  *   <title>Custom animatable properties</title>
409  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
410  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
411  *   instance for animation purposes.</para>
412  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
413  *   property it is necessary to set the #ClutterActorMeta:name property on the
414  *   given action or constraint.</para>
415  *   <para>The property can be accessed using the following syntax:</para>
416  *   <informalexample>
417  *     <programlisting>
418  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
419  *     </programlisting>
420  *   </informalexample>
421  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
422  *   <para>The <emphasis>section</emphasis> fragment can be one between
423  *   "actions", "constraints" and "effects".</para>
424  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
425  *   action or constraint, as specified by the #ClutterActorMeta:name
426  *   property.</para>
427  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
428  *   action or constraint property to be animated.</para>
429  *   <para>The example below animates a #ClutterBindConstraint applied to an
430  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
431  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
432  *   its initial state is overlapping the actor to which is bound to.</para>
433  *   <informalexample><programlisting>
434  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
435  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
436  * clutter_actor_add_constraint (rect, constraint);
437  *
438  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
439  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
440  * clutter_actor_add_constraint (rect, constraint);
441  *
442  * clutter_actor_set_reactive (origin, TRUE);
443  *
444  * g_signal_connect (origin, "button-press-event",
445  *                   G_CALLBACK (on_button_press),
446  *                   rect);
447  *   </programlisting></informalexample>
448  *   <para>On button press, the rectangle "slides" from behind the actor to
449  *   which is bound to, using the #ClutterBindConstraint:offset property to
450  *   achieve the effect:</para>
451  *   <informalexample><programlisting>
452  * gboolean
453  * on_button_press (ClutterActor *origin,
454  *                  ClutterEvent *event,
455  *                  ClutterActor *rect)
456  * {
457  *   ClutterTransition *transition;
458  *   ClutterInterval *interval;
459  *
460  *   /&ast; the offset that we want to apply; this will make the actor
461  *    &ast; slide in from behind the origin and rest at the right of
462  *    &ast; the origin, plus a padding value.
463  *    &ast;/
464  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
465  *
466  *   /&ast; the property we wish to animate; the "@constraints" section
467  *    &ast; tells Clutter to check inside the constraints associated
468  *    &ast; with the actor; the "bind-x" section is the name of the
469  *    &ast; constraint; and the "offset" is the name of the property
470  *    &ast; on the constraint.
471  *    &ast;/
472  *   const char *prop = "@constraints.bind-x.offset";
473  *
474  *   /&ast; create a new transition for the given property &ast;/
475  *   transition = clutter_property_transition_new (prop);
476  *
477  *   /&ast; set the easing mode and duration &ast;/
478  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
479  *                                       CLUTTER_EASE_OUT_CUBIC);
480  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
481  *
482  *   /&ast; create the interval with the initial and final values &ast;/
483  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
484  *   clutter_transition_set_interval (transition, interval);
485  *
486  *   /&ast; add the transition to the actor; this causes the animation
487  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
488  *    &ast; the transition later.
489  *    &ast;/
490  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
491  *
492  *   /&ast; we handled the event &ast;/
493  *   return CLUTTER_EVENT_STOP;
494  * }
495  *   </programlisting></informalexample>
496  * </refsect2>
497  */
498
499 /**
500  * CLUTTER_ACTOR_IS_MAPPED:
501  * @a: a #ClutterActor
502  *
503  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
504  *
505  * The mapped state is set when the actor is visible and all its parents up
506  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
507  *
508  * This check can be used to see if an actor is going to be painted, as only
509  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
510  *
511  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
512  * not be checked directly; instead, the recommended usage is to connect a
513  * handler on the #GObject::notify signal for the #ClutterActor:mapped
514  * property of #ClutterActor, and check the presence of
515  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
516  *
517  * It is also important to note that Clutter may delay the changes of
518  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
519  * limitations, or during the reparenting of an actor, to optimize
520  * unnecessary (and potentially expensive) state changes.
521  *
522  * Since: 0.2
523  */
524
525 /**
526  * CLUTTER_ACTOR_IS_REALIZED:
527  * @a: a #ClutterActor
528  *
529  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
530  *
531  * The realized state has an actor-dependant interpretation. If an
532  * actor wants to delay allocating resources until it is attached to a
533  * stage, it may use the realize state to do so. However it is
534  * perfectly acceptable for an actor to allocate Cogl resources before
535  * being realized because there is only one drawing context used by Clutter
536  * so any resources will work on any stage.  If an actor is mapped it
537  * must also be realized, but an actor can be realized and unmapped
538  * (this is so hiding an actor temporarily doesn't do an expensive
539  * unrealize/realize).
540  *
541  * To be realized an actor must be inside a stage, and all its parents
542  * must be realized.
543  *
544  * Since: 0.2
545  */
546
547 /**
548  * CLUTTER_ACTOR_IS_VISIBLE:
549  * @a: a #ClutterActor
550  *
551  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
552  * Equivalent to the ClutterActor::visible object property.
553  *
554  * Note that an actor is only painted onscreen if it's mapped, which
555  * means it's visible, and all its parents are visible, and one of the
556  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
557  *
558  * Since: 0.2
559  */
560
561 /**
562  * CLUTTER_ACTOR_IS_REACTIVE:
563  * @a: a #ClutterActor
564  *
565  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
566  *
567  * Only reactive actors will receive event-related signals.
568  *
569  * Since: 0.6
570  */
571
572 #ifdef HAVE_CONFIG_H
573 #include "config.h"
574 #endif
575
576 #include <math.h>
577
578 #include <gobject/gvaluecollector.h>
579
580 #include <cogl/cogl.h>
581
582 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
583 #define CLUTTER_ENABLE_EXPERIMENTAL_API
584
585 #include "clutter-actor-private.h"
586
587 #include "clutter-action.h"
588 #include "clutter-actor-meta-private.h"
589 #include "clutter-animatable.h"
590 #include "clutter-color-static.h"
591 #include "clutter-color.h"
592 #include "clutter-constraint.h"
593 #include "clutter-container.h"
594 #include "clutter-content-private.h"
595 #include "clutter-debug.h"
596 #include "clutter-effect-private.h"
597 #include "clutter-enum-types.h"
598 #include "clutter-fixed-layout.h"
599 #include "clutter-flatten-effect.h"
600 #include "clutter-interval.h"
601 #include "clutter-main.h"
602 #include "clutter-marshal.h"
603 #include "clutter-paint-nodes.h"
604 #include "clutter-paint-node-private.h"
605 #include "clutter-paint-volume-private.h"
606 #include "clutter-private.h"
607 #include "clutter-profile.h"
608 #include "clutter-property-transition.h"
609 #include "clutter-scriptable.h"
610 #include "clutter-script-private.h"
611 #include "clutter-stage-private.h"
612 #include "clutter-timeline.h"
613 #include "clutter-transition.h"
614 #include "clutter-units.h"
615
616 #include "deprecated/clutter-actor.h"
617 #include "deprecated/clutter-behaviour.h"
618 #include "deprecated/clutter-container.h"
619
620 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
621 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
622
623 /* Internal enum used to control mapped state update.  This is a hint
624  * which indicates when to do something other than just enforce
625  * invariants.
626  */
627 typedef enum {
628   MAP_STATE_CHECK,           /* just enforce invariants. */
629   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
630                               * used when about to unparent.
631                               */
632   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
633                               * used to set mapped on toplevels.
634                               */
635   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
636                               * used just before unmapping parent.
637                               */
638 } MapStateChange;
639
640 /* 3 entries should be a good compromise, few layout managers
641  * will ask for 3 different preferred size in each allocation cycle */
642 #define N_CACHED_SIZE_REQUESTS 3
643
644 struct _ClutterActorPrivate
645 {
646   /* request mode */
647   ClutterRequestMode request_mode;
648
649   /* our cached size requests for different width / height */
650   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
651   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
652
653   /* An age of 0 means the entry is not set */
654   guint cached_height_age;
655   guint cached_width_age;
656
657   /* the bounding box of the actor, relative to the parent's
658    * allocation
659    */
660   ClutterActorBox allocation;
661   ClutterAllocationFlags allocation_flags;
662
663   /* clip, in actor coordinates */
664   cairo_rectangle_t clip;
665
666   /* the cached transformation matrix; see apply_transform() */
667   CoglMatrix transform;
668
669   guint8 opacity;
670   gint opacity_override;
671
672   ClutterOffscreenRedirect offscreen_redirect;
673
674   /* This is an internal effect used to implement the
675      offscreen-redirect property */
676   ClutterEffect *flatten_effect;
677
678   /* scene graph */
679   ClutterActor *parent;
680   ClutterActor *prev_sibling;
681   ClutterActor *next_sibling;
682   ClutterActor *first_child;
683   ClutterActor *last_child;
684
685   gint n_children;
686
687   /* tracks whenever the children of an actor are changed; the
688    * age is incremented by 1 whenever an actor is added or
689    * removed. the age is not incremented when the first or the
690    * last child pointers are changed, or when grandchildren of
691    * an actor are changed.
692    */
693   gint age;
694
695   gchar *name; /* a non-unique name, used for debugging */
696   guint32 id; /* unique id, used for backward compatibility */
697
698   gint32 pick_id; /* per-stage unique id, used for picking */
699
700   /* a back-pointer to the Pango context that we can use
701    * to create pre-configured PangoLayout
702    */
703   PangoContext *pango_context;
704
705   /* the text direction configured for this child - either by
706    * application code, or by the actor's parent
707    */
708   ClutterTextDirection text_direction;
709
710   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
711   gint internal_child;
712
713   /* meta classes */
714   ClutterMetaGroup *actions;
715   ClutterMetaGroup *constraints;
716   ClutterMetaGroup *effects;
717
718   /* delegate object used to allocate the children of this actor */
719   ClutterLayoutManager *layout_manager;
720
721   /* delegate object used to paint the contents of this actor */
722   ClutterContent *content;
723
724   ClutterActorBox content_box;
725   ClutterContentGravity content_gravity;
726   ClutterScalingFilter min_filter;
727   ClutterScalingFilter mag_filter;
728
729   /* used when painting, to update the paint volume */
730   ClutterEffect *current_effect;
731
732   /* This is used to store an effect which needs to be redrawn. A
733      redraw can be queued to start from a particular effect. This is
734      used by parametrised effects that can cache an image of the
735      actor. If a parameter of the effect changes then it only needs to
736      redraw the cached image, not the actual actor. The pointer is
737      only valid if is_dirty == TRUE. If the pointer is NULL then the
738      whole actor is dirty. */
739   ClutterEffect *effect_to_redraw;
740
741   /* This is used when painting effects to implement the
742      clutter_actor_continue_paint() function. It points to the node in
743      the list of effects that is next in the chain */
744   const GList *next_effect_to_paint;
745
746   ClutterPaintVolume paint_volume;
747
748   /* NB: This volume isn't relative to this actor, it is in eye
749    * coordinates so that it can remain valid after the actor changes.
750    */
751   ClutterPaintVolume last_paint_volume;
752
753   ClutterStageQueueRedrawEntry *queue_redraw_entry;
754
755   ClutterColor bg_color;
756
757   /* bitfields */
758
759   /* fixed position and sizes */
760   guint position_set                : 1;
761   guint min_width_set               : 1;
762   guint min_height_set              : 1;
763   guint natural_width_set           : 1;
764   guint natural_height_set          : 1;
765   /* cached request is invalid (implies allocation is too) */
766   guint needs_width_request         : 1;
767   /* cached request is invalid (implies allocation is too) */
768   guint needs_height_request        : 1;
769   /* cached allocation is invalid (request has changed, probably) */
770   guint needs_allocation            : 1;
771   guint show_on_set_parent          : 1;
772   guint has_clip                    : 1;
773   guint clip_to_allocation          : 1;
774   guint enable_model_view_transform : 1;
775   guint enable_paint_unmapped       : 1;
776   guint has_pointer                 : 1;
777   guint propagated_one_redraw       : 1;
778   guint paint_volume_valid          : 1;
779   guint last_paint_volume_valid     : 1;
780   guint in_clone_paint              : 1;
781   guint transform_valid             : 1;
782   /* This is TRUE if anything has queued a redraw since we were last
783      painted. In this case effect_to_redraw will point to an effect
784      the redraw was queued from or it will be NULL if the redraw was
785      queued without an effect. */
786   guint is_dirty                    : 1;
787   guint bg_color_set                : 1;
788   guint content_box_valid           : 1;
789   guint x_expand_set                : 1;
790   guint y_expand_set                : 1;
791   guint needs_compute_expand        : 1;
792   guint needs_x_expand              : 1;
793   guint needs_y_expand              : 1;
794 };
795
796 enum
797 {
798   PROP_0,
799
800   PROP_NAME,
801
802   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
803    * when set they force a size request, when gotten they
804    * get the allocation if the allocation is valid, and the
805    * request otherwise
806    */
807   PROP_X,
808   PROP_Y,
809   PROP_WIDTH,
810   PROP_HEIGHT,
811
812   PROP_POSITION,
813   PROP_SIZE,
814
815   /* Then the rest of these size-related properties are the "actual"
816    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
817    */
818   PROP_FIXED_X,
819   PROP_FIXED_Y,
820
821   PROP_FIXED_POSITION_SET,
822
823   PROP_MIN_WIDTH,
824   PROP_MIN_WIDTH_SET,
825
826   PROP_MIN_HEIGHT,
827   PROP_MIN_HEIGHT_SET,
828
829   PROP_NATURAL_WIDTH,
830   PROP_NATURAL_WIDTH_SET,
831
832   PROP_NATURAL_HEIGHT,
833   PROP_NATURAL_HEIGHT_SET,
834
835   PROP_REQUEST_MODE,
836
837   /* Allocation properties are read-only */
838   PROP_ALLOCATION,
839
840   PROP_DEPTH,
841
842   PROP_CLIP,
843   PROP_HAS_CLIP,
844   PROP_CLIP_TO_ALLOCATION,
845
846   PROP_OPACITY,
847
848   PROP_OFFSCREEN_REDIRECT,
849
850   PROP_VISIBLE,
851   PROP_MAPPED,
852   PROP_REALIZED,
853   PROP_REACTIVE,
854
855   PROP_SCALE_X,
856   PROP_SCALE_Y,
857   PROP_SCALE_CENTER_X,
858   PROP_SCALE_CENTER_Y,
859   PROP_SCALE_GRAVITY,
860
861   PROP_ROTATION_ANGLE_X,
862   PROP_ROTATION_ANGLE_Y,
863   PROP_ROTATION_ANGLE_Z,
864   PROP_ROTATION_CENTER_X,
865   PROP_ROTATION_CENTER_Y,
866   PROP_ROTATION_CENTER_Z,
867   /* This property only makes sense for the z rotation because the
868      others would depend on the actor having a size along the
869      z-axis */
870   PROP_ROTATION_CENTER_Z_GRAVITY,
871
872   PROP_ANCHOR_X,
873   PROP_ANCHOR_Y,
874   PROP_ANCHOR_GRAVITY,
875
876   PROP_SHOW_ON_SET_PARENT,
877
878   PROP_TEXT_DIRECTION,
879   PROP_HAS_POINTER,
880
881   PROP_ACTIONS,
882   PROP_CONSTRAINTS,
883   PROP_EFFECT,
884
885   PROP_LAYOUT_MANAGER,
886
887   PROP_X_EXPAND,
888   PROP_Y_EXPAND,
889   PROP_X_ALIGN,
890   PROP_Y_ALIGN,
891   PROP_MARGIN_TOP,
892   PROP_MARGIN_BOTTOM,
893   PROP_MARGIN_LEFT,
894   PROP_MARGIN_RIGHT,
895
896   PROP_BACKGROUND_COLOR,
897   PROP_BACKGROUND_COLOR_SET,
898
899   PROP_FIRST_CHILD,
900   PROP_LAST_CHILD,
901
902   PROP_CONTENT,
903   PROP_CONTENT_GRAVITY,
904   PROP_CONTENT_BOX,
905   PROP_MINIFICATION_FILTER,
906   PROP_MAGNIFICATION_FILTER,
907
908   PROP_LAST
909 };
910
911 static GParamSpec *obj_props[PROP_LAST];
912
913 enum
914 {
915   SHOW,
916   HIDE,
917   DESTROY,
918   PARENT_SET,
919   KEY_FOCUS_IN,
920   KEY_FOCUS_OUT,
921   PAINT,
922   PICK,
923   REALIZE,
924   UNREALIZE,
925   QUEUE_REDRAW,
926   QUEUE_RELAYOUT,
927   EVENT,
928   CAPTURED_EVENT,
929   BUTTON_PRESS_EVENT,
930   BUTTON_RELEASE_EVENT,
931   SCROLL_EVENT,
932   KEY_PRESS_EVENT,
933   KEY_RELEASE_EVENT,
934   MOTION_EVENT,
935   ENTER_EVENT,
936   LEAVE_EVENT,
937   ALLOCATION_CHANGED,
938   TRANSITIONS_COMPLETED,
939
940   LAST_SIGNAL
941 };
942
943 static guint actor_signals[LAST_SIGNAL] = { 0, };
944
945 typedef struct _TransitionClosure
946 {
947   ClutterActor *actor;
948   ClutterTransition *transition;
949   gchar *name;
950   gulong completed_id;
951 } TransitionClosure;
952
953 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
954 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
955 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
956 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
957
958 /* These setters are all static for now, maybe they should be in the
959  * public API, but they are perhaps obscure enough to leave only as
960  * properties
961  */
962 static void clutter_actor_set_min_width          (ClutterActor *self,
963                                                   gfloat        min_width);
964 static void clutter_actor_set_min_height         (ClutterActor *self,
965                                                   gfloat        min_height);
966 static void clutter_actor_set_natural_width      (ClutterActor *self,
967                                                   gfloat        natural_width);
968 static void clutter_actor_set_natural_height     (ClutterActor *self,
969                                                   gfloat        natural_height);
970 static void clutter_actor_set_min_width_set      (ClutterActor *self,
971                                                   gboolean      use_min_width);
972 static void clutter_actor_set_min_height_set     (ClutterActor *self,
973                                                   gboolean      use_min_height);
974 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
975                                                   gboolean  use_natural_width);
976 static void clutter_actor_set_natural_height_set (ClutterActor *self,
977                                                   gboolean  use_natural_height);
978 static void clutter_actor_update_map_state       (ClutterActor  *self,
979                                                   MapStateChange change);
980 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
981
982 /* Helper routines for managing anchor coords */
983 static void clutter_anchor_coord_get_units (ClutterActor      *self,
984                                             const AnchorCoord *coord,
985                                             gfloat            *x,
986                                             gfloat            *y,
987                                             gfloat            *z);
988 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
989                                             gfloat             x,
990                                             gfloat             y,
991                                             gfloat             z);
992
993 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
994 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
995                                                         ClutterGravity     gravity);
996
997 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
998
999 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
1000
1001 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
1002                                                                ClutterActor *ancestor,
1003                                                                CoglMatrix *matrix);
1004
1005 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
1006
1007 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
1008
1009 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
1010                                                                 const ClutterColor *color);
1011
1012 static void on_layout_manager_changed (ClutterLayoutManager *manager,
1013                                        ClutterActor         *self);
1014
1015 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
1016
1017 /* Helper macro which translates by the anchor coord, applies the
1018    given transformation and then translates back */
1019 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
1020   gfloat _tx, _ty, _tz;                                                \
1021   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
1022   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
1023   { _transform; }                                                      \
1024   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
1025
1026 static GQuark quark_shader_data = 0;
1027 static GQuark quark_actor_layout_info = 0;
1028 static GQuark quark_actor_transform_info = 0;
1029 static GQuark quark_actor_animation_info = 0;
1030
1031 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1032                          clutter_actor,
1033                          G_TYPE_INITIALLY_UNOWNED,
1034                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1035                                                 clutter_container_iface_init)
1036                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1037                                                 clutter_scriptable_iface_init)
1038                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1039                                                 clutter_animatable_iface_init)
1040                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1041                                                 atk_implementor_iface_init));
1042
1043 /*< private >
1044  * clutter_actor_get_debug_name:
1045  * @actor: a #ClutterActor
1046  *
1047  * Retrieves a printable name of @actor for debugging messages
1048  *
1049  * Return value: a string with a printable name
1050  */
1051 const gchar *
1052 _clutter_actor_get_debug_name (ClutterActor *actor)
1053 {
1054   return actor->priv->name != NULL ? actor->priv->name
1055                                    : G_OBJECT_TYPE_NAME (actor);
1056 }
1057
1058 #ifdef CLUTTER_ENABLE_DEBUG
1059 /* XXX - this is for debugging only, remove once working (or leave
1060  * in only in some debug mode). Should leave it for a little while
1061  * until we're confident in the new map/realize/visible handling.
1062  */
1063 static inline void
1064 clutter_actor_verify_map_state (ClutterActor *self)
1065 {
1066   ClutterActorPrivate *priv = self->priv;
1067
1068   if (CLUTTER_ACTOR_IS_REALIZED (self))
1069     {
1070       /* all bets are off during reparent when we're potentially realized,
1071        * but should not be according to invariants
1072        */
1073       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1074         {
1075           if (priv->parent == NULL)
1076             {
1077               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1078                 {
1079                 }
1080               else
1081                 g_warning ("Realized non-toplevel actor '%s' should "
1082                            "have a parent",
1083                            _clutter_actor_get_debug_name (self));
1084             }
1085           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1086             {
1087               g_warning ("Realized actor %s has an unrealized parent %s",
1088                          _clutter_actor_get_debug_name (self),
1089                          _clutter_actor_get_debug_name (priv->parent));
1090             }
1091         }
1092     }
1093
1094   if (CLUTTER_ACTOR_IS_MAPPED (self))
1095     {
1096       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1097         g_warning ("Actor '%s' is mapped but not realized",
1098                    _clutter_actor_get_debug_name (self));
1099
1100       /* remaining bets are off during reparent when we're potentially
1101        * mapped, but should not be according to invariants
1102        */
1103       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1104         {
1105           if (priv->parent == NULL)
1106             {
1107               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1108                 {
1109                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1110                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1111                     {
1112                       g_warning ("Toplevel actor '%s' is mapped "
1113                                  "but not visible",
1114                                  _clutter_actor_get_debug_name (self));
1115                     }
1116                 }
1117               else
1118                 {
1119                   g_warning ("Mapped actor '%s' should have a parent",
1120                              _clutter_actor_get_debug_name (self));
1121                 }
1122             }
1123           else
1124             {
1125               ClutterActor *iter = self;
1126
1127               /* check for the enable_paint_unmapped flag on the actor
1128                * and parents; if the flag is enabled at any point of this
1129                * branch of the scene graph then all the later checks
1130                * become pointless
1131                */
1132               while (iter != NULL)
1133                 {
1134                   if (iter->priv->enable_paint_unmapped)
1135                     return;
1136
1137                   iter = iter->priv->parent;
1138                 }
1139
1140               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1141                 {
1142                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1143                              "is not visible",
1144                              _clutter_actor_get_debug_name (self),
1145                              _clutter_actor_get_debug_name (priv->parent));
1146                 }
1147
1148               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1149                 {
1150                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1151                              "is not realized",
1152                              _clutter_actor_get_debug_name (self),
1153                              _clutter_actor_get_debug_name (priv->parent));
1154                 }
1155
1156               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1157                 {
1158                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1159                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1160                                "parent '%s' is not mapped",
1161                                _clutter_actor_get_debug_name (self),
1162                                _clutter_actor_get_debug_name (priv->parent));
1163                 }
1164             }
1165         }
1166     }
1167 }
1168
1169 #endif /* CLUTTER_ENABLE_DEBUG */
1170
1171 static void
1172 clutter_actor_set_mapped (ClutterActor *self,
1173                           gboolean      mapped)
1174 {
1175   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1176     return;
1177
1178   if (mapped)
1179     {
1180       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1181       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1182     }
1183   else
1184     {
1185       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1186       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1187     }
1188 }
1189
1190 /* this function updates the mapped and realized states according to
1191  * invariants, in the appropriate order.
1192  */
1193 static void
1194 clutter_actor_update_map_state (ClutterActor  *self,
1195                                 MapStateChange change)
1196 {
1197   gboolean was_mapped;
1198
1199   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1200
1201   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1202     {
1203       /* the mapped flag on top-level actors must be set by the
1204        * per-backend implementation because it might be asynchronous.
1205        *
1206        * That is, the MAPPED flag on toplevels currently tracks the X
1207        * server mapped-ness of the window, while the expected behavior
1208        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1209        * This creates some weird complexity by breaking the invariant
1210        * that if we're visible and all ancestors shown then we are
1211        * also mapped - instead, we are mapped if all ancestors
1212        * _possibly excepting_ the stage are mapped. The stage
1213        * will map/unmap for example when it is minimized or
1214        * moved to another workspace.
1215        *
1216        * So, the only invariant on the stage is that if visible it
1217        * should be realized, and that it has to be visible to be
1218        * mapped.
1219        */
1220       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1221         clutter_actor_realize (self);
1222
1223       switch (change)
1224         {
1225         case MAP_STATE_CHECK:
1226           break;
1227
1228         case MAP_STATE_MAKE_MAPPED:
1229           g_assert (!was_mapped);
1230           clutter_actor_set_mapped (self, TRUE);
1231           break;
1232
1233         case MAP_STATE_MAKE_UNMAPPED:
1234           g_assert (was_mapped);
1235           clutter_actor_set_mapped (self, FALSE);
1236           break;
1237
1238         case MAP_STATE_MAKE_UNREALIZED:
1239           /* we only use MAKE_UNREALIZED in unparent,
1240            * and unparenting a stage isn't possible.
1241            * If someone wants to just unrealize a stage
1242            * then clutter_actor_unrealize() doesn't
1243            * go through this codepath.
1244            */
1245           g_warning ("Trying to force unrealize stage is not allowed");
1246           break;
1247         }
1248
1249       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1250           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1251           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1252         {
1253           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1254                      "it is somehow still mapped",
1255                      _clutter_actor_get_debug_name (self));
1256         }
1257     }
1258   else
1259     {
1260       ClutterActorPrivate *priv = self->priv;
1261       ClutterActor *parent = priv->parent;
1262       gboolean should_be_mapped;
1263       gboolean may_be_realized;
1264       gboolean must_be_realized;
1265
1266       should_be_mapped = FALSE;
1267       may_be_realized = TRUE;
1268       must_be_realized = FALSE;
1269
1270       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1271         {
1272           may_be_realized = FALSE;
1273         }
1274       else
1275         {
1276           /* Maintain invariant that if parent is mapped, and we are
1277            * visible, then we are mapped ...  unless parent is a
1278            * stage, in which case we map regardless of parent's map
1279            * state but do require stage to be visible and realized.
1280            *
1281            * If parent is realized, that does not force us to be
1282            * realized; but if parent is unrealized, that does force
1283            * us to be unrealized.
1284            *
1285            * The reason we don't force children to realize with
1286            * parents is _clutter_actor_rerealize(); if we require that
1287            * a realized parent means children are realized, then to
1288            * unrealize an actor we would have to unrealize its
1289            * parents, which would end up meaning unrealizing and
1290            * hiding the entire stage. So we allow unrealizing a
1291            * child (as long as that child is not mapped) while that
1292            * child still has a realized parent.
1293            *
1294            * Also, if we unrealize from leaf nodes to root, and
1295            * realize from root to leaf, the invariants are never
1296            * violated if we allow children to be unrealized
1297            * while parents are realized.
1298            *
1299            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1300            * to force us to unmap, even though parent is still
1301            * mapped. This is because we're unmapping from leaf nodes
1302            * up to root nodes.
1303            */
1304           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1305               change != MAP_STATE_MAKE_UNMAPPED)
1306             {
1307               gboolean parent_is_visible_realized_toplevel;
1308
1309               parent_is_visible_realized_toplevel =
1310                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1311                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1312                  CLUTTER_ACTOR_IS_REALIZED (parent));
1313
1314               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1315                   parent_is_visible_realized_toplevel)
1316                 {
1317                   must_be_realized = TRUE;
1318                   should_be_mapped = TRUE;
1319                 }
1320             }
1321
1322           /* if the actor has been set to be painted even if unmapped
1323            * then we should map it and check for realization as well;
1324            * this is an override for the branch of the scene graph
1325            * which begins with this node
1326            */
1327           if (priv->enable_paint_unmapped)
1328             {
1329               if (priv->parent == NULL)
1330                 g_warning ("Attempting to map an unparented actor '%s'",
1331                            _clutter_actor_get_debug_name (self));
1332
1333               should_be_mapped = TRUE;
1334               must_be_realized = TRUE;
1335             }
1336
1337           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1338             may_be_realized = FALSE;
1339         }
1340
1341       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1342         {
1343           if (parent == NULL)
1344             g_warning ("Attempting to map a child that does not "
1345                        "meet the necessary invariants: the actor '%s' "
1346                        "has no parent",
1347                        _clutter_actor_get_debug_name (self));
1348           else
1349             g_warning ("Attempting to map a child that does not "
1350                        "meet the necessary invariants: the actor '%s' "
1351                        "is parented to an unmapped actor '%s'",
1352                        _clutter_actor_get_debug_name (self),
1353                        _clutter_actor_get_debug_name (priv->parent));
1354         }
1355
1356       /* If in reparent, we temporarily suspend unmap and unrealize.
1357        *
1358        * We want to go in the order "realize, map" and "unmap, unrealize"
1359        */
1360
1361       /* Unmap */
1362       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1363         clutter_actor_set_mapped (self, FALSE);
1364
1365       /* Realize */
1366       if (must_be_realized)
1367         clutter_actor_realize (self);
1368
1369       /* if we must be realized then we may be, presumably */
1370       g_assert (!(must_be_realized && !may_be_realized));
1371
1372       /* Unrealize */
1373       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1374         clutter_actor_unrealize_not_hiding (self);
1375
1376       /* Map */
1377       if (should_be_mapped)
1378         {
1379           if (!must_be_realized)
1380             g_warning ("Somehow we think actor '%s' should be mapped but "
1381                        "not realized, which isn't allowed",
1382                        _clutter_actor_get_debug_name (self));
1383
1384           /* realization is allowed to fail (though I don't know what
1385            * an app is supposed to do about that - shouldn't it just
1386            * be a g_error? anyway, we have to avoid mapping if this
1387            * happens)
1388            */
1389           if (CLUTTER_ACTOR_IS_REALIZED (self))
1390             clutter_actor_set_mapped (self, TRUE);
1391         }
1392     }
1393
1394 #ifdef CLUTTER_ENABLE_DEBUG
1395   /* check all invariants were kept */
1396   clutter_actor_verify_map_state (self);
1397 #endif
1398 }
1399
1400 static void
1401 clutter_actor_real_map (ClutterActor *self)
1402 {
1403   ClutterActorPrivate *priv = self->priv;
1404   ClutterActor *stage, *iter;
1405
1406   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1407
1408   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1409                 _clutter_actor_get_debug_name (self));
1410
1411   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1412
1413   stage = _clutter_actor_get_stage_internal (self);
1414   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1415
1416   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1417                 priv->pick_id,
1418                 _clutter_actor_get_debug_name (self));
1419
1420   /* notify on parent mapped before potentially mapping
1421    * children, so apps see a top-down notification.
1422    */
1423   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1424
1425   for (iter = self->priv->first_child;
1426        iter != NULL;
1427        iter = iter->priv->next_sibling)
1428     {
1429       clutter_actor_map (iter);
1430     }
1431 }
1432
1433 /**
1434  * clutter_actor_map:
1435  * @self: A #ClutterActor
1436  *
1437  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1438  * and realizes its children if they are visible. Does nothing if the
1439  * actor is not visible.
1440  *
1441  * Calling this function is strongly disencouraged: the default
1442  * implementation of #ClutterActorClass.map() will map all the children
1443  * of an actor when mapping its parent.
1444  *
1445  * When overriding map, it is mandatory to chain up to the parent
1446  * implementation.
1447  *
1448  * Since: 1.0
1449  */
1450 void
1451 clutter_actor_map (ClutterActor *self)
1452 {
1453   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1454
1455   if (CLUTTER_ACTOR_IS_MAPPED (self))
1456     return;
1457
1458   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1459     return;
1460
1461   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1462 }
1463
1464 static void
1465 clutter_actor_real_unmap (ClutterActor *self)
1466 {
1467   ClutterActorPrivate *priv = self->priv;
1468   ClutterActor *iter;
1469
1470   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1471
1472   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1473                 _clutter_actor_get_debug_name (self));
1474
1475   for (iter = self->priv->first_child;
1476        iter != NULL;
1477        iter = iter->priv->next_sibling)
1478     {
1479       clutter_actor_unmap (iter);
1480     }
1481
1482   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1483
1484   /* clear the contents of the last paint volume, so that hiding + moving +
1485    * showing will not result in the wrong area being repainted
1486    */
1487   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1488   priv->last_paint_volume_valid = TRUE;
1489
1490   /* notify on parent mapped after potentially unmapping
1491    * children, so apps see a bottom-up notification.
1492    */
1493   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1494
1495   /* relinquish keyboard focus if we were unmapped while owning it */
1496   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1497     {
1498       ClutterStage *stage;
1499
1500       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1501
1502       if (stage != NULL)
1503         _clutter_stage_release_pick_id (stage, priv->pick_id);
1504
1505       priv->pick_id = -1;
1506
1507       if (stage != NULL &&
1508           clutter_stage_get_key_focus (stage) == self)
1509         {
1510           clutter_stage_set_key_focus (stage, NULL);
1511         }
1512     }
1513 }
1514
1515 /**
1516  * clutter_actor_unmap:
1517  * @self: A #ClutterActor
1518  *
1519  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1520  * unmaps its children if they were mapped.
1521  *
1522  * Calling this function is not encouraged: the default #ClutterActor
1523  * implementation of #ClutterActorClass.unmap() will also unmap any
1524  * eventual children by default when their parent is unmapped.
1525  *
1526  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1527  * chain up to the parent implementation.
1528  *
1529  * <note>It is important to note that the implementation of the
1530  * #ClutterActorClass.unmap() virtual function may be called after
1531  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1532  * implementation, but it is guaranteed to be called before the
1533  * #GObjectClass.finalize() implementation.</note>
1534  *
1535  * Since: 1.0
1536  */
1537 void
1538 clutter_actor_unmap (ClutterActor *self)
1539 {
1540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1541
1542   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1543     return;
1544
1545   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1546 }
1547
1548 static void
1549 clutter_actor_real_show (ClutterActor *self)
1550 {
1551   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1552     {
1553       ClutterActorPrivate *priv = self->priv;
1554
1555       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1556
1557       /* we notify on the "visible" flag in the clutter_actor_show()
1558        * wrapper so the entire show signal emission completes first
1559        * (?)
1560        */
1561       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1562
1563       /* we queue a relayout unless the actor is inside a
1564        * container that explicitly told us not to
1565        */
1566       if (priv->parent != NULL &&
1567           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1568         {
1569           /* While an actor is hidden the parent may not have
1570            * allocated/requested so we need to start from scratch
1571            * and avoid the short-circuiting in
1572            * clutter_actor_queue_relayout().
1573            */
1574           priv->needs_width_request  = FALSE;
1575           priv->needs_height_request = FALSE;
1576           priv->needs_allocation     = FALSE;
1577           clutter_actor_queue_relayout (self);
1578         }
1579     }
1580 }
1581
1582 static inline void
1583 set_show_on_set_parent (ClutterActor *self,
1584                         gboolean      set_show)
1585 {
1586   ClutterActorPrivate *priv = self->priv;
1587
1588   set_show = !!set_show;
1589
1590   if (priv->show_on_set_parent == set_show)
1591     return;
1592
1593   if (priv->parent == NULL)
1594     {
1595       priv->show_on_set_parent = set_show;
1596       g_object_notify_by_pspec (G_OBJECT (self),
1597                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1598     }
1599 }
1600
1601 /**
1602  * clutter_actor_show:
1603  * @self: A #ClutterActor
1604  *
1605  * Flags an actor to be displayed. An actor that isn't shown will not
1606  * be rendered on the stage.
1607  *
1608  * Actors are visible by default.
1609  *
1610  * If this function is called on an actor without a parent, the
1611  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1612  * effect.
1613  */
1614 void
1615 clutter_actor_show (ClutterActor *self)
1616 {
1617   ClutterActorPrivate *priv;
1618
1619   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1620
1621   /* simple optimization */
1622   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1623     {
1624       /* we still need to set the :show-on-set-parent property, in
1625        * case show() is called on an unparented actor
1626        */
1627       set_show_on_set_parent (self, TRUE);
1628       return;
1629     }
1630
1631 #ifdef CLUTTER_ENABLE_DEBUG
1632   clutter_actor_verify_map_state (self);
1633 #endif
1634
1635   priv = self->priv;
1636
1637   g_object_freeze_notify (G_OBJECT (self));
1638
1639   set_show_on_set_parent (self, TRUE);
1640
1641   /* if we're showing a child that needs to expand, or may
1642    * expand, then we need to recompute the expand flags for
1643    * its parent as well
1644    */
1645   if (priv->needs_compute_expand ||
1646       priv->needs_x_expand ||
1647       priv->needs_y_expand)
1648     {
1649       clutter_actor_queue_compute_expand (self);
1650     }
1651
1652   g_signal_emit (self, actor_signals[SHOW], 0);
1653   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1654
1655   if (priv->parent != NULL)
1656     clutter_actor_queue_redraw (priv->parent);
1657
1658   g_object_thaw_notify (G_OBJECT (self));
1659 }
1660
1661 /**
1662  * clutter_actor_show_all:
1663  * @self: a #ClutterActor
1664  *
1665  * Calls clutter_actor_show() on all children of an actor (if any).
1666  *
1667  * Since: 0.2
1668  *
1669  * Deprecated: 1.10: Actors are visible by default
1670  */
1671 void
1672 clutter_actor_show_all (ClutterActor *self)
1673 {
1674   ClutterActorClass *klass;
1675
1676   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1677
1678   klass = CLUTTER_ACTOR_GET_CLASS (self);
1679   if (klass->show_all)
1680     klass->show_all (self);
1681 }
1682
1683 static void
1684 clutter_actor_real_hide (ClutterActor *self)
1685 {
1686   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1687     {
1688       ClutterActorPrivate *priv = self->priv;
1689
1690       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1691
1692       /* we notify on the "visible" flag in the clutter_actor_hide()
1693        * wrapper so the entire hide signal emission completes first
1694        * (?)
1695        */
1696       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1697
1698       /* we queue a relayout unless the actor is inside a
1699        * container that explicitly told us not to
1700        */
1701       if (priv->parent != NULL &&
1702           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1703         clutter_actor_queue_relayout (priv->parent);
1704     }
1705 }
1706
1707 /**
1708  * clutter_actor_hide:
1709  * @self: A #ClutterActor
1710  *
1711  * Flags an actor to be hidden. A hidden actor will not be
1712  * rendered on the stage.
1713  *
1714  * Actors are visible by default.
1715  *
1716  * If this function is called on an actor without a parent, the
1717  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1718  * as a side-effect.
1719  */
1720 void
1721 clutter_actor_hide (ClutterActor *self)
1722 {
1723   ClutterActorPrivate *priv;
1724
1725   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1726
1727   /* simple optimization */
1728   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1729     {
1730       /* we still need to set the :show-on-set-parent property, in
1731        * case hide() is called on an unparented actor
1732        */
1733       set_show_on_set_parent (self, FALSE);
1734       return;
1735     }
1736
1737 #ifdef CLUTTER_ENABLE_DEBUG
1738   clutter_actor_verify_map_state (self);
1739 #endif
1740
1741   priv = self->priv;
1742
1743   g_object_freeze_notify (G_OBJECT (self));
1744
1745   set_show_on_set_parent (self, FALSE);
1746
1747   /* if we're hiding a child that needs to expand, or may
1748    * expand, then we need to recompute the expand flags for
1749    * its parent as well
1750    */
1751   if (priv->needs_compute_expand ||
1752       priv->needs_x_expand ||
1753       priv->needs_y_expand)
1754     {
1755       clutter_actor_queue_compute_expand (self);
1756     }
1757
1758   g_signal_emit (self, actor_signals[HIDE], 0);
1759   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1760
1761   if (priv->parent != NULL)
1762     clutter_actor_queue_redraw (priv->parent);
1763
1764   g_object_thaw_notify (G_OBJECT (self));
1765 }
1766
1767 /**
1768  * clutter_actor_hide_all:
1769  * @self: a #ClutterActor
1770  *
1771  * Calls clutter_actor_hide() on all child actors (if any).
1772  *
1773  * Since: 0.2
1774  *
1775  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1776  *   prevent its children from being painted as well.
1777  */
1778 void
1779 clutter_actor_hide_all (ClutterActor *self)
1780 {
1781   ClutterActorClass *klass;
1782
1783   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1784
1785   klass = CLUTTER_ACTOR_GET_CLASS (self);
1786   if (klass->hide_all)
1787     klass->hide_all (self);
1788 }
1789
1790 /**
1791  * clutter_actor_realize:
1792  * @self: A #ClutterActor
1793  *
1794  * Realization informs the actor that it is attached to a stage. It
1795  * can use this to allocate resources if it wanted to delay allocation
1796  * until it would be rendered. However it is perfectly acceptable for
1797  * an actor to create resources before being realized because Clutter
1798  * only ever has a single rendering context so that actor is free to
1799  * be moved from one stage to another.
1800  *
1801  * This function does nothing if the actor is already realized.
1802  *
1803  * Because a realized actor must have realized parent actors, calling
1804  * clutter_actor_realize() will also realize all parents of the actor.
1805  *
1806  * This function does not realize child actors, except in the special
1807  * case that realizing the stage, when the stage is visible, will
1808  * suddenly map (and thus realize) the children of the stage.
1809  **/
1810 void
1811 clutter_actor_realize (ClutterActor *self)
1812 {
1813   ClutterActorPrivate *priv;
1814
1815   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1816
1817   priv = self->priv;
1818
1819 #ifdef CLUTTER_ENABLE_DEBUG
1820   clutter_actor_verify_map_state (self);
1821 #endif
1822
1823   if (CLUTTER_ACTOR_IS_REALIZED (self))
1824     return;
1825
1826   /* To be realized, our parent actors must be realized first.
1827    * This will only succeed if we're inside a toplevel.
1828    */
1829   if (priv->parent != NULL)
1830     clutter_actor_realize (priv->parent);
1831
1832   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1833     {
1834       /* toplevels can be realized at any time */
1835     }
1836   else
1837     {
1838       /* "Fail" the realization if parent is missing or unrealized;
1839        * this should really be a g_warning() not some kind of runtime
1840        * failure; how can an app possibly recover? Instead it's a bug
1841        * in the app and the app should get an explanatory warning so
1842        * someone can fix it. But for now it's too hard to fix this
1843        * because e.g. ClutterTexture needs reworking.
1844        */
1845       if (priv->parent == NULL ||
1846           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1847         return;
1848     }
1849
1850   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1851
1852   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1853   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1854
1855   g_signal_emit (self, actor_signals[REALIZE], 0);
1856
1857   /* Stage actor is allowed to unset the realized flag again in its
1858    * default signal handler, though that is a pathological situation.
1859    */
1860
1861   /* If realization "failed" we'll have to update child state. */
1862   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1863 }
1864
1865 static void
1866 clutter_actor_real_unrealize (ClutterActor *self)
1867 {
1868   /* we must be unmapped (implying our children are also unmapped) */
1869   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1870 }
1871
1872 /**
1873  * clutter_actor_unrealize:
1874  * @self: A #ClutterActor
1875  *
1876  * Unrealization informs the actor that it may be being destroyed or
1877  * moved to another stage. The actor may want to destroy any
1878  * underlying graphics resources at this point. However it is
1879  * perfectly acceptable for it to retain the resources until the actor
1880  * is destroyed because Clutter only ever uses a single rendering
1881  * context and all of the graphics resources are valid on any stage.
1882  *
1883  * Because mapped actors must be realized, actors may not be
1884  * unrealized if they are mapped. This function hides the actor to be
1885  * sure it isn't mapped, an application-visible side effect that you
1886  * may not be expecting.
1887  *
1888  * This function should not be called by application code.
1889  */
1890 void
1891 clutter_actor_unrealize (ClutterActor *self)
1892 {
1893   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1894   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1895
1896 /* This function should not really be in the public API, because
1897  * there isn't a good reason to call it. ClutterActor will already
1898  * unrealize things for you when it's important to do so.
1899  *
1900  * If you were using clutter_actor_unrealize() in a dispose
1901  * implementation, then don't, just chain up to ClutterActor's
1902  * dispose.
1903  *
1904  * If you were using clutter_actor_unrealize() to implement
1905  * unrealizing children of your container, then don't, ClutterActor
1906  * will already take care of that.
1907  *
1908  * If you were using clutter_actor_unrealize() to re-realize to
1909  * create your resources in a different way, then use
1910  * _clutter_actor_rerealize() (inside Clutter) or just call your
1911  * code that recreates your resources directly (outside Clutter).
1912  */
1913
1914 #ifdef CLUTTER_ENABLE_DEBUG
1915   clutter_actor_verify_map_state (self);
1916 #endif
1917
1918   clutter_actor_hide (self);
1919
1920   clutter_actor_unrealize_not_hiding (self);
1921 }
1922
1923 static ClutterActorTraverseVisitFlags
1924 unrealize_actor_before_children_cb (ClutterActor *self,
1925                                     int depth,
1926                                     void *user_data)
1927 {
1928   /* If an actor is already unrealized we know its children have also
1929    * already been unrealized... */
1930   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1931     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1932
1933   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1934
1935   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1936 }
1937
1938 static ClutterActorTraverseVisitFlags
1939 unrealize_actor_after_children_cb (ClutterActor *self,
1940                                    int depth,
1941                                    void *user_data)
1942 {
1943   /* We want to unset the realized flag only _after_
1944    * child actors are unrealized, to maintain invariants.
1945    */
1946   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1947   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1948   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1949 }
1950
1951 /*
1952  * clutter_actor_unrealize_not_hiding:
1953  * @self: A #ClutterActor
1954  *
1955  * Unrealization informs the actor that it may be being destroyed or
1956  * moved to another stage. The actor may want to destroy any
1957  * underlying graphics resources at this point. However it is
1958  * perfectly acceptable for it to retain the resources until the actor
1959  * is destroyed because Clutter only ever uses a single rendering
1960  * context and all of the graphics resources are valid on any stage.
1961  *
1962  * Because mapped actors must be realized, actors may not be
1963  * unrealized if they are mapped. You must hide the actor or one of
1964  * its parents before attempting to unrealize.
1965  *
1966  * This function is separate from clutter_actor_unrealize() because it
1967  * does not automatically hide the actor.
1968  * Actors need not be hidden to be unrealized, they just need to
1969  * be unmapped. In fact we don't want to mess up the application's
1970  * setting of the "visible" flag, so hiding is very undesirable.
1971  *
1972  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1973  * backward compatibility.
1974  */
1975 static void
1976 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1977 {
1978   _clutter_actor_traverse (self,
1979                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1980                            unrealize_actor_before_children_cb,
1981                            unrealize_actor_after_children_cb,
1982                            NULL);
1983 }
1984
1985 /*
1986  * _clutter_actor_rerealize:
1987  * @self: A #ClutterActor
1988  * @callback: Function to call while unrealized
1989  * @data: data for callback
1990  *
1991  * If an actor is already unrealized, this just calls the callback.
1992  *
1993  * If it is realized, it unrealizes temporarily, calls the callback,
1994  * and then re-realizes the actor.
1995  *
1996  * As a side effect, leaves all children of the actor unrealized if
1997  * the actor was realized but not showing.  This is because when we
1998  * unrealize the actor temporarily we must unrealize its children
1999  * (e.g. children of a stage can't be realized if stage window is
2000  * gone). And we aren't clever enough to save the realization state of
2001  * all children. In most cases this should not matter, because
2002  * the children will automatically realize when they next become mapped.
2003  */
2004 void
2005 _clutter_actor_rerealize (ClutterActor    *self,
2006                           ClutterCallback  callback,
2007                           void            *data)
2008 {
2009   gboolean was_mapped;
2010   gboolean was_showing;
2011   gboolean was_realized;
2012
2013   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2014
2015 #ifdef CLUTTER_ENABLE_DEBUG
2016   clutter_actor_verify_map_state (self);
2017 #endif
2018
2019   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
2020   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
2021   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
2022
2023   /* Must be unmapped to unrealize. Note we only have to hide this
2024    * actor if it was mapped (if all parents were showing).  If actor
2025    * is merely visible (but not mapped), then that's fine, we can
2026    * leave it visible.
2027    */
2028   if (was_mapped)
2029     clutter_actor_hide (self);
2030
2031   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2032
2033   /* unrealize self and all children */
2034   clutter_actor_unrealize_not_hiding (self);
2035
2036   if (callback != NULL)
2037     {
2038       (* callback) (self, data);
2039     }
2040
2041   if (was_showing)
2042     clutter_actor_show (self); /* will realize only if mapping implies it */
2043   else if (was_realized)
2044     clutter_actor_realize (self); /* realize self and all parents */
2045 }
2046
2047 static void
2048 clutter_actor_real_pick (ClutterActor       *self,
2049                          const ClutterColor *color)
2050 {
2051   /* the default implementation is just to paint a rectangle
2052    * with the same size of the actor using the passed color
2053    */
2054   if (clutter_actor_should_pick_paint (self))
2055     {
2056       ClutterActorBox box = { 0, };
2057       float width, height;
2058
2059       clutter_actor_get_allocation_box (self, &box);
2060
2061       width = box.x2 - box.x1;
2062       height = box.y2 - box.y1;
2063
2064       cogl_set_source_color4ub (color->red,
2065                                 color->green,
2066                                 color->blue,
2067                                 color->alpha);
2068
2069       cogl_rectangle (0, 0, width, height);
2070     }
2071
2072   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2073    * with existing container classes that override the pick() virtual
2074    * and chain up to the default implementation - otherwise we'll end up
2075    * painting our children twice.
2076    *
2077    * this has to go away for 2.0; hopefully along the pick() itself.
2078    */
2079   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2080     {
2081       ClutterActor *iter;
2082
2083       for (iter = self->priv->first_child;
2084            iter != NULL;
2085            iter = iter->priv->next_sibling)
2086         clutter_actor_paint (iter);
2087     }
2088 }
2089
2090 /**
2091  * clutter_actor_should_pick_paint:
2092  * @self: A #ClutterActor
2093  *
2094  * Should be called inside the implementation of the
2095  * #ClutterActor::pick virtual function in order to check whether
2096  * the actor should paint itself in pick mode or not.
2097  *
2098  * This function should never be called directly by applications.
2099  *
2100  * Return value: %TRUE if the actor should paint its silhouette,
2101  *   %FALSE otherwise
2102  */
2103 gboolean
2104 clutter_actor_should_pick_paint (ClutterActor *self)
2105 {
2106   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2107
2108   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2109       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2110        CLUTTER_ACTOR_IS_REACTIVE (self)))
2111     return TRUE;
2112
2113   return FALSE;
2114 }
2115
2116 static void
2117 clutter_actor_real_get_preferred_width (ClutterActor *self,
2118                                         gfloat        for_height,
2119                                         gfloat       *min_width_p,
2120                                         gfloat       *natural_width_p)
2121 {
2122   ClutterActorPrivate *priv = self->priv;
2123
2124   if (priv->n_children != 0 &&
2125       priv->layout_manager != NULL)
2126     {
2127       ClutterContainer *container = CLUTTER_CONTAINER (self);
2128
2129       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2130                     "for the preferred width",
2131                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2132                     priv->layout_manager);
2133
2134       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2135                                                   container,
2136                                                   for_height,
2137                                                   min_width_p,
2138                                                   natural_width_p);
2139
2140       return;
2141     }
2142
2143   /* Default implementation is always 0x0, usually an actor
2144    * using this default is relying on someone to set the
2145    * request manually
2146    */
2147   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2148
2149   if (min_width_p)
2150     *min_width_p = 0;
2151
2152   if (natural_width_p)
2153     *natural_width_p = 0;
2154 }
2155
2156 static void
2157 clutter_actor_real_get_preferred_height (ClutterActor *self,
2158                                          gfloat        for_width,
2159                                          gfloat       *min_height_p,
2160                                          gfloat       *natural_height_p)
2161 {
2162   ClutterActorPrivate *priv = self->priv;
2163
2164   if (priv->n_children != 0 &&
2165       priv->layout_manager != NULL)
2166     {
2167       ClutterContainer *container = CLUTTER_CONTAINER (self);
2168
2169       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2170                     "for the preferred height",
2171                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2172                     priv->layout_manager);
2173
2174       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2175                                                    container,
2176                                                    for_width,
2177                                                    min_height_p,
2178                                                    natural_height_p);
2179
2180       return;
2181     }
2182   /* Default implementation is always 0x0, usually an actor
2183    * using this default is relying on someone to set the
2184    * request manually
2185    */
2186   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2187
2188   if (min_height_p)
2189     *min_height_p = 0;
2190
2191   if (natural_height_p)
2192     *natural_height_p = 0;
2193 }
2194
2195 static void
2196 clutter_actor_store_old_geometry (ClutterActor    *self,
2197                                   ClutterActorBox *box)
2198 {
2199   *box = self->priv->allocation;
2200 }
2201
2202 static inline void
2203 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2204                                           const ClutterActorBox *old)
2205 {
2206   ClutterActorPrivate *priv = self->priv;
2207   GObject *obj = G_OBJECT (self);
2208
2209   g_object_freeze_notify (obj);
2210
2211   /* to avoid excessive requisition or allocation cycles we
2212    * use the cached values.
2213    *
2214    * - if we don't have an allocation we assume that we need
2215    *   to notify anyway
2216    * - if we don't have a width or a height request we notify
2217    *   width and height
2218    * - if we have a valid allocation then we check the old
2219    *   bounding box with the current allocation and we notify
2220    *   the changes
2221    */
2222   if (priv->needs_allocation)
2223     {
2224       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2225       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2226       g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2227       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2228       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2229       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2230     }
2231   else if (priv->needs_width_request || priv->needs_height_request)
2232     {
2233       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2234       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2235       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2236     }
2237   else
2238     {
2239       gfloat x, y;
2240       gfloat width, height;
2241
2242       x = priv->allocation.x1;
2243       y = priv->allocation.y1;
2244       width = priv->allocation.x2 - priv->allocation.x1;
2245       height = priv->allocation.y2 - priv->allocation.y1;
2246
2247       if (x != old->x1)
2248         {
2249           g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2250           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2251         }
2252
2253       if (y != old->y1)
2254         {
2255           g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2256           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2257         }
2258
2259       if (width != (old->x2 - old->x1))
2260         {
2261           g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2262           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2263         }
2264
2265       if (height != (old->y2 - old->y1))
2266         {
2267           g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2268           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2269         }
2270     }
2271
2272   g_object_thaw_notify (obj);
2273 }
2274
2275 /*< private >
2276  * clutter_actor_set_allocation_internal:
2277  * @self: a #ClutterActor
2278  * @box: a #ClutterActorBox
2279  * @flags: allocation flags
2280  *
2281  * Stores the allocation of @self.
2282  *
2283  * This function only performs basic storage and property notification.
2284  *
2285  * This function should be called by clutter_actor_set_allocation()
2286  * and by the default implementation of #ClutterActorClass.allocate().
2287  *
2288  * Return value: %TRUE if the allocation of the #ClutterActor has been
2289  *   changed, and %FALSE otherwise
2290  */
2291 static inline gboolean
2292 clutter_actor_set_allocation_internal (ClutterActor           *self,
2293                                        const ClutterActorBox  *box,
2294                                        ClutterAllocationFlags  flags)
2295 {
2296   ClutterActorPrivate *priv = self->priv;
2297   GObject *obj;
2298   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2299   gboolean retval;
2300   ClutterActorBox old_alloc = { 0, };
2301
2302   obj = G_OBJECT (self);
2303
2304   g_object_freeze_notify (obj);
2305
2306   clutter_actor_store_old_geometry (self, &old_alloc);
2307
2308   x1_changed = priv->allocation.x1 != box->x1;
2309   y1_changed = priv->allocation.y1 != box->y1;
2310   x2_changed = priv->allocation.x2 != box->x2;
2311   y2_changed = priv->allocation.y2 != box->y2;
2312
2313   priv->allocation = *box;
2314   priv->allocation_flags = flags;
2315
2316   /* allocation is authoritative */
2317   priv->needs_width_request = FALSE;
2318   priv->needs_height_request = FALSE;
2319   priv->needs_allocation = FALSE;
2320
2321   if (x1_changed ||
2322       y1_changed ||
2323       x2_changed ||
2324       y2_changed)
2325     {
2326       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2327                     _clutter_actor_get_debug_name (self));
2328
2329       priv->transform_valid = FALSE;
2330
2331       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2332
2333       /* if the allocation changes, so does the content box */
2334       if (priv->content != NULL)
2335         {
2336           priv->content_box_valid = FALSE;
2337           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2338         }
2339
2340       retval = TRUE;
2341     }
2342   else
2343     retval = FALSE;
2344
2345   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2346
2347   g_object_thaw_notify (obj);
2348
2349   return retval;
2350 }
2351
2352 static void clutter_actor_real_allocate (ClutterActor           *self,
2353                                          const ClutterActorBox  *box,
2354                                          ClutterAllocationFlags  flags);
2355
2356 static inline void
2357 clutter_actor_maybe_layout_children (ClutterActor           *self,
2358                                      const ClutterActorBox  *allocation,
2359                                      ClutterAllocationFlags  flags)
2360 {
2361   ClutterActorPrivate *priv = self->priv;
2362
2363   /* this is going to be a bit hard to follow, so let's put an explanation
2364    * here.
2365    *
2366    * we want ClutterActor to have a default layout manager if the actor was
2367    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2368    *
2369    * we also want any subclass of ClutterActor that does not override the
2370    * ::allocate() virtual function to delegate to a layout manager.
2371    *
2372    * finally, we want to allow people subclassing ClutterActor and overriding
2373    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2374    *
2375    * on the other hand, we want existing actor subclasses overriding the
2376    * ::allocate() virtual function and chaining up to the parent's
2377    * implementation to continue working without allocating their children
2378    * twice, or without entering an allocation loop.
2379    *
2380    * for the first two points, we check if the class of the actor is
2381    * overridding the ::allocate() virtual function; if it isn't, then we
2382    * follow through with checking whether we have children and a layout
2383    * manager, and eventually calling clutter_layout_manager_allocate().
2384    *
2385    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2386    * allocation flags that we got passed, and if it is present, we continue
2387    * with the check above.
2388    *
2389    * if neither of these two checks yields a positive result, we just
2390    * assume that the ::allocate() virtual function that resulted in this
2391    * function being called will also allocate the children of the actor.
2392    */
2393
2394   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2395     goto check_layout;
2396
2397   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2398     goto check_layout;
2399
2400   return;
2401
2402 check_layout:
2403   if (priv->n_children != 0 &&
2404       priv->layout_manager != NULL)
2405     {
2406       ClutterContainer *container = CLUTTER_CONTAINER (self);
2407       ClutterAllocationFlags children_flags;
2408       ClutterActorBox children_box;
2409
2410       /* normalize the box passed to the layout manager */
2411       children_box.x1 = children_box.y1 = 0.f;
2412       children_box.x2 = (allocation->x2 - allocation->x1);
2413       children_box.y2 = (allocation->y2 - allocation->y1);
2414
2415       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2416        * the actor's children, since it refers only to the current
2417        * actor's allocation.
2418        */
2419       children_flags = flags;
2420       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2421
2422       CLUTTER_NOTE (LAYOUT,
2423                     "Allocating %d children of %s "
2424                     "at { %.2f, %.2f - %.2f x %.2f } "
2425                     "using %s",
2426                     priv->n_children,
2427                     _clutter_actor_get_debug_name (self),
2428                     allocation->x1,
2429                     allocation->y1,
2430                     (allocation->x2 - allocation->x1),
2431                     (allocation->y2 - allocation->y1),
2432                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2433
2434       clutter_layout_manager_allocate (priv->layout_manager,
2435                                        container,
2436                                        &children_box,
2437                                        children_flags);
2438     }
2439 }
2440
2441 static void
2442 clutter_actor_real_allocate (ClutterActor           *self,
2443                              const ClutterActorBox  *box,
2444                              ClutterAllocationFlags  flags)
2445 {
2446   ClutterActorPrivate *priv = self->priv;
2447   gboolean changed;
2448
2449   g_object_freeze_notify (G_OBJECT (self));
2450
2451   changed = clutter_actor_set_allocation_internal (self, box, flags);
2452
2453   /* we allocate our children before we notify changes in our geometry,
2454    * so that people connecting to properties will be able to get valid
2455    * data out of the sub-tree of the scene graph that has this actor at
2456    * the root.
2457    */
2458   clutter_actor_maybe_layout_children (self, box, flags);
2459
2460   if (changed)
2461     {
2462       ClutterActorBox signal_box = priv->allocation;
2463       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2464
2465       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2466                      &signal_box,
2467                      signal_flags);
2468     }
2469
2470   g_object_thaw_notify (G_OBJECT (self));
2471 }
2472
2473 static void
2474 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2475                                     ClutterActor *origin)
2476 {
2477   /* no point in queuing a redraw on a destroyed actor */
2478   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2479     return;
2480
2481   /* NB: We can't bail out early here if the actor is hidden in case
2482    * the actor bas been cloned. In this case the clone will need to
2483    * receive the signal so it can queue its own redraw.
2484    */
2485
2486   /* calls klass->queue_redraw in default handler */
2487   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2488 }
2489
2490 static void
2491 clutter_actor_real_queue_redraw (ClutterActor *self,
2492                                  ClutterActor *origin)
2493 {
2494   ClutterActor *parent;
2495
2496   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2497                 _clutter_actor_get_debug_name (self),
2498                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2499                                : "same actor");
2500
2501   /* no point in queuing a redraw on a destroyed actor */
2502   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2503     return;
2504
2505   /* If the queue redraw is coming from a child then the actor has
2506      become dirty and any queued effect is no longer valid */
2507   if (self != origin)
2508     {
2509       self->priv->is_dirty = TRUE;
2510       self->priv->effect_to_redraw = NULL;
2511     }
2512
2513   /* If the actor isn't visible, we still had to emit the signal
2514    * to allow for a ClutterClone, but the appearance of the parent
2515    * won't change so we don't have to propagate up the hierarchy.
2516    */
2517   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2518     return;
2519
2520   /* Although we could determine here that a full stage redraw
2521    * has already been queued and immediately bail out, we actually
2522    * guarantee that we will propagate a queue-redraw signal to our
2523    * parent at least once so that it's possible to implement a
2524    * container that tracks which of its children have queued a
2525    * redraw.
2526    */
2527   if (self->priv->propagated_one_redraw)
2528     {
2529       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2530       if (stage != NULL &&
2531           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2532         return;
2533     }
2534
2535   self->priv->propagated_one_redraw = TRUE;
2536
2537   /* notify parents, if they are all visible eventually we'll
2538    * queue redraw on the stage, which queues the redraw idle.
2539    */
2540   parent = clutter_actor_get_parent (self);
2541   if (parent != NULL)
2542     {
2543       /* this will go up recursively */
2544       _clutter_actor_signal_queue_redraw (parent, origin);
2545     }
2546 }
2547
2548 static void
2549 clutter_actor_real_queue_relayout (ClutterActor *self)
2550 {
2551   ClutterActorPrivate *priv = self->priv;
2552
2553   /* no point in queueing a redraw on a destroyed actor */
2554   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2555     return;
2556
2557   priv->needs_width_request  = TRUE;
2558   priv->needs_height_request = TRUE;
2559   priv->needs_allocation     = TRUE;
2560
2561   /* reset the cached size requests */
2562   memset (priv->width_requests, 0,
2563           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2564   memset (priv->height_requests, 0,
2565           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2566
2567   /* We need to go all the way up the hierarchy */
2568   if (priv->parent != NULL)
2569     _clutter_actor_queue_only_relayout (priv->parent);
2570 }
2571
2572 /**
2573  * clutter_actor_apply_relative_transform_to_point:
2574  * @self: A #ClutterActor
2575  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2576  *   default #ClutterStage
2577  * @point: A point as #ClutterVertex
2578  * @vertex: (out caller-allocates): The translated #ClutterVertex
2579  *
2580  * Transforms @point in coordinates relative to the actor into
2581  * ancestor-relative coordinates using the relevant transform
2582  * stack (i.e. scale, rotation, etc).
2583  *
2584  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2585  * this case, the coordinates returned will be the coordinates on
2586  * the stage before the projection is applied. This is different from
2587  * the behaviour of clutter_actor_apply_transform_to_point().
2588  *
2589  * Since: 0.6
2590  */
2591 void
2592 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2593                                                  ClutterActor        *ancestor,
2594                                                  const ClutterVertex *point,
2595                                                  ClutterVertex       *vertex)
2596 {
2597   gfloat w;
2598   CoglMatrix matrix;
2599
2600   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2601   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2602   g_return_if_fail (point != NULL);
2603   g_return_if_fail (vertex != NULL);
2604
2605   *vertex = *point;
2606   w = 1.0;
2607
2608   if (ancestor == NULL)
2609     ancestor = _clutter_actor_get_stage_internal (self);
2610
2611   if (ancestor == NULL)
2612     {
2613       *vertex = *point;
2614       return;
2615     }
2616
2617   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2618   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2619 }
2620
2621 static gboolean
2622 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2623                                          const ClutterVertex *vertices_in,
2624                                          ClutterVertex *vertices_out,
2625                                          int n_vertices)
2626 {
2627   ClutterActor *stage;
2628   CoglMatrix modelview;
2629   CoglMatrix projection;
2630   float viewport[4];
2631
2632   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2633
2634   stage = _clutter_actor_get_stage_internal (self);
2635
2636   /* We really can't do anything meaningful in this case so don't try
2637    * to do any transform */
2638   if (stage == NULL)
2639     return FALSE;
2640
2641   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2642    * that gets us to stage coordinates, we want to go all the way to eye
2643    * coordinates */
2644   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2645
2646   /* Fetch the projection and viewport */
2647   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2648   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2649                                &viewport[0],
2650                                &viewport[1],
2651                                &viewport[2],
2652                                &viewport[3]);
2653
2654   _clutter_util_fully_transform_vertices (&modelview,
2655                                           &projection,
2656                                           viewport,
2657                                           vertices_in,
2658                                           vertices_out,
2659                                           n_vertices);
2660
2661   return TRUE;
2662 }
2663
2664 /**
2665  * clutter_actor_apply_transform_to_point:
2666  * @self: A #ClutterActor
2667  * @point: A point as #ClutterVertex
2668  * @vertex: (out caller-allocates): The translated #ClutterVertex
2669  *
2670  * Transforms @point in coordinates relative to the actor
2671  * into screen-relative coordinates with the current actor
2672  * transformation (i.e. scale, rotation, etc)
2673  *
2674  * Since: 0.4
2675  **/
2676 void
2677 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2678                                         const ClutterVertex *point,
2679                                         ClutterVertex       *vertex)
2680 {
2681   g_return_if_fail (point != NULL);
2682   g_return_if_fail (vertex != NULL);
2683   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2684 }
2685
2686 /*
2687  * _clutter_actor_get_relative_transformation_matrix:
2688  * @self: The actor whose coordinate space you want to transform from.
2689  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2690  *            or %NULL if you want to transform all the way to eye coordinates.
2691  * @matrix: A #CoglMatrix to store the transformation
2692  *
2693  * This gets a transformation @matrix that will transform coordinates from the
2694  * coordinate space of @self into the coordinate space of @ancestor.
2695  *
2696  * For example if you need a matrix that can transform the local actor
2697  * coordinates of @self into stage coordinates you would pass the actor's stage
2698  * pointer as the @ancestor.
2699  *
2700  * If you pass %NULL then the transformation will take you all the way through
2701  * to eye coordinates. This can be useful if you want to extract the entire
2702  * modelview transform that Clutter applies before applying the projection
2703  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2704  * using cogl_set_modelview_matrix() for example then you would want a matrix
2705  * that transforms into eye coordinates.
2706  *
2707  * <note><para>This function explicitly initializes the given @matrix. If you just
2708  * want clutter to multiply a relative transformation with an existing matrix
2709  * you can use clutter_actor_apply_relative_transformation_matrix()
2710  * instead.</para></note>
2711  *
2712  */
2713 /* XXX: We should consider caching the stage relative modelview along with
2714  * the actor itself */
2715 static void
2716 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2717                                                    ClutterActor *ancestor,
2718                                                    CoglMatrix *matrix)
2719 {
2720   cogl_matrix_init_identity (matrix);
2721
2722   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2723 }
2724
2725 /* Project the given @box into stage window coordinates, writing the
2726  * transformed vertices to @verts[]. */
2727 static gboolean
2728 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2729                                           const ClutterActorBox *box,
2730                                           ClutterVertex          verts[])
2731 {
2732   ClutterVertex box_vertices[4];
2733
2734   box_vertices[0].x = box->x1;
2735   box_vertices[0].y = box->y1;
2736   box_vertices[0].z = 0;
2737   box_vertices[1].x = box->x2;
2738   box_vertices[1].y = box->y1;
2739   box_vertices[1].z = 0;
2740   box_vertices[2].x = box->x1;
2741   box_vertices[2].y = box->y2;
2742   box_vertices[2].z = 0;
2743   box_vertices[3].x = box->x2;
2744   box_vertices[3].y = box->y2;
2745   box_vertices[3].z = 0;
2746
2747   return
2748     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2749 }
2750
2751 /**
2752  * clutter_actor_get_allocation_vertices:
2753  * @self: A #ClutterActor
2754  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2755  *   against, or %NULL to use the #ClutterStage
2756  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2757  *   location for an array of 4 #ClutterVertex in which to store the result
2758  *
2759  * Calculates the transformed coordinates of the four corners of the
2760  * actor in the plane of @ancestor. The returned vertices relate to
2761  * the #ClutterActorBox coordinates as follows:
2762  * <itemizedlist>
2763  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2764  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2765  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2766  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2767  * </itemizedlist>
2768  *
2769  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2770  * this case, the coordinates returned will be the coordinates on
2771  * the stage before the projection is applied. This is different from
2772  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2773  *
2774  * Since: 0.6
2775  */
2776 void
2777 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2778                                        ClutterActor  *ancestor,
2779                                        ClutterVertex  verts[])
2780 {
2781   ClutterActorPrivate *priv;
2782   ClutterActorBox box;
2783   ClutterVertex vertices[4];
2784   CoglMatrix modelview;
2785
2786   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2787   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2788
2789   if (ancestor == NULL)
2790     ancestor = _clutter_actor_get_stage_internal (self);
2791
2792   /* Fallback to a NOP transform if the actor isn't parented under a
2793    * stage. */
2794   if (ancestor == NULL)
2795     ancestor = self;
2796
2797   priv = self->priv;
2798
2799   /* if the actor needs to be allocated we force a relayout, so that
2800    * we will have valid values to use in the transformations */
2801   if (priv->needs_allocation)
2802     {
2803       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2804       if (stage)
2805         _clutter_stage_maybe_relayout (stage);
2806       else
2807         {
2808           box.x1 = box.y1 = 0;
2809           /* The result isn't really meaningful in this case but at
2810            * least try to do something *vaguely* reasonable... */
2811           clutter_actor_get_size (self, &box.x2, &box.y2);
2812         }
2813     }
2814
2815   clutter_actor_get_allocation_box (self, &box);
2816
2817   vertices[0].x = box.x1;
2818   vertices[0].y = box.y1;
2819   vertices[0].z = 0;
2820   vertices[1].x = box.x2;
2821   vertices[1].y = box.y1;
2822   vertices[1].z = 0;
2823   vertices[2].x = box.x1;
2824   vertices[2].y = box.y2;
2825   vertices[2].z = 0;
2826   vertices[3].x = box.x2;
2827   vertices[3].y = box.y2;
2828   vertices[3].z = 0;
2829
2830   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2831                                                      &modelview);
2832
2833   cogl_matrix_transform_points (&modelview,
2834                                 3,
2835                                 sizeof (ClutterVertex),
2836                                 vertices,
2837                                 sizeof (ClutterVertex),
2838                                 vertices,
2839                                 4);
2840 }
2841
2842 /**
2843  * clutter_actor_get_abs_allocation_vertices:
2844  * @self: A #ClutterActor
2845  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2846  *   of 4 #ClutterVertex where to store the result.
2847  *
2848  * Calculates the transformed screen coordinates of the four corners of
2849  * the actor; the returned vertices relate to the #ClutterActorBox
2850  * coordinates  as follows:
2851  * <itemizedlist>
2852  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2853  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2854  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2855  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2856  * </itemizedlist>
2857  *
2858  * Since: 0.4
2859  */
2860 void
2861 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2862                                            ClutterVertex  verts[])
2863 {
2864   ClutterActorPrivate *priv;
2865   ClutterActorBox actor_space_allocation;
2866
2867   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2868
2869   priv = self->priv;
2870
2871   /* if the actor needs to be allocated we force a relayout, so that
2872    * the actor allocation box will be valid for
2873    * _clutter_actor_transform_and_project_box()
2874    */
2875   if (priv->needs_allocation)
2876     {
2877       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2878       /* There's nothing meaningful we can do now */
2879       if (!stage)
2880         return;
2881
2882       _clutter_stage_maybe_relayout (stage);
2883     }
2884
2885   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2886    * own coordinate space... */
2887   actor_space_allocation.x1 = 0;
2888   actor_space_allocation.y1 = 0;
2889   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2890   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2891   _clutter_actor_transform_and_project_box (self,
2892                                             &actor_space_allocation,
2893                                             verts);
2894 }
2895
2896 static void
2897 clutter_actor_real_apply_transform (ClutterActor *self,
2898                                     CoglMatrix   *matrix)
2899 {
2900   ClutterActorPrivate *priv = self->priv;
2901
2902   if (!priv->transform_valid)
2903     {
2904       CoglMatrix *transform = &priv->transform;
2905       const ClutterTransformInfo *info;
2906
2907       info = _clutter_actor_get_transform_info_or_defaults (self);
2908
2909       cogl_matrix_init_identity (transform);
2910
2911       cogl_matrix_translate (transform,
2912                              priv->allocation.x1,
2913                              priv->allocation.y1,
2914                              0.0);
2915
2916       if (info->depth)
2917         cogl_matrix_translate (transform, 0, 0, info->depth);
2918
2919       /*
2920        * because the rotation involves translations, we must scale
2921        * before applying the rotations (if we apply the scale after
2922        * the rotations, the translations included in the rotation are
2923        * not scaled and so the entire object will move on the screen
2924        * as a result of rotating it).
2925        */
2926       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2927         {
2928           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2929                                         &info->scale_center,
2930                                         cogl_matrix_scale (transform,
2931                                                            info->scale_x,
2932                                                            info->scale_y,
2933                                                            1.0));
2934         }
2935
2936       if (info->rz_angle)
2937         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2938                                       &info->rz_center,
2939                                       cogl_matrix_rotate (transform,
2940                                                           info->rz_angle,
2941                                                           0, 0, 1.0));
2942
2943       if (info->ry_angle)
2944         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2945                                       &info->ry_center,
2946                                       cogl_matrix_rotate (transform,
2947                                                           info->ry_angle,
2948                                                           0, 1.0, 0));
2949
2950       if (info->rx_angle)
2951         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2952                                       &info->rx_center,
2953                                       cogl_matrix_rotate (transform,
2954                                                           info->rx_angle,
2955                                                           1.0, 0, 0));
2956
2957       if (!clutter_anchor_coord_is_zero (&info->anchor))
2958         {
2959           gfloat x, y, z;
2960
2961           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2962           cogl_matrix_translate (transform, -x, -y, -z);
2963         }
2964
2965       priv->transform_valid = TRUE;
2966     }
2967
2968   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2969 }
2970
2971 /* Applies the transforms associated with this actor to the given
2972  * matrix. */
2973 void
2974 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2975                                           CoglMatrix *matrix)
2976 {
2977   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2978 }
2979
2980 /*
2981  * clutter_actor_apply_relative_transformation_matrix:
2982  * @self: The actor whose coordinate space you want to transform from.
2983  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2984  *            or %NULL if you want to transform all the way to eye coordinates.
2985  * @matrix: A #CoglMatrix to apply the transformation too.
2986  *
2987  * This multiplies a transform with @matrix that will transform coordinates
2988  * from the coordinate space of @self into the coordinate space of @ancestor.
2989  *
2990  * For example if you need a matrix that can transform the local actor
2991  * coordinates of @self into stage coordinates you would pass the actor's stage
2992  * pointer as the @ancestor.
2993  *
2994  * If you pass %NULL then the transformation will take you all the way through
2995  * to eye coordinates. This can be useful if you want to extract the entire
2996  * modelview transform that Clutter applies before applying the projection
2997  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2998  * using cogl_set_modelview_matrix() for example then you would want a matrix
2999  * that transforms into eye coordinates.
3000  *
3001  * <note>This function doesn't initialize the given @matrix, it simply
3002  * multiplies the requested transformation matrix with the existing contents of
3003  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
3004  * before calling this function, or you can use
3005  * clutter_actor_get_relative_transformation_matrix() instead.</note>
3006  */
3007 void
3008 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
3009                                                      ClutterActor *ancestor,
3010                                                      CoglMatrix *matrix)
3011 {
3012   ClutterActor *parent;
3013
3014   /* Note we terminate before ever calling stage->apply_transform()
3015    * since that would conceptually be relative to the underlying
3016    * window OpenGL coordinates so we'd need a special @ancestor
3017    * value to represent the fake parent of the stage. */
3018   if (self == ancestor)
3019     return;
3020
3021   parent = clutter_actor_get_parent (self);
3022
3023   if (parent != NULL)
3024     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3025                                                          matrix);
3026
3027   _clutter_actor_apply_modelview_transform (self, matrix);
3028 }
3029
3030 static void
3031 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3032                                        ClutterPaintVolume *pv,
3033                                        const char *label,
3034                                        const CoglColor *color)
3035 {
3036   static CoglPipeline *outline = NULL;
3037   CoglPrimitive *prim;
3038   ClutterVertex line_ends[12 * 2];
3039   int n_vertices;
3040   CoglContext *ctx =
3041     clutter_backend_get_cogl_context (clutter_get_default_backend ());
3042   /* XXX: at some point we'll query this from the stage but we can't
3043    * do that until the osx backend uses Cogl natively. */
3044   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3045
3046   if (outline == NULL)
3047     outline = cogl_pipeline_new (ctx);
3048
3049   _clutter_paint_volume_complete (pv);
3050
3051   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3052
3053   /* Front face */
3054   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3055   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3056   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3057   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3058
3059   if (!pv->is_2d)
3060     {
3061       /* Back face */
3062       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3063       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3064       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3065       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3066
3067       /* Lines connecting front face to back face */
3068       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3069       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3070       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3071       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3072     }
3073
3074   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3075                                 n_vertices,
3076                                 (CoglVertexP3 *)line_ends);
3077
3078   cogl_pipeline_set_color (outline, color);
3079   cogl_framebuffer_draw_primitive (fb, outline, prim);
3080   cogl_object_unref (prim);
3081
3082   if (label)
3083     {
3084       PangoLayout *layout;
3085       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3086       pango_layout_set_text (layout, label, -1);
3087       cogl_pango_render_layout (layout,
3088                                 pv->vertices[0].x,
3089                                 pv->vertices[0].y,
3090                                 color,
3091                                 0);
3092       g_object_unref (layout);
3093     }
3094 }
3095
3096 static void
3097 _clutter_actor_draw_paint_volume (ClutterActor *self)
3098 {
3099   ClutterPaintVolume *pv;
3100   CoglColor color;
3101
3102   pv = _clutter_actor_get_paint_volume_mutable (self);
3103   if (!pv)
3104     {
3105       gfloat width, height;
3106       ClutterPaintVolume fake_pv;
3107
3108       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3109       _clutter_paint_volume_init_static (&fake_pv, stage);
3110
3111       clutter_actor_get_size (self, &width, &height);
3112       clutter_paint_volume_set_width (&fake_pv, width);
3113       clutter_paint_volume_set_height (&fake_pv, height);
3114
3115       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3116       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3117                                              _clutter_actor_get_debug_name (self),
3118                                              &color);
3119
3120       clutter_paint_volume_free (&fake_pv);
3121     }
3122   else
3123     {
3124       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3125       _clutter_actor_draw_paint_volume_full (self, pv,
3126                                              _clutter_actor_get_debug_name (self),
3127                                              &color);
3128     }
3129 }
3130
3131 static void
3132 _clutter_actor_paint_cull_result (ClutterActor *self,
3133                                   gboolean success,
3134                                   ClutterCullResult result)
3135 {
3136   ClutterPaintVolume *pv;
3137   CoglColor color;
3138
3139   if (success)
3140     {
3141       if (result == CLUTTER_CULL_RESULT_IN)
3142         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3143       else if (result == CLUTTER_CULL_RESULT_OUT)
3144         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3145       else
3146         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3147     }
3148   else
3149     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3150
3151   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3152     _clutter_actor_draw_paint_volume_full (self, pv,
3153                                            _clutter_actor_get_debug_name (self),
3154                                            &color);
3155   else
3156     {
3157       PangoLayout *layout;
3158       char *label =
3159         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3160       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3161       cogl_set_source_color (&color);
3162
3163       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3164       pango_layout_set_text (layout, label, -1);
3165       cogl_pango_render_layout (layout,
3166                                 0,
3167                                 0,
3168                                 &color,
3169                                 0);
3170       g_free (label);
3171       g_object_unref (layout);
3172     }
3173 }
3174
3175 static int clone_paint_level = 0;
3176
3177 void
3178 _clutter_actor_push_clone_paint (void)
3179 {
3180   clone_paint_level++;
3181 }
3182
3183 void
3184 _clutter_actor_pop_clone_paint (void)
3185 {
3186   clone_paint_level--;
3187 }
3188
3189 static gboolean
3190 in_clone_paint (void)
3191 {
3192   return clone_paint_level > 0;
3193 }
3194
3195 /* Returns TRUE if the actor can be ignored */
3196 /* FIXME: we should return a ClutterCullResult, and
3197  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3198  * means there's no point in trying to cull descendants of the current
3199  * node. */
3200 static gboolean
3201 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3202 {
3203   ClutterActorPrivate *priv = self->priv;
3204   ClutterActor *stage;
3205   const ClutterPlane *stage_clip;
3206
3207   if (!priv->last_paint_volume_valid)
3208     {
3209       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3210                     "->last_paint_volume_valid == FALSE",
3211                     _clutter_actor_get_debug_name (self));
3212       return FALSE;
3213     }
3214
3215   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3216     return FALSE;
3217
3218   stage = _clutter_actor_get_stage_internal (self);
3219   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3220   if (G_UNLIKELY (!stage_clip))
3221     {
3222       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3223                     "No stage clip set",
3224                     _clutter_actor_get_debug_name (self));
3225       return FALSE;
3226     }
3227
3228   if (cogl_get_draw_framebuffer () !=
3229       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3230     {
3231       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3232                     "Current framebuffer doesn't correspond to stage",
3233                     _clutter_actor_get_debug_name (self));
3234       return FALSE;
3235     }
3236
3237   *result_out =
3238     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3239   return TRUE;
3240 }
3241
3242 static void
3243 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3244 {
3245   ClutterActorPrivate *priv = self->priv;
3246   const ClutterPaintVolume *pv;
3247
3248   if (priv->last_paint_volume_valid)
3249     {
3250       clutter_paint_volume_free (&priv->last_paint_volume);
3251       priv->last_paint_volume_valid = FALSE;
3252     }
3253
3254   pv = clutter_actor_get_paint_volume (self);
3255   if (!pv)
3256     {
3257       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3258                     "Actor failed to report a paint volume",
3259                     _clutter_actor_get_debug_name (self));
3260       return;
3261     }
3262
3263   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3264
3265   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3266                                             NULL); /* eye coordinates */
3267
3268   priv->last_paint_volume_valid = TRUE;
3269 }
3270
3271 static inline gboolean
3272 actor_has_shader_data (ClutterActor *self)
3273 {
3274   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3275 }
3276
3277 guint32
3278 _clutter_actor_get_pick_id (ClutterActor *self)
3279 {
3280   if (self->priv->pick_id < 0)
3281     return 0;
3282
3283   return self->priv->pick_id;
3284 }
3285
3286 /* This is the same as clutter_actor_add_effect except that it doesn't
3287    queue a redraw and it doesn't notify on the effect property */
3288 static void
3289 _clutter_actor_add_effect_internal (ClutterActor  *self,
3290                                     ClutterEffect *effect)
3291 {
3292   ClutterActorPrivate *priv = self->priv;
3293
3294   if (priv->effects == NULL)
3295     {
3296       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3297       priv->effects->actor = self;
3298     }
3299
3300   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3301 }
3302
3303 /* This is the same as clutter_actor_remove_effect except that it doesn't
3304    queue a redraw and it doesn't notify on the effect property */
3305 static void
3306 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3307                                        ClutterEffect *effect)
3308 {
3309   ClutterActorPrivate *priv = self->priv;
3310
3311   if (priv->effects == NULL)
3312     return;
3313
3314   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3315
3316   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3317     g_clear_object (&priv->effects);
3318 }
3319
3320 static gboolean
3321 needs_flatten_effect (ClutterActor *self)
3322 {
3323   ClutterActorPrivate *priv = self->priv;
3324
3325   if (G_UNLIKELY (clutter_paint_debug_flags &
3326                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3327     return FALSE;
3328
3329   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3330     return TRUE;
3331   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3332     {
3333       if (clutter_actor_get_paint_opacity (self) < 255 &&
3334           clutter_actor_has_overlaps (self))
3335         return TRUE;
3336     }
3337
3338   return FALSE;
3339 }
3340
3341 static void
3342 add_or_remove_flatten_effect (ClutterActor *self)
3343 {
3344   ClutterActorPrivate *priv = self->priv;
3345
3346   /* Add or remove the flatten effect depending on the
3347      offscreen-redirect property. */
3348   if (needs_flatten_effect (self))
3349     {
3350       if (priv->flatten_effect == NULL)
3351         {
3352           ClutterActorMeta *actor_meta;
3353           gint priority;
3354
3355           priv->flatten_effect = _clutter_flatten_effect_new ();
3356           /* Keep a reference to the effect so that we can queue
3357              redraws from it */
3358           g_object_ref_sink (priv->flatten_effect);
3359
3360           /* Set the priority of the effect to high so that it will
3361              always be applied to the actor first. It uses an internal
3362              priority so that it won't be visible to applications */
3363           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3364           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3365           _clutter_actor_meta_set_priority (actor_meta, priority);
3366
3367           /* This will add the effect without queueing a redraw */
3368           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3369         }
3370     }
3371   else
3372     {
3373       if (priv->flatten_effect != NULL)
3374         {
3375           /* Destroy the effect so that it will lose its fbo cache of
3376              the actor */
3377           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3378           g_clear_object (&priv->flatten_effect);
3379         }
3380     }
3381 }
3382
3383 static void
3384 clutter_actor_real_paint (ClutterActor *actor)
3385 {
3386   ClutterActorPrivate *priv = actor->priv;
3387   ClutterActor *iter;
3388
3389   for (iter = priv->first_child;
3390        iter != NULL;
3391        iter = iter->priv->next_sibling)
3392     {
3393       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3394                     _clutter_actor_get_debug_name (iter),
3395                     _clutter_actor_get_debug_name (actor),
3396                     iter->priv->allocation.x1,
3397                     iter->priv->allocation.y1,
3398                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3399                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3400
3401       clutter_actor_paint (iter);
3402     }
3403 }
3404
3405 static gboolean
3406 clutter_actor_paint_node (ClutterActor     *actor,
3407                           ClutterPaintNode *root)
3408 {
3409   ClutterActorPrivate *priv = actor->priv;
3410
3411   if (root == NULL)
3412     return FALSE;
3413
3414   if (priv->bg_color_set &&
3415       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3416     {
3417       ClutterPaintNode *node;
3418       ClutterColor bg_color;
3419       ClutterActorBox box;
3420
3421       box.x1 = 0.f;
3422       box.y1 = 0.f;
3423       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3424       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3425
3426       bg_color = priv->bg_color;
3427       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3428                      * priv->bg_color.alpha
3429                      / 255;
3430
3431       node = clutter_color_node_new (&bg_color);
3432       clutter_paint_node_set_name (node, "backgroundColor");
3433       clutter_paint_node_add_rectangle (node, &box);
3434       clutter_paint_node_add_child (root, node);
3435       clutter_paint_node_unref (node);
3436     }
3437
3438   if (priv->content != NULL)
3439     _clutter_content_paint_content (priv->content, actor, root);
3440
3441   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3442     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3443
3444   if (clutter_paint_node_get_n_children (root) == 0)
3445     return FALSE;
3446
3447 #ifdef CLUTTER_ENABLE_DEBUG
3448   if (CLUTTER_HAS_DEBUG (PAINT))
3449     {
3450       /* dump the tree only if we have one */
3451       _clutter_paint_node_dump_tree (root);
3452     }
3453 #endif /* CLUTTER_ENABLE_DEBUG */
3454
3455   _clutter_paint_node_paint (root);
3456
3457 #if 0
3458   /* XXX: Uncomment this when we disable emitting the paint signal */
3459   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3460 #endif
3461
3462   return TRUE;
3463 }
3464
3465 /**
3466  * clutter_actor_paint:
3467  * @self: A #ClutterActor
3468  *
3469  * Renders the actor to display.
3470  *
3471  * This function should not be called directly by applications.
3472  * Call clutter_actor_queue_redraw() to queue paints, instead.
3473  *
3474  * This function is context-aware, and will either cause a
3475  * regular paint or a pick paint.
3476  *
3477  * This function will emit the #ClutterActor::paint signal or
3478  * the #ClutterActor::pick signal, depending on the context.
3479  *
3480  * This function does not paint the actor if the actor is set to 0,
3481  * unless it is performing a pick paint.
3482  */
3483 void
3484 clutter_actor_paint (ClutterActor *self)
3485 {
3486   ClutterActorPrivate *priv;
3487   ClutterPickMode pick_mode;
3488   gboolean clip_set = FALSE;
3489   gboolean shader_applied = FALSE;
3490
3491   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3492                           "Actor real-paint counter",
3493                           "Increments each time any actor is painted",
3494                           0 /* no application private data */);
3495   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3496                           "Actor pick-paint counter",
3497                           "Increments each time any actor is painted "
3498                           "for picking",
3499                           0 /* no application private data */);
3500
3501   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3502
3503   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3504     return;
3505
3506   priv = self->priv;
3507
3508   pick_mode = _clutter_context_get_pick_mode ();
3509
3510   if (pick_mode == CLUTTER_PICK_NONE)
3511     priv->propagated_one_redraw = FALSE;
3512
3513   /* It's an important optimization that we consider painting of
3514    * actors with 0 opacity to be a NOP... */
3515   if (pick_mode == CLUTTER_PICK_NONE &&
3516       /* ignore top-levels, since they might be transparent */
3517       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3518       /* Use the override opacity if its been set */
3519       ((priv->opacity_override >= 0) ?
3520        priv->opacity_override : priv->opacity) == 0)
3521     return;
3522
3523   /* if we aren't paintable (not in a toplevel with all
3524    * parents paintable) then do nothing.
3525    */
3526   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3527     return;
3528
3529   /* mark that we are in the paint process */
3530   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3531
3532   cogl_push_matrix();
3533
3534   if (priv->enable_model_view_transform)
3535     {
3536       CoglMatrix matrix;
3537
3538       /* XXX: It could be better to cache the modelview with the actor
3539        * instead of progressively building up the transformations on
3540        * the matrix stack every time we paint. */
3541       cogl_get_modelview_matrix (&matrix);
3542       _clutter_actor_apply_modelview_transform (self, &matrix);
3543
3544 #ifdef CLUTTER_ENABLE_DEBUG
3545       /* Catch when out-of-band transforms have been made by actors not as part
3546        * of an apply_transform vfunc... */
3547       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3548         {
3549           CoglMatrix expected_matrix;
3550
3551           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3552                                                              &expected_matrix);
3553
3554           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3555             {
3556               GString *buf = g_string_sized_new (1024);
3557               ClutterActor *parent;
3558
3559               parent = self;
3560               while (parent != NULL)
3561                 {
3562                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3563
3564                   if (parent->priv->parent != NULL)
3565                     g_string_append (buf, "->");
3566
3567                   parent = parent->priv->parent;
3568                 }
3569
3570               g_warning ("Unexpected transform found when painting actor "
3571                          "\"%s\". This will be caused by one of the actor's "
3572                          "ancestors (%s) using the Cogl API directly to transform "
3573                          "children instead of using ::apply_transform().",
3574                          _clutter_actor_get_debug_name (self),
3575                          buf->str);
3576
3577               g_string_free (buf, TRUE);
3578             }
3579         }
3580 #endif /* CLUTTER_ENABLE_DEBUG */
3581
3582       cogl_set_modelview_matrix (&matrix);
3583     }
3584
3585   if (priv->has_clip)
3586     {
3587       cogl_clip_push_rectangle (priv->clip.x,
3588                                 priv->clip.y,
3589                                 priv->clip.x + priv->clip.width,
3590                                 priv->clip.y + priv->clip.height);
3591       clip_set = TRUE;
3592     }
3593   else if (priv->clip_to_allocation)
3594     {
3595       gfloat width, height;
3596
3597       width  = priv->allocation.x2 - priv->allocation.x1;
3598       height = priv->allocation.y2 - priv->allocation.y1;
3599
3600       cogl_clip_push_rectangle (0, 0, width, height);
3601       clip_set = TRUE;
3602     }
3603
3604   if (pick_mode == CLUTTER_PICK_NONE)
3605     {
3606       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3607
3608       /* We check whether we need to add the flatten effect before
3609          each paint so that we can avoid having a mechanism for
3610          applications to notify when the value of the
3611          has_overlaps virtual changes. */
3612       add_or_remove_flatten_effect (self);
3613     }
3614   else
3615     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3616
3617   /* We save the current paint volume so that the next time the
3618    * actor queues a redraw we can constrain the redraw to just
3619    * cover the union of the new bounding box and the old.
3620    *
3621    * We also fetch the current paint volume to perform culling so
3622    * we can avoid painting actors outside the current clip region.
3623    *
3624    * If we are painting inside a clone, we should neither update
3625    * the paint volume or use it to cull painting, since the paint
3626    * box represents the location of the source actor on the
3627    * screen.
3628    *
3629    * XXX: We are starting to do a lot of vertex transforms on
3630    * the CPU in a typical paint, so at some point we should
3631    * audit these and consider caching some things.
3632    *
3633    * NB: We don't perform culling while picking at this point because
3634    * clutter-stage.c doesn't setup the clipping planes appropriately.
3635    *
3636    * NB: We don't want to update the last-paint-volume during picking
3637    * because the last-paint-volume is used to determine the old screen
3638    * space location of an actor that has moved so we can know the
3639    * minimal region to redraw to clear an old view of the actor. If we
3640    * update this during picking then by the time we come around to
3641    * paint then the last-paint-volume would likely represent the new
3642    * actor position not the old.
3643    */
3644   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3645     {
3646       gboolean success;
3647       /* annoyingly gcc warns if uninitialized even though
3648        * the initialization is redundant :-( */
3649       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3650
3651       if (G_LIKELY ((clutter_paint_debug_flags &
3652                      (CLUTTER_DEBUG_DISABLE_CULLING |
3653                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3654                     (CLUTTER_DEBUG_DISABLE_CULLING |
3655                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3656         _clutter_actor_update_last_paint_volume (self);
3657
3658       success = cull_actor (self, &result);
3659
3660       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3661         _clutter_actor_paint_cull_result (self, success, result);
3662       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3663         goto done;
3664     }
3665
3666   if (priv->effects == NULL)
3667     {
3668       if (pick_mode == CLUTTER_PICK_NONE &&
3669           actor_has_shader_data (self))
3670         {
3671           _clutter_actor_shader_pre_paint (self, FALSE);
3672           shader_applied = TRUE;
3673         }
3674
3675       priv->next_effect_to_paint = NULL;
3676     }
3677   else
3678     priv->next_effect_to_paint =
3679       _clutter_meta_group_peek_metas (priv->effects);
3680
3681   clutter_actor_continue_paint (self);
3682
3683   if (shader_applied)
3684     _clutter_actor_shader_post_paint (self);
3685
3686   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3687                   pick_mode == CLUTTER_PICK_NONE))
3688     _clutter_actor_draw_paint_volume (self);
3689
3690 done:
3691   /* If we make it here then the actor has run through a complete
3692      paint run including all the effects so it's no longer dirty */
3693   if (pick_mode == CLUTTER_PICK_NONE)
3694     priv->is_dirty = FALSE;
3695
3696   if (clip_set)
3697     cogl_clip_pop();
3698
3699   cogl_pop_matrix();
3700
3701   /* paint sequence complete */
3702   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3703 }
3704
3705 /**
3706  * clutter_actor_continue_paint:
3707  * @self: A #ClutterActor
3708  *
3709  * Run the next stage of the paint sequence. This function should only
3710  * be called within the implementation of the ‘run’ virtual of a
3711  * #ClutterEffect. It will cause the run method of the next effect to
3712  * be applied, or it will paint the actual actor if the current effect
3713  * is the last effect in the chain.
3714  *
3715  * Since: 1.8
3716  */
3717 void
3718 clutter_actor_continue_paint (ClutterActor *self)
3719 {
3720   ClutterActorPrivate *priv;
3721
3722   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3723   /* This should only be called from with in the ‘run’ implementation
3724      of a ClutterEffect */
3725   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3726
3727   priv = self->priv;
3728
3729   /* Skip any effects that are disabled */
3730   while (priv->next_effect_to_paint &&
3731          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3732     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3733
3734   /* If this has come from the last effect then we'll just paint the
3735      actual actor */
3736   if (priv->next_effect_to_paint == NULL)
3737     {
3738       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3739         {
3740           ClutterPaintNode *dummy;
3741
3742           /* XXX - this will go away in 2.0, when we can get rid of this
3743            * stuff and switch to a pure retained render tree of PaintNodes
3744            * for the entire frame, starting from the Stage; the paint()
3745            * virtual function can then be called directly.
3746            */
3747           dummy = _clutter_dummy_node_new (self);
3748           clutter_paint_node_set_name (dummy, "Root");
3749
3750           /* XXX - for 1.12, we use the return value of paint_node() to
3751            * decide whether we should emit the ::paint signal.
3752            */
3753           clutter_actor_paint_node (self, dummy);
3754           clutter_paint_node_unref (dummy);
3755
3756           g_signal_emit (self, actor_signals[PAINT], 0);
3757         }
3758       else
3759         {
3760           ClutterColor col = { 0, };
3761
3762           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3763
3764           /* Actor will then paint silhouette of itself in supplied
3765            * color.  See clutter_stage_get_actor_at_pos() for where
3766            * picking is enabled.
3767            */
3768           g_signal_emit (self, actor_signals[PICK], 0, &col);
3769         }
3770     }
3771   else
3772     {
3773       ClutterEffect *old_current_effect;
3774       ClutterEffectPaintFlags run_flags = 0;
3775
3776       /* Cache the current effect so that we can put it back before
3777          returning */
3778       old_current_effect = priv->current_effect;
3779
3780       priv->current_effect = priv->next_effect_to_paint->data;
3781       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3782
3783       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3784         {
3785           if (priv->is_dirty)
3786             {
3787               /* If there's an effect queued with this redraw then all
3788                  effects up to that one will be considered dirty. It
3789                  is expected the queued effect will paint the cached
3790                  image and not call clutter_actor_continue_paint again
3791                  (although it should work ok if it does) */
3792               if (priv->effect_to_redraw == NULL ||
3793                   priv->current_effect != priv->effect_to_redraw)
3794                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3795             }
3796
3797           _clutter_effect_paint (priv->current_effect, run_flags);
3798         }
3799       else
3800         {
3801           /* We can't determine when an actor has been modified since
3802              its last pick so lets just assume it has always been
3803              modified */
3804           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3805
3806           _clutter_effect_pick (priv->current_effect, run_flags);
3807         }
3808
3809       priv->current_effect = old_current_effect;
3810     }
3811 }
3812
3813 static void
3814 _clutter_actor_stop_transitions (ClutterActor *self)
3815 {
3816   const ClutterAnimationInfo *info;
3817   GHashTableIter iter;
3818   gpointer value;
3819
3820   info = _clutter_actor_get_animation_info_or_defaults (self);
3821   if (info->transitions == NULL)
3822     return;
3823
3824   g_hash_table_iter_init (&iter, info->transitions);
3825   while (g_hash_table_iter_next (&iter, NULL, &value))
3826     {
3827       TransitionClosure *closure = value;
3828       clutter_timeline_stop (CLUTTER_TIMELINE (closure->transition));
3829     }
3830 }
3831
3832 static ClutterActorTraverseVisitFlags
3833 invalidate_queue_redraw_entry (ClutterActor *self,
3834                                int           depth,
3835                                gpointer      user_data)
3836 {
3837   ClutterActorPrivate *priv = self->priv;
3838
3839   if (priv->queue_redraw_entry != NULL)
3840     {
3841       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3842       priv->queue_redraw_entry = NULL;
3843     }
3844
3845   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3846 }
3847
3848 static inline void
3849 remove_child (ClutterActor *self,
3850               ClutterActor *child)
3851 {
3852   ClutterActor *prev_sibling, *next_sibling;
3853
3854   prev_sibling = child->priv->prev_sibling;
3855   next_sibling = child->priv->next_sibling;
3856
3857   if (prev_sibling != NULL)
3858     prev_sibling->priv->next_sibling = next_sibling;
3859
3860   if (next_sibling != NULL)
3861     next_sibling->priv->prev_sibling = prev_sibling;
3862
3863   if (self->priv->first_child == child)
3864     self->priv->first_child = next_sibling;
3865
3866   if (self->priv->last_child == child)
3867     self->priv->last_child = prev_sibling;
3868
3869   child->priv->parent = NULL;
3870   child->priv->prev_sibling = NULL;
3871   child->priv->next_sibling = NULL;
3872 }
3873
3874 typedef enum {
3875   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3876   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3877   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3878   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3879   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3880   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3881   REMOVE_CHILD_STOP_TRANSITIONS   = 1 << 6,
3882
3883   /* default flags for public API */
3884   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_STOP_TRANSITIONS |
3885                                     REMOVE_CHILD_DESTROY_META |
3886                                     REMOVE_CHILD_EMIT_PARENT_SET |
3887                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3888                                     REMOVE_CHILD_CHECK_STATE |
3889                                     REMOVE_CHILD_FLUSH_QUEUE |
3890                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3891
3892   /* flags for legacy/deprecated API */
3893   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_STOP_TRANSITIONS |
3894                                     REMOVE_CHILD_CHECK_STATE |
3895                                     REMOVE_CHILD_FLUSH_QUEUE |
3896                                     REMOVE_CHILD_EMIT_PARENT_SET |
3897                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3898 } ClutterActorRemoveChildFlags;
3899
3900 /*< private >
3901  * clutter_actor_remove_child_internal:
3902  * @self: a #ClutterActor
3903  * @child: the child of @self that has to be removed
3904  * @flags: control the removal operations
3905  *
3906  * Removes @child from the list of children of @self.
3907  */
3908 static void
3909 clutter_actor_remove_child_internal (ClutterActor                 *self,
3910                                      ClutterActor                 *child,
3911                                      ClutterActorRemoveChildFlags  flags)
3912 {
3913   ClutterActor *old_first, *old_last;
3914   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3915   gboolean flush_queue;
3916   gboolean notify_first_last;
3917   gboolean was_mapped;
3918   gboolean stop_transitions;
3919
3920   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3921   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3922   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3923   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3924   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3925   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3926   stop_transitions = (flags & REMOVE_CHILD_STOP_TRANSITIONS) != 0;
3927
3928   g_object_freeze_notify (G_OBJECT (self));
3929
3930   if (stop_transitions)
3931     _clutter_actor_stop_transitions (child);
3932
3933   if (destroy_meta)
3934     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3935
3936   if (check_state)
3937     {
3938       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3939
3940       /* we need to unrealize *before* we set parent_actor to NULL,
3941        * because in an unrealize method actors are dissociating from the
3942        * stage, which means they need to be able to
3943        * clutter_actor_get_stage().
3944        *
3945        * yhis should unmap and unrealize, unless we're reparenting.
3946        */
3947       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3948     }
3949   else
3950     was_mapped = FALSE;
3951
3952   if (flush_queue)
3953     {
3954       /* We take this opportunity to invalidate any queue redraw entry
3955        * associated with the actor and descendants since we won't be able to
3956        * determine the appropriate stage after this.
3957        *
3958        * we do this after we updated the mapped state because actors might
3959        * end up queueing redraws inside their mapped/unmapped virtual
3960        * functions, and if we invalidate the redraw entry we could end up
3961        * with an inconsistent state and weird memory corruption. see
3962        * bugs:
3963        *
3964        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3965        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3966        */
3967       _clutter_actor_traverse (child,
3968                                0,
3969                                invalidate_queue_redraw_entry,
3970                                NULL,
3971                                NULL);
3972     }
3973
3974   old_first = self->priv->first_child;
3975   old_last = self->priv->last_child;
3976
3977   remove_child (self, child);
3978
3979   self->priv->n_children -= 1;
3980
3981   self->priv->age += 1;
3982
3983   /* if the child that got removed was visible and set to
3984    * expand then we want to reset the parent's state in
3985    * case the child was the only thing that was making it
3986    * expand.
3987    */
3988   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
3989       (child->priv->needs_compute_expand ||
3990        child->priv->needs_x_expand ||
3991        child->priv->needs_y_expand))
3992     {
3993       clutter_actor_queue_compute_expand (self);
3994     }
3995
3996   /* clutter_actor_reparent() will emit ::parent-set for us */
3997   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3998     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3999
4000   /* if the child was mapped then we need to relayout ourselves to account
4001    * for the removed child
4002    */
4003   if (was_mapped)
4004     clutter_actor_queue_relayout (self);
4005
4006   /* we need to emit the signal before dropping the reference */
4007   if (emit_actor_removed)
4008     g_signal_emit_by_name (self, "actor-removed", child);
4009
4010   if (notify_first_last)
4011     {
4012       if (old_first != self->priv->first_child)
4013         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
4014
4015       if (old_last != self->priv->last_child)
4016         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
4017     }
4018
4019   g_object_thaw_notify (G_OBJECT (self));
4020
4021   /* remove the reference we acquired in clutter_actor_add_child() */
4022   g_object_unref (child);
4023 }
4024
4025 static const ClutterTransformInfo default_transform_info = {
4026   0.0, { 0, },          /* rotation-x */
4027   0.0, { 0, },          /* rotation-y */
4028   0.0, { 0, },          /* rotation-z */
4029
4030   1.0, 1.0, { 0, },     /* scale */
4031
4032   { 0, },               /* anchor */
4033
4034   0.0,                  /* depth */
4035 };
4036
4037 /*< private >
4038  * _clutter_actor_get_transform_info_or_defaults:
4039  * @self: a #ClutterActor
4040  *
4041  * Retrieves the ClutterTransformInfo structure associated to an actor.
4042  *
4043  * If the actor does not have a ClutterTransformInfo structure associated
4044  * to it, then the default structure will be returned.
4045  *
4046  * This function should only be used for getters.
4047  *
4048  * Return value: a const pointer to the ClutterTransformInfo structure
4049  */
4050 const ClutterTransformInfo *
4051 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4052 {
4053   ClutterTransformInfo *info;
4054
4055   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4056   if (info != NULL)
4057     return info;
4058
4059   return &default_transform_info;
4060 }
4061
4062 static void
4063 clutter_transform_info_free (gpointer data)
4064 {
4065   if (data != NULL)
4066     g_slice_free (ClutterTransformInfo, data);
4067 }
4068
4069 /*< private >
4070  * _clutter_actor_get_transform_info:
4071  * @self: a #ClutterActor
4072  *
4073  * Retrieves a pointer to the ClutterTransformInfo structure.
4074  *
4075  * If the actor does not have a ClutterTransformInfo associated to it, one
4076  * will be created and initialized to the default values.
4077  *
4078  * This function should be used for setters.
4079  *
4080  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4081  * instead.
4082  *
4083  * Return value: (transfer none): a pointer to the ClutterTransformInfo
4084  *   structure
4085  */
4086 ClutterTransformInfo *
4087 _clutter_actor_get_transform_info (ClutterActor *self)
4088 {
4089   ClutterTransformInfo *info;
4090
4091   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4092   if (info == NULL)
4093     {
4094       info = g_slice_new (ClutterTransformInfo);
4095
4096       *info = default_transform_info;
4097
4098       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4099                                info,
4100                                clutter_transform_info_free);
4101     }
4102
4103   return info;
4104 }
4105
4106 /*< private >
4107  * clutter_actor_set_rotation_angle_internal:
4108  * @self: a #ClutterActor
4109  * @axis: the axis of the angle to change
4110  * @angle: the angle of rotation
4111  *
4112  * Sets the rotation angle on the given axis without affecting the
4113  * rotation center point.
4114  */
4115 static inline void
4116 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4117                                            ClutterRotateAxis  axis,
4118                                            gdouble            angle)
4119 {
4120   GObject *obj = G_OBJECT (self);
4121   ClutterTransformInfo *info;
4122
4123   info = _clutter_actor_get_transform_info (self);
4124
4125   g_object_freeze_notify (obj);
4126
4127   switch (axis)
4128     {
4129     case CLUTTER_X_AXIS:
4130       info->rx_angle = angle;
4131       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4132       break;
4133
4134     case CLUTTER_Y_AXIS:
4135       info->ry_angle = angle;
4136       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4137       break;
4138
4139     case CLUTTER_Z_AXIS:
4140       info->rz_angle = angle;
4141       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4142       break;
4143     }
4144
4145   self->priv->transform_valid = FALSE;
4146
4147   g_object_thaw_notify (obj);
4148
4149   clutter_actor_queue_redraw (self);
4150 }
4151
4152 static inline void
4153 clutter_actor_set_rotation_angle (ClutterActor      *self,
4154                                   ClutterRotateAxis  axis,
4155                                   gdouble            angle)
4156 {
4157   const ClutterTransformInfo *info;
4158   const double *cur_angle_p = NULL;
4159   GParamSpec *pspec = NULL;
4160
4161   info = _clutter_actor_get_transform_info_or_defaults (self);
4162
4163   switch (axis)
4164     {
4165     case CLUTTER_X_AXIS:
4166       cur_angle_p = &info->rx_angle;
4167       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4168       break;
4169
4170     case CLUTTER_Y_AXIS:
4171       cur_angle_p = &info->ry_angle;
4172       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4173       break;
4174
4175     case CLUTTER_Z_AXIS:
4176       cur_angle_p = &info->rz_angle;
4177       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4178       break;
4179     }
4180
4181   g_assert (pspec != NULL);
4182   g_assert (cur_angle_p != NULL);
4183
4184   if (_clutter_actor_get_transition (self, pspec) == NULL)
4185     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4186   else
4187     _clutter_actor_update_transition (self, pspec, angle);
4188
4189   clutter_actor_queue_redraw (self);
4190 }
4191
4192 /*< private >
4193  * clutter_actor_set_rotation_center_internal:
4194  * @self: a #ClutterActor
4195  * @axis: the axis of the center to change
4196  * @center: the coordinates of the rotation center
4197  *
4198  * Sets the rotation center on the given axis without affecting the
4199  * rotation angle.
4200  */
4201 static inline void
4202 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4203                                             ClutterRotateAxis    axis,
4204                                             const ClutterVertex *center)
4205 {
4206   GObject *obj = G_OBJECT (self);
4207   ClutterTransformInfo *info;
4208   ClutterVertex v = { 0, 0, 0 };
4209
4210   info = _clutter_actor_get_transform_info (self);
4211
4212   if (center != NULL)
4213     v = *center;
4214
4215   g_object_freeze_notify (obj);
4216
4217   switch (axis)
4218     {
4219     case CLUTTER_X_AXIS:
4220       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4221       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4222       break;
4223
4224     case CLUTTER_Y_AXIS:
4225       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4226       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4227       break;
4228
4229     case CLUTTER_Z_AXIS:
4230       /* if the previously set rotation center was fractional, then
4231        * setting explicit coordinates will have to notify the
4232        * :rotation-center-z-gravity property as well
4233        */
4234       if (info->rz_center.is_fractional)
4235         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4236
4237       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4238       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4239       break;
4240     }
4241
4242   self->priv->transform_valid = FALSE;
4243
4244   g_object_thaw_notify (obj);
4245
4246   clutter_actor_queue_redraw (self);
4247 }
4248
4249 static void
4250 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4251                                          double factor,
4252                                          GParamSpec *pspec)
4253 {
4254   GObject *obj = G_OBJECT (self);
4255   ClutterTransformInfo *info;
4256
4257   info = _clutter_actor_get_transform_info (self);
4258
4259   if (pspec == obj_props[PROP_SCALE_X])
4260     info->scale_x = factor;
4261   else
4262     info->scale_y = factor;
4263
4264   self->priv->transform_valid = FALSE;
4265   clutter_actor_queue_redraw (self);
4266   g_object_notify_by_pspec (obj, pspec);
4267 }
4268
4269 static inline void
4270 clutter_actor_set_scale_factor (ClutterActor      *self,
4271                                 ClutterRotateAxis  axis,
4272                                 gdouble            factor)
4273 {
4274   const ClutterTransformInfo *info;
4275   const double *scale_p = NULL;
4276   GParamSpec *pspec = NULL;
4277
4278   info = _clutter_actor_get_transform_info_or_defaults (self);
4279
4280   switch (axis)
4281     {
4282     case CLUTTER_X_AXIS:
4283       pspec = obj_props[PROP_SCALE_X];
4284       scale_p = &info->scale_x;
4285       break;
4286
4287     case CLUTTER_Y_AXIS:
4288       pspec = obj_props[PROP_SCALE_Y];
4289       scale_p = &info->scale_y;
4290       break;
4291
4292     case CLUTTER_Z_AXIS:
4293       break;
4294     }
4295
4296   g_assert (pspec != NULL);
4297   g_assert (scale_p != NULL);
4298
4299   if (_clutter_actor_get_transition (self, pspec) == NULL)
4300     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4301   else
4302     _clutter_actor_update_transition (self, pspec, factor);
4303
4304   clutter_actor_queue_redraw (self);
4305 }
4306
4307 static inline void
4308 clutter_actor_set_scale_center (ClutterActor      *self,
4309                                 ClutterRotateAxis  axis,
4310                                 gfloat             coord)
4311 {
4312   GObject *obj = G_OBJECT (self);
4313   ClutterTransformInfo *info;
4314   gfloat center_x, center_y;
4315
4316   info = _clutter_actor_get_transform_info (self);
4317
4318   g_object_freeze_notify (obj);
4319
4320   /* get the current scale center coordinates */
4321   clutter_anchor_coord_get_units (self, &info->scale_center,
4322                                   &center_x,
4323                                   &center_y,
4324                                   NULL);
4325
4326   /* we need to notify this too, because setting explicit coordinates will
4327    * change the gravity as a side effect
4328    */
4329   if (info->scale_center.is_fractional)
4330     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4331
4332   switch (axis)
4333     {
4334     case CLUTTER_X_AXIS:
4335       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4336       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4337       break;
4338
4339     case CLUTTER_Y_AXIS:
4340       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4341       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4342       break;
4343
4344     default:
4345       g_assert_not_reached ();
4346     }
4347
4348   self->priv->transform_valid = FALSE;
4349
4350   clutter_actor_queue_redraw (self);
4351
4352   g_object_thaw_notify (obj);
4353 }
4354
4355 static inline void
4356 clutter_actor_set_scale_gravity (ClutterActor   *self,
4357                                  ClutterGravity  gravity)
4358 {
4359   ClutterTransformInfo *info;
4360   GObject *obj;
4361
4362   info = _clutter_actor_get_transform_info (self);
4363   obj = G_OBJECT (self);
4364
4365   if (gravity == CLUTTER_GRAVITY_NONE)
4366     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4367   else
4368     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4369
4370   self->priv->transform_valid = FALSE;
4371
4372   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4373   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4374   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4375
4376   clutter_actor_queue_redraw (self);
4377 }
4378
4379 static inline void
4380 clutter_actor_set_anchor_coord (ClutterActor      *self,
4381                                 ClutterRotateAxis  axis,
4382                                 gfloat             coord)
4383 {
4384   GObject *obj = G_OBJECT (self);
4385   ClutterTransformInfo *info;
4386   gfloat anchor_x, anchor_y;
4387
4388   info = _clutter_actor_get_transform_info (self);
4389
4390   g_object_freeze_notify (obj);
4391
4392   clutter_anchor_coord_get_units (self, &info->anchor,
4393                                   &anchor_x,
4394                                   &anchor_y,
4395                                   NULL);
4396
4397   if (info->anchor.is_fractional)
4398     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4399
4400   switch (axis)
4401     {
4402     case CLUTTER_X_AXIS:
4403       clutter_anchor_coord_set_units (&info->anchor,
4404                                       coord,
4405                                       anchor_y,
4406                                       0.0);
4407       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4408       break;
4409
4410     case CLUTTER_Y_AXIS:
4411       clutter_anchor_coord_set_units (&info->anchor,
4412                                       anchor_x,
4413                                       coord,
4414                                       0.0);
4415       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4416       break;
4417
4418     default:
4419       g_assert_not_reached ();
4420     }
4421
4422   self->priv->transform_valid = FALSE;
4423
4424   clutter_actor_queue_redraw (self);
4425
4426   g_object_thaw_notify (obj);
4427 }
4428
4429 static void
4430 clutter_actor_set_property (GObject      *object,
4431                             guint         prop_id,
4432                             const GValue *value,
4433                             GParamSpec   *pspec)
4434 {
4435   ClutterActor *actor = CLUTTER_ACTOR (object);
4436   ClutterActorPrivate *priv = actor->priv;
4437
4438   switch (prop_id)
4439     {
4440     case PROP_X:
4441       clutter_actor_set_x (actor, g_value_get_float (value));
4442       break;
4443
4444     case PROP_Y:
4445       clutter_actor_set_y (actor, g_value_get_float (value));
4446       break;
4447
4448     case PROP_POSITION:
4449       {
4450         const ClutterPoint *pos = g_value_get_boxed (value);
4451
4452         if (pos != NULL)
4453           clutter_actor_set_position (actor, pos->x, pos->y);
4454         else
4455           clutter_actor_set_fixed_position_set (actor, FALSE);
4456       }
4457       break;
4458
4459     case PROP_WIDTH:
4460       clutter_actor_set_width (actor, g_value_get_float (value));
4461       break;
4462
4463     case PROP_HEIGHT:
4464       clutter_actor_set_height (actor, g_value_get_float (value));
4465       break;
4466
4467     case PROP_SIZE:
4468       {
4469         const ClutterSize *size = g_value_get_boxed (value);
4470
4471         if (size != NULL)
4472           clutter_actor_set_size (actor, size->width, size->height);
4473         else
4474           clutter_actor_set_size (actor, -1, -1);
4475       }
4476       break;
4477
4478     case PROP_FIXED_X:
4479       clutter_actor_set_x (actor, g_value_get_float (value));
4480       break;
4481
4482     case PROP_FIXED_Y:
4483       clutter_actor_set_y (actor, g_value_get_float (value));
4484       break;
4485
4486     case PROP_FIXED_POSITION_SET:
4487       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4488       break;
4489
4490     case PROP_MIN_WIDTH:
4491       clutter_actor_set_min_width (actor, g_value_get_float (value));
4492       break;
4493
4494     case PROP_MIN_HEIGHT:
4495       clutter_actor_set_min_height (actor, g_value_get_float (value));
4496       break;
4497
4498     case PROP_NATURAL_WIDTH:
4499       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4500       break;
4501
4502     case PROP_NATURAL_HEIGHT:
4503       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4504       break;
4505
4506     case PROP_MIN_WIDTH_SET:
4507       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4508       break;
4509
4510     case PROP_MIN_HEIGHT_SET:
4511       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4512       break;
4513
4514     case PROP_NATURAL_WIDTH_SET:
4515       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4516       break;
4517
4518     case PROP_NATURAL_HEIGHT_SET:
4519       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4520       break;
4521
4522     case PROP_REQUEST_MODE:
4523       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4524       break;
4525
4526     case PROP_DEPTH:
4527       clutter_actor_set_depth (actor, g_value_get_float (value));
4528       break;
4529
4530     case PROP_OPACITY:
4531       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4532       break;
4533
4534     case PROP_OFFSCREEN_REDIRECT:
4535       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4536       break;
4537
4538     case PROP_NAME:
4539       clutter_actor_set_name (actor, g_value_get_string (value));
4540       break;
4541
4542     case PROP_VISIBLE:
4543       if (g_value_get_boolean (value) == TRUE)
4544         clutter_actor_show (actor);
4545       else
4546         clutter_actor_hide (actor);
4547       break;
4548
4549     case PROP_SCALE_X:
4550       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4551                                       g_value_get_double (value));
4552       break;
4553
4554     case PROP_SCALE_Y:
4555       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4556                                       g_value_get_double (value));
4557       break;
4558
4559     case PROP_SCALE_CENTER_X:
4560       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4561                                       g_value_get_float (value));
4562       break;
4563
4564     case PROP_SCALE_CENTER_Y:
4565       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4566                                       g_value_get_float (value));
4567       break;
4568
4569     case PROP_SCALE_GRAVITY:
4570       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4571       break;
4572
4573     case PROP_CLIP:
4574       {
4575         const ClutterGeometry *geom = g_value_get_boxed (value);
4576
4577         clutter_actor_set_clip (actor,
4578                                 geom->x, geom->y,
4579                                 geom->width, geom->height);
4580       }
4581       break;
4582
4583     case PROP_CLIP_TO_ALLOCATION:
4584       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4585       break;
4586
4587     case PROP_REACTIVE:
4588       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4589       break;
4590
4591     case PROP_ROTATION_ANGLE_X:
4592       clutter_actor_set_rotation_angle (actor,
4593                                         CLUTTER_X_AXIS,
4594                                         g_value_get_double (value));
4595       break;
4596
4597     case PROP_ROTATION_ANGLE_Y:
4598       clutter_actor_set_rotation_angle (actor,
4599                                         CLUTTER_Y_AXIS,
4600                                         g_value_get_double (value));
4601       break;
4602
4603     case PROP_ROTATION_ANGLE_Z:
4604       clutter_actor_set_rotation_angle (actor,
4605                                         CLUTTER_Z_AXIS,
4606                                         g_value_get_double (value));
4607       break;
4608
4609     case PROP_ROTATION_CENTER_X:
4610       clutter_actor_set_rotation_center_internal (actor,
4611                                                   CLUTTER_X_AXIS,
4612                                                   g_value_get_boxed (value));
4613       break;
4614
4615     case PROP_ROTATION_CENTER_Y:
4616       clutter_actor_set_rotation_center_internal (actor,
4617                                                   CLUTTER_Y_AXIS,
4618                                                   g_value_get_boxed (value));
4619       break;
4620
4621     case PROP_ROTATION_CENTER_Z:
4622       clutter_actor_set_rotation_center_internal (actor,
4623                                                   CLUTTER_Z_AXIS,
4624                                                   g_value_get_boxed (value));
4625       break;
4626
4627     case PROP_ROTATION_CENTER_Z_GRAVITY:
4628       {
4629         const ClutterTransformInfo *info;
4630
4631         info = _clutter_actor_get_transform_info_or_defaults (actor);
4632         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4633                                                    g_value_get_enum (value));
4634       }
4635       break;
4636
4637     case PROP_ANCHOR_X:
4638       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4639                                       g_value_get_float (value));
4640       break;
4641
4642     case PROP_ANCHOR_Y:
4643       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4644                                       g_value_get_float (value));
4645       break;
4646
4647     case PROP_ANCHOR_GRAVITY:
4648       clutter_actor_set_anchor_point_from_gravity (actor,
4649                                                    g_value_get_enum (value));
4650       break;
4651
4652     case PROP_SHOW_ON_SET_PARENT:
4653       priv->show_on_set_parent = g_value_get_boolean (value);
4654       break;
4655
4656     case PROP_TEXT_DIRECTION:
4657       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4658       break;
4659
4660     case PROP_ACTIONS:
4661       clutter_actor_add_action (actor, g_value_get_object (value));
4662       break;
4663
4664     case PROP_CONSTRAINTS:
4665       clutter_actor_add_constraint (actor, g_value_get_object (value));
4666       break;
4667
4668     case PROP_EFFECT:
4669       clutter_actor_add_effect (actor, g_value_get_object (value));
4670       break;
4671
4672     case PROP_LAYOUT_MANAGER:
4673       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4674       break;
4675
4676     case PROP_X_EXPAND:
4677       clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4678       break;
4679
4680     case PROP_Y_EXPAND:
4681       clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4682       break;
4683
4684     case PROP_X_ALIGN:
4685       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4686       break;
4687
4688     case PROP_Y_ALIGN:
4689       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4690       break;
4691
4692     case PROP_MARGIN_TOP:
4693       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4694       break;
4695
4696     case PROP_MARGIN_BOTTOM:
4697       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4698       break;
4699
4700     case PROP_MARGIN_LEFT:
4701       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4702       break;
4703
4704     case PROP_MARGIN_RIGHT:
4705       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4706       break;
4707
4708     case PROP_BACKGROUND_COLOR:
4709       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4710       break;
4711
4712     case PROP_CONTENT:
4713       clutter_actor_set_content (actor, g_value_get_object (value));
4714       break;
4715
4716     case PROP_CONTENT_GRAVITY:
4717       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4718       break;
4719
4720     case PROP_MINIFICATION_FILTER:
4721       clutter_actor_set_content_scaling_filters (actor,
4722                                                  g_value_get_enum (value),
4723                                                  actor->priv->mag_filter);
4724       break;
4725
4726     case PROP_MAGNIFICATION_FILTER:
4727       clutter_actor_set_content_scaling_filters (actor,
4728                                                  actor->priv->min_filter,
4729                                                  g_value_get_enum (value));
4730       break;
4731
4732     default:
4733       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4734       break;
4735     }
4736 }
4737
4738 static void
4739 clutter_actor_get_property (GObject    *object,
4740                             guint       prop_id,
4741                             GValue     *value,
4742                             GParamSpec *pspec)
4743 {
4744   ClutterActor *actor = CLUTTER_ACTOR (object);
4745   ClutterActorPrivate *priv = actor->priv;
4746
4747   switch (prop_id)
4748     {
4749     case PROP_X:
4750       g_value_set_float (value, clutter_actor_get_x (actor));
4751       break;
4752
4753     case PROP_Y:
4754       g_value_set_float (value, clutter_actor_get_y (actor));
4755       break;
4756
4757     case PROP_POSITION:
4758       {
4759         ClutterPoint position;
4760
4761         clutter_point_init (&position,
4762                             clutter_actor_get_x (actor),
4763                             clutter_actor_get_y (actor));
4764         g_value_set_boxed (value, &position);
4765       }
4766       break;
4767
4768     case PROP_WIDTH:
4769       g_value_set_float (value, clutter_actor_get_width (actor));
4770       break;
4771
4772     case PROP_HEIGHT:
4773       g_value_set_float (value, clutter_actor_get_height (actor));
4774       break;
4775
4776     case PROP_SIZE:
4777       {
4778         ClutterSize size;
4779
4780         clutter_size_init (&size,
4781                            clutter_actor_get_width (actor),
4782                            clutter_actor_get_height (actor));
4783         g_value_set_boxed (value, &size);
4784       }
4785       break;
4786
4787     case PROP_FIXED_X:
4788       {
4789         const ClutterLayoutInfo *info;
4790
4791         info = _clutter_actor_get_layout_info_or_defaults (actor);
4792         g_value_set_float (value, info->fixed_pos.x);
4793       }
4794       break;
4795
4796     case PROP_FIXED_Y:
4797       {
4798         const ClutterLayoutInfo *info;
4799
4800         info = _clutter_actor_get_layout_info_or_defaults (actor);
4801         g_value_set_float (value, info->fixed_pos.y);
4802       }
4803       break;
4804
4805     case PROP_FIXED_POSITION_SET:
4806       g_value_set_boolean (value, priv->position_set);
4807       break;
4808
4809     case PROP_MIN_WIDTH:
4810       {
4811         const ClutterLayoutInfo *info;
4812
4813         info = _clutter_actor_get_layout_info_or_defaults (actor);
4814         g_value_set_float (value, info->minimum.width);
4815       }
4816       break;
4817
4818     case PROP_MIN_HEIGHT:
4819       {
4820         const ClutterLayoutInfo *info;
4821
4822         info = _clutter_actor_get_layout_info_or_defaults (actor);
4823         g_value_set_float (value, info->minimum.height);
4824       }
4825       break;
4826
4827     case PROP_NATURAL_WIDTH:
4828       {
4829         const ClutterLayoutInfo *info;
4830
4831         info = _clutter_actor_get_layout_info_or_defaults (actor);
4832         g_value_set_float (value, info->natural.width);
4833       }
4834       break;
4835
4836     case PROP_NATURAL_HEIGHT:
4837       {
4838         const ClutterLayoutInfo *info;
4839
4840         info = _clutter_actor_get_layout_info_or_defaults (actor);
4841         g_value_set_float (value, info->natural.height);
4842       }
4843       break;
4844
4845     case PROP_MIN_WIDTH_SET:
4846       g_value_set_boolean (value, priv->min_width_set);
4847       break;
4848
4849     case PROP_MIN_HEIGHT_SET:
4850       g_value_set_boolean (value, priv->min_height_set);
4851       break;
4852
4853     case PROP_NATURAL_WIDTH_SET:
4854       g_value_set_boolean (value, priv->natural_width_set);
4855       break;
4856
4857     case PROP_NATURAL_HEIGHT_SET:
4858       g_value_set_boolean (value, priv->natural_height_set);
4859       break;
4860
4861     case PROP_REQUEST_MODE:
4862       g_value_set_enum (value, priv->request_mode);
4863       break;
4864
4865     case PROP_ALLOCATION:
4866       g_value_set_boxed (value, &priv->allocation);
4867       break;
4868
4869     case PROP_DEPTH:
4870       g_value_set_float (value, clutter_actor_get_depth (actor));
4871       break;
4872
4873     case PROP_OPACITY:
4874       g_value_set_uint (value, priv->opacity);
4875       break;
4876
4877     case PROP_OFFSCREEN_REDIRECT:
4878       g_value_set_enum (value, priv->offscreen_redirect);
4879       break;
4880
4881     case PROP_NAME:
4882       g_value_set_string (value, priv->name);
4883       break;
4884
4885     case PROP_VISIBLE:
4886       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4887       break;
4888
4889     case PROP_MAPPED:
4890       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4891       break;
4892
4893     case PROP_REALIZED:
4894       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4895       break;
4896
4897     case PROP_HAS_CLIP:
4898       g_value_set_boolean (value, priv->has_clip);
4899       break;
4900
4901     case PROP_CLIP:
4902       {
4903         ClutterGeometry clip;
4904
4905         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4906         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4907         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4908         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4909
4910         g_value_set_boxed (value, &clip);
4911       }
4912       break;
4913
4914     case PROP_CLIP_TO_ALLOCATION:
4915       g_value_set_boolean (value, priv->clip_to_allocation);
4916       break;
4917
4918     case PROP_SCALE_X:
4919       {
4920         const ClutterTransformInfo *info;
4921
4922         info = _clutter_actor_get_transform_info_or_defaults (actor);
4923         g_value_set_double (value, info->scale_x);
4924       }
4925       break;
4926
4927     case PROP_SCALE_Y:
4928       {
4929         const ClutterTransformInfo *info;
4930
4931         info = _clutter_actor_get_transform_info_or_defaults (actor);
4932         g_value_set_double (value, info->scale_y);
4933       }
4934       break;
4935
4936     case PROP_SCALE_CENTER_X:
4937       {
4938         gfloat center;
4939
4940         clutter_actor_get_scale_center (actor, &center, NULL);
4941
4942         g_value_set_float (value, center);
4943       }
4944       break;
4945
4946     case PROP_SCALE_CENTER_Y:
4947       {
4948         gfloat center;
4949
4950         clutter_actor_get_scale_center (actor, NULL, &center);
4951
4952         g_value_set_float (value, center);
4953       }
4954       break;
4955
4956     case PROP_SCALE_GRAVITY:
4957       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4958       break;
4959
4960     case PROP_REACTIVE:
4961       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4962       break;
4963
4964     case PROP_ROTATION_ANGLE_X:
4965       {
4966         const ClutterTransformInfo *info;
4967
4968         info = _clutter_actor_get_transform_info_or_defaults (actor);
4969         g_value_set_double (value, info->rx_angle);
4970       }
4971       break;
4972
4973     case PROP_ROTATION_ANGLE_Y:
4974       {
4975         const ClutterTransformInfo *info;
4976
4977         info = _clutter_actor_get_transform_info_or_defaults (actor);
4978         g_value_set_double (value, info->ry_angle);
4979       }
4980       break;
4981
4982     case PROP_ROTATION_ANGLE_Z:
4983       {
4984         const ClutterTransformInfo *info;
4985
4986         info = _clutter_actor_get_transform_info_or_defaults (actor);
4987         g_value_set_double (value, info->rz_angle);
4988       }
4989       break;
4990
4991     case PROP_ROTATION_CENTER_X:
4992       {
4993         ClutterVertex center;
4994
4995         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4996                                     &center.x,
4997                                     &center.y,
4998                                     &center.z);
4999
5000         g_value_set_boxed (value, &center);
5001       }
5002       break;
5003
5004     case PROP_ROTATION_CENTER_Y:
5005       {
5006         ClutterVertex center;
5007
5008         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
5009                                     &center.x,
5010                                     &center.y,
5011                                     &center.z);
5012
5013         g_value_set_boxed (value, &center);
5014       }
5015       break;
5016
5017     case PROP_ROTATION_CENTER_Z:
5018       {
5019         ClutterVertex center;
5020
5021         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
5022                                     &center.x,
5023                                     &center.y,
5024                                     &center.z);
5025
5026         g_value_set_boxed (value, &center);
5027       }
5028       break;
5029
5030     case PROP_ROTATION_CENTER_Z_GRAVITY:
5031       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
5032       break;
5033
5034     case PROP_ANCHOR_X:
5035       {
5036         const ClutterTransformInfo *info;
5037         gfloat anchor_x;
5038
5039         info = _clutter_actor_get_transform_info_or_defaults (actor);
5040         clutter_anchor_coord_get_units (actor, &info->anchor,
5041                                         &anchor_x,
5042                                         NULL,
5043                                         NULL);
5044         g_value_set_float (value, anchor_x);
5045       }
5046       break;
5047
5048     case PROP_ANCHOR_Y:
5049       {
5050         const ClutterTransformInfo *info;
5051         gfloat anchor_y;
5052
5053         info = _clutter_actor_get_transform_info_or_defaults (actor);
5054         clutter_anchor_coord_get_units (actor, &info->anchor,
5055                                         NULL,
5056                                         &anchor_y,
5057                                         NULL);
5058         g_value_set_float (value, anchor_y);
5059       }
5060       break;
5061
5062     case PROP_ANCHOR_GRAVITY:
5063       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5064       break;
5065
5066     case PROP_SHOW_ON_SET_PARENT:
5067       g_value_set_boolean (value, priv->show_on_set_parent);
5068       break;
5069
5070     case PROP_TEXT_DIRECTION:
5071       g_value_set_enum (value, priv->text_direction);
5072       break;
5073
5074     case PROP_HAS_POINTER:
5075       g_value_set_boolean (value, priv->has_pointer);
5076       break;
5077
5078     case PROP_LAYOUT_MANAGER:
5079       g_value_set_object (value, priv->layout_manager);
5080       break;
5081
5082     case PROP_X_EXPAND:
5083       {
5084         const ClutterLayoutInfo *info;
5085
5086         info = _clutter_actor_get_layout_info_or_defaults (actor);
5087         g_value_set_boolean (value, info->x_expand);
5088       }
5089       break;
5090
5091     case PROP_Y_EXPAND:
5092       {
5093         const ClutterLayoutInfo *info;
5094
5095         info = _clutter_actor_get_layout_info_or_defaults (actor);
5096         g_value_set_boolean (value, info->y_expand);
5097       }
5098       break;
5099
5100     case PROP_X_ALIGN:
5101       {
5102         const ClutterLayoutInfo *info;
5103
5104         info = _clutter_actor_get_layout_info_or_defaults (actor);
5105         g_value_set_enum (value, info->x_align);
5106       }
5107       break;
5108
5109     case PROP_Y_ALIGN:
5110       {
5111         const ClutterLayoutInfo *info;
5112
5113         info = _clutter_actor_get_layout_info_or_defaults (actor);
5114         g_value_set_enum (value, info->y_align);
5115       }
5116       break;
5117
5118     case PROP_MARGIN_TOP:
5119       {
5120         const ClutterLayoutInfo *info;
5121
5122         info = _clutter_actor_get_layout_info_or_defaults (actor);
5123         g_value_set_float (value, info->margin.top);
5124       }
5125       break;
5126
5127     case PROP_MARGIN_BOTTOM:
5128       {
5129         const ClutterLayoutInfo *info;
5130
5131         info = _clutter_actor_get_layout_info_or_defaults (actor);
5132         g_value_set_float (value, info->margin.bottom);
5133       }
5134       break;
5135
5136     case PROP_MARGIN_LEFT:
5137       {
5138         const ClutterLayoutInfo *info;
5139
5140         info = _clutter_actor_get_layout_info_or_defaults (actor);
5141         g_value_set_float (value, info->margin.left);
5142       }
5143       break;
5144
5145     case PROP_MARGIN_RIGHT:
5146       {
5147         const ClutterLayoutInfo *info;
5148
5149         info = _clutter_actor_get_layout_info_or_defaults (actor);
5150         g_value_set_float (value, info->margin.right);
5151       }
5152       break;
5153
5154     case PROP_BACKGROUND_COLOR_SET:
5155       g_value_set_boolean (value, priv->bg_color_set);
5156       break;
5157
5158     case PROP_BACKGROUND_COLOR:
5159       g_value_set_boxed (value, &priv->bg_color);
5160       break;
5161
5162     case PROP_FIRST_CHILD:
5163       g_value_set_object (value, priv->first_child);
5164       break;
5165
5166     case PROP_LAST_CHILD:
5167       g_value_set_object (value, priv->last_child);
5168       break;
5169
5170     case PROP_CONTENT:
5171       g_value_set_object (value, priv->content);
5172       break;
5173
5174     case PROP_CONTENT_GRAVITY:
5175       g_value_set_enum (value, priv->content_gravity);
5176       break;
5177
5178     case PROP_CONTENT_BOX:
5179       {
5180         ClutterActorBox box = { 0, };
5181
5182         clutter_actor_get_content_box (actor, &box);
5183         g_value_set_boxed (value, &box);
5184       }
5185       break;
5186
5187     case PROP_MINIFICATION_FILTER:
5188       g_value_set_enum (value, priv->min_filter);
5189       break;
5190
5191     case PROP_MAGNIFICATION_FILTER:
5192       g_value_set_enum (value, priv->mag_filter);
5193       break;
5194
5195     default:
5196       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5197       break;
5198     }
5199 }
5200
5201 static void
5202 clutter_actor_dispose (GObject *object)
5203 {
5204   ClutterActor *self = CLUTTER_ACTOR (object);
5205   ClutterActorPrivate *priv = self->priv;
5206
5207   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5208                 priv->id,
5209                 g_type_name (G_OBJECT_TYPE (self)),
5210                 object->ref_count);
5211
5212   g_signal_emit (self, actor_signals[DESTROY], 0);
5213
5214   /* avoid recursing when called from clutter_actor_destroy() */
5215   if (priv->parent != NULL)
5216     {
5217       ClutterActor *parent = priv->parent;
5218
5219       /* go through the Container implementation unless this
5220        * is an internal child and has been marked as such.
5221        *
5222        * removing the actor from its parent will reset the
5223        * realized and mapped states.
5224        */
5225       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5226         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5227       else
5228         clutter_actor_remove_child_internal (parent, self,
5229                                              REMOVE_CHILD_LEGACY_FLAGS);
5230     }
5231
5232   /* parent must be gone at this point */
5233   g_assert (priv->parent == NULL);
5234
5235   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5236     {
5237       /* can't be mapped or realized with no parent */
5238       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5239       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5240     }
5241
5242   g_clear_object (&priv->pango_context);
5243   g_clear_object (&priv->actions);
5244   g_clear_object (&priv->constraints);
5245   g_clear_object (&priv->effects);
5246   g_clear_object (&priv->flatten_effect);
5247
5248   if (priv->layout_manager != NULL)
5249     {
5250       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5251       g_clear_object (&priv->layout_manager);
5252     }
5253
5254   if (priv->content != NULL)
5255     {
5256       _clutter_content_detached (priv->content, self);
5257       g_clear_object (&priv->content);
5258     }
5259
5260   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5261 }
5262
5263 static void
5264 clutter_actor_finalize (GObject *object)
5265 {
5266   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5267
5268   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5269                 priv->name != NULL ? priv->name : "<none>",
5270                 priv->id,
5271                 g_type_name (G_OBJECT_TYPE (object)));
5272
5273   _clutter_context_release_id (priv->id);
5274
5275   g_free (priv->name);
5276
5277   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5278 }
5279
5280
5281 /**
5282  * clutter_actor_get_accessible:
5283  * @self: a #ClutterActor
5284  *
5285  * Returns the accessible object that describes the actor to an
5286  * assistive technology.
5287  *
5288  * If no class-specific #AtkObject implementation is available for the
5289  * actor instance in question, it will inherit an #AtkObject
5290  * implementation from the first ancestor class for which such an
5291  * implementation is defined.
5292  *
5293  * The documentation of the <ulink
5294  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5295  * library contains more information about accessible objects and
5296  * their uses.
5297  *
5298  * Returns: (transfer none): the #AtkObject associated with @actor
5299  */
5300 AtkObject *
5301 clutter_actor_get_accessible (ClutterActor *self)
5302 {
5303   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5304
5305   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5306 }
5307
5308 static AtkObject *
5309 clutter_actor_real_get_accessible (ClutterActor *actor)
5310 {
5311   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5312 }
5313
5314 static AtkObject *
5315 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5316 {
5317   AtkObject *accessible;
5318
5319   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5320   if (accessible != NULL)
5321     g_object_ref (accessible);
5322
5323   return accessible;
5324 }
5325
5326 static void
5327 atk_implementor_iface_init (AtkImplementorIface *iface)
5328 {
5329   iface->ref_accessible = _clutter_actor_ref_accessible;
5330 }
5331
5332 static gboolean
5333 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5334                                            ClutterPaintVolume *volume)
5335 {
5336   ClutterActorPrivate *priv = self->priv;
5337   gboolean res = TRUE;
5338
5339   /* we start from the allocation */
5340   clutter_paint_volume_set_width (volume,
5341                                   priv->allocation.x2 - priv->allocation.x1);
5342   clutter_paint_volume_set_height (volume,
5343                                    priv->allocation.y2 - priv->allocation.y1);
5344
5345   /* if the actor has a clip set then we have a pretty definite
5346    * size for the paint volume: the actor cannot possibly paint
5347    * outside the clip region.
5348    */
5349   if (priv->clip_to_allocation)
5350     {
5351       /* the allocation has already been set, so we just flip the
5352        * return value
5353        */
5354       res = TRUE;
5355     }
5356   else
5357     {
5358       ClutterActor *child;
5359
5360       if (priv->has_clip &&
5361           priv->clip.width >= 0 &&
5362           priv->clip.height >= 0)
5363         {
5364           ClutterVertex origin;
5365
5366           origin.x = priv->clip.x;
5367           origin.y = priv->clip.y;
5368           origin.z = 0;
5369
5370           clutter_paint_volume_set_origin (volume, &origin);
5371           clutter_paint_volume_set_width (volume, priv->clip.width);
5372           clutter_paint_volume_set_height (volume, priv->clip.height);
5373
5374           res = TRUE;
5375         }
5376
5377       /* if we don't have children we just bail out here... */
5378       if (priv->n_children == 0)
5379         return res;
5380
5381       /* ...but if we have children then we ask for their paint volume in
5382        * our coordinates. if any of our children replies that it doesn't
5383        * have a paint volume, we bail out
5384        */
5385       for (child = priv->first_child;
5386            child != NULL;
5387            child = child->priv->next_sibling)
5388         {
5389           const ClutterPaintVolume *child_volume;
5390
5391           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5392             continue;
5393
5394           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5395           if (child_volume == NULL)
5396             {
5397               res = FALSE;
5398               break;
5399             }
5400
5401           clutter_paint_volume_union (volume, child_volume);
5402           res = TRUE;
5403         }
5404     }
5405
5406   return res;
5407
5408 }
5409
5410 static gboolean
5411 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5412                                      ClutterPaintVolume *volume)
5413 {
5414   ClutterActorClass *klass;
5415   gboolean res;
5416
5417   klass = CLUTTER_ACTOR_GET_CLASS (self);
5418
5419   /* XXX - this thoroughly sucks, but we don't want to penalize users
5420    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5421    * redraw. This should go away in 2.0.
5422    */
5423   if (klass->paint == clutter_actor_real_paint &&
5424       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5425     {
5426       res = TRUE;
5427     }
5428   else
5429     {
5430       /* this is the default return value: we cannot know if a class
5431        * is going to paint outside its allocation, so we take the
5432        * conservative approach.
5433        */
5434       res = FALSE;
5435     }
5436
5437   /* update_default_paint_volume() should only fail if one of the children
5438    * reported an invalid, or no, paint volume
5439    */
5440   if (!clutter_actor_update_default_paint_volume (self, volume))
5441     return FALSE;
5442
5443   return res;
5444 }
5445
5446 /**
5447  * clutter_actor_get_default_paint_volume:
5448  * @self: a #ClutterActor
5449  *
5450  * Retrieves the default paint volume for @self.
5451  *
5452  * This function provides the same #ClutterPaintVolume that would be
5453  * computed by the default implementation inside #ClutterActor of the
5454  * #ClutterActorClass.get_paint_volume() virtual function.
5455  *
5456  * This function should only be used by #ClutterActor subclasses that
5457  * cannot chain up to the parent implementation when computing their
5458  * paint volume.
5459  *
5460  * Return value: (transfer none): a pointer to the default
5461  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5462  *   the actor could not compute a valid paint volume. The returned value
5463  *   is not guaranteed to be stable across multiple frames, so if you
5464  *   want to retain it, you will need to copy it using
5465  *   clutter_paint_volume_copy().
5466  *
5467  * Since: 1.10
5468  */
5469 const ClutterPaintVolume *
5470 clutter_actor_get_default_paint_volume (ClutterActor *self)
5471 {
5472   ClutterPaintVolume volume;
5473   ClutterPaintVolume *res;
5474
5475   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5476
5477   res = NULL;
5478   _clutter_paint_volume_init_static (&volume, self);
5479   if (clutter_actor_update_default_paint_volume (self, &volume))
5480     {
5481       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5482
5483       if (stage != NULL)
5484         {
5485           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5486           _clutter_paint_volume_copy_static (&volume, res);
5487         }
5488     }
5489
5490   clutter_paint_volume_free (&volume);
5491
5492   return res;
5493 }
5494
5495 static gboolean
5496 clutter_actor_real_has_overlaps (ClutterActor *self)
5497 {
5498   /* By default we'll assume that all actors need an offscreen redirect to get
5499    * the correct opacity. Actors such as ClutterTexture that would never need
5500    * an offscreen redirect can override this to return FALSE. */
5501   return TRUE;
5502 }
5503
5504 static void
5505 clutter_actor_real_destroy (ClutterActor *actor)
5506 {
5507   ClutterActorIter iter;
5508
5509   g_object_freeze_notify (G_OBJECT (actor));
5510
5511   clutter_actor_iter_init (&iter, actor);
5512   while (clutter_actor_iter_next (&iter, NULL))
5513     clutter_actor_iter_destroy (&iter);
5514
5515   g_object_thaw_notify (G_OBJECT (actor));
5516 }
5517
5518 static GObject *
5519 clutter_actor_constructor (GType gtype,
5520                            guint n_props,
5521                            GObjectConstructParam *props)
5522 {
5523   GObjectClass *gobject_class;
5524   ClutterActor *self;
5525   GObject *retval;
5526
5527   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5528   retval = gobject_class->constructor (gtype, n_props, props);
5529   self = CLUTTER_ACTOR (retval);
5530
5531   if (self->priv->layout_manager == NULL)
5532     {
5533       ClutterLayoutManager *default_layout;
5534
5535       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5536
5537       default_layout = clutter_fixed_layout_new ();
5538       clutter_actor_set_layout_manager (self, default_layout);
5539     }
5540
5541   return retval;
5542 }
5543
5544 static void
5545 clutter_actor_class_init (ClutterActorClass *klass)
5546 {
5547   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5548
5549   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5550   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5551   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5552   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5553
5554   object_class->constructor = clutter_actor_constructor;
5555   object_class->set_property = clutter_actor_set_property;
5556   object_class->get_property = clutter_actor_get_property;
5557   object_class->dispose = clutter_actor_dispose;
5558   object_class->finalize = clutter_actor_finalize;
5559
5560   klass->show = clutter_actor_real_show;
5561   klass->show_all = clutter_actor_show;
5562   klass->hide = clutter_actor_real_hide;
5563   klass->hide_all = clutter_actor_hide;
5564   klass->map = clutter_actor_real_map;
5565   klass->unmap = clutter_actor_real_unmap;
5566   klass->unrealize = clutter_actor_real_unrealize;
5567   klass->pick = clutter_actor_real_pick;
5568   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5569   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5570   klass->allocate = clutter_actor_real_allocate;
5571   klass->queue_redraw = clutter_actor_real_queue_redraw;
5572   klass->queue_relayout = clutter_actor_real_queue_relayout;
5573   klass->apply_transform = clutter_actor_real_apply_transform;
5574   klass->get_accessible = clutter_actor_real_get_accessible;
5575   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5576   klass->has_overlaps = clutter_actor_real_has_overlaps;
5577   klass->paint = clutter_actor_real_paint;
5578   klass->destroy = clutter_actor_real_destroy;
5579
5580   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5581
5582   /**
5583    * ClutterActor:x:
5584    *
5585    * X coordinate of the actor in pixels. If written, forces a fixed
5586    * position for the actor. If read, returns the fixed position if any,
5587    * otherwise the allocation if available, otherwise 0.
5588    *
5589    * The #ClutterActor:x property is animatable.
5590    */
5591   obj_props[PROP_X] =
5592     g_param_spec_float ("x",
5593                         P_("X coordinate"),
5594                         P_("X coordinate of the actor"),
5595                         -G_MAXFLOAT, G_MAXFLOAT,
5596                         0.0,
5597                         G_PARAM_READWRITE |
5598                         G_PARAM_STATIC_STRINGS |
5599                         CLUTTER_PARAM_ANIMATABLE);
5600
5601   /**
5602    * ClutterActor:y:
5603    *
5604    * Y coordinate of the actor in pixels. If written, forces a fixed
5605    * position for the actor.  If read, returns the fixed position if
5606    * any, otherwise the allocation if available, otherwise 0.
5607    *
5608    * The #ClutterActor:y property is animatable.
5609    */
5610   obj_props[PROP_Y] =
5611     g_param_spec_float ("y",
5612                         P_("Y coordinate"),
5613                         P_("Y coordinate of the actor"),
5614                         -G_MAXFLOAT, G_MAXFLOAT,
5615                         0.0,
5616                         G_PARAM_READWRITE |
5617                         G_PARAM_STATIC_STRINGS |
5618                         CLUTTER_PARAM_ANIMATABLE);
5619
5620   /**
5621    * ClutterActor:position:
5622    *
5623    * The position of the origin of the actor.
5624    *
5625    * This property is a shorthand for setting and getting the
5626    * #ClutterActor:x and #ClutterActor:y properties at the same
5627    * time.
5628    *
5629    * The #ClutterActor:position property is animatable.
5630    *
5631    * Since: 1.12
5632    */
5633   obj_props[PROP_POSITION] =
5634     g_param_spec_boxed ("position",
5635                         P_("Position"),
5636                         P_("The position of the origin of the actor"),
5637                         CLUTTER_TYPE_POINT,
5638                         G_PARAM_READWRITE |
5639                         G_PARAM_STATIC_STRINGS |
5640                         CLUTTER_PARAM_ANIMATABLE);
5641
5642   /**
5643    * ClutterActor:width:
5644    *
5645    * Width of the actor (in pixels). If written, forces the minimum and
5646    * natural size request of the actor to the given width. If read, returns
5647    * the allocated width if available, otherwise the width request.
5648    *
5649    * The #ClutterActor:width property is animatable.
5650    */
5651   obj_props[PROP_WIDTH] =
5652     g_param_spec_float ("width",
5653                         P_("Width"),
5654                         P_("Width of the actor"),
5655                         0.0, G_MAXFLOAT,
5656                         0.0,
5657                         G_PARAM_READWRITE |
5658                         G_PARAM_STATIC_STRINGS |
5659                         CLUTTER_PARAM_ANIMATABLE);
5660
5661   /**
5662    * ClutterActor:height:
5663    *
5664    * Height of the actor (in pixels).  If written, forces the minimum and
5665    * natural size request of the actor to the given height. If read, returns
5666    * the allocated height if available, otherwise the height request.
5667    *
5668    * The #ClutterActor:height property is animatable.
5669    */
5670   obj_props[PROP_HEIGHT] =
5671     g_param_spec_float ("height",
5672                         P_("Height"),
5673                         P_("Height of the actor"),
5674                         0.0, G_MAXFLOAT,
5675                         0.0,
5676                         G_PARAM_READWRITE |
5677                         G_PARAM_STATIC_STRINGS |
5678                         CLUTTER_PARAM_ANIMATABLE);
5679
5680   /**
5681    * ClutterActor:size:
5682    *
5683    * The size of the actor.
5684    *
5685    * This property is a shorthand for setting and getting the
5686    * #ClutterActor:width and #ClutterActor:height at the same time.
5687    *
5688    * The #ClutterActor:size property is animatable.
5689    *
5690    * Since: 1.12
5691    */
5692   obj_props[PROP_SIZE] =
5693     g_param_spec_boxed ("size",
5694                         P_("Size"),
5695                         P_("The size of the actor"),
5696                         CLUTTER_TYPE_SIZE,
5697                         G_PARAM_READWRITE |
5698                         G_PARAM_STATIC_STRINGS |
5699                         CLUTTER_PARAM_ANIMATABLE);
5700
5701   /**
5702    * ClutterActor:fixed-x:
5703    *
5704    * The fixed X position of the actor in pixels.
5705    *
5706    * Writing this property sets #ClutterActor:fixed-position-set
5707    * property as well, as a side effect
5708    *
5709    * Since: 0.8
5710    */
5711   obj_props[PROP_FIXED_X] =
5712     g_param_spec_float ("fixed-x",
5713                         P_("Fixed X"),
5714                         P_("Forced X position of the actor"),
5715                         -G_MAXFLOAT, G_MAXFLOAT,
5716                         0.0,
5717                         CLUTTER_PARAM_READWRITE);
5718
5719   /**
5720    * ClutterActor:fixed-y:
5721    *
5722    * The fixed Y position of the actor in pixels.
5723    *
5724    * Writing this property sets the #ClutterActor:fixed-position-set
5725    * property as well, as a side effect
5726    *
5727    * Since: 0.8
5728    */
5729   obj_props[PROP_FIXED_Y] =
5730     g_param_spec_float ("fixed-y",
5731                         P_("Fixed Y"),
5732                         P_("Forced Y position of the actor"),
5733                         -G_MAXFLOAT, G_MAXFLOAT,
5734                         0,
5735                         CLUTTER_PARAM_READWRITE);
5736
5737   /**
5738    * ClutterActor:fixed-position-set:
5739    *
5740    * This flag controls whether the #ClutterActor:fixed-x and
5741    * #ClutterActor:fixed-y properties are used
5742    *
5743    * Since: 0.8
5744    */
5745   obj_props[PROP_FIXED_POSITION_SET] =
5746     g_param_spec_boolean ("fixed-position-set",
5747                           P_("Fixed position set"),
5748                           P_("Whether to use fixed positioning for the actor"),
5749                           FALSE,
5750                           CLUTTER_PARAM_READWRITE);
5751
5752   /**
5753    * ClutterActor:min-width:
5754    *
5755    * A forced minimum width request for the actor, in pixels
5756    *
5757    * Writing this property sets the #ClutterActor:min-width-set property
5758    * as well, as a side effect.
5759    *
5760    *This property overrides the usual width request of the actor.
5761    *
5762    * Since: 0.8
5763    */
5764   obj_props[PROP_MIN_WIDTH] =
5765     g_param_spec_float ("min-width",
5766                         P_("Min Width"),
5767                         P_("Forced minimum width request for the actor"),
5768                         0.0, G_MAXFLOAT,
5769                         0.0,
5770                         CLUTTER_PARAM_READWRITE);
5771
5772   /**
5773    * ClutterActor:min-height:
5774    *
5775    * A forced minimum height request for the actor, in pixels
5776    *
5777    * Writing this property sets the #ClutterActor:min-height-set property
5778    * as well, as a side effect. This property overrides the usual height
5779    * request of the actor.
5780    *
5781    * Since: 0.8
5782    */
5783   obj_props[PROP_MIN_HEIGHT] =
5784     g_param_spec_float ("min-height",
5785                         P_("Min Height"),
5786                         P_("Forced minimum height request for the actor"),
5787                         0.0, G_MAXFLOAT,
5788                         0.0,
5789                         CLUTTER_PARAM_READWRITE);
5790
5791   /**
5792    * ClutterActor:natural-width:
5793    *
5794    * A forced natural width request for the actor, in pixels
5795    *
5796    * Writing this property sets the #ClutterActor:natural-width-set
5797    * property as well, as a side effect. This property overrides the
5798    * usual width request of the actor
5799    *
5800    * Since: 0.8
5801    */
5802   obj_props[PROP_NATURAL_WIDTH] =
5803     g_param_spec_float ("natural-width",
5804                         P_("Natural Width"),
5805                         P_("Forced natural width request for the actor"),
5806                         0.0, G_MAXFLOAT,
5807                         0.0,
5808                         CLUTTER_PARAM_READWRITE);
5809
5810   /**
5811    * ClutterActor:natural-height:
5812    *
5813    * A forced natural height request for the actor, in pixels
5814    *
5815    * Writing this property sets the #ClutterActor:natural-height-set
5816    * property as well, as a side effect. This property overrides the
5817    * usual height request of the actor
5818    *
5819    * Since: 0.8
5820    */
5821   obj_props[PROP_NATURAL_HEIGHT] =
5822     g_param_spec_float ("natural-height",
5823                         P_("Natural Height"),
5824                         P_("Forced natural height request for the actor"),
5825                         0.0, G_MAXFLOAT,
5826                         0.0,
5827                         CLUTTER_PARAM_READWRITE);
5828
5829   /**
5830    * ClutterActor:min-width-set:
5831    *
5832    * This flag controls whether the #ClutterActor:min-width property
5833    * is used
5834    *
5835    * Since: 0.8
5836    */
5837   obj_props[PROP_MIN_WIDTH_SET] =
5838     g_param_spec_boolean ("min-width-set",
5839                           P_("Minimum width set"),
5840                           P_("Whether to use the min-width property"),
5841                           FALSE,
5842                           CLUTTER_PARAM_READWRITE);
5843
5844   /**
5845    * ClutterActor:min-height-set:
5846    *
5847    * This flag controls whether the #ClutterActor:min-height property
5848    * is used
5849    *
5850    * Since: 0.8
5851    */
5852   obj_props[PROP_MIN_HEIGHT_SET] =
5853     g_param_spec_boolean ("min-height-set",
5854                           P_("Minimum height set"),
5855                           P_("Whether to use the min-height property"),
5856                           FALSE,
5857                           CLUTTER_PARAM_READWRITE);
5858
5859   /**
5860    * ClutterActor:natural-width-set:
5861    *
5862    * This flag controls whether the #ClutterActor:natural-width property
5863    * is used
5864    *
5865    * Since: 0.8
5866    */
5867   obj_props[PROP_NATURAL_WIDTH_SET] =
5868     g_param_spec_boolean ("natural-width-set",
5869                           P_("Natural width set"),
5870                           P_("Whether to use the natural-width property"),
5871                           FALSE,
5872                           CLUTTER_PARAM_READWRITE);
5873
5874   /**
5875    * ClutterActor:natural-height-set:
5876    *
5877    * This flag controls whether the #ClutterActor:natural-height property
5878    * is used
5879    *
5880    * Since: 0.8
5881    */
5882   obj_props[PROP_NATURAL_HEIGHT_SET] =
5883     g_param_spec_boolean ("natural-height-set",
5884                           P_("Natural height set"),
5885                           P_("Whether to use the natural-height property"),
5886                           FALSE,
5887                           CLUTTER_PARAM_READWRITE);
5888
5889   /**
5890    * ClutterActor:allocation:
5891    *
5892    * The allocation for the actor, in pixels
5893    *
5894    * This is property is read-only, but you might monitor it to know when an
5895    * actor moves or resizes
5896    *
5897    * Since: 0.8
5898    */
5899   obj_props[PROP_ALLOCATION] =
5900     g_param_spec_boxed ("allocation",
5901                         P_("Allocation"),
5902                         P_("The actor's allocation"),
5903                         CLUTTER_TYPE_ACTOR_BOX,
5904                         G_PARAM_READABLE |
5905                         G_PARAM_STATIC_STRINGS |
5906                         CLUTTER_PARAM_ANIMATABLE);
5907
5908   /**
5909    * ClutterActor:request-mode:
5910    *
5911    * Request mode for the #ClutterActor. The request mode determines the
5912    * type of geometry management used by the actor, either height for width
5913    * (the default) or width for height.
5914    *
5915    * For actors implementing height for width, the parent container should get
5916    * the preferred width first, and then the preferred height for that width.
5917    *
5918    * For actors implementing width for height, the parent container should get
5919    * the preferred height first, and then the preferred width for that height.
5920    *
5921    * For instance:
5922    *
5923    * |[
5924    *   ClutterRequestMode mode;
5925    *   gfloat natural_width, min_width;
5926    *   gfloat natural_height, min_height;
5927    *
5928    *   mode = clutter_actor_get_request_mode (child);
5929    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5930    *     {
5931    *       clutter_actor_get_preferred_width (child, -1,
5932    *                                          &amp;min_width,
5933    *                                          &amp;natural_width);
5934    *       clutter_actor_get_preferred_height (child, natural_width,
5935    *                                           &amp;min_height,
5936    *                                           &amp;natural_height);
5937    *     }
5938    *   else
5939    *     {
5940    *       clutter_actor_get_preferred_height (child, -1,
5941    *                                           &amp;min_height,
5942    *                                           &amp;natural_height);
5943    *       clutter_actor_get_preferred_width (child, natural_height,
5944    *                                          &amp;min_width,
5945    *                                          &amp;natural_width);
5946    *     }
5947    * ]|
5948    *
5949    * will retrieve the minimum and natural width and height depending on the
5950    * preferred request mode of the #ClutterActor "child".
5951    *
5952    * The clutter_actor_get_preferred_size() function will implement this
5953    * check for you.
5954    *
5955    * Since: 0.8
5956    */
5957   obj_props[PROP_REQUEST_MODE] =
5958     g_param_spec_enum ("request-mode",
5959                        P_("Request Mode"),
5960                        P_("The actor's request mode"),
5961                        CLUTTER_TYPE_REQUEST_MODE,
5962                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5963                        CLUTTER_PARAM_READWRITE);
5964
5965   /**
5966    * ClutterActor:depth:
5967    *
5968    * The position of the actor on the Z axis.
5969    *
5970    * The #ClutterActor:depth property is relative to the parent's
5971    * modelview matrix.
5972    *
5973    * The #ClutterActor:depth property is animatable.
5974    *
5975    * Since: 0.6
5976    */
5977   obj_props[PROP_DEPTH] =
5978     g_param_spec_float ("depth",
5979                         P_("Depth"),
5980                         P_("Position on the Z axis"),
5981                         -G_MAXFLOAT, G_MAXFLOAT,
5982                         0.0,
5983                         G_PARAM_READWRITE |
5984                         G_PARAM_STATIC_STRINGS |
5985                         CLUTTER_PARAM_ANIMATABLE);
5986
5987   /**
5988    * ClutterActor:opacity:
5989    *
5990    * Opacity of an actor, between 0 (fully transparent) and
5991    * 255 (fully opaque)
5992    *
5993    * The #ClutterActor:opacity property is animatable.
5994    */
5995   obj_props[PROP_OPACITY] =
5996     g_param_spec_uint ("opacity",
5997                        P_("Opacity"),
5998                        P_("Opacity of an actor"),
5999                        0, 255,
6000                        255,
6001                        G_PARAM_READWRITE |
6002                        G_PARAM_STATIC_STRINGS |
6003                        CLUTTER_PARAM_ANIMATABLE);
6004
6005   /**
6006    * ClutterActor:offscreen-redirect:
6007    *
6008    * Determines the conditions in which the actor will be redirected
6009    * to an offscreen framebuffer while being painted. For example this
6010    * can be used to cache an actor in a framebuffer or for improved
6011    * handling of transparent actors. See
6012    * clutter_actor_set_offscreen_redirect() for details.
6013    *
6014    * Since: 1.8
6015    */
6016   obj_props[PROP_OFFSCREEN_REDIRECT] =
6017     g_param_spec_flags ("offscreen-redirect",
6018                         P_("Offscreen redirect"),
6019                         P_("Flags controlling when to flatten the actor into a single image"),
6020                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
6021                         0,
6022                         CLUTTER_PARAM_READWRITE);
6023
6024   /**
6025    * ClutterActor:visible:
6026    *
6027    * Whether the actor is set to be visible or not
6028    *
6029    * See also #ClutterActor:mapped
6030    */
6031   obj_props[PROP_VISIBLE] =
6032     g_param_spec_boolean ("visible",
6033                           P_("Visible"),
6034                           P_("Whether the actor is visible or not"),
6035                           FALSE,
6036                           CLUTTER_PARAM_READWRITE);
6037
6038   /**
6039    * ClutterActor:mapped:
6040    *
6041    * Whether the actor is mapped (will be painted when the stage
6042    * to which it belongs is mapped)
6043    *
6044    * Since: 1.0
6045    */
6046   obj_props[PROP_MAPPED] =
6047     g_param_spec_boolean ("mapped",
6048                           P_("Mapped"),
6049                           P_("Whether the actor will be painted"),
6050                           FALSE,
6051                           CLUTTER_PARAM_READABLE);
6052
6053   /**
6054    * ClutterActor:realized:
6055    *
6056    * Whether the actor has been realized
6057    *
6058    * Since: 1.0
6059    */
6060   obj_props[PROP_REALIZED] =
6061     g_param_spec_boolean ("realized",
6062                           P_("Realized"),
6063                           P_("Whether the actor has been realized"),
6064                           FALSE,
6065                           CLUTTER_PARAM_READABLE);
6066
6067   /**
6068    * ClutterActor:reactive:
6069    *
6070    * Whether the actor is reactive to events or not
6071    *
6072    * Only reactive actors will emit event-related signals
6073    *
6074    * Since: 0.6
6075    */
6076   obj_props[PROP_REACTIVE] =
6077     g_param_spec_boolean ("reactive",
6078                           P_("Reactive"),
6079                           P_("Whether the actor is reactive to events"),
6080                           FALSE,
6081                           CLUTTER_PARAM_READWRITE);
6082
6083   /**
6084    * ClutterActor:has-clip:
6085    *
6086    * Whether the actor has the #ClutterActor:clip property set or not
6087    */
6088   obj_props[PROP_HAS_CLIP] =
6089     g_param_spec_boolean ("has-clip",
6090                           P_("Has Clip"),
6091                           P_("Whether the actor has a clip set"),
6092                           FALSE,
6093                           CLUTTER_PARAM_READABLE);
6094
6095   /**
6096    * ClutterActor:clip:
6097    *
6098    * The clip region for the actor, in actor-relative coordinates
6099    *
6100    * Every part of the actor outside the clip region will not be
6101    * painted
6102    */
6103   obj_props[PROP_CLIP] =
6104     g_param_spec_boxed ("clip",
6105                         P_("Clip"),
6106                         P_("The clip region for the actor"),
6107                         CLUTTER_TYPE_GEOMETRY,
6108                         CLUTTER_PARAM_READWRITE);
6109
6110   /**
6111    * ClutterActor:name:
6112    *
6113    * The name of the actor
6114    *
6115    * Since: 0.2
6116    */
6117   obj_props[PROP_NAME] =
6118     g_param_spec_string ("name",
6119                          P_("Name"),
6120                          P_("Name of the actor"),
6121                          NULL,
6122                          CLUTTER_PARAM_READWRITE);
6123
6124   /**
6125    * ClutterActor:scale-x:
6126    *
6127    * The horizontal scale of the actor.
6128    *
6129    * The #ClutterActor:scale-x property is animatable.
6130    *
6131    * Since: 0.6
6132    */
6133   obj_props[PROP_SCALE_X] =
6134     g_param_spec_double ("scale-x",
6135                          P_("Scale X"),
6136                          P_("Scale factor on the X axis"),
6137                          0.0, G_MAXDOUBLE,
6138                          1.0,
6139                          G_PARAM_READWRITE |
6140                          G_PARAM_STATIC_STRINGS |
6141                          CLUTTER_PARAM_ANIMATABLE);
6142
6143   /**
6144    * ClutterActor:scale-y:
6145    *
6146    * The vertical scale of the actor.
6147    *
6148    * The #ClutterActor:scale-y property is animatable.
6149    *
6150    * Since: 0.6
6151    */
6152   obj_props[PROP_SCALE_Y] =
6153     g_param_spec_double ("scale-y",
6154                          P_("Scale Y"),
6155                          P_("Scale factor on the Y axis"),
6156                          0.0, G_MAXDOUBLE,
6157                          1.0,
6158                          G_PARAM_READWRITE |
6159                          G_PARAM_STATIC_STRINGS |
6160                          CLUTTER_PARAM_ANIMATABLE);
6161
6162   /**
6163    * ClutterActor:scale-center-x:
6164    *
6165    * The horizontal center point for scaling
6166    *
6167    * Since: 1.0
6168    */
6169   obj_props[PROP_SCALE_CENTER_X] =
6170     g_param_spec_float ("scale-center-x",
6171                         P_("Scale Center X"),
6172                         P_("Horizontal scale center"),
6173                         -G_MAXFLOAT, G_MAXFLOAT,
6174                         0.0,
6175                         CLUTTER_PARAM_READWRITE);
6176
6177   /**
6178    * ClutterActor:scale-center-y:
6179    *
6180    * The vertical center point for scaling
6181    *
6182    * Since: 1.0
6183    */
6184   obj_props[PROP_SCALE_CENTER_Y] =
6185     g_param_spec_float ("scale-center-y",
6186                         P_("Scale Center Y"),
6187                         P_("Vertical scale center"),
6188                         -G_MAXFLOAT, G_MAXFLOAT,
6189                         0.0,
6190                         CLUTTER_PARAM_READWRITE);
6191
6192   /**
6193    * ClutterActor:scale-gravity:
6194    *
6195    * The center point for scaling expressed as a #ClutterGravity
6196    *
6197    * Since: 1.0
6198    */
6199   obj_props[PROP_SCALE_GRAVITY] =
6200     g_param_spec_enum ("scale-gravity",
6201                        P_("Scale Gravity"),
6202                        P_("The center of scaling"),
6203                        CLUTTER_TYPE_GRAVITY,
6204                        CLUTTER_GRAVITY_NONE,
6205                        CLUTTER_PARAM_READWRITE);
6206
6207   /**
6208    * ClutterActor:rotation-angle-x:
6209    *
6210    * The rotation angle on the X axis.
6211    *
6212    * The #ClutterActor:rotation-angle-x property is animatable.
6213    *
6214    * Since: 0.6
6215    */
6216   obj_props[PROP_ROTATION_ANGLE_X] =
6217     g_param_spec_double ("rotation-angle-x",
6218                          P_("Rotation Angle X"),
6219                          P_("The rotation angle on the X axis"),
6220                          -G_MAXDOUBLE, G_MAXDOUBLE,
6221                          0.0,
6222                          G_PARAM_READWRITE |
6223                          G_PARAM_STATIC_STRINGS |
6224                          CLUTTER_PARAM_ANIMATABLE);
6225
6226   /**
6227    * ClutterActor:rotation-angle-y:
6228    *
6229    * The rotation angle on the Y axis
6230    *
6231    * The #ClutterActor:rotation-angle-y property is animatable.
6232    *
6233    * Since: 0.6
6234    */
6235   obj_props[PROP_ROTATION_ANGLE_Y] =
6236     g_param_spec_double ("rotation-angle-y",
6237                          P_("Rotation Angle Y"),
6238                          P_("The rotation angle on the Y axis"),
6239                          -G_MAXDOUBLE, G_MAXDOUBLE,
6240                          0.0,
6241                          G_PARAM_READWRITE |
6242                          G_PARAM_STATIC_STRINGS |
6243                          CLUTTER_PARAM_ANIMATABLE);
6244
6245   /**
6246    * ClutterActor:rotation-angle-z:
6247    *
6248    * The rotation angle on the Z axis
6249    *
6250    * The #ClutterActor:rotation-angle-z property is animatable.
6251    *
6252    * Since: 0.6
6253    */
6254   obj_props[PROP_ROTATION_ANGLE_Z] =
6255     g_param_spec_double ("rotation-angle-z",
6256                          P_("Rotation Angle Z"),
6257                          P_("The rotation angle on the Z axis"),
6258                          -G_MAXDOUBLE, G_MAXDOUBLE,
6259                          0.0,
6260                          G_PARAM_READWRITE |
6261                          G_PARAM_STATIC_STRINGS |
6262                          CLUTTER_PARAM_ANIMATABLE);
6263
6264   /**
6265    * ClutterActor:rotation-center-x:
6266    *
6267    * The rotation center on the X axis.
6268    *
6269    * Since: 0.6
6270    */
6271   obj_props[PROP_ROTATION_CENTER_X] =
6272     g_param_spec_boxed ("rotation-center-x",
6273                         P_("Rotation Center X"),
6274                         P_("The rotation center on the X axis"),
6275                         CLUTTER_TYPE_VERTEX,
6276                         CLUTTER_PARAM_READWRITE);
6277
6278   /**
6279    * ClutterActor:rotation-center-y:
6280    *
6281    * The rotation center on the Y axis.
6282    *
6283    * Since: 0.6
6284    */
6285   obj_props[PROP_ROTATION_CENTER_Y] =
6286     g_param_spec_boxed ("rotation-center-y",
6287                         P_("Rotation Center Y"),
6288                         P_("The rotation center on the Y axis"),
6289                         CLUTTER_TYPE_VERTEX,
6290                         CLUTTER_PARAM_READWRITE);
6291
6292   /**
6293    * ClutterActor:rotation-center-z:
6294    *
6295    * The rotation center on the Z axis.
6296    *
6297    * Since: 0.6
6298    */
6299   obj_props[PROP_ROTATION_CENTER_Z] =
6300     g_param_spec_boxed ("rotation-center-z",
6301                         P_("Rotation Center Z"),
6302                         P_("The rotation center on the Z axis"),
6303                         CLUTTER_TYPE_VERTEX,
6304                         CLUTTER_PARAM_READWRITE);
6305
6306   /**
6307    * ClutterActor:rotation-center-z-gravity:
6308    *
6309    * The rotation center on the Z axis expressed as a #ClutterGravity.
6310    *
6311    * Since: 1.0
6312    */
6313   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6314     g_param_spec_enum ("rotation-center-z-gravity",
6315                        P_("Rotation Center Z Gravity"),
6316                        P_("Center point for rotation around the Z axis"),
6317                        CLUTTER_TYPE_GRAVITY,
6318                        CLUTTER_GRAVITY_NONE,
6319                        CLUTTER_PARAM_READWRITE);
6320
6321   /**
6322    * ClutterActor:anchor-x:
6323    *
6324    * The X coordinate of an actor's anchor point, relative to
6325    * the actor coordinate space, in pixels
6326    *
6327    * Since: 0.8
6328    */
6329   obj_props[PROP_ANCHOR_X] =
6330     g_param_spec_float ("anchor-x",
6331                         P_("Anchor X"),
6332                         P_("X coordinate of the anchor point"),
6333                         -G_MAXFLOAT, G_MAXFLOAT,
6334                         0,
6335                         CLUTTER_PARAM_READWRITE);
6336
6337   /**
6338    * ClutterActor:anchor-y:
6339    *
6340    * The Y coordinate of an actor's anchor point, relative to
6341    * the actor coordinate space, in pixels
6342    *
6343    * Since: 0.8
6344    */
6345   obj_props[PROP_ANCHOR_Y] =
6346     g_param_spec_float ("anchor-y",
6347                         P_("Anchor Y"),
6348                         P_("Y coordinate of the anchor point"),
6349                         -G_MAXFLOAT, G_MAXFLOAT,
6350                         0,
6351                         CLUTTER_PARAM_READWRITE);
6352
6353   /**
6354    * ClutterActor:anchor-gravity:
6355    *
6356    * The anchor point expressed as a #ClutterGravity
6357    *
6358    * Since: 1.0
6359    */
6360   obj_props[PROP_ANCHOR_GRAVITY] =
6361     g_param_spec_enum ("anchor-gravity",
6362                        P_("Anchor Gravity"),
6363                        P_("The anchor point as a ClutterGravity"),
6364                        CLUTTER_TYPE_GRAVITY,
6365                        CLUTTER_GRAVITY_NONE,
6366                        CLUTTER_PARAM_READWRITE);
6367
6368   /**
6369    * ClutterActor:show-on-set-parent:
6370    *
6371    * If %TRUE, the actor is automatically shown when parented.
6372    *
6373    * Calling clutter_actor_hide() on an actor which has not been
6374    * parented will set this property to %FALSE as a side effect.
6375    *
6376    * Since: 0.8
6377    */
6378   obj_props[PROP_SHOW_ON_SET_PARENT] =
6379     g_param_spec_boolean ("show-on-set-parent",
6380                           P_("Show on set parent"),
6381                           P_("Whether the actor is shown when parented"),
6382                           TRUE,
6383                           CLUTTER_PARAM_READWRITE);
6384
6385   /**
6386    * ClutterActor:clip-to-allocation:
6387    *
6388    * Whether the clip region should track the allocated area
6389    * of the actor.
6390    *
6391    * This property is ignored if a clip area has been explicitly
6392    * set using clutter_actor_set_clip().
6393    *
6394    * Since: 1.0
6395    */
6396   obj_props[PROP_CLIP_TO_ALLOCATION] =
6397     g_param_spec_boolean ("clip-to-allocation",
6398                           P_("Clip to Allocation"),
6399                           P_("Sets the clip region to track the actor's allocation"),
6400                           FALSE,
6401                           CLUTTER_PARAM_READWRITE);
6402
6403   /**
6404    * ClutterActor:text-direction:
6405    *
6406    * The direction of the text inside a #ClutterActor.
6407    *
6408    * Since: 1.0
6409    */
6410   obj_props[PROP_TEXT_DIRECTION] =
6411     g_param_spec_enum ("text-direction",
6412                        P_("Text Direction"),
6413                        P_("Direction of the text"),
6414                        CLUTTER_TYPE_TEXT_DIRECTION,
6415                        CLUTTER_TEXT_DIRECTION_LTR,
6416                        CLUTTER_PARAM_READWRITE);
6417
6418   /**
6419    * ClutterActor:has-pointer:
6420    *
6421    * Whether the actor contains the pointer of a #ClutterInputDevice
6422    * or not.
6423    *
6424    * Since: 1.2
6425    */
6426   obj_props[PROP_HAS_POINTER] =
6427     g_param_spec_boolean ("has-pointer",
6428                           P_("Has Pointer"),
6429                           P_("Whether the actor contains the pointer of an input device"),
6430                           FALSE,
6431                           CLUTTER_PARAM_READABLE);
6432
6433   /**
6434    * ClutterActor:actions:
6435    *
6436    * Adds a #ClutterAction to the actor
6437    *
6438    * Since: 1.4
6439    */
6440   obj_props[PROP_ACTIONS] =
6441     g_param_spec_object ("actions",
6442                          P_("Actions"),
6443                          P_("Adds an action to the actor"),
6444                          CLUTTER_TYPE_ACTION,
6445                          CLUTTER_PARAM_WRITABLE);
6446
6447   /**
6448    * ClutterActor:constraints:
6449    *
6450    * Adds a #ClutterConstraint to the actor
6451    *
6452    * Since: 1.4
6453    */
6454   obj_props[PROP_CONSTRAINTS] =
6455     g_param_spec_object ("constraints",
6456                          P_("Constraints"),
6457                          P_("Adds a constraint to the actor"),
6458                          CLUTTER_TYPE_CONSTRAINT,
6459                          CLUTTER_PARAM_WRITABLE);
6460
6461   /**
6462    * ClutterActor:effect:
6463    *
6464    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6465    *
6466    * Since: 1.4
6467    */
6468   obj_props[PROP_EFFECT] =
6469     g_param_spec_object ("effect",
6470                          P_("Effect"),
6471                          P_("Add an effect to be applied on the actor"),
6472                          CLUTTER_TYPE_EFFECT,
6473                          CLUTTER_PARAM_WRITABLE);
6474
6475   /**
6476    * ClutterActor:layout-manager:
6477    *
6478    * A delegate object for controlling the layout of the children of
6479    * an actor.
6480    *
6481    * Since: 1.10
6482    */
6483   obj_props[PROP_LAYOUT_MANAGER] =
6484     g_param_spec_object ("layout-manager",
6485                          P_("Layout Manager"),
6486                          P_("The object controlling the layout of an actor's children"),
6487                          CLUTTER_TYPE_LAYOUT_MANAGER,
6488                          CLUTTER_PARAM_READWRITE);
6489
6490   /**
6491    * ClutterActor:x-expand:
6492    *
6493    * Whether a layout manager should assign more space to the actor on
6494    * the X axis.
6495    *
6496    * Since: 1.12
6497    */
6498   obj_props[PROP_X_EXPAND] =
6499     g_param_spec_boolean ("x-expand",
6500                           P_("X Expand"),
6501                           P_("Whether extra horizontal space should be assigned to the actor"),
6502                           FALSE,
6503                           G_PARAM_READWRITE |
6504                           G_PARAM_STATIC_STRINGS);
6505
6506   /**
6507    * ClutterActor:y-expand:
6508    *
6509    * Whether a layout manager should assign more space to the actor on
6510    * the Y axis.
6511    *
6512    * Since: 1.12
6513    */
6514   obj_props[PROP_Y_EXPAND] =
6515     g_param_spec_boolean ("y-expand",
6516                           P_("Y Expand"),
6517                           P_("Whether extra vertical space should be assigned to the actor"),
6518                           FALSE,
6519                           G_PARAM_READWRITE |
6520                           G_PARAM_STATIC_STRINGS);
6521
6522   /**
6523    * ClutterActor:x-align:
6524    *
6525    * The alignment of an actor on the X axis, if the actor has been given
6526    * extra space for its allocation. See also the #ClutterActor:x-expand
6527    * property.
6528    *
6529    * Since: 1.10
6530    */
6531   obj_props[PROP_X_ALIGN] =
6532     g_param_spec_enum ("x-align",
6533                        P_("X Alignment"),
6534                        P_("The alignment of the actor on the X axis within its allocation"),
6535                        CLUTTER_TYPE_ACTOR_ALIGN,
6536                        CLUTTER_ACTOR_ALIGN_FILL,
6537                        CLUTTER_PARAM_READWRITE);
6538
6539   /**
6540    * ClutterActor:y-align:
6541    *
6542    * The alignment of an actor on the Y axis, if the actor has been given
6543    * extra space for its allocation.
6544    *
6545    * Since: 1.10
6546    */
6547   obj_props[PROP_Y_ALIGN] =
6548     g_param_spec_enum ("y-align",
6549                        P_("Y Alignment"),
6550                        P_("The alignment of the actor on the Y axis within its allocation"),
6551                        CLUTTER_TYPE_ACTOR_ALIGN,
6552                        CLUTTER_ACTOR_ALIGN_FILL,
6553                        CLUTTER_PARAM_READWRITE);
6554
6555   /**
6556    * ClutterActor:margin-top:
6557    *
6558    * The margin (in pixels) from the top of the actor.
6559    *
6560    * This property adds a margin to the actor's preferred size; the margin
6561    * will be automatically taken into account when allocating the actor.
6562    *
6563    * Since: 1.10
6564    */
6565   obj_props[PROP_MARGIN_TOP] =
6566     g_param_spec_float ("margin-top",
6567                         P_("Margin Top"),
6568                         P_("Extra space at the top"),
6569                         0.0, G_MAXFLOAT,
6570                         0.0,
6571                         CLUTTER_PARAM_READWRITE);
6572
6573   /**
6574    * ClutterActor:margin-bottom:
6575    *
6576    * The margin (in pixels) from the bottom of the actor.
6577    *
6578    * This property adds a margin to the actor's preferred size; the margin
6579    * will be automatically taken into account when allocating the actor.
6580    *
6581    * Since: 1.10
6582    */
6583   obj_props[PROP_MARGIN_BOTTOM] =
6584     g_param_spec_float ("margin-bottom",
6585                         P_("Margin Bottom"),
6586                         P_("Extra space at the bottom"),
6587                         0.0, G_MAXFLOAT,
6588                         0.0,
6589                         CLUTTER_PARAM_READWRITE);
6590
6591   /**
6592    * ClutterActor:margin-left:
6593    *
6594    * The margin (in pixels) from the left of the actor.
6595    *
6596    * This property adds a margin to the actor's preferred size; the margin
6597    * will be automatically taken into account when allocating the actor.
6598    *
6599    * Since: 1.10
6600    */
6601   obj_props[PROP_MARGIN_LEFT] =
6602     g_param_spec_float ("margin-left",
6603                         P_("Margin Left"),
6604                         P_("Extra space at the left"),
6605                         0.0, G_MAXFLOAT,
6606                         0.0,
6607                         CLUTTER_PARAM_READWRITE);
6608
6609   /**
6610    * ClutterActor:margin-right:
6611    *
6612    * The margin (in pixels) from the right of the actor.
6613    *
6614    * This property adds a margin to the actor's preferred size; the margin
6615    * will be automatically taken into account when allocating the actor.
6616    *
6617    * Since: 1.10
6618    */
6619   obj_props[PROP_MARGIN_RIGHT] =
6620     g_param_spec_float ("margin-right",
6621                         P_("Margin Right"),
6622                         P_("Extra space at the right"),
6623                         0.0, G_MAXFLOAT,
6624                         0.0,
6625                         CLUTTER_PARAM_READWRITE);
6626
6627   /**
6628    * ClutterActor:background-color-set:
6629    *
6630    * Whether the #ClutterActor:background-color property has been set.
6631    *
6632    * Since: 1.10
6633    */
6634   obj_props[PROP_BACKGROUND_COLOR_SET] =
6635     g_param_spec_boolean ("background-color-set",
6636                           P_("Background Color Set"),
6637                           P_("Whether the background color is set"),
6638                           FALSE,
6639                           CLUTTER_PARAM_READABLE);
6640
6641   /**
6642    * ClutterActor:background-color:
6643    *
6644    * Paints a solid fill of the actor's allocation using the specified
6645    * color.
6646    *
6647    * The #ClutterActor:background-color property is animatable.
6648    *
6649    * Since: 1.10
6650    */
6651   obj_props[PROP_BACKGROUND_COLOR] =
6652     clutter_param_spec_color ("background-color",
6653                               P_("Background color"),
6654                               P_("The actor's background color"),
6655                               CLUTTER_COLOR_Transparent,
6656                               G_PARAM_READWRITE |
6657                               G_PARAM_STATIC_STRINGS |
6658                               CLUTTER_PARAM_ANIMATABLE);
6659
6660   /**
6661    * ClutterActor:first-child:
6662    *
6663    * The actor's first child.
6664    *
6665    * Since: 1.10
6666    */
6667   obj_props[PROP_FIRST_CHILD] =
6668     g_param_spec_object ("first-child",
6669                          P_("First Child"),
6670                          P_("The actor's first child"),
6671                          CLUTTER_TYPE_ACTOR,
6672                          CLUTTER_PARAM_READABLE);
6673
6674   /**
6675    * ClutterActor:last-child:
6676    *
6677    * The actor's last child.
6678    *
6679    * Since: 1.10
6680    */
6681   obj_props[PROP_LAST_CHILD] =
6682     g_param_spec_object ("last-child",
6683                          P_("Last Child"),
6684                          P_("The actor's last child"),
6685                          CLUTTER_TYPE_ACTOR,
6686                          CLUTTER_PARAM_READABLE);
6687
6688   /**
6689    * ClutterActor:content:
6690    *
6691    * The #ClutterContent implementation that controls the content
6692    * of the actor.
6693    *
6694    * Since: 1.10
6695    */
6696   obj_props[PROP_CONTENT] =
6697     g_param_spec_object ("content",
6698                          P_("Content"),
6699                          P_("Delegate object for painting the actor's content"),
6700                          CLUTTER_TYPE_CONTENT,
6701                          CLUTTER_PARAM_READWRITE);
6702
6703   /**
6704    * ClutterActor:content-gravity:
6705    *
6706    * The alignment that should be honoured by the #ClutterContent
6707    * set with the #ClutterActor:content property.
6708    *
6709    * Changing the value of this property will change the bounding box of
6710    * the content; you can use the #ClutterActor:content-box property to
6711    * get the position and size of the content within the actor's
6712    * allocation.
6713    *
6714    * This property is meaningful only for #ClutterContent implementations
6715    * that have a preferred size, and if the preferred size is smaller than
6716    * the actor's allocation.
6717    *
6718    * The #ClutterActor:content-gravity property is animatable.
6719    *
6720    * Since: 1.10
6721    */
6722   obj_props[PROP_CONTENT_GRAVITY] =
6723     g_param_spec_enum ("content-gravity",
6724                        P_("Content Gravity"),
6725                        P_("Alignment of the actor's content"),
6726                        CLUTTER_TYPE_CONTENT_GRAVITY,
6727                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6728                        CLUTTER_PARAM_READWRITE);
6729
6730   /**
6731    * ClutterActor:content-box:
6732    *
6733    * The bounding box for the #ClutterContent used by the actor.
6734    *
6735    * The value of this property is controlled by the #ClutterActor:allocation
6736    * and #ClutterActor:content-gravity properties of #ClutterActor.
6737    *
6738    * The bounding box for the content is guaranteed to never exceed the
6739    * allocation's of the actor.
6740    *
6741    * Since: 1.10
6742    */
6743   obj_props[PROP_CONTENT_BOX] =
6744     g_param_spec_boxed ("content-box",
6745                         P_("Content Box"),
6746                         P_("The bounding box of the actor's content"),
6747                         CLUTTER_TYPE_ACTOR_BOX,
6748                         G_PARAM_READABLE |
6749                         G_PARAM_STATIC_STRINGS |
6750                         CLUTTER_PARAM_ANIMATABLE);
6751
6752   obj_props[PROP_MINIFICATION_FILTER] =
6753     g_param_spec_enum ("minification-filter",
6754                        P_("Minification Filter"),
6755                        P_("The filter used when reducing the size of the content"),
6756                        CLUTTER_TYPE_SCALING_FILTER,
6757                        CLUTTER_SCALING_FILTER_LINEAR,
6758                        CLUTTER_PARAM_READWRITE);
6759
6760   obj_props[PROP_MAGNIFICATION_FILTER] =
6761     g_param_spec_enum ("magnification-filter",
6762                        P_("Magnification Filter"),
6763                        P_("The filter used when increasing the size of the content"),
6764                        CLUTTER_TYPE_SCALING_FILTER,
6765                        CLUTTER_SCALING_FILTER_LINEAR,
6766                        CLUTTER_PARAM_READWRITE);
6767
6768   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6769
6770   /**
6771    * ClutterActor::destroy:
6772    * @actor: the #ClutterActor which emitted the signal
6773    *
6774    * The ::destroy signal notifies that all references held on the
6775    * actor which emitted it should be released.
6776    *
6777    * The ::destroy signal should be used by all holders of a reference
6778    * on @actor.
6779    *
6780    * This signal might result in the finalization of the #ClutterActor
6781    * if all references are released.
6782    *
6783    * Composite actors and actors implementing the #ClutterContainer
6784    * interface should override the default implementation of the
6785    * class handler of this signal and call clutter_actor_destroy() on
6786    * their children. When overriding the default class handler, it is
6787    * required to chain up to the parent's implementation.
6788    *
6789    * Since: 0.2
6790    */
6791   actor_signals[DESTROY] =
6792     g_signal_new (I_("destroy"),
6793                   G_TYPE_FROM_CLASS (object_class),
6794                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6795                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6796                   NULL, NULL,
6797                   _clutter_marshal_VOID__VOID,
6798                   G_TYPE_NONE, 0);
6799   /**
6800    * ClutterActor::show:
6801    * @actor: the object which received the signal
6802    *
6803    * The ::show signal is emitted when an actor is visible and
6804    * rendered on the stage.
6805    *
6806    * Since: 0.2
6807    */
6808   actor_signals[SHOW] =
6809     g_signal_new (I_("show"),
6810                   G_TYPE_FROM_CLASS (object_class),
6811                   G_SIGNAL_RUN_FIRST,
6812                   G_STRUCT_OFFSET (ClutterActorClass, show),
6813                   NULL, NULL,
6814                   _clutter_marshal_VOID__VOID,
6815                   G_TYPE_NONE, 0);
6816   /**
6817    * ClutterActor::hide:
6818    * @actor: the object which received the signal
6819    *
6820    * The ::hide signal is emitted when an actor is no longer rendered
6821    * on the stage.
6822    *
6823    * Since: 0.2
6824    */
6825   actor_signals[HIDE] =
6826     g_signal_new (I_("hide"),
6827                   G_TYPE_FROM_CLASS (object_class),
6828                   G_SIGNAL_RUN_FIRST,
6829                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6830                   NULL, NULL,
6831                   _clutter_marshal_VOID__VOID,
6832                   G_TYPE_NONE, 0);
6833   /**
6834    * ClutterActor::parent-set:
6835    * @actor: the object which received the signal
6836    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6837    *
6838    * This signal is emitted when the parent of the actor changes.
6839    *
6840    * Since: 0.2
6841    */
6842   actor_signals[PARENT_SET] =
6843     g_signal_new (I_("parent-set"),
6844                   G_TYPE_FROM_CLASS (object_class),
6845                   G_SIGNAL_RUN_LAST,
6846                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6847                   NULL, NULL,
6848                   _clutter_marshal_VOID__OBJECT,
6849                   G_TYPE_NONE, 1,
6850                   CLUTTER_TYPE_ACTOR);
6851
6852   /**
6853    * ClutterActor::queue-redraw:
6854    * @actor: the actor we're bubbling the redraw request through
6855    * @origin: the actor which initiated the redraw request
6856    *
6857    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6858    * is called on @origin.
6859    *
6860    * The default implementation for #ClutterActor chains up to the
6861    * parent actor and queues a redraw on the parent, thus "bubbling"
6862    * the redraw queue up through the actor graph. The default
6863    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6864    * in a main loop idle handler.
6865    *
6866    * Note that the @origin actor may be the stage, or a container; it
6867    * does not have to be a leaf node in the actor graph.
6868    *
6869    * Toolkits embedding a #ClutterStage which require a redraw and
6870    * relayout cycle can stop the emission of this signal using the
6871    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6872    * themselves, like:
6873    *
6874    * |[
6875    *   static void
6876    *   on_redraw_complete (gpointer data)
6877    *   {
6878    *     ClutterStage *stage = data;
6879    *
6880    *     /&ast; execute the Clutter drawing pipeline &ast;/
6881    *     clutter_stage_ensure_redraw (stage);
6882    *   }
6883    *
6884    *   static void
6885    *   on_stage_queue_redraw (ClutterStage *stage)
6886    *   {
6887    *     /&ast; this prevents the default handler to run &ast;/
6888    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6889    *
6890    *     /&ast; queue a redraw with the host toolkit and call
6891    *      &ast; a function when the redraw has been completed
6892    *      &ast;/
6893    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6894    *   }
6895    * ]|
6896    *
6897    * <note><para>This signal is emitted before the Clutter paint
6898    * pipeline is executed. If you want to know when the pipeline has
6899    * been completed you should connect to the ::paint signal on the
6900    * Stage with g_signal_connect_after().</para></note>
6901    *
6902    * Since: 1.0
6903    */
6904   actor_signals[QUEUE_REDRAW] =
6905     g_signal_new (I_("queue-redraw"),
6906                   G_TYPE_FROM_CLASS (object_class),
6907                   G_SIGNAL_RUN_LAST |
6908                   G_SIGNAL_NO_HOOKS,
6909                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6910                   NULL, NULL,
6911                   _clutter_marshal_VOID__OBJECT,
6912                   G_TYPE_NONE, 1,
6913                   CLUTTER_TYPE_ACTOR);
6914
6915   /**
6916    * ClutterActor::queue-relayout:
6917    * @actor: the actor being queued for relayout
6918    *
6919    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6920    * is called on an actor.
6921    *
6922    * The default implementation for #ClutterActor chains up to the
6923    * parent actor and queues a relayout on the parent, thus "bubbling"
6924    * the relayout queue up through the actor graph.
6925    *
6926    * The main purpose of this signal is to allow relayout to be propagated
6927    * properly in the procense of #ClutterClone actors. Applications will
6928    * not normally need to connect to this signal.
6929    *
6930    * Since: 1.2
6931    */
6932   actor_signals[QUEUE_RELAYOUT] =
6933     g_signal_new (I_("queue-relayout"),
6934                   G_TYPE_FROM_CLASS (object_class),
6935                   G_SIGNAL_RUN_LAST |
6936                   G_SIGNAL_NO_HOOKS,
6937                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6938                   NULL, NULL,
6939                   _clutter_marshal_VOID__VOID,
6940                   G_TYPE_NONE, 0);
6941
6942   /**
6943    * ClutterActor::event:
6944    * @actor: the actor which received the event
6945    * @event: a #ClutterEvent
6946    *
6947    * The ::event signal is emitted each time an event is received
6948    * by the @actor. This signal will be emitted on every actor,
6949    * following the hierarchy chain, until it reaches the top-level
6950    * container (the #ClutterStage).
6951    *
6952    * Return value: %TRUE if the event has been handled by the actor,
6953    *   or %FALSE to continue the emission.
6954    *
6955    * Since: 0.6
6956    */
6957   actor_signals[EVENT] =
6958     g_signal_new (I_("event"),
6959                   G_TYPE_FROM_CLASS (object_class),
6960                   G_SIGNAL_RUN_LAST,
6961                   G_STRUCT_OFFSET (ClutterActorClass, event),
6962                   _clutter_boolean_handled_accumulator, NULL,
6963                   _clutter_marshal_BOOLEAN__BOXED,
6964                   G_TYPE_BOOLEAN, 1,
6965                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6966   /**
6967    * ClutterActor::button-press-event:
6968    * @actor: the actor which received the event
6969    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6970    *
6971    * The ::button-press-event signal is emitted each time a mouse button
6972    * is pressed on @actor.
6973    *
6974    * Return value: %TRUE if the event has been handled by the actor,
6975    *   or %FALSE to continue the emission.
6976    *
6977    * Since: 0.6
6978    */
6979   actor_signals[BUTTON_PRESS_EVENT] =
6980     g_signal_new (I_("button-press-event"),
6981                   G_TYPE_FROM_CLASS (object_class),
6982                   G_SIGNAL_RUN_LAST,
6983                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6984                   _clutter_boolean_handled_accumulator, NULL,
6985                   _clutter_marshal_BOOLEAN__BOXED,
6986                   G_TYPE_BOOLEAN, 1,
6987                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6988   /**
6989    * ClutterActor::button-release-event:
6990    * @actor: the actor which received the event
6991    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6992    *
6993    * The ::button-release-event signal is emitted each time a mouse button
6994    * is released on @actor.
6995    *
6996    * Return value: %TRUE if the event has been handled by the actor,
6997    *   or %FALSE to continue the emission.
6998    *
6999    * Since: 0.6
7000    */
7001   actor_signals[BUTTON_RELEASE_EVENT] =
7002     g_signal_new (I_("button-release-event"),
7003                   G_TYPE_FROM_CLASS (object_class),
7004                   G_SIGNAL_RUN_LAST,
7005                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
7006                   _clutter_boolean_handled_accumulator, NULL,
7007                   _clutter_marshal_BOOLEAN__BOXED,
7008                   G_TYPE_BOOLEAN, 1,
7009                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7010   /**
7011    * ClutterActor::scroll-event:
7012    * @actor: the actor which received the event
7013    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
7014    *
7015    * The ::scroll-event signal is emitted each time the mouse is
7016    * scrolled on @actor
7017    *
7018    * Return value: %TRUE if the event has been handled by the actor,
7019    *   or %FALSE to continue the emission.
7020    *
7021    * Since: 0.6
7022    */
7023   actor_signals[SCROLL_EVENT] =
7024     g_signal_new (I_("scroll-event"),
7025                   G_TYPE_FROM_CLASS (object_class),
7026                   G_SIGNAL_RUN_LAST,
7027                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
7028                   _clutter_boolean_handled_accumulator, NULL,
7029                   _clutter_marshal_BOOLEAN__BOXED,
7030                   G_TYPE_BOOLEAN, 1,
7031                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7032   /**
7033    * ClutterActor::key-press-event:
7034    * @actor: the actor which received the event
7035    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7036    *
7037    * The ::key-press-event signal is emitted each time a keyboard button
7038    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
7039    *
7040    * Return value: %TRUE if the event has been handled by the actor,
7041    *   or %FALSE to continue the emission.
7042    *
7043    * Since: 0.6
7044    */
7045   actor_signals[KEY_PRESS_EVENT] =
7046     g_signal_new (I_("key-press-event"),
7047                   G_TYPE_FROM_CLASS (object_class),
7048                   G_SIGNAL_RUN_LAST,
7049                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7050                   _clutter_boolean_handled_accumulator, NULL,
7051                   _clutter_marshal_BOOLEAN__BOXED,
7052                   G_TYPE_BOOLEAN, 1,
7053                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7054   /**
7055    * ClutterActor::key-release-event:
7056    * @actor: the actor which received the event
7057    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7058    *
7059    * The ::key-release-event signal is emitted each time a keyboard button
7060    * is released while @actor has key focus (see
7061    * clutter_stage_set_key_focus()).
7062    *
7063    * Return value: %TRUE if the event has been handled by the actor,
7064    *   or %FALSE to continue the emission.
7065    *
7066    * Since: 0.6
7067    */
7068   actor_signals[KEY_RELEASE_EVENT] =
7069     g_signal_new (I_("key-release-event"),
7070                   G_TYPE_FROM_CLASS (object_class),
7071                   G_SIGNAL_RUN_LAST,
7072                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7073                   _clutter_boolean_handled_accumulator, NULL,
7074                   _clutter_marshal_BOOLEAN__BOXED,
7075                   G_TYPE_BOOLEAN, 1,
7076                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7077   /**
7078    * ClutterActor::motion-event:
7079    * @actor: the actor which received the event
7080    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7081    *
7082    * The ::motion-event signal is emitted each time the mouse pointer is
7083    * moved over @actor.
7084    *
7085    * Return value: %TRUE if the event has been handled by the actor,
7086    *   or %FALSE to continue the emission.
7087    *
7088    * Since: 0.6
7089    */
7090   actor_signals[MOTION_EVENT] =
7091     g_signal_new (I_("motion-event"),
7092                   G_TYPE_FROM_CLASS (object_class),
7093                   G_SIGNAL_RUN_LAST,
7094                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7095                   _clutter_boolean_handled_accumulator, NULL,
7096                   _clutter_marshal_BOOLEAN__BOXED,
7097                   G_TYPE_BOOLEAN, 1,
7098                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7099
7100   /**
7101    * ClutterActor::key-focus-in:
7102    * @actor: the actor which now has key focus
7103    *
7104    * The ::key-focus-in signal is emitted when @actor receives key focus.
7105    *
7106    * Since: 0.6
7107    */
7108   actor_signals[KEY_FOCUS_IN] =
7109     g_signal_new (I_("key-focus-in"),
7110                   G_TYPE_FROM_CLASS (object_class),
7111                   G_SIGNAL_RUN_LAST,
7112                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7113                   NULL, NULL,
7114                   _clutter_marshal_VOID__VOID,
7115                   G_TYPE_NONE, 0);
7116
7117   /**
7118    * ClutterActor::key-focus-out:
7119    * @actor: the actor which now has key focus
7120    *
7121    * The ::key-focus-out signal is emitted when @actor loses key focus.
7122    *
7123    * Since: 0.6
7124    */
7125   actor_signals[KEY_FOCUS_OUT] =
7126     g_signal_new (I_("key-focus-out"),
7127                   G_TYPE_FROM_CLASS (object_class),
7128                   G_SIGNAL_RUN_LAST,
7129                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7130                   NULL, NULL,
7131                   _clutter_marshal_VOID__VOID,
7132                   G_TYPE_NONE, 0);
7133
7134   /**
7135    * ClutterActor::enter-event:
7136    * @actor: the actor which the pointer has entered.
7137    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7138    *
7139    * The ::enter-event signal is emitted when the pointer enters the @actor
7140    *
7141    * Return value: %TRUE if the event has been handled by the actor,
7142    *   or %FALSE to continue the emission.
7143    *
7144    * Since: 0.6
7145    */
7146   actor_signals[ENTER_EVENT] =
7147     g_signal_new (I_("enter-event"),
7148                   G_TYPE_FROM_CLASS (object_class),
7149                   G_SIGNAL_RUN_LAST,
7150                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7151                   _clutter_boolean_handled_accumulator, NULL,
7152                   _clutter_marshal_BOOLEAN__BOXED,
7153                   G_TYPE_BOOLEAN, 1,
7154                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7155
7156   /**
7157    * ClutterActor::leave-event:
7158    * @actor: the actor which the pointer has left
7159    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7160    *
7161    * The ::leave-event signal is emitted when the pointer leaves the @actor.
7162    *
7163    * Return value: %TRUE if the event has been handled by the actor,
7164    *   or %FALSE to continue the emission.
7165    *
7166    * Since: 0.6
7167    */
7168   actor_signals[LEAVE_EVENT] =
7169     g_signal_new (I_("leave-event"),
7170                   G_TYPE_FROM_CLASS (object_class),
7171                   G_SIGNAL_RUN_LAST,
7172                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7173                   _clutter_boolean_handled_accumulator, NULL,
7174                   _clutter_marshal_BOOLEAN__BOXED,
7175                   G_TYPE_BOOLEAN, 1,
7176                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7177
7178   /**
7179    * ClutterActor::captured-event:
7180    * @actor: the actor which received the signal
7181    * @event: a #ClutterEvent
7182    *
7183    * The ::captured-event signal is emitted when an event is captured
7184    * by Clutter. This signal will be emitted starting from the top-level
7185    * container (the #ClutterStage) to the actor which received the event
7186    * going down the hierarchy. This signal can be used to intercept every
7187    * event before the specialized events (like
7188    * ClutterActor::button-press-event or ::key-released-event) are
7189    * emitted.
7190    *
7191    * Return value: %TRUE if the event has been handled by the actor,
7192    *   or %FALSE to continue the emission.
7193    *
7194    * Since: 0.6
7195    */
7196   actor_signals[CAPTURED_EVENT] =
7197     g_signal_new (I_("captured-event"),
7198                   G_TYPE_FROM_CLASS (object_class),
7199                   G_SIGNAL_RUN_LAST,
7200                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7201                   _clutter_boolean_handled_accumulator, NULL,
7202                   _clutter_marshal_BOOLEAN__BOXED,
7203                   G_TYPE_BOOLEAN, 1,
7204                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7205
7206   /**
7207    * ClutterActor::paint:
7208    * @actor: the #ClutterActor that received the signal
7209    *
7210    * The ::paint signal is emitted each time an actor is being painted.
7211    *
7212    * Subclasses of #ClutterActor should override the class signal handler
7213    * and paint themselves in that function.
7214    *
7215    * It is possible to connect a handler to the ::paint signal in order
7216    * to set up some custom aspect of a paint.
7217    *
7218    * Since: 0.8
7219    */
7220   actor_signals[PAINT] =
7221     g_signal_new (I_("paint"),
7222                   G_TYPE_FROM_CLASS (object_class),
7223                   G_SIGNAL_RUN_LAST |
7224                   G_SIGNAL_NO_HOOKS,
7225                   G_STRUCT_OFFSET (ClutterActorClass, paint),
7226                   NULL, NULL,
7227                   _clutter_marshal_VOID__VOID,
7228                   G_TYPE_NONE, 0);
7229   /**
7230    * ClutterActor::realize:
7231    * @actor: the #ClutterActor that received the signal
7232    *
7233    * The ::realize signal is emitted each time an actor is being
7234    * realized.
7235    *
7236    * Since: 0.8
7237    */
7238   actor_signals[REALIZE] =
7239     g_signal_new (I_("realize"),
7240                   G_TYPE_FROM_CLASS (object_class),
7241                   G_SIGNAL_RUN_LAST,
7242                   G_STRUCT_OFFSET (ClutterActorClass, realize),
7243                   NULL, NULL,
7244                   _clutter_marshal_VOID__VOID,
7245                   G_TYPE_NONE, 0);
7246   /**
7247    * ClutterActor::unrealize:
7248    * @actor: the #ClutterActor that received the signal
7249    *
7250    * The ::unrealize signal is emitted each time an actor is being
7251    * unrealized.
7252    *
7253    * Since: 0.8
7254    */
7255   actor_signals[UNREALIZE] =
7256     g_signal_new (I_("unrealize"),
7257                   G_TYPE_FROM_CLASS (object_class),
7258                   G_SIGNAL_RUN_LAST,
7259                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7260                   NULL, NULL,
7261                   _clutter_marshal_VOID__VOID,
7262                   G_TYPE_NONE, 0);
7263
7264   /**
7265    * ClutterActor::pick:
7266    * @actor: the #ClutterActor that received the signal
7267    * @color: the #ClutterColor to be used when picking
7268    *
7269    * The ::pick signal is emitted each time an actor is being painted
7270    * in "pick mode". The pick mode is used to identify the actor during
7271    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7272    * The actor should paint its shape using the passed @pick_color.
7273    *
7274    * Subclasses of #ClutterActor should override the class signal handler
7275    * and paint themselves in that function.
7276    *
7277    * It is possible to connect a handler to the ::pick signal in order
7278    * to set up some custom aspect of a paint in pick mode.
7279    *
7280    * Since: 1.0
7281    */
7282   actor_signals[PICK] =
7283     g_signal_new (I_("pick"),
7284                   G_TYPE_FROM_CLASS (object_class),
7285                   G_SIGNAL_RUN_LAST,
7286                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7287                   NULL, NULL,
7288                   _clutter_marshal_VOID__BOXED,
7289                   G_TYPE_NONE, 1,
7290                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7291
7292   /**
7293    * ClutterActor::allocation-changed:
7294    * @actor: the #ClutterActor that emitted the signal
7295    * @box: a #ClutterActorBox with the new allocation
7296    * @flags: #ClutterAllocationFlags for the allocation
7297    *
7298    * The ::allocation-changed signal is emitted when the
7299    * #ClutterActor:allocation property changes. Usually, application
7300    * code should just use the notifications for the :allocation property
7301    * but if you want to track the allocation flags as well, for instance
7302    * to know whether the absolute origin of @actor changed, then you might
7303    * want use this signal instead.
7304    *
7305    * Since: 1.0
7306    */
7307   actor_signals[ALLOCATION_CHANGED] =
7308     g_signal_new (I_("allocation-changed"),
7309                   G_TYPE_FROM_CLASS (object_class),
7310                   G_SIGNAL_RUN_LAST,
7311                   0,
7312                   NULL, NULL,
7313                   _clutter_marshal_VOID__BOXED_FLAGS,
7314                   G_TYPE_NONE, 2,
7315                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7316                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7317
7318   /**
7319    * ClutterActor::transitions-completed:
7320    * @actor: a #ClutterActor
7321    *
7322    * The ::transitions-completed signal is emitted once all transitions
7323    * involving @actor are complete.
7324    *
7325    * Since: 1.10
7326    */
7327   actor_signals[TRANSITIONS_COMPLETED] =
7328     g_signal_new (I_("transitions-completed"),
7329                   G_TYPE_FROM_CLASS (object_class),
7330                   G_SIGNAL_RUN_LAST,
7331                   0,
7332                   NULL, NULL,
7333                   _clutter_marshal_VOID__VOID,
7334                   G_TYPE_NONE, 0);
7335 }
7336
7337 static void
7338 clutter_actor_init (ClutterActor *self)
7339 {
7340   ClutterActorPrivate *priv;
7341
7342   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7343
7344   priv->id = _clutter_context_acquire_id (self);
7345   priv->pick_id = -1;
7346
7347   priv->opacity = 0xff;
7348   priv->show_on_set_parent = TRUE;
7349
7350   priv->needs_width_request = TRUE;
7351   priv->needs_height_request = TRUE;
7352   priv->needs_allocation = TRUE;
7353
7354   priv->cached_width_age = 1;
7355   priv->cached_height_age = 1;
7356
7357   priv->opacity_override = -1;
7358   priv->enable_model_view_transform = TRUE;
7359
7360   /* Initialize an empty paint volume to start with */
7361   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7362   priv->last_paint_volume_valid = TRUE;
7363
7364   priv->transform_valid = FALSE;
7365
7366   /* the default is to stretch the content, to match the
7367    * current behaviour of basically all actors. also, it's
7368    * the easiest thing to compute.
7369    */
7370   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7371   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7372   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7373
7374   /* this flag will be set to TRUE if the actor gets a child
7375    * or if the [xy]-expand flags are explicitly set; until
7376    * then, the actor does not need to expand.
7377    *
7378    * this also allows us to avoid computing the expand flag
7379    * when building up a scene.
7380    */
7381   priv->needs_compute_expand = FALSE;
7382 }
7383
7384 /**
7385  * clutter_actor_new:
7386  *
7387  * Creates a new #ClutterActor.
7388  *
7389  * A newly created actor has a floating reference, which will be sunk
7390  * when it is added to another actor.
7391  *
7392  * Return value: (transfer full): the newly created #ClutterActor
7393  *
7394  * Since: 1.10
7395  */
7396 ClutterActor *
7397 clutter_actor_new (void)
7398 {
7399   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7400 }
7401
7402 /**
7403  * clutter_actor_destroy:
7404  * @self: a #ClutterActor
7405  *
7406  * Destroys an actor.  When an actor is destroyed, it will break any
7407  * references it holds to other objects.  If the actor is inside a
7408  * container, the actor will be removed.
7409  *
7410  * When you destroy a container, its children will be destroyed as well.
7411  *
7412  * Note: you cannot destroy the #ClutterStage returned by
7413  * clutter_stage_get_default().
7414  */
7415 void
7416 clutter_actor_destroy (ClutterActor *self)
7417 {
7418   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7419
7420   g_object_ref (self);
7421
7422   /* avoid recursion while destroying */
7423   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7424     {
7425       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7426
7427       g_object_run_dispose (G_OBJECT (self));
7428
7429       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7430     }
7431
7432   g_object_unref (self);
7433 }
7434
7435 void
7436 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7437                                     ClutterPaintVolume *clip)
7438 {
7439   ClutterActorPrivate *priv = self->priv;
7440   ClutterPaintVolume *pv;
7441   gboolean clipped;
7442
7443   /* Remove queue entry early in the process, otherwise a new
7444      queue_redraw() during signal handling could put back this
7445      object in the stage redraw list (but the entry is freed as
7446      soon as we return from this function, causing a segfault
7447      later)
7448   */
7449   priv->queue_redraw_entry = NULL;
7450
7451   /* If we've been explicitly passed a clip volume then there's
7452    * nothing more to calculate, but otherwise the only thing we know
7453    * is that the change is constrained to the given actor.
7454    *
7455    * The idea is that if we know the paint volume for where the actor
7456    * was last drawn (in eye coordinates) and we also have the paint
7457    * volume for where it will be drawn next (in actor coordinates)
7458    * then if we queue a redraw for both these volumes that will cover
7459    * everything that needs to be redrawn to clear the old view and
7460    * show the latest view of the actor.
7461    *
7462    * Don't clip this redraw if we don't know what position we had for
7463    * the previous redraw since we don't know where to set the clip so
7464    * it will clear the actor as it is currently.
7465    */
7466   if (clip)
7467     {
7468       _clutter_actor_set_queue_redraw_clip (self, clip);
7469       clipped = TRUE;
7470     }
7471   else if (G_LIKELY (priv->last_paint_volume_valid))
7472     {
7473       pv = _clutter_actor_get_paint_volume_mutable (self);
7474       if (pv)
7475         {
7476           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7477
7478           /* make sure we redraw the actors old position... */
7479           _clutter_actor_set_queue_redraw_clip (stage,
7480                                                 &priv->last_paint_volume);
7481           _clutter_actor_signal_queue_redraw (stage, stage);
7482           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7483
7484           /* XXX: Ideally the redraw signal would take a clip volume
7485            * argument, but that would be an ABI break. Until we can
7486            * break the ABI we pass the argument out-of-band
7487            */
7488
7489           /* setup the clip for the actors new position... */
7490           _clutter_actor_set_queue_redraw_clip (self, pv);
7491           clipped = TRUE;
7492         }
7493       else
7494         clipped = FALSE;
7495     }
7496   else
7497     clipped = FALSE;
7498
7499   _clutter_actor_signal_queue_redraw (self, self);
7500
7501   /* Just in case anyone is manually firing redraw signals without
7502    * using the public queue_redraw() API we are careful to ensure that
7503    * our out-of-band clip member is cleared before returning...
7504    *
7505    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7506    */
7507   if (G_LIKELY (clipped))
7508     _clutter_actor_set_queue_redraw_clip (self, NULL);
7509 }
7510
7511 static void
7512 _clutter_actor_get_allocation_clip (ClutterActor *self,
7513                                     ClutterActorBox *clip)
7514 {
7515   ClutterActorBox allocation;
7516
7517   /* XXX: we don't care if we get an out of date allocation here
7518    * because clutter_actor_queue_redraw_with_clip knows to ignore
7519    * the clip if the actor's allocation is invalid.
7520    *
7521    * This is noted because clutter_actor_get_allocation_box does some
7522    * unnecessary work to support buggy code with a comment suggesting
7523    * that it could be changed later which would be good for this use
7524    * case!
7525    */
7526   clutter_actor_get_allocation_box (self, &allocation);
7527
7528   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7529    * actor's own coordinate space but the allocation is in parent
7530    * coordinates */
7531   clip->x1 = 0;
7532   clip->y1 = 0;
7533   clip->x2 = allocation.x2 - allocation.x1;
7534   clip->y2 = allocation.y2 - allocation.y1;
7535 }
7536
7537 void
7538 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7539                                   ClutterRedrawFlags  flags,
7540                                   ClutterPaintVolume *volume,
7541                                   ClutterEffect      *effect)
7542 {
7543   ClutterActorPrivate *priv = self->priv;
7544   ClutterPaintVolume allocation_pv;
7545   ClutterPaintVolume *pv;
7546   gboolean should_free_pv;
7547   ClutterActor *stage;
7548
7549   /* Here's an outline of the actor queue redraw mechanism:
7550    *
7551    * The process starts in one of the following two functions which
7552    * are wrappers for this function:
7553    * clutter_actor_queue_redraw
7554    * _clutter_actor_queue_redraw_with_clip
7555    *
7556    * additionally, an effect can queue a redraw by wrapping this
7557    * function in clutter_effect_queue_rerun
7558    *
7559    * This functions queues an entry in a list associated with the
7560    * stage which is a list of actors that queued a redraw while
7561    * updating the timelines, performing layouting and processing other
7562    * mainloop sources before the next paint starts.
7563    *
7564    * We aim to minimize the processing done at this point because
7565    * there is a good chance other events will happen while updating
7566    * the scenegraph that would invalidate any expensive work we might
7567    * otherwise try to do here. For example we don't try and resolve
7568    * the screen space bounding box of an actor at this stage so as to
7569    * minimize how much of the screen redraw because it's possible
7570    * something else will happen which will force a full redraw anyway.
7571    *
7572    * When all updates are complete and we come to paint the stage then
7573    * we iterate this list and actually emit the "queue-redraw" signals
7574    * for each of the listed actors which will bubble up to the stage
7575    * for each actor and at that point we will transform the actors
7576    * paint volume into screen coordinates to determine the clip region
7577    * for what needs to be redrawn in the next paint.
7578    *
7579    * Besides minimizing redundant work another reason for this
7580    * deferred design is that it's more likely we will be able to
7581    * determine the paint volume of an actor once we've finished
7582    * updating the scenegraph because its allocation should be up to
7583    * date. NB: If we can't determine an actors paint volume then we
7584    * can't automatically queue a clipped redraw which can make a big
7585    * difference to performance.
7586    *
7587    * So the control flow goes like this:
7588    * One of clutter_actor_queue_redraw,
7589    *        _clutter_actor_queue_redraw_with_clip
7590    *     or clutter_effect_queue_rerun
7591    *
7592    * then control moves to:
7593    *   _clutter_stage_queue_actor_redraw
7594    *
7595    * later during _clutter_stage_do_update, once relayouting is done
7596    * and the scenegraph has been updated we will call:
7597    * _clutter_stage_finish_queue_redraws
7598    *
7599    * _clutter_stage_finish_queue_redraws will call
7600    * _clutter_actor_finish_queue_redraw for each listed actor.
7601    * Note: actors *are* allowed to queue further redraws during this
7602    * process (considering clone actors or texture_new_from_actor which
7603    * respond to their source queueing a redraw by queuing a redraw
7604    * themselves). We repeat the process until the list is empty.
7605    *
7606    * This will result in the "queue-redraw" signal being fired for
7607    * each actor which will pass control to the default signal handler:
7608    * clutter_actor_real_queue_redraw
7609    *
7610    * This will bubble up to the stages handler:
7611    * clutter_stage_real_queue_redraw
7612    *
7613    * clutter_stage_real_queue_redraw will transform the actors paint
7614    * volume into screen space and add it as a clip region for the next
7615    * paint.
7616    */
7617
7618   /* ignore queueing a redraw for actors being destroyed */
7619   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7620     return;
7621
7622   stage = _clutter_actor_get_stage_internal (self);
7623
7624   /* Ignore queueing a redraw for actors not descended from a stage */
7625   if (stage == NULL)
7626     return;
7627
7628   /* ignore queueing a redraw on stages that are being destroyed */
7629   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7630     return;
7631
7632   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7633     {
7634       ClutterActorBox allocation_clip;
7635       ClutterVertex origin;
7636
7637       /* If the actor doesn't have a valid allocation then we will
7638        * queue a full stage redraw. */
7639       if (priv->needs_allocation)
7640         {
7641           /* NB: NULL denotes an undefined clip which will result in a
7642            * full redraw... */
7643           _clutter_actor_set_queue_redraw_clip (self, NULL);
7644           _clutter_actor_signal_queue_redraw (self, self);
7645           return;
7646         }
7647
7648       _clutter_paint_volume_init_static (&allocation_pv, self);
7649       pv = &allocation_pv;
7650
7651       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7652
7653       origin.x = allocation_clip.x1;
7654       origin.y = allocation_clip.y1;
7655       origin.z = 0;
7656       clutter_paint_volume_set_origin (pv, &origin);
7657       clutter_paint_volume_set_width (pv,
7658                                       allocation_clip.x2 - allocation_clip.x1);
7659       clutter_paint_volume_set_height (pv,
7660                                        allocation_clip.y2 -
7661                                        allocation_clip.y1);
7662       should_free_pv = TRUE;
7663     }
7664   else
7665     {
7666       pv = volume;
7667       should_free_pv = FALSE;
7668     }
7669
7670   self->priv->queue_redraw_entry =
7671     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7672                                        priv->queue_redraw_entry,
7673                                        self,
7674                                        pv);
7675
7676   if (should_free_pv)
7677     clutter_paint_volume_free (pv);
7678
7679   /* If this is the first redraw queued then we can directly use the
7680      effect parameter */
7681   if (!priv->is_dirty)
7682     priv->effect_to_redraw = effect;
7683   /* Otherwise we need to merge it with the existing effect parameter */
7684   else if (effect != NULL)
7685     {
7686       /* If there's already an effect then we need to use whichever is
7687          later in the chain of actors. Otherwise a full redraw has
7688          already been queued on the actor so we need to ignore the
7689          effect parameter */
7690       if (priv->effect_to_redraw != NULL)
7691         {
7692           if (priv->effects == NULL)
7693             g_warning ("Redraw queued with an effect that is "
7694                        "not applied to the actor");
7695           else
7696             {
7697               const GList *l;
7698
7699               for (l = _clutter_meta_group_peek_metas (priv->effects);
7700                    l != NULL;
7701                    l = l->next)
7702                 {
7703                   if (l->data == priv->effect_to_redraw ||
7704                       l->data == effect)
7705                     priv->effect_to_redraw = l->data;
7706                 }
7707             }
7708         }
7709     }
7710   else
7711     {
7712       /* If no effect is specified then we need to redraw the whole
7713          actor */
7714       priv->effect_to_redraw = NULL;
7715     }
7716
7717   priv->is_dirty = TRUE;
7718 }
7719
7720 /**
7721  * clutter_actor_queue_redraw:
7722  * @self: A #ClutterActor
7723  *
7724  * Queues up a redraw of an actor and any children. The redraw occurs
7725  * once the main loop becomes idle (after the current batch of events
7726  * has been processed, roughly).
7727  *
7728  * Applications rarely need to call this, as redraws are handled
7729  * automatically by modification functions.
7730  *
7731  * This function will not do anything if @self is not visible, or
7732  * if the actor is inside an invisible part of the scenegraph.
7733  *
7734  * Also be aware that painting is a NOP for actors with an opacity of
7735  * 0
7736  *
7737  * When you are implementing a custom actor you must queue a redraw
7738  * whenever some private state changes that will affect painting or
7739  * picking of your actor.
7740  */
7741 void
7742 clutter_actor_queue_redraw (ClutterActor *self)
7743 {
7744   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7745
7746   _clutter_actor_queue_redraw_full (self,
7747                                     0, /* flags */
7748                                     NULL, /* clip volume */
7749                                     NULL /* effect */);
7750 }
7751
7752 /*< private >
7753  * _clutter_actor_queue_redraw_with_clip:
7754  * @self: A #ClutterActor
7755  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7756  *   this queue redraw.
7757  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7758  *   redrawn or %NULL if you are just using a @flag to state your
7759  *   desired clipping.
7760  *
7761  * Queues up a clipped redraw of an actor and any children. The redraw
7762  * occurs once the main loop becomes idle (after the current batch of
7763  * events has been processed, roughly).
7764  *
7765  * If no flags are given the clip volume is defined by @volume
7766  * specified in actor coordinates and tells Clutter that only content
7767  * within this volume has been changed so Clutter can optionally
7768  * optimize the redraw.
7769  *
7770  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7771  * should be %NULL and this tells Clutter to use the actor's current
7772  * allocation as a clip box. This flag can only be used for 2D actors,
7773  * because any actor with depth may be projected outside its
7774  * allocation.
7775  *
7776  * Applications rarely need to call this, as redraws are handled
7777  * automatically by modification functions.
7778  *
7779  * This function will not do anything if @self is not visible, or if
7780  * the actor is inside an invisible part of the scenegraph.
7781  *
7782  * Also be aware that painting is a NOP for actors with an opacity of
7783  * 0
7784  *
7785  * When you are implementing a custom actor you must queue a redraw
7786  * whenever some private state changes that will affect painting or
7787  * picking of your actor.
7788  */
7789 void
7790 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7791                                        ClutterRedrawFlags  flags,
7792                                        ClutterPaintVolume *volume)
7793 {
7794   _clutter_actor_queue_redraw_full (self,
7795                                     flags, /* flags */
7796                                     volume, /* clip volume */
7797                                     NULL /* effect */);
7798 }
7799
7800 static void
7801 _clutter_actor_queue_only_relayout (ClutterActor *self)
7802 {
7803   ClutterActorPrivate *priv = self->priv;
7804
7805   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7806     return;
7807
7808   if (priv->needs_width_request &&
7809       priv->needs_height_request &&
7810       priv->needs_allocation)
7811     return; /* save some cpu cycles */
7812
7813 #if CLUTTER_ENABLE_DEBUG
7814   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7815     {
7816       g_warning ("The actor '%s' is currently inside an allocation "
7817                  "cycle; calling clutter_actor_queue_relayout() is "
7818                  "not recommended",
7819                  _clutter_actor_get_debug_name (self));
7820     }
7821 #endif /* CLUTTER_ENABLE_DEBUG */
7822
7823   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7824 }
7825
7826 /**
7827  * clutter_actor_queue_redraw_with_clip:
7828  * @self: a #ClutterActor
7829  * @clip: (allow-none): a rectangular clip region, or %NULL
7830  *
7831  * Queues a redraw on @self limited to a specific, actor-relative
7832  * rectangular area.
7833  *
7834  * If @clip is %NULL this function is equivalent to
7835  * clutter_actor_queue_redraw().
7836  *
7837  * Since: 1.10
7838  */
7839 void
7840 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7841                                       const cairo_rectangle_int_t *clip)
7842 {
7843   ClutterPaintVolume volume;
7844   ClutterVertex origin;
7845
7846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7847
7848   if (clip == NULL)
7849     {
7850       clutter_actor_queue_redraw (self);
7851       return;
7852     }
7853
7854   _clutter_paint_volume_init_static (&volume, self);
7855
7856   origin.x = clip->x;
7857   origin.y = clip->y;
7858   origin.z = 0.0f;
7859
7860   clutter_paint_volume_set_origin (&volume, &origin);
7861   clutter_paint_volume_set_width (&volume, clip->width);
7862   clutter_paint_volume_set_height (&volume, clip->height);
7863
7864   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7865
7866   clutter_paint_volume_free (&volume);
7867 }
7868
7869 /**
7870  * clutter_actor_queue_relayout:
7871  * @self: A #ClutterActor
7872  *
7873  * Indicates that the actor's size request or other layout-affecting
7874  * properties may have changed. This function is used inside #ClutterActor
7875  * subclass implementations, not by applications directly.
7876  *
7877  * Queueing a new layout automatically queues a redraw as well.
7878  *
7879  * Since: 0.8
7880  */
7881 void
7882 clutter_actor_queue_relayout (ClutterActor *self)
7883 {
7884   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7885
7886   _clutter_actor_queue_only_relayout (self);
7887   clutter_actor_queue_redraw (self);
7888 }
7889
7890 /**
7891  * clutter_actor_get_preferred_size:
7892  * @self: a #ClutterActor
7893  * @min_width_p: (out) (allow-none): return location for the minimum
7894  *   width, or %NULL
7895  * @min_height_p: (out) (allow-none): return location for the minimum
7896  *   height, or %NULL
7897  * @natural_width_p: (out) (allow-none): return location for the natural
7898  *   width, or %NULL
7899  * @natural_height_p: (out) (allow-none): return location for the natural
7900  *   height, or %NULL
7901  *
7902  * Computes the preferred minimum and natural size of an actor, taking into
7903  * account the actor's geometry management (either height-for-width
7904  * or width-for-height).
7905  *
7906  * The width and height used to compute the preferred height and preferred
7907  * width are the actor's natural ones.
7908  *
7909  * If you need to control the height for the preferred width, or the width for
7910  * the preferred height, you should use clutter_actor_get_preferred_width()
7911  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7912  * geometry management using the #ClutterActor:request-mode property.
7913  *
7914  * Since: 0.8
7915  */
7916 void
7917 clutter_actor_get_preferred_size (ClutterActor *self,
7918                                   gfloat       *min_width_p,
7919                                   gfloat       *min_height_p,
7920                                   gfloat       *natural_width_p,
7921                                   gfloat       *natural_height_p)
7922 {
7923   ClutterActorPrivate *priv;
7924   gfloat min_width, min_height;
7925   gfloat natural_width, natural_height;
7926
7927   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7928
7929   priv = self->priv;
7930
7931   min_width = min_height = 0;
7932   natural_width = natural_height = 0;
7933
7934   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7935     {
7936       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7937       clutter_actor_get_preferred_width (self, -1,
7938                                          &min_width,
7939                                          &natural_width);
7940       clutter_actor_get_preferred_height (self, natural_width,
7941                                           &min_height,
7942                                           &natural_height);
7943     }
7944   else
7945     {
7946       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7947       clutter_actor_get_preferred_height (self, -1,
7948                                           &min_height,
7949                                           &natural_height);
7950       clutter_actor_get_preferred_width (self, natural_height,
7951                                          &min_width,
7952                                          &natural_width);
7953     }
7954
7955   if (min_width_p)
7956     *min_width_p = min_width;
7957
7958   if (min_height_p)
7959     *min_height_p = min_height;
7960
7961   if (natural_width_p)
7962     *natural_width_p = natural_width;
7963
7964   if (natural_height_p)
7965     *natural_height_p = natural_height;
7966 }
7967
7968 /*< private >
7969  * effective_align:
7970  * @align: a #ClutterActorAlign
7971  * @direction: a #ClutterTextDirection
7972  *
7973  * Retrieves the correct alignment depending on the text direction
7974  *
7975  * Return value: the effective alignment
7976  */
7977 static ClutterActorAlign
7978 effective_align (ClutterActorAlign    align,
7979                  ClutterTextDirection direction)
7980 {
7981   ClutterActorAlign res;
7982
7983   switch (align)
7984     {
7985     case CLUTTER_ACTOR_ALIGN_START:
7986       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7987           ? CLUTTER_ACTOR_ALIGN_END
7988           : CLUTTER_ACTOR_ALIGN_START;
7989       break;
7990
7991     case CLUTTER_ACTOR_ALIGN_END:
7992       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7993           ? CLUTTER_ACTOR_ALIGN_START
7994           : CLUTTER_ACTOR_ALIGN_END;
7995       break;
7996
7997     default:
7998       res = align;
7999       break;
8000     }
8001
8002   return res;
8003 }
8004
8005 /*< private >
8006  * _clutter_actor_get_effective_x_align:
8007  * @self: a #ClutterActor
8008  *
8009  * Retrieves the effective horizontal alignment, taking into
8010  * consideration the text direction of @self.
8011  *
8012  * Return value: the effective horizontal alignment
8013  */
8014 ClutterActorAlign
8015 _clutter_actor_get_effective_x_align (ClutterActor *self)
8016 {
8017   return effective_align (clutter_actor_get_x_align (self),
8018                           clutter_actor_get_text_direction (self));
8019 }
8020
8021 static inline void
8022 adjust_for_margin (float  margin_start,
8023                    float  margin_end,
8024                    float *minimum_size,
8025                    float *natural_size,
8026                    float *allocated_start,
8027                    float *allocated_end)
8028 {
8029   *minimum_size -= (margin_start + margin_end);
8030   *natural_size -= (margin_start + margin_end);
8031   *allocated_start += margin_start;
8032   *allocated_end -= margin_end;
8033 }
8034
8035 static inline void
8036 adjust_for_alignment (ClutterActorAlign  alignment,
8037                       float              natural_size,
8038                       float             *allocated_start,
8039                       float             *allocated_end)
8040 {
8041   float allocated_size = *allocated_end - *allocated_start;
8042
8043   switch (alignment)
8044     {
8045     case CLUTTER_ACTOR_ALIGN_FILL:
8046       /* do nothing */
8047       break;
8048
8049     case CLUTTER_ACTOR_ALIGN_START:
8050       /* keep start */
8051       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8052       break;
8053
8054     case CLUTTER_ACTOR_ALIGN_END:
8055       if (allocated_size > natural_size)
8056         {
8057           *allocated_start += (allocated_size - natural_size);
8058           *allocated_end = *allocated_start + natural_size;
8059         }
8060       break;
8061
8062     case CLUTTER_ACTOR_ALIGN_CENTER:
8063       if (allocated_size > natural_size)
8064         {
8065           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8066           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8067         }
8068       break;
8069     }
8070 }
8071
8072 /*< private >
8073  * clutter_actor_adjust_width:
8074  * @self: a #ClutterActor
8075  * @minimum_width: (inout): the actor's preferred minimum width, which
8076  *   will be adjusted depending on the margin
8077  * @natural_width: (inout): the actor's preferred natural width, which
8078  *   will be adjusted depending on the margin
8079  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8080  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8081  *
8082  * Adjusts the preferred and allocated position and size of an actor,
8083  * depending on the margin and alignment properties.
8084  */
8085 static void
8086 clutter_actor_adjust_width (ClutterActor *self,
8087                             gfloat       *minimum_width,
8088                             gfloat       *natural_width,
8089                             gfloat       *adjusted_x1,
8090                             gfloat       *adjusted_x2)
8091 {
8092   ClutterTextDirection text_dir;
8093   const ClutterLayoutInfo *info;
8094
8095   info = _clutter_actor_get_layout_info_or_defaults (self);
8096   text_dir = clutter_actor_get_text_direction (self);
8097
8098   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8099
8100   /* this will tweak natural_width to remove the margin, so that
8101    * adjust_for_alignment() will use the correct size
8102    */
8103   adjust_for_margin (info->margin.left, info->margin.right,
8104                      minimum_width, natural_width,
8105                      adjusted_x1, adjusted_x2);
8106
8107   adjust_for_alignment (effective_align (info->x_align, text_dir),
8108                         *natural_width,
8109                         adjusted_x1, adjusted_x2);
8110 }
8111
8112 /*< private >
8113  * clutter_actor_adjust_height:
8114  * @self: a #ClutterActor
8115  * @minimum_height: (inout): the actor's preferred minimum height, which
8116  *   will be adjusted depending on the margin
8117  * @natural_height: (inout): the actor's preferred natural height, which
8118  *   will be adjusted depending on the margin
8119  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8120  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8121  *
8122  * Adjusts the preferred and allocated position and size of an actor,
8123  * depending on the margin and alignment properties.
8124  */
8125 static void
8126 clutter_actor_adjust_height (ClutterActor *self,
8127                              gfloat       *minimum_height,
8128                              gfloat       *natural_height,
8129                              gfloat       *adjusted_y1,
8130                              gfloat       *adjusted_y2)
8131 {
8132   const ClutterLayoutInfo *info;
8133
8134   info = _clutter_actor_get_layout_info_or_defaults (self);
8135
8136   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8137
8138   /* this will tweak natural_height to remove the margin, so that
8139    * adjust_for_alignment() will use the correct size
8140    */
8141   adjust_for_margin (info->margin.top, info->margin.bottom,
8142                      minimum_height, natural_height,
8143                      adjusted_y1,
8144                      adjusted_y2);
8145
8146   /* we don't use effective_align() here, because text direction
8147    * only affects the horizontal axis
8148    */
8149   adjust_for_alignment (info->y_align,
8150                         *natural_height,
8151                         adjusted_y1,
8152                         adjusted_y2);
8153
8154 }
8155
8156 /* looks for a cached size request for this for_size. If not
8157  * found, returns the oldest entry so it can be overwritten */
8158 static gboolean
8159 _clutter_actor_get_cached_size_request (gfloat         for_size,
8160                                         SizeRequest   *cached_size_requests,
8161                                         SizeRequest  **result)
8162 {
8163   guint i;
8164
8165   *result = &cached_size_requests[0];
8166
8167   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8168     {
8169       SizeRequest *sr;
8170
8171       sr = &cached_size_requests[i];
8172
8173       if (sr->age > 0 &&
8174           sr->for_size == for_size)
8175         {
8176           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8177           *result = sr;
8178           return TRUE;
8179         }
8180       else if (sr->age < (*result)->age)
8181         {
8182           *result = sr;
8183         }
8184     }
8185
8186   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8187
8188   return FALSE;
8189 }
8190
8191 /**
8192  * clutter_actor_get_preferred_width:
8193  * @self: A #ClutterActor
8194  * @for_height: available height when computing the preferred width,
8195  *   or a negative value to indicate that no height is defined
8196  * @min_width_p: (out) (allow-none): return location for minimum width,
8197  *   or %NULL
8198  * @natural_width_p: (out) (allow-none): return location for the natural
8199  *   width, or %NULL
8200  *
8201  * Computes the requested minimum and natural widths for an actor,
8202  * optionally depending on the specified height, or if they are
8203  * already computed, returns the cached values.
8204  *
8205  * An actor may not get its request - depending on the layout
8206  * manager that's in effect.
8207  *
8208  * A request should not incorporate the actor's scale or anchor point;
8209  * those transformations do not affect layout, only rendering.
8210  *
8211  * Since: 0.8
8212  */
8213 void
8214 clutter_actor_get_preferred_width (ClutterActor *self,
8215                                    gfloat        for_height,
8216                                    gfloat       *min_width_p,
8217                                    gfloat       *natural_width_p)
8218 {
8219   float request_min_width, request_natural_width;
8220   SizeRequest *cached_size_request;
8221   const ClutterLayoutInfo *info;
8222   ClutterActorPrivate *priv;
8223   gboolean found_in_cache;
8224
8225   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8226
8227   priv = self->priv;
8228
8229   info = _clutter_actor_get_layout_info_or_defaults (self);
8230
8231   /* we shortcircuit the case of a fixed size set using set_width() */
8232   if (priv->min_width_set && priv->natural_width_set)
8233     {
8234       if (min_width_p != NULL)
8235         *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8236
8237       if (natural_width_p != NULL)
8238         *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8239
8240       return;
8241     }
8242
8243   /* the remaining cases are:
8244    *
8245    *   - either min_width or natural_width have been set
8246    *   - neither min_width or natural_width have been set
8247    *
8248    * in both cases, we go through the cache (and through the actor in case
8249    * of cache misses) and determine the authoritative value depending on
8250    * the *_set flags.
8251    */
8252
8253   if (!priv->needs_width_request)
8254     {
8255       found_in_cache =
8256         _clutter_actor_get_cached_size_request (for_height,
8257                                                 priv->width_requests,
8258                                                 &cached_size_request);
8259     }
8260   else
8261     {
8262       /* if the actor needs a width request we use the first slot */
8263       found_in_cache = FALSE;
8264       cached_size_request = &priv->width_requests[0];
8265     }
8266
8267   if (!found_in_cache)
8268     {
8269       gfloat minimum_width, natural_width;
8270       ClutterActorClass *klass;
8271
8272       minimum_width = natural_width = 0;
8273
8274       /* adjust for the margin */
8275       if (for_height >= 0)
8276         {
8277           for_height -= (info->margin.top + info->margin.bottom);
8278           if (for_height < 0)
8279             for_height = 0;
8280         }
8281
8282       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8283
8284       klass = CLUTTER_ACTOR_GET_CLASS (self);
8285       klass->get_preferred_width (self, for_height,
8286                                   &minimum_width,
8287                                   &natural_width);
8288
8289       /* adjust for the margin */
8290       minimum_width += (info->margin.left + info->margin.right);
8291       natural_width += (info->margin.left + info->margin.right);
8292
8293       /* Due to accumulated float errors, it's better not to warn
8294        * on this, but just fix it.
8295        */
8296       if (natural_width < minimum_width)
8297         natural_width = minimum_width;
8298
8299       cached_size_request->min_size = minimum_width;
8300       cached_size_request->natural_size = natural_width;
8301       cached_size_request->for_size = for_height;
8302       cached_size_request->age = priv->cached_width_age;
8303
8304       priv->cached_width_age += 1;
8305       priv->needs_width_request = FALSE;
8306     }
8307
8308   if (!priv->min_width_set)
8309     request_min_width = cached_size_request->min_size;
8310   else
8311     request_min_width = info->margin.left
8312                       + info->minimum.width
8313                       + info->margin.right;
8314
8315   if (!priv->natural_width_set)
8316     request_natural_width = cached_size_request->natural_size;
8317   else
8318     request_natural_width = info->margin.left
8319                           + info->natural.width
8320                           + info->margin.right;
8321
8322   if (min_width_p)
8323     *min_width_p = request_min_width;
8324
8325   if (natural_width_p)
8326     *natural_width_p = request_natural_width;
8327 }
8328
8329 /**
8330  * clutter_actor_get_preferred_height:
8331  * @self: A #ClutterActor
8332  * @for_width: available width to assume in computing desired height,
8333  *   or a negative value to indicate that no width is defined
8334  * @min_height_p: (out) (allow-none): return location for minimum height,
8335  *   or %NULL
8336  * @natural_height_p: (out) (allow-none): return location for natural
8337  *   height, or %NULL
8338  *
8339  * Computes the requested minimum and natural heights for an actor,
8340  * or if they are already computed, returns the cached values.
8341  *
8342  * An actor may not get its request - depending on the layout
8343  * manager that's in effect.
8344  *
8345  * A request should not incorporate the actor's scale or anchor point;
8346  * those transformations do not affect layout, only rendering.
8347  *
8348  * Since: 0.8
8349  */
8350 void
8351 clutter_actor_get_preferred_height (ClutterActor *self,
8352                                     gfloat        for_width,
8353                                     gfloat       *min_height_p,
8354                                     gfloat       *natural_height_p)
8355 {
8356   float request_min_height, request_natural_height;
8357   SizeRequest *cached_size_request;
8358   const ClutterLayoutInfo *info;
8359   ClutterActorPrivate *priv;
8360   gboolean found_in_cache;
8361
8362   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8363
8364   priv = self->priv;
8365
8366   info = _clutter_actor_get_layout_info_or_defaults (self);
8367
8368   /* we shortcircuit the case of a fixed size set using set_height() */
8369   if (priv->min_height_set && priv->natural_height_set)
8370     {
8371       if (min_height_p != NULL)
8372         *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8373
8374       if (natural_height_p != NULL)
8375         *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8376
8377       return;
8378     }
8379
8380   /* the remaining cases are:
8381    *
8382    *   - either min_height or natural_height have been set
8383    *   - neither min_height or natural_height have been set
8384    *
8385    * in both cases, we go through the cache (and through the actor in case
8386    * of cache misses) and determine the authoritative value depending on
8387    * the *_set flags.
8388    */
8389
8390   if (!priv->needs_height_request)
8391     {
8392       found_in_cache =
8393         _clutter_actor_get_cached_size_request (for_width,
8394                                                 priv->height_requests,
8395                                                 &cached_size_request);
8396     }
8397   else
8398     {
8399       found_in_cache = FALSE;
8400       cached_size_request = &priv->height_requests[0];
8401     }
8402
8403   if (!found_in_cache)
8404     {
8405       gfloat minimum_height, natural_height;
8406       ClutterActorClass *klass;
8407
8408       minimum_height = natural_height = 0;
8409
8410       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8411
8412       /* adjust for margin */
8413       if (for_width >= 0)
8414         {
8415           for_width -= (info->margin.left + info->margin.right);
8416           if (for_width < 0)
8417             for_width = 0;
8418         }
8419
8420       klass = CLUTTER_ACTOR_GET_CLASS (self);
8421       klass->get_preferred_height (self, for_width,
8422                                    &minimum_height,
8423                                    &natural_height);
8424
8425       /* adjust for margin */
8426       minimum_height += (info->margin.top + info->margin.bottom);
8427       natural_height += (info->margin.top + info->margin.bottom);
8428
8429       /* Due to accumulated float errors, it's better not to warn
8430        * on this, but just fix it.
8431        */
8432       if (natural_height < minimum_height)
8433         natural_height = minimum_height;
8434
8435       cached_size_request->min_size = minimum_height;
8436       cached_size_request->natural_size = natural_height;
8437       cached_size_request->for_size = for_width;
8438       cached_size_request->age = priv->cached_height_age;
8439
8440       priv->cached_height_age += 1;
8441       priv->needs_height_request = FALSE;
8442     }
8443
8444   if (!priv->min_height_set)
8445     request_min_height = cached_size_request->min_size;
8446   else
8447     request_min_height = info->margin.top
8448                        + info->minimum.height
8449                        + info->margin.bottom;
8450
8451   if (!priv->natural_height_set)
8452     request_natural_height = cached_size_request->natural_size;
8453   else
8454     request_natural_height = info->margin.top
8455                            + info->natural.height
8456                            + info->margin.bottom;
8457
8458   if (min_height_p)
8459     *min_height_p = request_min_height;
8460
8461   if (natural_height_p)
8462     *natural_height_p = request_natural_height;
8463 }
8464
8465 /**
8466  * clutter_actor_get_allocation_box:
8467  * @self: A #ClutterActor
8468  * @box: (out): the function fills this in with the actor's allocation
8469  *
8470  * Gets the layout box an actor has been assigned. The allocation can
8471  * only be assumed valid inside a paint() method; anywhere else, it
8472  * may be out-of-date.
8473  *
8474  * An allocation does not incorporate the actor's scale or anchor point;
8475  * those transformations do not affect layout, only rendering.
8476  *
8477  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8478  * of functions inside the implementation of the get_preferred_width()
8479  * or get_preferred_height() virtual functions.</note>
8480  *
8481  * Since: 0.8
8482  */
8483 void
8484 clutter_actor_get_allocation_box (ClutterActor    *self,
8485                                   ClutterActorBox *box)
8486 {
8487   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8488
8489   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8490    * which limits calling get_allocation to inside paint() basically; or
8491    * we can 2) force a layout, which could be expensive if someone calls
8492    * get_allocation somewhere silly; or we can 3) just return the latest
8493    * value, allowing it to be out-of-date, and assume people know what
8494    * they are doing.
8495    *
8496    * The least-surprises approach that keeps existing code working is
8497    * likely to be 2). People can end up doing some inefficient things,
8498    * though, and in general code that requires 2) is probably broken.
8499    */
8500
8501   /* this implements 2) */
8502   if (G_UNLIKELY (self->priv->needs_allocation))
8503     {
8504       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8505
8506       /* do not queue a relayout on an unparented actor */
8507       if (stage)
8508         _clutter_stage_maybe_relayout (stage);
8509     }
8510
8511   /* commenting out the code above and just keeping this assigment
8512    * implements 3)
8513    */
8514   *box = self->priv->allocation;
8515 }
8516
8517 /**
8518  * clutter_actor_get_allocation_geometry:
8519  * @self: A #ClutterActor
8520  * @geom: (out): allocation geometry in pixels
8521  *
8522  * Gets the layout box an actor has been assigned.  The allocation can
8523  * only be assumed valid inside a paint() method; anywhere else, it
8524  * may be out-of-date.
8525  *
8526  * An allocation does not incorporate the actor's scale or anchor point;
8527  * those transformations do not affect layout, only rendering.
8528  *
8529  * The returned rectangle is in pixels.
8530  *
8531  * Since: 0.8
8532  */
8533 void
8534 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8535                                        ClutterGeometry *geom)
8536 {
8537   ClutterActorBox box;
8538
8539   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8540   g_return_if_fail (geom != NULL);
8541
8542   clutter_actor_get_allocation_box (self, &box);
8543
8544   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8545   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8546   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8547   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8548 }
8549
8550 static void
8551 clutter_actor_update_constraints (ClutterActor    *self,
8552                                   ClutterActorBox *allocation)
8553 {
8554   ClutterActorPrivate *priv = self->priv;
8555   const GList *constraints, *l;
8556
8557   if (priv->constraints == NULL)
8558     return;
8559
8560   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8561   for (l = constraints; l != NULL; l = l->next)
8562     {
8563       ClutterConstraint *constraint = l->data;
8564       ClutterActorMeta *meta = l->data;
8565
8566       if (clutter_actor_meta_get_enabled (meta))
8567         {
8568           _clutter_constraint_update_allocation (constraint,
8569                                                  self,
8570                                                  allocation);
8571
8572           CLUTTER_NOTE (LAYOUT,
8573                         "Allocation of '%s' after constraint '%s': "
8574                         "{ %.2f, %.2f, %.2f, %.2f }",
8575                         _clutter_actor_get_debug_name (self),
8576                         _clutter_actor_meta_get_debug_name (meta),
8577                         allocation->x1,
8578                         allocation->y1,
8579                         allocation->x2,
8580                         allocation->y2);
8581         }
8582     }
8583 }
8584
8585 /*< private >
8586  * clutter_actor_adjust_allocation:
8587  * @self: a #ClutterActor
8588  * @allocation: (inout): the allocation to adjust
8589  *
8590  * Adjusts the passed allocation box taking into account the actor's
8591  * layout information, like alignment, expansion, and margin.
8592  */
8593 static void
8594 clutter_actor_adjust_allocation (ClutterActor    *self,
8595                                  ClutterActorBox *allocation)
8596 {
8597   ClutterActorBox adj_allocation;
8598   float alloc_width, alloc_height;
8599   float min_width, min_height;
8600   float nat_width, nat_height;
8601   ClutterRequestMode req_mode;
8602
8603   adj_allocation = *allocation;
8604
8605   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8606
8607   /* we want to hit the cache, so we use the public API */
8608   req_mode = clutter_actor_get_request_mode (self);
8609
8610   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8611     {
8612       clutter_actor_get_preferred_width (self, -1,
8613                                          &min_width,
8614                                          &nat_width);
8615       clutter_actor_get_preferred_height (self, alloc_width,
8616                                           &min_height,
8617                                           &nat_height);
8618     }
8619   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8620     {
8621       clutter_actor_get_preferred_height (self, -1,
8622                                           &min_height,
8623                                           &nat_height);
8624       clutter_actor_get_preferred_height (self, alloc_height,
8625                                           &min_width,
8626                                           &nat_width);
8627     }
8628
8629 #ifdef CLUTTER_ENABLE_DEBUG
8630   /* warn about underallocations */
8631   if (_clutter_diagnostic_enabled () &&
8632       (floorf (min_width - alloc_width) > 0 ||
8633        floorf (min_height - alloc_height) > 0))
8634     {
8635       ClutterActor *parent = clutter_actor_get_parent (self);
8636
8637       /* the only actors that are allowed to be underallocated are the Stage,
8638        * as it doesn't have an implicit size, and Actors that specifically
8639        * told us that they want to opt-out from layout control mechanisms
8640        * through the NO_LAYOUT escape hatch.
8641        */
8642       if (parent != NULL &&
8643           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8644         {
8645           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8646                      "of %.2f x %.2f from its parent actor '%s', but its "
8647                      "requested minimum size is of %.2f x %.2f",
8648                      _clutter_actor_get_debug_name (self),
8649                      alloc_width, alloc_height,
8650                      _clutter_actor_get_debug_name (parent),
8651                      min_width, min_height);
8652         }
8653     }
8654 #endif
8655
8656   clutter_actor_adjust_width (self,
8657                               &min_width,
8658                               &nat_width,
8659                               &adj_allocation.x1,
8660                               &adj_allocation.x2);
8661
8662   clutter_actor_adjust_height (self,
8663                                &min_height,
8664                                &nat_height,
8665                                &adj_allocation.y1,
8666                                &adj_allocation.y2);
8667
8668   /* we maintain the invariant that an allocation cannot be adjusted
8669    * to be outside the parent-given box
8670    */
8671   if (adj_allocation.x1 < allocation->x1 ||
8672       adj_allocation.y1 < allocation->y1 ||
8673       adj_allocation.x2 > allocation->x2 ||
8674       adj_allocation.y2 > allocation->y2)
8675     {
8676       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8677                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8678                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8679                  _clutter_actor_get_debug_name (self),
8680                  adj_allocation.x1, adj_allocation.y1,
8681                  adj_allocation.x2 - adj_allocation.x1,
8682                  adj_allocation.y2 - adj_allocation.y1,
8683                  allocation->x1, allocation->y1,
8684                  allocation->x2 - allocation->x1,
8685                  allocation->y2 - allocation->y1);
8686       return;
8687     }
8688
8689   *allocation = adj_allocation;
8690 }
8691
8692 static void
8693 clutter_actor_allocate_internal (ClutterActor           *self,
8694                                  const ClutterActorBox  *allocation,
8695                                  ClutterAllocationFlags  flags)
8696 {
8697   ClutterActorClass *klass;
8698
8699   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8700
8701   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8702                 _clutter_actor_get_debug_name (self));
8703
8704   klass = CLUTTER_ACTOR_GET_CLASS (self);
8705   klass->allocate (self, allocation, flags);
8706
8707   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8708
8709   clutter_actor_queue_redraw (self);
8710 }
8711
8712 /**
8713  * clutter_actor_allocate:
8714  * @self: A #ClutterActor
8715  * @box: new allocation of the actor, in parent-relative coordinates
8716  * @flags: flags that control the allocation
8717  *
8718  * Called by the parent of an actor to assign the actor its size.
8719  * Should never be called by applications (except when implementing
8720  * a container or layout manager).
8721  *
8722  * Actors can know from their allocation box whether they have moved
8723  * with respect to their parent actor. The @flags parameter describes
8724  * additional information about the allocation, for instance whether
8725  * the parent has moved with respect to the stage, for example because
8726  * a grandparent's origin has moved.
8727  *
8728  * Since: 0.8
8729  */
8730 void
8731 clutter_actor_allocate (ClutterActor           *self,
8732                         const ClutterActorBox  *box,
8733                         ClutterAllocationFlags  flags)
8734 {
8735   ClutterActorBox old_allocation, real_allocation;
8736   gboolean origin_changed, child_moved, size_changed;
8737   gboolean stage_allocation_changed;
8738   ClutterActorPrivate *priv;
8739
8740   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8741   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8742     {
8743       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8744                  "which isn't a descendent of the stage!\n",
8745                  self, _clutter_actor_get_debug_name (self));
8746       return;
8747     }
8748
8749   priv = self->priv;
8750
8751   old_allocation = priv->allocation;
8752   real_allocation = *box;
8753
8754   /* constraints are allowed to modify the allocation only here; we do
8755    * this prior to all the other checks so that we can bail out if the
8756    * allocation did not change
8757    */
8758   clutter_actor_update_constraints (self, &real_allocation);
8759
8760   /* adjust the allocation depending on the align/margin properties */
8761   clutter_actor_adjust_allocation (self, &real_allocation);
8762
8763   if (real_allocation.x2 < real_allocation.x1 ||
8764       real_allocation.y2 < real_allocation.y1)
8765     {
8766       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8767                  _clutter_actor_get_debug_name (self),
8768                  real_allocation.x2 - real_allocation.x1,
8769                  real_allocation.y2 - real_allocation.y1);
8770     }
8771
8772   /* we allow 0-sized actors, but not negative-sized ones */
8773   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8774   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8775
8776   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8777
8778   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8779                  real_allocation.y1 != old_allocation.y1);
8780
8781   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8782                   real_allocation.y2 != old_allocation.y2);
8783
8784   if (origin_changed || child_moved || size_changed)
8785     stage_allocation_changed = TRUE;
8786   else
8787     stage_allocation_changed = FALSE;
8788
8789   /* If we get an allocation "out of the blue"
8790    * (we did not queue relayout), then we want to
8791    * ignore it. But if we have needs_allocation set,
8792    * we want to guarantee that allocate() virtual
8793    * method is always called, i.e. that queue_relayout()
8794    * always results in an allocate() invocation on
8795    * an actor.
8796    *
8797    * The optimization here is to avoid re-allocating
8798    * actors that did not queue relayout and were
8799    * not moved.
8800    */
8801   if (!priv->needs_allocation && !stage_allocation_changed)
8802     {
8803       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8804       return;
8805     }
8806
8807   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8808    * clutter_actor_allocate(), it indicates whether the parent has its
8809    * absolute origin moved; when passed in to ClutterActor::allocate()
8810    * virtual method though, it indicates whether the child has its
8811    * absolute origin moved.  So we set it when child_moved is TRUE
8812    */
8813   if (child_moved)
8814     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8815
8816   /* store the flags here, so that they can be propagated by the
8817    * transition code
8818    */
8819   self->priv->allocation_flags = flags;
8820
8821   if (_clutter_actor_get_transition (self, obj_props[PROP_ALLOCATION]) == NULL)
8822     {
8823       _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
8824                                         &priv->allocation,
8825                                         &real_allocation);
8826     }
8827   else
8828     _clutter_actor_update_transition (self, obj_props[PROP_ALLOCATION],
8829                                       &real_allocation);
8830 }
8831
8832 /**
8833  * clutter_actor_set_allocation:
8834  * @self: a #ClutterActor
8835  * @box: a #ClutterActorBox
8836  * @flags: allocation flags
8837  *
8838  * Stores the allocation of @self as defined by @box.
8839  *
8840  * This function can only be called from within the implementation of
8841  * the #ClutterActorClass.allocate() virtual function.
8842  *
8843  * The allocation should have been adjusted to take into account constraints,
8844  * alignment, and margin properties. If you are implementing a #ClutterActor
8845  * subclass that provides its own layout management policy for its children
8846  * instead of using a #ClutterLayoutManager delegate, you should not call
8847  * this function on the children of @self; instead, you should call
8848  * clutter_actor_allocate(), which will adjust the allocation box for
8849  * you.
8850  *
8851  * This function should only be used by subclasses of #ClutterActor
8852  * that wish to store their allocation but cannot chain up to the
8853  * parent's implementation; the default implementation of the
8854  * #ClutterActorClass.allocate() virtual function will call this
8855  * function.
8856  *
8857  * It is important to note that, while chaining up was the recommended
8858  * behaviour for #ClutterActor subclasses prior to the introduction of
8859  * this function, it is recommended to call clutter_actor_set_allocation()
8860  * instead.
8861  *
8862  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8863  * to handle the allocation of its children, this function will call
8864  * the clutter_layout_manager_allocate() function only if the
8865  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8866  * expected that the subclass will call clutter_layout_manager_allocate()
8867  * by itself. For instance, the following code:
8868  *
8869  * |[
8870  * static void
8871  * my_actor_allocate (ClutterActor *actor,
8872  *                    const ClutterActorBox *allocation,
8873  *                    ClutterAllocationFlags flags)
8874  * {
8875  *   ClutterActorBox new_alloc;
8876  *   ClutterAllocationFlags new_flags;
8877  *
8878  *   adjust_allocation (allocation, &amp;new_alloc);
8879  *
8880  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8881  *
8882  *   /&ast; this will use the layout manager set on the actor &ast;/
8883  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8884  * }
8885  * ]|
8886  *
8887  * is equivalent to this:
8888  *
8889  * |[
8890  * static void
8891  * my_actor_allocate (ClutterActor *actor,
8892  *                    const ClutterActorBox *allocation,
8893  *                    ClutterAllocationFlags flags)
8894  * {
8895  *   ClutterLayoutManager *layout;
8896  *   ClutterActorBox new_alloc;
8897  *
8898  *   adjust_allocation (allocation, &amp;new_alloc);
8899  *
8900  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8901  *
8902  *   layout = clutter_actor_get_layout_manager (actor);
8903  *   clutter_layout_manager_allocate (layout,
8904  *                                    CLUTTER_CONTAINER (actor),
8905  *                                    &amp;new_alloc,
8906  *                                    flags);
8907  * }
8908  * ]|
8909  *
8910  * Since: 1.10
8911  */
8912 void
8913 clutter_actor_set_allocation (ClutterActor           *self,
8914                               const ClutterActorBox  *box,
8915                               ClutterAllocationFlags  flags)
8916 {
8917   ClutterActorPrivate *priv;
8918   gboolean changed;
8919
8920   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8921   g_return_if_fail (box != NULL);
8922
8923   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8924     {
8925       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8926                   "can only be called from within the implementation of "
8927                   "the ClutterActor::allocate() virtual function.");
8928       return;
8929     }
8930
8931   priv = self->priv;
8932
8933   g_object_freeze_notify (G_OBJECT (self));
8934
8935   changed = clutter_actor_set_allocation_internal (self, box, flags);
8936
8937   /* we allocate our children before we notify changes in our geometry,
8938    * so that people connecting to properties will be able to get valid
8939    * data out of the sub-tree of the scene graph that has this actor at
8940    * the root.
8941    */
8942   clutter_actor_maybe_layout_children (self, box, flags);
8943
8944   if (changed)
8945     {
8946       ClutterActorBox signal_box = priv->allocation;
8947       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8948
8949       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8950                      &signal_box,
8951                      signal_flags);
8952     }
8953
8954   g_object_thaw_notify (G_OBJECT (self));
8955 }
8956
8957 /**
8958  * clutter_actor_set_geometry:
8959  * @self: A #ClutterActor
8960  * @geometry: A #ClutterGeometry
8961  *
8962  * Sets the actor's fixed position and forces its minimum and natural
8963  * size, in pixels. This means the untransformed actor will have the
8964  * given geometry. This is the same as calling clutter_actor_set_position()
8965  * and clutter_actor_set_size().
8966  *
8967  * Deprecated: 1.10: Use clutter_actor_set_position() and
8968  *   clutter_actor_set_size() instead.
8969  */
8970 void
8971 clutter_actor_set_geometry (ClutterActor          *self,
8972                             const ClutterGeometry *geometry)
8973 {
8974   g_object_freeze_notify (G_OBJECT (self));
8975
8976   clutter_actor_set_position (self, geometry->x, geometry->y);
8977   clutter_actor_set_size (self, geometry->width, geometry->height);
8978
8979   g_object_thaw_notify (G_OBJECT (self));
8980 }
8981
8982 /**
8983  * clutter_actor_get_geometry:
8984  * @self: A #ClutterActor
8985  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8986  *
8987  * Gets the size and position of an actor relative to its parent
8988  * actor. This is the same as calling clutter_actor_get_position() and
8989  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8990  * requested size and position if the actor's allocation is invalid.
8991  *
8992  * Deprecated: 1.10: Use clutter_actor_get_position() and
8993  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8994  *   instead.
8995  */
8996 void
8997 clutter_actor_get_geometry (ClutterActor    *self,
8998                             ClutterGeometry *geometry)
8999 {
9000   gfloat x, y, width, height;
9001
9002   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9003   g_return_if_fail (geometry != NULL);
9004
9005   clutter_actor_get_position (self, &x, &y);
9006   clutter_actor_get_size (self, &width, &height);
9007
9008   geometry->x = (int) x;
9009   geometry->y = (int) y;
9010   geometry->width = (int) width;
9011   geometry->height = (int) height;
9012 }
9013
9014 /**
9015  * clutter_actor_set_position:
9016  * @self: A #ClutterActor
9017  * @x: New left position of actor in pixels.
9018  * @y: New top position of actor in pixels.
9019  *
9020  * Sets the actor's fixed position in pixels relative to any parent
9021  * actor.
9022  *
9023  * If a layout manager is in use, this position will override the
9024  * layout manager and force a fixed position.
9025  */
9026 void
9027 clutter_actor_set_position (ClutterActor *self,
9028                             gfloat        x,
9029                             gfloat        y)
9030 {
9031   ClutterPoint new_position;
9032
9033   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9034
9035   clutter_point_init (&new_position, x, y);
9036
9037   if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
9038     {
9039       ClutterPoint cur_position;
9040
9041       cur_position.x = clutter_actor_get_x (self);
9042       cur_position.y = clutter_actor_get_y (self);
9043
9044       _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
9045                                         &cur_position,
9046                                         &new_position);
9047     }
9048   else
9049     _clutter_actor_update_transition (self,
9050                                       obj_props[PROP_POSITION],
9051                                       &new_position);
9052
9053   clutter_actor_queue_relayout (self);
9054 }
9055
9056 /**
9057  * clutter_actor_get_fixed_position_set:
9058  * @self: A #ClutterActor
9059  *
9060  * Checks whether an actor has a fixed position set (and will thus be
9061  * unaffected by any layout manager).
9062  *
9063  * Return value: %TRUE if the fixed position is set on the actor
9064  *
9065  * Since: 0.8
9066  */
9067 gboolean
9068 clutter_actor_get_fixed_position_set (ClutterActor *self)
9069 {
9070   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9071
9072   return self->priv->position_set;
9073 }
9074
9075 /**
9076  * clutter_actor_set_fixed_position_set:
9077  * @self: A #ClutterActor
9078  * @is_set: whether to use fixed position
9079  *
9080  * Sets whether an actor has a fixed position set (and will thus be
9081  * unaffected by any layout manager).
9082  *
9083  * Since: 0.8
9084  */
9085 void
9086 clutter_actor_set_fixed_position_set (ClutterActor *self,
9087                                       gboolean      is_set)
9088 {
9089   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9090
9091   if (self->priv->position_set == (is_set != FALSE))
9092     return;
9093
9094   self->priv->position_set = is_set != FALSE;
9095   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9096
9097   clutter_actor_queue_relayout (self);
9098 }
9099
9100 /**
9101  * clutter_actor_move_by:
9102  * @self: A #ClutterActor
9103  * @dx: Distance to move Actor on X axis.
9104  * @dy: Distance to move Actor on Y axis.
9105  *
9106  * Moves an actor by the specified distance relative to its current
9107  * position in pixels.
9108  *
9109  * This function modifies the fixed position of an actor and thus removes
9110  * it from any layout management. Another way to move an actor is with an
9111  * anchor point, see clutter_actor_set_anchor_point().
9112  *
9113  * Since: 0.2
9114  */
9115 void
9116 clutter_actor_move_by (ClutterActor *self,
9117                        gfloat        dx,
9118                        gfloat        dy)
9119 {
9120   const ClutterLayoutInfo *info;
9121   gfloat x, y;
9122
9123   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9124
9125   info = _clutter_actor_get_layout_info_or_defaults (self);
9126   x = info->fixed_pos.x;
9127   y = info->fixed_pos.y;
9128
9129   clutter_actor_set_position (self, x + dx, y + dy);
9130 }
9131
9132 static void
9133 clutter_actor_set_min_width (ClutterActor *self,
9134                              gfloat        min_width)
9135 {
9136   ClutterActorPrivate *priv = self->priv;
9137   ClutterActorBox old = { 0, };
9138   ClutterLayoutInfo *info;
9139
9140   /* if we are setting the size on a top-level actor and the
9141    * backend only supports static top-levels (e.g. framebuffers)
9142    * then we ignore the passed value and we override it with
9143    * the stage implementation's preferred size.
9144    */
9145   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9146       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9147     return;
9148
9149   info = _clutter_actor_get_layout_info (self);
9150
9151   if (priv->min_width_set && min_width == info->minimum.width)
9152     return;
9153
9154   g_object_freeze_notify (G_OBJECT (self));
9155
9156   clutter_actor_store_old_geometry (self, &old);
9157
9158   info->minimum.width = min_width;
9159   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9160   clutter_actor_set_min_width_set (self, TRUE);
9161
9162   clutter_actor_notify_if_geometry_changed (self, &old);
9163
9164   g_object_thaw_notify (G_OBJECT (self));
9165
9166   clutter_actor_queue_relayout (self);
9167 }
9168
9169 static void
9170 clutter_actor_set_min_height (ClutterActor *self,
9171                               gfloat        min_height)
9172
9173 {
9174   ClutterActorPrivate *priv = self->priv;
9175   ClutterActorBox old = { 0, };
9176   ClutterLayoutInfo *info;
9177
9178   /* if we are setting the size on a top-level actor and the
9179    * backend only supports static top-levels (e.g. framebuffers)
9180    * then we ignore the passed value and we override it with
9181    * the stage implementation's preferred size.
9182    */
9183   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9184       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9185     return;
9186
9187   info = _clutter_actor_get_layout_info (self);
9188
9189   if (priv->min_height_set && min_height == info->minimum.height)
9190     return;
9191
9192   g_object_freeze_notify (G_OBJECT (self));
9193
9194   clutter_actor_store_old_geometry (self, &old);
9195
9196   info->minimum.height = min_height;
9197   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9198   clutter_actor_set_min_height_set (self, TRUE);
9199
9200   clutter_actor_notify_if_geometry_changed (self, &old);
9201
9202   g_object_thaw_notify (G_OBJECT (self));
9203
9204   clutter_actor_queue_relayout (self);
9205 }
9206
9207 static void
9208 clutter_actor_set_natural_width (ClutterActor *self,
9209                                  gfloat        natural_width)
9210 {
9211   ClutterActorPrivate *priv = self->priv;
9212   ClutterActorBox old = { 0, };
9213   ClutterLayoutInfo *info;
9214
9215   /* if we are setting the size on a top-level actor and the
9216    * backend only supports static top-levels (e.g. framebuffers)
9217    * then we ignore the passed value and we override it with
9218    * the stage implementation's preferred size.
9219    */
9220   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9221       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9222     return;
9223
9224   info = _clutter_actor_get_layout_info (self);
9225
9226   if (priv->natural_width_set && natural_width == info->natural.width)
9227     return;
9228
9229   g_object_freeze_notify (G_OBJECT (self));
9230
9231   clutter_actor_store_old_geometry (self, &old);
9232
9233   info->natural.width = natural_width;
9234   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9235   clutter_actor_set_natural_width_set (self, TRUE);
9236
9237   clutter_actor_notify_if_geometry_changed (self, &old);
9238
9239   g_object_thaw_notify (G_OBJECT (self));
9240
9241   clutter_actor_queue_relayout (self);
9242 }
9243
9244 static void
9245 clutter_actor_set_natural_height (ClutterActor *self,
9246                                   gfloat        natural_height)
9247 {
9248   ClutterActorPrivate *priv = self->priv;
9249   ClutterActorBox old = { 0, };
9250   ClutterLayoutInfo *info;
9251
9252   /* if we are setting the size on a top-level actor and the
9253    * backend only supports static top-levels (e.g. framebuffers)
9254    * then we ignore the passed value and we override it with
9255    * the stage implementation's preferred size.
9256    */
9257   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9258       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9259     return;
9260
9261   info = _clutter_actor_get_layout_info (self);
9262
9263   if (priv->natural_height_set && natural_height == info->natural.height)
9264     return;
9265
9266   g_object_freeze_notify (G_OBJECT (self));
9267
9268   clutter_actor_store_old_geometry (self, &old);
9269
9270   info->natural.height = natural_height;
9271   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9272   clutter_actor_set_natural_height_set (self, TRUE);
9273
9274   clutter_actor_notify_if_geometry_changed (self, &old);
9275
9276   g_object_thaw_notify (G_OBJECT (self));
9277
9278   clutter_actor_queue_relayout (self);
9279 }
9280
9281 static void
9282 clutter_actor_set_min_width_set (ClutterActor *self,
9283                                  gboolean      use_min_width)
9284 {
9285   ClutterActorPrivate *priv = self->priv;
9286   ClutterActorBox old = { 0, };
9287
9288   if (priv->min_width_set == (use_min_width != FALSE))
9289     return;
9290
9291   clutter_actor_store_old_geometry (self, &old);
9292
9293   priv->min_width_set = use_min_width != FALSE;
9294   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9295
9296   clutter_actor_notify_if_geometry_changed (self, &old);
9297
9298   clutter_actor_queue_relayout (self);
9299 }
9300
9301 static void
9302 clutter_actor_set_min_height_set (ClutterActor *self,
9303                                   gboolean      use_min_height)
9304 {
9305   ClutterActorPrivate *priv = self->priv;
9306   ClutterActorBox old = { 0, };
9307
9308   if (priv->min_height_set == (use_min_height != FALSE))
9309     return;
9310
9311   clutter_actor_store_old_geometry (self, &old);
9312
9313   priv->min_height_set = use_min_height != FALSE;
9314   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9315
9316   clutter_actor_notify_if_geometry_changed (self, &old);
9317
9318   clutter_actor_queue_relayout (self);
9319 }
9320
9321 static void
9322 clutter_actor_set_natural_width_set (ClutterActor *self,
9323                                      gboolean      use_natural_width)
9324 {
9325   ClutterActorPrivate *priv = self->priv;
9326   ClutterActorBox old = { 0, };
9327
9328   if (priv->natural_width_set == (use_natural_width != FALSE))
9329     return;
9330
9331   clutter_actor_store_old_geometry (self, &old);
9332
9333   priv->natural_width_set = use_natural_width != FALSE;
9334   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9335
9336   clutter_actor_notify_if_geometry_changed (self, &old);
9337
9338   clutter_actor_queue_relayout (self);
9339 }
9340
9341 static void
9342 clutter_actor_set_natural_height_set (ClutterActor *self,
9343                                       gboolean      use_natural_height)
9344 {
9345   ClutterActorPrivate *priv = self->priv;
9346   ClutterActorBox old = { 0, };
9347
9348   if (priv->natural_height_set == (use_natural_height != FALSE))
9349     return;
9350
9351   clutter_actor_store_old_geometry (self, &old);
9352
9353   priv->natural_height_set = use_natural_height != FALSE;
9354   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9355
9356   clutter_actor_notify_if_geometry_changed (self, &old);
9357
9358   clutter_actor_queue_relayout (self);
9359 }
9360
9361 /**
9362  * clutter_actor_set_request_mode:
9363  * @self: a #ClutterActor
9364  * @mode: the request mode
9365  *
9366  * Sets the geometry request mode of @self.
9367  *
9368  * The @mode determines the order for invoking
9369  * clutter_actor_get_preferred_width() and
9370  * clutter_actor_get_preferred_height()
9371  *
9372  * Since: 1.2
9373  */
9374 void
9375 clutter_actor_set_request_mode (ClutterActor       *self,
9376                                 ClutterRequestMode  mode)
9377 {
9378   ClutterActorPrivate *priv;
9379
9380   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9381
9382   priv = self->priv;
9383
9384   if (priv->request_mode == mode)
9385     return;
9386
9387   priv->request_mode = mode;
9388
9389   priv->needs_width_request = TRUE;
9390   priv->needs_height_request = TRUE;
9391
9392   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9393
9394   clutter_actor_queue_relayout (self);
9395 }
9396
9397 /**
9398  * clutter_actor_get_request_mode:
9399  * @self: a #ClutterActor
9400  *
9401  * Retrieves the geometry request mode of @self
9402  *
9403  * Return value: the request mode for the actor
9404  *
9405  * Since: 1.2
9406  */
9407 ClutterRequestMode
9408 clutter_actor_get_request_mode (ClutterActor *self)
9409 {
9410   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9411                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9412
9413   return self->priv->request_mode;
9414 }
9415
9416 /* variant of set_width() without checks and without notification
9417  * freeze+thaw, for internal usage only
9418  */
9419 static inline void
9420 clutter_actor_set_width_internal (ClutterActor *self,
9421                                   gfloat        width)
9422 {
9423   if (width >= 0)
9424     {
9425       /* the Stage will use the :min-width to control the minimum
9426        * width to be resized to, so we should not be setting it
9427        * along with the :natural-width
9428        */
9429       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9430         clutter_actor_set_min_width (self, width);
9431
9432       clutter_actor_set_natural_width (self, width);
9433     }
9434   else
9435     {
9436       /* we only unset the :natural-width for the Stage */
9437       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9438         clutter_actor_set_min_width_set (self, FALSE);
9439
9440       clutter_actor_set_natural_width_set (self, FALSE);
9441     }
9442 }
9443
9444 /* variant of set_height() without checks and without notification
9445  * freeze+thaw, for internal usage only
9446  */
9447 static inline void
9448 clutter_actor_set_height_internal (ClutterActor *self,
9449                                    gfloat        height)
9450 {
9451   if (height >= 0)
9452     {
9453       /* see the comment above in set_width_internal() */
9454       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9455         clutter_actor_set_min_height (self, height);
9456
9457       clutter_actor_set_natural_height (self, height);
9458     }
9459   else
9460     {
9461       /* see the comment above in set_width_internal() */
9462       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9463         clutter_actor_set_min_height_set (self, FALSE);
9464
9465       clutter_actor_set_natural_height_set (self, FALSE);
9466     }
9467 }
9468
9469 static void
9470 clutter_actor_set_size_internal (ClutterActor      *self,
9471                                  const ClutterSize *size)
9472 {
9473   if (size != NULL)
9474     {
9475       clutter_actor_set_width_internal (self, size->width);
9476       clutter_actor_set_height_internal (self, size->height);
9477     }
9478   else
9479     {
9480       clutter_actor_set_width_internal (self, -1);
9481       clutter_actor_set_height_internal (self, -1);
9482     }
9483 }
9484
9485 /**
9486  * clutter_actor_set_size:
9487  * @self: A #ClutterActor
9488  * @width: New width of actor in pixels, or -1
9489  * @height: New height of actor in pixels, or -1
9490  *
9491  * Sets the actor's size request in pixels. This overrides any
9492  * "normal" size request the actor would have. For example
9493  * a text actor might normally request the size of the text;
9494  * this function would force a specific size instead.
9495  *
9496  * If @width and/or @height are -1 the actor will use its
9497  * "normal" size request instead of overriding it, i.e.
9498  * you can "unset" the size with -1.
9499  *
9500  * This function sets or unsets both the minimum and natural size.
9501  */
9502 void
9503 clutter_actor_set_size (ClutterActor *self,
9504                         gfloat        width,
9505                         gfloat        height)
9506 {
9507   ClutterSize new_size;
9508
9509   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9510
9511   clutter_size_init (&new_size, width, height);
9512
9513   if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9514     {
9515       /* minor optimization: if we don't have a duration then we can
9516        * skip the get_size() below, to avoid the chance of going through
9517        * get_preferred_width() and get_preferred_height() just to jump to
9518        * a new desired size
9519        */
9520       if (clutter_actor_get_easing_duration (self) == 0)
9521         {
9522           g_object_freeze_notify (G_OBJECT (self));
9523
9524           clutter_actor_set_size_internal (self, &new_size);
9525
9526           g_object_thaw_notify (G_OBJECT (self));
9527
9528           return;
9529         }
9530       else
9531         {
9532           ClutterSize cur_size;
9533
9534           clutter_size_init (&cur_size,
9535                              clutter_actor_get_width (self),
9536                              clutter_actor_get_height (self));
9537
9538          _clutter_actor_create_transition (self,
9539                                            obj_props[PROP_SIZE],
9540                                            &cur_size,
9541                                            &new_size);
9542         }
9543     }
9544   else
9545     _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9546
9547   clutter_actor_queue_relayout (self);
9548 }
9549
9550 /**
9551  * clutter_actor_get_size:
9552  * @self: A #ClutterActor
9553  * @width: (out) (allow-none): return location for the width, or %NULL.
9554  * @height: (out) (allow-none): return location for the height, or %NULL.
9555  *
9556  * This function tries to "do what you mean" and return
9557  * the size an actor will have. If the actor has a valid
9558  * allocation, the allocation will be returned; otherwise,
9559  * the actors natural size request will be returned.
9560  *
9561  * If you care whether you get the request vs. the allocation, you
9562  * should probably call a different function like
9563  * clutter_actor_get_allocation_box() or
9564  * clutter_actor_get_preferred_width().
9565  *
9566  * Since: 0.2
9567  */
9568 void
9569 clutter_actor_get_size (ClutterActor *self,
9570                         gfloat       *width,
9571                         gfloat       *height)
9572 {
9573   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9574
9575   if (width)
9576     *width = clutter_actor_get_width (self);
9577
9578   if (height)
9579     *height = clutter_actor_get_height (self);
9580 }
9581
9582 /**
9583  * clutter_actor_get_position:
9584  * @self: a #ClutterActor
9585  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9586  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9587  *
9588  * This function tries to "do what you mean" and tell you where the
9589  * actor is, prior to any transformations. Retrieves the fixed
9590  * position of an actor in pixels, if one has been set; otherwise, if
9591  * the allocation is valid, returns the actor's allocated position;
9592  * otherwise, returns 0,0.
9593  *
9594  * The returned position is in pixels.
9595  *
9596  * Since: 0.6
9597  */
9598 void
9599 clutter_actor_get_position (ClutterActor *self,
9600                             gfloat       *x,
9601                             gfloat       *y)
9602 {
9603   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9604
9605   if (x)
9606     *x = clutter_actor_get_x (self);
9607
9608   if (y)
9609     *y = clutter_actor_get_y (self);
9610 }
9611
9612 /**
9613  * clutter_actor_get_transformed_position:
9614  * @self: A #ClutterActor
9615  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9616  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9617  *
9618  * Gets the absolute position of an actor, in pixels relative to the stage.
9619  *
9620  * Since: 0.8
9621  */
9622 void
9623 clutter_actor_get_transformed_position (ClutterActor *self,
9624                                         gfloat       *x,
9625                                         gfloat       *y)
9626 {
9627   ClutterVertex v1;
9628   ClutterVertex v2;
9629
9630   v1.x = v1.y = v1.z = 0;
9631   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9632
9633   if (x)
9634     *x = v2.x;
9635
9636   if (y)
9637     *y = v2.y;
9638 }
9639
9640 /**
9641  * clutter_actor_get_transformed_size:
9642  * @self: A #ClutterActor
9643  * @width: (out) (allow-none): return location for the width, or %NULL
9644  * @height: (out) (allow-none): return location for the height, or %NULL
9645  *
9646  * Gets the absolute size of an actor in pixels, taking into account the
9647  * scaling factors.
9648  *
9649  * If the actor has a valid allocation, the allocated size will be used.
9650  * If the actor has not a valid allocation then the preferred size will
9651  * be transformed and returned.
9652  *
9653  * If you want the transformed allocation, see
9654  * clutter_actor_get_abs_allocation_vertices() instead.
9655  *
9656  * <note>When the actor (or one of its ancestors) is rotated around the
9657  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9658  * as a generic quadrangle; in that case this function returns the size
9659  * of the smallest rectangle that encapsulates the entire quad. Please
9660  * note that in this case no assumptions can be made about the relative
9661  * position of this envelope to the absolute position of the actor, as
9662  * returned by clutter_actor_get_transformed_position(); if you need this
9663  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9664  * to get the coords of the actual quadrangle.</note>
9665  *
9666  * Since: 0.8
9667  */
9668 void
9669 clutter_actor_get_transformed_size (ClutterActor *self,
9670                                     gfloat       *width,
9671                                     gfloat       *height)
9672 {
9673   ClutterActorPrivate *priv;
9674   ClutterVertex v[4];
9675   gfloat x_min, x_max, y_min, y_max;
9676   gint i;
9677
9678   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9679
9680   priv = self->priv;
9681
9682   /* if the actor hasn't been allocated yet, get the preferred
9683    * size and transform that
9684    */
9685   if (priv->needs_allocation)
9686     {
9687       gfloat natural_width, natural_height;
9688       ClutterActorBox box;
9689
9690       /* Make a fake allocation to transform.
9691        *
9692        * NB: _clutter_actor_transform_and_project_box expects a box in
9693        * the actor's coordinate space... */
9694
9695       box.x1 = 0;
9696       box.y1 = 0;
9697
9698       natural_width = natural_height = 0;
9699       clutter_actor_get_preferred_size (self, NULL, NULL,
9700                                         &natural_width,
9701                                         &natural_height);
9702
9703       box.x2 = natural_width;
9704       box.y2 = natural_height;
9705
9706       _clutter_actor_transform_and_project_box (self, &box, v);
9707     }
9708   else
9709     clutter_actor_get_abs_allocation_vertices (self, v);
9710
9711   x_min = x_max = v[0].x;
9712   y_min = y_max = v[0].y;
9713
9714   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9715     {
9716       if (v[i].x < x_min)
9717         x_min = v[i].x;
9718
9719       if (v[i].x > x_max)
9720         x_max = v[i].x;
9721
9722       if (v[i].y < y_min)
9723         y_min = v[i].y;
9724
9725       if (v[i].y > y_max)
9726         y_max = v[i].y;
9727     }
9728
9729   if (width)
9730     *width  = x_max - x_min;
9731
9732   if (height)
9733     *height = y_max - y_min;
9734 }
9735
9736 /**
9737  * clutter_actor_get_width:
9738  * @self: A #ClutterActor
9739  *
9740  * Retrieves the width of a #ClutterActor.
9741  *
9742  * If the actor has a valid allocation, this function will return the
9743  * width of the allocated area given to the actor.
9744  *
9745  * If the actor does not have a valid allocation, this function will
9746  * return the actor's natural width, that is the preferred width of
9747  * the actor.
9748  *
9749  * If you care whether you get the preferred width or the width that
9750  * has been assigned to the actor, you should probably call a different
9751  * function like clutter_actor_get_allocation_box() to retrieve the
9752  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9753  * preferred width.
9754  *
9755  * If an actor has a fixed width, for instance a width that has been
9756  * assigned using clutter_actor_set_width(), the width returned will
9757  * be the same value.
9758  *
9759  * Return value: the width of the actor, in pixels
9760  */
9761 gfloat
9762 clutter_actor_get_width (ClutterActor *self)
9763 {
9764   ClutterActorPrivate *priv;
9765
9766   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9767
9768   priv = self->priv;
9769
9770   if (priv->needs_allocation)
9771     {
9772       gfloat natural_width = 0;
9773
9774       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9775         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9776       else
9777         {
9778           gfloat natural_height = 0;
9779
9780           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9781           clutter_actor_get_preferred_width (self, natural_height,
9782                                              NULL,
9783                                              &natural_width);
9784         }
9785
9786       return natural_width;
9787     }
9788   else
9789     return priv->allocation.x2 - priv->allocation.x1;
9790 }
9791
9792 /**
9793  * clutter_actor_get_height:
9794  * @self: A #ClutterActor
9795  *
9796  * Retrieves the height of a #ClutterActor.
9797  *
9798  * If the actor has a valid allocation, this function will return the
9799  * height of the allocated area given to the actor.
9800  *
9801  * If the actor does not have a valid allocation, this function will
9802  * return the actor's natural height, that is the preferred height of
9803  * the actor.
9804  *
9805  * If you care whether you get the preferred height or the height that
9806  * has been assigned to the actor, you should probably call a different
9807  * function like clutter_actor_get_allocation_box() to retrieve the
9808  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9809  * preferred height.
9810  *
9811  * If an actor has a fixed height, for instance a height that has been
9812  * assigned using clutter_actor_set_height(), the height returned will
9813  * be the same value.
9814  *
9815  * Return value: the height of the actor, in pixels
9816  */
9817 gfloat
9818 clutter_actor_get_height (ClutterActor *self)
9819 {
9820   ClutterActorPrivate *priv;
9821
9822   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9823
9824   priv = self->priv;
9825
9826   if (priv->needs_allocation)
9827     {
9828       gfloat natural_height = 0;
9829
9830       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9831         {
9832           gfloat natural_width = 0;
9833
9834           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9835           clutter_actor_get_preferred_height (self, natural_width,
9836                                               NULL, &natural_height);
9837         }
9838       else
9839         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9840
9841       return natural_height;
9842     }
9843   else
9844     return priv->allocation.y2 - priv->allocation.y1;
9845 }
9846
9847 /**
9848  * clutter_actor_set_width:
9849  * @self: A #ClutterActor
9850  * @width: Requested new width for the actor, in pixels, or -1
9851  *
9852  * Forces a width on an actor, causing the actor's preferred width
9853  * and height (if any) to be ignored.
9854  *
9855  * If @width is -1 the actor will use its preferred width request
9856  * instead of overriding it, i.e. you can "unset" the width with -1.
9857  *
9858  * This function sets both the minimum and natural size of the actor.
9859  *
9860  * since: 0.2
9861  */
9862 void
9863 clutter_actor_set_width (ClutterActor *self,
9864                          gfloat        width)
9865 {
9866   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9867
9868   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9869     {
9870       float cur_size;
9871
9872       /* minor optimization: if we don't have a duration
9873        * then we can skip the get_width() below, to avoid
9874        * the chance of going through get_preferred_width()
9875        * just to jump to a new desired width.
9876        */
9877       if (clutter_actor_get_easing_duration (self) == 0)
9878         {
9879           g_object_freeze_notify (G_OBJECT (self));
9880
9881           clutter_actor_set_width_internal (self, width);
9882
9883           g_object_thaw_notify (G_OBJECT (self));
9884
9885           return;
9886         }
9887       else
9888         cur_size = clutter_actor_get_width (self);
9889
9890       _clutter_actor_create_transition (self,
9891                                         obj_props[PROP_WIDTH],
9892                                         cur_size,
9893                                         width);
9894     }
9895   else
9896     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9897 }
9898
9899 /**
9900  * clutter_actor_set_height:
9901  * @self: A #ClutterActor
9902  * @height: Requested new height for the actor, in pixels, or -1
9903  *
9904  * Forces a height on an actor, causing the actor's preferred width
9905  * and height (if any) to be ignored.
9906  *
9907  * If @height is -1 the actor will use its preferred height instead of
9908  * overriding it, i.e. you can "unset" the height with -1.
9909  *
9910  * This function sets both the minimum and natural size of the actor.
9911  *
9912  * since: 0.2
9913  */
9914 void
9915 clutter_actor_set_height (ClutterActor *self,
9916                           gfloat        height)
9917 {
9918   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9919
9920   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9921     {
9922       float cur_size;
9923
9924       /* see the comment in clutter_actor_set_width() above */
9925       if (clutter_actor_get_easing_duration (self) == 0)
9926         {
9927           g_object_freeze_notify (G_OBJECT (self));
9928
9929           clutter_actor_set_height_internal (self, height);
9930
9931           g_object_thaw_notify (G_OBJECT (self));
9932
9933           return;
9934         }
9935       else
9936         cur_size = clutter_actor_get_height (self);
9937
9938       _clutter_actor_create_transition (self,
9939                                         obj_props[PROP_HEIGHT],
9940                                         cur_size,
9941                                         height);
9942     }
9943   else
9944     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9945 }
9946
9947 static inline void
9948 clutter_actor_set_x_internal (ClutterActor *self,
9949                               float         x)
9950 {
9951   ClutterActorPrivate *priv = self->priv;
9952   ClutterLayoutInfo *linfo;
9953   ClutterActorBox old = { 0, };
9954
9955   linfo = _clutter_actor_get_layout_info (self);
9956
9957   if (priv->position_set && linfo->fixed_pos.x == x)
9958     return;
9959
9960   clutter_actor_store_old_geometry (self, &old);
9961
9962   linfo->fixed_pos.x = x;
9963   clutter_actor_set_fixed_position_set (self, TRUE);
9964
9965   clutter_actor_notify_if_geometry_changed (self, &old);
9966
9967   clutter_actor_queue_relayout (self);
9968 }
9969
9970 static inline void
9971 clutter_actor_set_y_internal (ClutterActor *self,
9972                               float         y)
9973 {
9974   ClutterActorPrivate *priv = self->priv;
9975   ClutterLayoutInfo *linfo;
9976   ClutterActorBox old = { 0, };
9977
9978   linfo = _clutter_actor_get_layout_info (self);
9979
9980   if (priv->position_set && linfo->fixed_pos.y == y)
9981     return;
9982
9983   clutter_actor_store_old_geometry (self, &old);
9984
9985   linfo->fixed_pos.y = y;
9986   clutter_actor_set_fixed_position_set (self, TRUE);
9987
9988   clutter_actor_notify_if_geometry_changed (self, &old);
9989
9990   clutter_actor_queue_relayout (self);
9991 }
9992
9993 static void
9994 clutter_actor_set_position_internal (ClutterActor       *self,
9995                                      const ClutterPoint *position)
9996 {
9997   ClutterActorPrivate *priv = self->priv;
9998   ClutterLayoutInfo *linfo;
9999   ClutterActorBox old = { 0, };
10000
10001   linfo = _clutter_actor_get_layout_info (self);
10002
10003   if (priv->position_set &&
10004       clutter_point_equals (position, &linfo->fixed_pos))
10005     return;
10006
10007   clutter_actor_store_old_geometry (self, &old);
10008
10009   if (position != NULL)
10010     {
10011       linfo->fixed_pos = *position;
10012       clutter_actor_set_fixed_position_set (self, TRUE);
10013     }
10014   else
10015     clutter_actor_set_fixed_position_set (self, FALSE);
10016
10017   clutter_actor_notify_if_geometry_changed (self, &old);
10018
10019   clutter_actor_queue_relayout (self);
10020 }
10021
10022 /**
10023  * clutter_actor_set_x:
10024  * @self: a #ClutterActor
10025  * @x: the actor's position on the X axis
10026  *
10027  * Sets the actor's X coordinate, relative to its parent, in pixels.
10028  *
10029  * Overrides any layout manager and forces a fixed position for
10030  * the actor.
10031  *
10032  * The #ClutterActor:x property is animatable.
10033  *
10034  * Since: 0.6
10035  */
10036 void
10037 clutter_actor_set_x (ClutterActor *self,
10038                      gfloat        x)
10039 {
10040   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10041
10042   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
10043     {
10044       float cur_position = clutter_actor_get_x (self);
10045
10046       _clutter_actor_create_transition (self, obj_props[PROP_X],
10047                                         cur_position,
10048                                         x);
10049     }
10050   else
10051     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
10052 }
10053
10054 /**
10055  * clutter_actor_set_y:
10056  * @self: a #ClutterActor
10057  * @y: the actor's position on the Y axis
10058  *
10059  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
10060  *
10061  * Overrides any layout manager and forces a fixed position for
10062  * the actor.
10063  *
10064  * The #ClutterActor:y property is animatable.
10065  *
10066  * Since: 0.6
10067  */
10068 void
10069 clutter_actor_set_y (ClutterActor *self,
10070                      gfloat        y)
10071 {
10072   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10073
10074   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
10075     {
10076       float cur_position = clutter_actor_get_y (self);
10077
10078       _clutter_actor_create_transition (self, obj_props[PROP_Y],
10079                                         cur_position,
10080                                         y);
10081     }
10082   else
10083     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10084 }
10085
10086 /**
10087  * clutter_actor_get_x:
10088  * @self: A #ClutterActor
10089  *
10090  * Retrieves the X coordinate of a #ClutterActor.
10091  *
10092  * This function tries to "do what you mean", by returning the
10093  * correct value depending on the actor's state.
10094  *
10095  * If the actor has a valid allocation, this function will return
10096  * the X coordinate of the origin of the allocation box.
10097  *
10098  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10099  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10100  * function will return that coordinate.
10101  *
10102  * If both the allocation and a fixed position are missing, this function
10103  * will return 0.
10104  *
10105  * Return value: the X coordinate, in pixels, ignoring any
10106  *   transformation (i.e. scaling, rotation)
10107  */
10108 gfloat
10109 clutter_actor_get_x (ClutterActor *self)
10110 {
10111   ClutterActorPrivate *priv;
10112
10113   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10114
10115   priv = self->priv;
10116
10117   if (priv->needs_allocation)
10118     {
10119       if (priv->position_set)
10120         {
10121           const ClutterLayoutInfo *info;
10122
10123           info = _clutter_actor_get_layout_info_or_defaults (self);
10124
10125           return info->fixed_pos.x;
10126         }
10127       else
10128         return 0;
10129     }
10130   else
10131     return priv->allocation.x1;
10132 }
10133
10134 /**
10135  * clutter_actor_get_y:
10136  * @self: A #ClutterActor
10137  *
10138  * Retrieves the Y coordinate of a #ClutterActor.
10139  *
10140  * This function tries to "do what you mean", by returning the
10141  * correct value depending on the actor's state.
10142  *
10143  * If the actor has a valid allocation, this function will return
10144  * the Y coordinate of the origin of the allocation box.
10145  *
10146  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10147  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10148  * function will return that coordinate.
10149  *
10150  * If both the allocation and a fixed position are missing, this function
10151  * will return 0.
10152  *
10153  * Return value: the Y coordinate, in pixels, ignoring any
10154  *   transformation (i.e. scaling, rotation)
10155  */
10156 gfloat
10157 clutter_actor_get_y (ClutterActor *self)
10158 {
10159   ClutterActorPrivate *priv;
10160
10161   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10162
10163   priv = self->priv;
10164
10165   if (priv->needs_allocation)
10166     {
10167       if (priv->position_set)
10168         {
10169           const ClutterLayoutInfo *info;
10170
10171           info = _clutter_actor_get_layout_info_or_defaults (self);
10172
10173           return info->fixed_pos.y;
10174         }
10175       else
10176         return 0;
10177     }
10178   else
10179     return priv->allocation.y1;
10180 }
10181
10182 /**
10183  * clutter_actor_set_scale:
10184  * @self: A #ClutterActor
10185  * @scale_x: double factor to scale actor by horizontally.
10186  * @scale_y: double factor to scale actor by vertically.
10187  *
10188  * Scales an actor with the given factors. The scaling is relative to
10189  * the scale center and the anchor point. The scale center is
10190  * unchanged by this function and defaults to 0,0.
10191  *
10192  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10193  * animatable.
10194  *
10195  * Since: 0.2
10196  */
10197 void
10198 clutter_actor_set_scale (ClutterActor *self,
10199                          gdouble       scale_x,
10200                          gdouble       scale_y)
10201 {
10202   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10203
10204   g_object_freeze_notify (G_OBJECT (self));
10205
10206   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10207   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10208
10209   g_object_thaw_notify (G_OBJECT (self));
10210 }
10211
10212 /**
10213  * clutter_actor_set_scale_full:
10214  * @self: A #ClutterActor
10215  * @scale_x: double factor to scale actor by horizontally.
10216  * @scale_y: double factor to scale actor by vertically.
10217  * @center_x: X coordinate of the center of the scale.
10218  * @center_y: Y coordinate of the center of the scale
10219  *
10220  * Scales an actor with the given factors around the given center
10221  * point. The center point is specified in pixels relative to the
10222  * anchor point (usually the top left corner of the actor).
10223  *
10224  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10225  * are animatable.
10226  *
10227  * Since: 1.0
10228  */
10229 void
10230 clutter_actor_set_scale_full (ClutterActor *self,
10231                               gdouble       scale_x,
10232                               gdouble       scale_y,
10233                               gfloat        center_x,
10234                               gfloat        center_y)
10235 {
10236   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10237
10238   g_object_freeze_notify (G_OBJECT (self));
10239
10240   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10241   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10242   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10243   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10244
10245   g_object_thaw_notify (G_OBJECT (self));
10246 }
10247
10248 /**
10249  * clutter_actor_set_scale_with_gravity:
10250  * @self: A #ClutterActor
10251  * @scale_x: double factor to scale actor by horizontally.
10252  * @scale_y: double factor to scale actor by vertically.
10253  * @gravity: the location of the scale center expressed as a compass
10254  * direction.
10255  *
10256  * Scales an actor with the given factors around the given
10257  * center point. The center point is specified as one of the compass
10258  * directions in #ClutterGravity. For example, setting it to north
10259  * will cause the top of the actor to remain unchanged and the rest of
10260  * the actor to expand left, right and downwards.
10261  *
10262  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10263  * animatable.
10264  *
10265  * Since: 1.0
10266  */
10267 void
10268 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
10269                                       gdouble         scale_x,
10270                                       gdouble         scale_y,
10271                                       ClutterGravity  gravity)
10272 {
10273   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10274
10275   g_object_freeze_notify (G_OBJECT (self));
10276
10277   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10278   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10279   clutter_actor_set_scale_gravity (self, gravity);
10280
10281   g_object_thaw_notify (G_OBJECT (self));
10282 }
10283
10284 /**
10285  * clutter_actor_get_scale:
10286  * @self: A #ClutterActor
10287  * @scale_x: (out) (allow-none): Location to store horizonal
10288  *   scale factor, or %NULL.
10289  * @scale_y: (out) (allow-none): Location to store vertical
10290  *   scale factor, or %NULL.
10291  *
10292  * Retrieves an actors scale factors.
10293  *
10294  * Since: 0.2
10295  */
10296 void
10297 clutter_actor_get_scale (ClutterActor *self,
10298                          gdouble      *scale_x,
10299                          gdouble      *scale_y)
10300 {
10301   const ClutterTransformInfo *info;
10302
10303   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10304
10305   info = _clutter_actor_get_transform_info_or_defaults (self);
10306
10307   if (scale_x)
10308     *scale_x = info->scale_x;
10309
10310   if (scale_y)
10311     *scale_y = info->scale_y;
10312 }
10313
10314 /**
10315  * clutter_actor_get_scale_center:
10316  * @self: A #ClutterActor
10317  * @center_x: (out) (allow-none): Location to store the X position
10318  *   of the scale center, or %NULL.
10319  * @center_y: (out) (allow-none): Location to store the Y position
10320  *   of the scale center, or %NULL.
10321  *
10322  * Retrieves the scale center coordinate in pixels relative to the top
10323  * left corner of the actor. If the scale center was specified using a
10324  * #ClutterGravity this will calculate the pixel offset using the
10325  * current size of the actor.
10326  *
10327  * Since: 1.0
10328  */
10329 void
10330 clutter_actor_get_scale_center (ClutterActor *self,
10331                                 gfloat       *center_x,
10332                                 gfloat       *center_y)
10333 {
10334   const ClutterTransformInfo *info;
10335
10336   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10337
10338   info = _clutter_actor_get_transform_info_or_defaults (self);
10339
10340   clutter_anchor_coord_get_units (self, &info->scale_center,
10341                                   center_x,
10342                                   center_y,
10343                                   NULL);
10344 }
10345
10346 /**
10347  * clutter_actor_get_scale_gravity:
10348  * @self: A #ClutterActor
10349  *
10350  * Retrieves the scale center as a compass direction. If the scale
10351  * center was specified in pixels or units this will return
10352  * %CLUTTER_GRAVITY_NONE.
10353  *
10354  * Return value: the scale gravity
10355  *
10356  * Since: 1.0
10357  */
10358 ClutterGravity
10359 clutter_actor_get_scale_gravity (ClutterActor *self)
10360 {
10361   const ClutterTransformInfo *info;
10362
10363   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10364
10365   info = _clutter_actor_get_transform_info_or_defaults (self);
10366
10367   return clutter_anchor_coord_get_gravity (&info->scale_center);
10368 }
10369
10370 static inline void
10371 clutter_actor_set_opacity_internal (ClutterActor *self,
10372                                     guint8        opacity)
10373 {
10374   ClutterActorPrivate *priv = self->priv;
10375
10376   if (priv->opacity != opacity)
10377     {
10378       priv->opacity = opacity;
10379
10380       /* Queue a redraw from the flatten effect so that it can use
10381          its cached image if available instead of having to redraw the
10382          actual actor. If it doesn't end up using the FBO then the
10383          effect is still able to continue the paint anyway. If there
10384          is no flatten effect yet then this is equivalent to queueing
10385          a full redraw */
10386       _clutter_actor_queue_redraw_full (self,
10387                                         0, /* flags */
10388                                         NULL, /* clip */
10389                                         priv->flatten_effect);
10390
10391       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10392     }
10393 }
10394
10395 /**
10396  * clutter_actor_set_opacity:
10397  * @self: A #ClutterActor
10398  * @opacity: New opacity value for the actor.
10399  *
10400  * Sets the actor's opacity, with zero being completely transparent and
10401  * 255 (0xff) being fully opaque.
10402  *
10403  * The #ClutterActor:opacity property is animatable.
10404  */
10405 void
10406 clutter_actor_set_opacity (ClutterActor *self,
10407                            guint8        opacity)
10408 {
10409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10410
10411   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10412     {
10413       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10414                                         self->priv->opacity,
10415                                         opacity);
10416     }
10417   else
10418     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10419 }
10420
10421 /*
10422  * clutter_actor_get_paint_opacity_internal:
10423  * @self: a #ClutterActor
10424  *
10425  * Retrieves the absolute opacity of the actor, as it appears on the stage
10426  *
10427  * This function does not do type checks
10428  *
10429  * Return value: the absolute opacity of the actor
10430  */
10431 static guint8
10432 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10433 {
10434   ClutterActorPrivate *priv = self->priv;
10435   ClutterActor *parent;
10436
10437   /* override the top-level opacity to always be 255; even in
10438    * case of ClutterStage:use-alpha being TRUE we want the rest
10439    * of the scene to be painted
10440    */
10441   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10442     return 255;
10443
10444   if (priv->opacity_override >= 0)
10445     return priv->opacity_override;
10446
10447   parent = priv->parent;
10448
10449   /* Factor in the actual actors opacity with parents */
10450   if (parent != NULL)
10451     {
10452       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10453
10454       if (opacity != 0xff)
10455         return (opacity * priv->opacity) / 0xff;
10456     }
10457
10458   return priv->opacity;
10459
10460 }
10461
10462 /**
10463  * clutter_actor_get_paint_opacity:
10464  * @self: A #ClutterActor
10465  *
10466  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10467  *
10468  * This function traverses the hierarchy chain and composites the opacity of
10469  * the actor with that of its parents.
10470  *
10471  * This function is intended for subclasses to use in the paint virtual
10472  * function, to paint themselves with the correct opacity.
10473  *
10474  * Return value: The actor opacity value.
10475  *
10476  * Since: 0.8
10477  */
10478 guint8
10479 clutter_actor_get_paint_opacity (ClutterActor *self)
10480 {
10481   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10482
10483   return clutter_actor_get_paint_opacity_internal (self);
10484 }
10485
10486 /**
10487  * clutter_actor_get_opacity:
10488  * @self: a #ClutterActor
10489  *
10490  * Retrieves the opacity value of an actor, as set by
10491  * clutter_actor_set_opacity().
10492  *
10493  * For retrieving the absolute opacity of the actor inside a paint
10494  * virtual function, see clutter_actor_get_paint_opacity().
10495  *
10496  * Return value: the opacity of the actor
10497  */
10498 guint8
10499 clutter_actor_get_opacity (ClutterActor *self)
10500 {
10501   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10502
10503   return self->priv->opacity;
10504 }
10505
10506 /**
10507  * clutter_actor_set_offscreen_redirect:
10508  * @self: A #ClutterActor
10509  * @redirect: New offscreen redirect flags for the actor.
10510  *
10511  * Defines the circumstances where the actor should be redirected into
10512  * an offscreen image. The offscreen image is used to flatten the
10513  * actor into a single image while painting for two main reasons.
10514  * Firstly, when the actor is painted a second time without any of its
10515  * contents changing it can simply repaint the cached image without
10516  * descending further down the actor hierarchy. Secondly, it will make
10517  * the opacity look correct even if there are overlapping primitives
10518  * in the actor.
10519  *
10520  * Caching the actor could in some cases be a performance win and in
10521  * some cases be a performance lose so it is important to determine
10522  * which value is right for an actor before modifying this value. For
10523  * example, there is never any reason to flatten an actor that is just
10524  * a single texture (such as a #ClutterTexture) because it is
10525  * effectively already cached in an image so the offscreen would be
10526  * redundant. Also if the actor contains primitives that are far apart
10527  * with a large transparent area in the middle (such as a large
10528  * CluterGroup with a small actor in the top left and a small actor in
10529  * the bottom right) then the cached image will contain the entire
10530  * image of the large area and the paint will waste time blending all
10531  * of the transparent pixels in the middle.
10532  *
10533  * The default method of implementing opacity on a container simply
10534  * forwards on the opacity to all of the children. If the children are
10535  * overlapping then it will appear as if they are two separate glassy
10536  * objects and there will be a break in the color where they
10537  * overlap. By redirecting to an offscreen buffer it will be as if the
10538  * two opaque objects are combined into one and then made transparent
10539  * which is usually what is expected.
10540  *
10541  * The image below demonstrates the difference between redirecting and
10542  * not. The image shows two Clutter groups, each containing a red and
10543  * a green rectangle which overlap. The opacity on the group is set to
10544  * 128 (which is 50%). When the offscreen redirect is not used, the
10545  * red rectangle can be seen through the blue rectangle as if the two
10546  * rectangles were separately transparent. When the redirect is used
10547  * the group as a whole is transparent instead so the red rectangle is
10548  * not visible where they overlap.
10549  *
10550  * <figure id="offscreen-redirect">
10551  *   <title>Sample of using an offscreen redirect for transparency</title>
10552  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10553  * </figure>
10554  *
10555  * The default value for this property is 0, so we effectively will
10556  * never redirect an actor offscreen by default. This means that there
10557  * are times that transparent actors may look glassy as described
10558  * above. The reason this is the default is because there is a
10559  * performance trade off between quality and performance here. In many
10560  * cases the default form of glassy opacity looks good enough, but if
10561  * it's not you will need to set the
10562  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10563  * redirection for opacity.
10564  *
10565  * Custom actors that don't contain any overlapping primitives are
10566  * recommended to override the has_overlaps() virtual to return %FALSE
10567  * for maximum efficiency.
10568  *
10569  * Since: 1.8
10570  */
10571 void
10572 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10573                                       ClutterOffscreenRedirect redirect)
10574 {
10575   ClutterActorPrivate *priv;
10576
10577   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10578
10579   priv = self->priv;
10580
10581   if (priv->offscreen_redirect != redirect)
10582     {
10583       priv->offscreen_redirect = redirect;
10584
10585       /* Queue a redraw from the effect so that it can use its cached
10586          image if available instead of having to redraw the actual
10587          actor. If it doesn't end up using the FBO then the effect is
10588          still able to continue the paint anyway. If there is no
10589          effect then this is equivalent to queuing a full redraw */
10590       _clutter_actor_queue_redraw_full (self,
10591                                         0, /* flags */
10592                                         NULL, /* clip */
10593                                         priv->flatten_effect);
10594
10595       g_object_notify_by_pspec (G_OBJECT (self),
10596                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10597     }
10598 }
10599
10600 /**
10601  * clutter_actor_get_offscreen_redirect:
10602  * @self: a #ClutterActor
10603  *
10604  * Retrieves whether to redirect the actor to an offscreen buffer, as
10605  * set by clutter_actor_set_offscreen_redirect().
10606  *
10607  * Return value: the value of the offscreen-redirect property of the actor
10608  *
10609  * Since: 1.8
10610  */
10611 ClutterOffscreenRedirect
10612 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10613 {
10614   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10615
10616   return self->priv->offscreen_redirect;
10617 }
10618
10619 /**
10620  * clutter_actor_set_name:
10621  * @self: A #ClutterActor
10622  * @name: Textual tag to apply to actor
10623  *
10624  * Sets the given name to @self. The name can be used to identify
10625  * a #ClutterActor.
10626  */
10627 void
10628 clutter_actor_set_name (ClutterActor *self,
10629                         const gchar  *name)
10630 {
10631   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10632
10633   g_free (self->priv->name);
10634   self->priv->name = g_strdup (name);
10635
10636   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10637 }
10638
10639 /**
10640  * clutter_actor_get_name:
10641  * @self: A #ClutterActor
10642  *
10643  * Retrieves the name of @self.
10644  *
10645  * Return value: the name of the actor, or %NULL. The returned string is
10646  *   owned by the actor and should not be modified or freed.
10647  */
10648 const gchar *
10649 clutter_actor_get_name (ClutterActor *self)
10650 {
10651   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10652
10653   return self->priv->name;
10654 }
10655
10656 /**
10657  * clutter_actor_get_gid:
10658  * @self: A #ClutterActor
10659  *
10660  * Retrieves the unique id for @self.
10661  *
10662  * Return value: Globally unique value for this object instance.
10663  *
10664  * Since: 0.6
10665  *
10666  * Deprecated: 1.8: The id is not used any longer.
10667  */
10668 guint32
10669 clutter_actor_get_gid (ClutterActor *self)
10670 {
10671   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10672
10673   return self->priv->id;
10674 }
10675
10676 static inline void
10677 clutter_actor_set_depth_internal (ClutterActor *self,
10678                                   float         depth)
10679 {
10680   ClutterTransformInfo *info;
10681
10682   info = _clutter_actor_get_transform_info (self);
10683
10684   if (info->depth != depth)
10685     {
10686       /* Sets Z value - XXX 2.0: should we invert? */
10687       info->depth = depth;
10688
10689       self->priv->transform_valid = FALSE;
10690
10691       /* FIXME - remove this crap; sadly, there are still containers
10692        * in Clutter that depend on this utter brain damage
10693        */
10694       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10695
10696       clutter_actor_queue_redraw (self);
10697
10698       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10699     }
10700 }
10701
10702 /**
10703  * clutter_actor_set_depth:
10704  * @self: a #ClutterActor
10705  * @depth: Z co-ord
10706  *
10707  * Sets the Z coordinate of @self to @depth.
10708  *
10709  * The unit used by @depth is dependant on the perspective setup. See
10710  * also clutter_stage_set_perspective().
10711  */
10712 void
10713 clutter_actor_set_depth (ClutterActor *self,
10714                          gfloat        depth)
10715 {
10716   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10717
10718   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10719     {
10720       const ClutterTransformInfo *info;
10721
10722       info = _clutter_actor_get_transform_info_or_defaults (self);
10723
10724       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10725                                         info->depth,
10726                                         depth);
10727     }
10728   else
10729     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10730
10731   clutter_actor_queue_redraw (self);
10732 }
10733
10734 /**
10735  * clutter_actor_get_depth:
10736  * @self: a #ClutterActor
10737  *
10738  * Retrieves the depth of @self.
10739  *
10740  * Return value: the depth of the actor
10741  */
10742 gfloat
10743 clutter_actor_get_depth (ClutterActor *self)
10744 {
10745   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10746
10747   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10748 }
10749
10750 /**
10751  * clutter_actor_set_rotation:
10752  * @self: a #ClutterActor
10753  * @axis: the axis of rotation
10754  * @angle: the angle of rotation
10755  * @x: X coordinate of the rotation center
10756  * @y: Y coordinate of the rotation center
10757  * @z: Z coordinate of the rotation center
10758  *
10759  * Sets the rotation angle of @self around the given axis.
10760  *
10761  * The rotation center coordinates used depend on the value of @axis:
10762  * <itemizedlist>
10763  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10764  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10765  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10766  * </itemizedlist>
10767  *
10768  * The rotation coordinates are relative to the anchor point of the
10769  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10770  * point is set, the upper left corner is assumed as the origin.
10771  *
10772  * Since: 0.8
10773  */
10774 void
10775 clutter_actor_set_rotation (ClutterActor      *self,
10776                             ClutterRotateAxis  axis,
10777                             gdouble            angle,
10778                             gfloat             x,
10779                             gfloat             y,
10780                             gfloat             z)
10781 {
10782   ClutterVertex v;
10783
10784   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10785
10786   v.x = x;
10787   v.y = y;
10788   v.z = z;
10789
10790   g_object_freeze_notify (G_OBJECT (self));
10791
10792   clutter_actor_set_rotation_angle (self, axis, angle);
10793   clutter_actor_set_rotation_center_internal (self, axis, &v);
10794
10795   g_object_thaw_notify (G_OBJECT (self));
10796 }
10797
10798 /**
10799  * clutter_actor_set_z_rotation_from_gravity:
10800  * @self: a #ClutterActor
10801  * @angle: the angle of rotation
10802  * @gravity: the center point of the rotation
10803  *
10804  * Sets the rotation angle of @self around the Z axis using the center
10805  * point specified as a compass point. For example to rotate such that
10806  * the center of the actor remains static you can use
10807  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10808  * will move accordingly.
10809  *
10810  * Since: 1.0
10811  */
10812 void
10813 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10814                                            gdouble         angle,
10815                                            ClutterGravity  gravity)
10816 {
10817   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10818
10819   if (gravity == CLUTTER_GRAVITY_NONE)
10820     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10821   else
10822     {
10823       GObject *obj = G_OBJECT (self);
10824       ClutterTransformInfo *info;
10825
10826       info = _clutter_actor_get_transform_info (self);
10827
10828       g_object_freeze_notify (obj);
10829
10830       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10831
10832       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10833       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10834       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10835
10836       g_object_thaw_notify (obj);
10837     }
10838 }
10839
10840 /**
10841  * clutter_actor_get_rotation:
10842  * @self: a #ClutterActor
10843  * @axis: the axis of rotation
10844  * @x: (out): return value for the X coordinate of the center of rotation
10845  * @y: (out): return value for the Y coordinate of the center of rotation
10846  * @z: (out): return value for the Z coordinate of the center of rotation
10847  *
10848  * Retrieves the angle and center of rotation on the given axis,
10849  * set using clutter_actor_set_rotation().
10850  *
10851  * Return value: the angle of rotation
10852  *
10853  * Since: 0.8
10854  */
10855 gdouble
10856 clutter_actor_get_rotation (ClutterActor      *self,
10857                             ClutterRotateAxis  axis,
10858                             gfloat            *x,
10859                             gfloat            *y,
10860                             gfloat            *z)
10861 {
10862   const ClutterTransformInfo *info;
10863   const AnchorCoord *anchor_coord;
10864   gdouble retval = 0;
10865
10866   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10867
10868   info = _clutter_actor_get_transform_info_or_defaults (self);
10869
10870   switch (axis)
10871     {
10872     case CLUTTER_X_AXIS:
10873       anchor_coord = &info->rx_center;
10874       retval = info->rx_angle;
10875       break;
10876
10877     case CLUTTER_Y_AXIS:
10878       anchor_coord = &info->ry_center;
10879       retval = info->ry_angle;
10880       break;
10881
10882     case CLUTTER_Z_AXIS:
10883       anchor_coord = &info->rz_center;
10884       retval = info->rz_angle;
10885       break;
10886
10887     default:
10888       anchor_coord = NULL;
10889       retval = 0.0;
10890       break;
10891     }
10892
10893   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10894
10895   return retval;
10896 }
10897
10898 /**
10899  * clutter_actor_get_z_rotation_gravity:
10900  * @self: A #ClutterActor
10901  *
10902  * Retrieves the center for the rotation around the Z axis as a
10903  * compass direction. If the center was specified in pixels or units
10904  * this will return %CLUTTER_GRAVITY_NONE.
10905  *
10906  * Return value: the Z rotation center
10907  *
10908  * Since: 1.0
10909  */
10910 ClutterGravity
10911 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10912 {
10913   const ClutterTransformInfo *info;
10914
10915   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10916
10917   info = _clutter_actor_get_transform_info_or_defaults (self);
10918
10919   return clutter_anchor_coord_get_gravity (&info->rz_center);
10920 }
10921
10922 /**
10923  * clutter_actor_set_clip:
10924  * @self: A #ClutterActor
10925  * @xoff: X offset of the clip rectangle
10926  * @yoff: Y offset of the clip rectangle
10927  * @width: Width of the clip rectangle
10928  * @height: Height of the clip rectangle
10929  *
10930  * Sets clip area for @self. The clip area is always computed from the
10931  * upper left corner of the actor, even if the anchor point is set
10932  * otherwise.
10933  *
10934  * Since: 0.6
10935  */
10936 void
10937 clutter_actor_set_clip (ClutterActor *self,
10938                         gfloat        xoff,
10939                         gfloat        yoff,
10940                         gfloat        width,
10941                         gfloat        height)
10942 {
10943   ClutterActorPrivate *priv;
10944
10945   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10946
10947   priv = self->priv;
10948
10949   if (priv->has_clip &&
10950       priv->clip.x == xoff &&
10951       priv->clip.y == yoff &&
10952       priv->clip.width == width &&
10953       priv->clip.height == height)
10954     return;
10955
10956   priv->clip.x = xoff;
10957   priv->clip.y = yoff;
10958   priv->clip.width = width;
10959   priv->clip.height = height;
10960
10961   priv->has_clip = TRUE;
10962
10963   clutter_actor_queue_redraw (self);
10964
10965   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10966   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10967 }
10968
10969 /**
10970  * clutter_actor_remove_clip:
10971  * @self: A #ClutterActor
10972  *
10973  * Removes clip area from @self.
10974  */
10975 void
10976 clutter_actor_remove_clip (ClutterActor *self)
10977 {
10978   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10979
10980   if (!self->priv->has_clip)
10981     return;
10982
10983   self->priv->has_clip = FALSE;
10984
10985   clutter_actor_queue_redraw (self);
10986
10987   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10988 }
10989
10990 /**
10991  * clutter_actor_has_clip:
10992  * @self: a #ClutterActor
10993  *
10994  * Determines whether the actor has a clip area set or not.
10995  *
10996  * Return value: %TRUE if the actor has a clip area set.
10997  *
10998  * Since: 0.1.1
10999  */
11000 gboolean
11001 clutter_actor_has_clip (ClutterActor *self)
11002 {
11003   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11004
11005   return self->priv->has_clip;
11006 }
11007
11008 /**
11009  * clutter_actor_get_clip:
11010  * @self: a #ClutterActor
11011  * @xoff: (out) (allow-none): return location for the X offset of
11012  *   the clip rectangle, or %NULL
11013  * @yoff: (out) (allow-none): return location for the Y offset of
11014  *   the clip rectangle, or %NULL
11015  * @width: (out) (allow-none): return location for the width of
11016  *   the clip rectangle, or %NULL
11017  * @height: (out) (allow-none): return location for the height of
11018  *   the clip rectangle, or %NULL
11019  *
11020  * Gets the clip area for @self, if any is set
11021  *
11022  * Since: 0.6
11023  */
11024 void
11025 clutter_actor_get_clip (ClutterActor *self,
11026                         gfloat       *xoff,
11027                         gfloat       *yoff,
11028                         gfloat       *width,
11029                         gfloat       *height)
11030 {
11031   ClutterActorPrivate *priv;
11032
11033   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11034
11035   priv = self->priv;
11036
11037   if (!priv->has_clip)
11038     return;
11039
11040   if (xoff != NULL)
11041     *xoff = priv->clip.x;
11042
11043   if (yoff != NULL)
11044     *yoff = priv->clip.y;
11045
11046   if (width != NULL)
11047     *width = priv->clip.width;
11048
11049   if (height != NULL)
11050     *height = priv->clip.height;
11051 }
11052
11053 /**
11054  * clutter_actor_get_children:
11055  * @self: a #ClutterActor
11056  *
11057  * Retrieves the list of children of @self.
11058  *
11059  * Return value: (transfer container) (element-type ClutterActor): A newly
11060  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
11061  *   done.
11062  *
11063  * Since: 1.10
11064  */
11065 GList *
11066 clutter_actor_get_children (ClutterActor *self)
11067 {
11068   ClutterActor *iter;
11069   GList *res;
11070
11071   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11072
11073   /* we walk the list backward so that we can use prepend(),
11074    * which is O(1)
11075    */
11076   for (iter = self->priv->last_child, res = NULL;
11077        iter != NULL;
11078        iter = iter->priv->prev_sibling)
11079     {
11080       res = g_list_prepend (res, iter);
11081     }
11082
11083   return res;
11084 }
11085
11086 /*< private >
11087  * insert_child_at_depth:
11088  * @self: a #ClutterActor
11089  * @child: a #ClutterActor
11090  *
11091  * Inserts @child inside the list of children held by @self, using
11092  * the depth as the insertion criteria.
11093  *
11094  * This sadly makes the insertion not O(1), but we can keep the
11095  * list sorted so that the painters algorithm we use for painting
11096  * the children will work correctly.
11097  */
11098 static void
11099 insert_child_at_depth (ClutterActor *self,
11100                        ClutterActor *child,
11101                        gpointer      dummy G_GNUC_UNUSED)
11102 {
11103   ClutterActor *iter;
11104   float child_depth;
11105
11106   child->priv->parent = self;
11107
11108   child_depth =
11109     _clutter_actor_get_transform_info_or_defaults (child)->depth;
11110
11111   /* special-case the first child */
11112   if (self->priv->n_children == 0)
11113     {
11114       self->priv->first_child = child;
11115       self->priv->last_child = child;
11116
11117       child->priv->next_sibling = NULL;
11118       child->priv->prev_sibling = NULL;
11119
11120       return;
11121     }
11122
11123   /* Find the right place to insert the child so that it will still be
11124      sorted and the child will be after all of the actors at the same
11125      dept */
11126   for (iter = self->priv->first_child;
11127        iter != NULL;
11128        iter = iter->priv->next_sibling)
11129     {
11130       float iter_depth;
11131
11132       iter_depth =
11133         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11134
11135       if (iter_depth > child_depth)
11136         break;
11137     }
11138
11139   if (iter != NULL)
11140     {
11141       ClutterActor *tmp = iter->priv->prev_sibling;
11142
11143       if (tmp != NULL)
11144         tmp->priv->next_sibling = child;
11145
11146       /* Insert the node before the found one */
11147       child->priv->prev_sibling = iter->priv->prev_sibling;
11148       child->priv->next_sibling = iter;
11149       iter->priv->prev_sibling = child;
11150     }
11151   else
11152     {
11153       ClutterActor *tmp = self->priv->last_child;
11154
11155       if (tmp != NULL)
11156         tmp->priv->next_sibling = child;
11157
11158       /* insert the node at the end of the list */
11159       child->priv->prev_sibling = self->priv->last_child;
11160       child->priv->next_sibling = NULL;
11161     }
11162
11163   if (child->priv->prev_sibling == NULL)
11164     self->priv->first_child = child;
11165
11166   if (child->priv->next_sibling == NULL)
11167     self->priv->last_child = child;
11168 }
11169
11170 static void
11171 insert_child_at_index (ClutterActor *self,
11172                        ClutterActor *child,
11173                        gpointer      data_)
11174 {
11175   gint index_ = GPOINTER_TO_INT (data_);
11176
11177   child->priv->parent = self;
11178
11179   if (index_ == 0)
11180     {
11181       ClutterActor *tmp = self->priv->first_child;
11182
11183       if (tmp != NULL)
11184         tmp->priv->prev_sibling = child;
11185
11186       child->priv->prev_sibling = NULL;
11187       child->priv->next_sibling = tmp;
11188     }
11189   else if (index_ < 0 || index_ >= self->priv->n_children)
11190     {
11191       ClutterActor *tmp = self->priv->last_child;
11192
11193       if (tmp != NULL)
11194         tmp->priv->next_sibling = child;
11195
11196       child->priv->prev_sibling = tmp;
11197       child->priv->next_sibling = NULL;
11198     }
11199   else
11200     {
11201       ClutterActor *iter;
11202       int i;
11203
11204       for (iter = self->priv->first_child, i = 0;
11205            iter != NULL;
11206            iter = iter->priv->next_sibling, i += 1)
11207         {
11208           if (index_ == i)
11209             {
11210               ClutterActor *tmp = iter->priv->prev_sibling;
11211
11212               child->priv->prev_sibling = tmp;
11213               child->priv->next_sibling = iter;
11214
11215               iter->priv->prev_sibling = child;
11216
11217               if (tmp != NULL)
11218                 tmp->priv->next_sibling = child;
11219
11220               break;
11221             }
11222         }
11223     }
11224
11225   if (child->priv->prev_sibling == NULL)
11226     self->priv->first_child = child;
11227
11228   if (child->priv->next_sibling == NULL)
11229     self->priv->last_child = child;
11230 }
11231
11232 static void
11233 insert_child_above (ClutterActor *self,
11234                     ClutterActor *child,
11235                     gpointer      data)
11236 {
11237   ClutterActor *sibling = data;
11238
11239   child->priv->parent = self;
11240
11241   if (sibling == NULL)
11242     sibling = self->priv->last_child;
11243
11244   child->priv->prev_sibling = sibling;
11245
11246   if (sibling != NULL)
11247     {
11248       ClutterActor *tmp = sibling->priv->next_sibling;
11249
11250       child->priv->next_sibling = tmp;
11251
11252       if (tmp != NULL)
11253         tmp->priv->prev_sibling = child;
11254
11255       sibling->priv->next_sibling = child;
11256     }
11257   else
11258     child->priv->next_sibling = NULL;
11259
11260   if (child->priv->prev_sibling == NULL)
11261     self->priv->first_child = child;
11262
11263   if (child->priv->next_sibling == NULL)
11264     self->priv->last_child = child;
11265 }
11266
11267 static void
11268 insert_child_below (ClutterActor *self,
11269                     ClutterActor *child,
11270                     gpointer      data)
11271 {
11272   ClutterActor *sibling = data;
11273
11274   child->priv->parent = self;
11275
11276   if (sibling == NULL)
11277     sibling = self->priv->first_child;
11278
11279   child->priv->next_sibling = sibling;
11280
11281   if (sibling != NULL)
11282     {
11283       ClutterActor *tmp = sibling->priv->prev_sibling;
11284
11285       child->priv->prev_sibling = tmp;
11286
11287       if (tmp != NULL)
11288         tmp->priv->next_sibling = child;
11289
11290       sibling->priv->prev_sibling = child;
11291     }
11292   else
11293     child->priv->prev_sibling = NULL;
11294
11295   if (child->priv->prev_sibling == NULL)
11296     self->priv->first_child = child;
11297
11298   if (child->priv->next_sibling == NULL)
11299     self->priv->last_child = child;
11300 }
11301
11302 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11303                                            ClutterActor *child,
11304                                            gpointer      data);
11305
11306 typedef enum {
11307   ADD_CHILD_CREATE_META        = 1 << 0,
11308   ADD_CHILD_EMIT_PARENT_SET    = 1 << 1,
11309   ADD_CHILD_EMIT_ACTOR_ADDED   = 1 << 2,
11310   ADD_CHILD_CHECK_STATE        = 1 << 3,
11311   ADD_CHILD_NOTIFY_FIRST_LAST  = 1 << 4,
11312   ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11313
11314   /* default flags for public API */
11315   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
11316                                ADD_CHILD_EMIT_PARENT_SET |
11317                                ADD_CHILD_EMIT_ACTOR_ADDED |
11318                                ADD_CHILD_CHECK_STATE |
11319                                ADD_CHILD_NOTIFY_FIRST_LAST |
11320                                ADD_CHILD_SHOW_ON_SET_PARENT,
11321
11322   /* flags for legacy/deprecated API */
11323   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
11324                                ADD_CHILD_CHECK_STATE |
11325                                ADD_CHILD_NOTIFY_FIRST_LAST |
11326                                ADD_CHILD_SHOW_ON_SET_PARENT
11327 } ClutterActorAddChildFlags;
11328
11329 /*< private >
11330  * clutter_actor_add_child_internal:
11331  * @self: a #ClutterActor
11332  * @child: a #ClutterActor
11333  * @flags: control flags for actions
11334  * @add_func: delegate function
11335  * @data: (closure): data to pass to @add_func
11336  *
11337  * Adds @child to the list of children of @self.
11338  *
11339  * The actual insertion inside the list is delegated to @add_func: this
11340  * function will just set up the state, perform basic checks, and emit
11341  * signals.
11342  *
11343  * The @flags argument is used to perform additional operations.
11344  */
11345 static inline void
11346 clutter_actor_add_child_internal (ClutterActor              *self,
11347                                   ClutterActor              *child,
11348                                   ClutterActorAddChildFlags  flags,
11349                                   ClutterActorAddChildFunc   add_func,
11350                                   gpointer                   data)
11351 {
11352   ClutterTextDirection text_dir;
11353   gboolean create_meta;
11354   gboolean emit_parent_set, emit_actor_added;
11355   gboolean check_state;
11356   gboolean notify_first_last;
11357   gboolean show_on_set_parent;
11358   ClutterActor *old_first_child, *old_last_child;
11359
11360   if (child->priv->parent != NULL)
11361     {
11362       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11363                  "use clutter_actor_remove_child() first.",
11364                  _clutter_actor_get_debug_name (child),
11365                  _clutter_actor_get_debug_name (child->priv->parent));
11366       return;
11367     }
11368
11369   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11370     {
11371       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11372                  "a child of another actor.",
11373                  _clutter_actor_get_debug_name (child));
11374       return;
11375     }
11376
11377 #if 0
11378   /* XXX - this check disallows calling methods that change the stacking
11379    * order within the destruction sequence, by triggering a critical
11380    * warning first, and leaving the actor in an undefined state, which
11381    * then ends up being caught by an assertion.
11382    *
11383    * the reproducible sequence is:
11384    *
11385    *   - actor gets destroyed;
11386    *   - another actor, linked to the first, will try to change the
11387    *     stacking order of the first actor;
11388    *   - changing the stacking order is a composite operation composed
11389    *     by the following steps:
11390    *     1. ref() the child;
11391    *     2. remove_child_internal(), which removes the reference;
11392    *     3. add_child_internal(), which adds a reference;
11393    *   - the state of the actor is not changed between (2) and (3), as
11394    *     it could be an expensive recomputation;
11395    *   - if (3) bails out, then the actor is in an undefined state, but
11396    *     still alive;
11397    *   - the destruction sequence terminates, but the actor is unparented
11398    *     while its state indicates being parented instead.
11399    *   - assertion failure.
11400    *
11401    * the obvious fix would be to decompose each set_child_*_sibling()
11402    * method into proper remove_child()/add_child(), with state validation;
11403    * this may cause excessive work, though, and trigger a cascade of other
11404    * bugs in code that assumes that a change in the stacking order is an
11405    * atomic operation.
11406    *
11407    * another potential fix is to just remove this check here, and let
11408    * code doing stacking order changes inside the destruction sequence
11409    * of an actor continue doing the work.
11410    *
11411    * the third fix is to silently bail out early from every
11412    * set_child_*_sibling() and set_child_at_index() method, and avoid
11413    * doing work.
11414    *
11415    * I have a preference for the second solution, since it involves the
11416    * least amount of work, and the least amount of code duplication.
11417    *
11418    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11419    */
11420   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11421     {
11422       g_warning ("The actor '%s' is currently being destroyed, and "
11423                  "cannot be added as a child of another actor.",
11424                  _clutter_actor_get_debug_name (child));
11425       return;
11426     }
11427 #endif
11428
11429   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11430   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11431   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11432   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11433   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11434   show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11435
11436   old_first_child = self->priv->first_child;
11437   old_last_child = self->priv->last_child;
11438
11439   g_object_freeze_notify (G_OBJECT (self));
11440
11441   if (create_meta)
11442     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11443
11444   g_object_ref_sink (child);
11445   child->priv->parent = NULL;
11446   child->priv->next_sibling = NULL;
11447   child->priv->prev_sibling = NULL;
11448
11449   /* delegate the actual insertion */
11450   add_func (self, child, data);
11451
11452   g_assert (child->priv->parent == self);
11453
11454   self->priv->n_children += 1;
11455
11456   self->priv->age += 1;
11457
11458   /* if push_internal() has been called then we automatically set
11459    * the flag on the actor
11460    */
11461   if (self->priv->internal_child)
11462     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11463
11464   /* children may cause their parent to expand, if they are set
11465    * to expand; if a child is not expanded then it cannot change
11466    * its parent's state. any further change later on will queue
11467    * an expand state check.
11468    *
11469    * this check, with the initial state of the needs_compute_expand
11470    * flag set to FALSE, should avoid recomputing the expand flags
11471    * state while building the actor tree.
11472    */
11473   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11474       (child->priv->needs_compute_expand ||
11475        child->priv->needs_x_expand ||
11476        child->priv->needs_y_expand))
11477     {
11478       clutter_actor_queue_compute_expand (self);
11479     }
11480
11481   /* clutter_actor_reparent() will emit ::parent-set for us */
11482   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11483     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11484
11485   if (check_state)
11486     {
11487       /* If parent is mapped or realized, we need to also be mapped or
11488        * realized once we're inside the parent.
11489        */
11490       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11491
11492       /* propagate the parent's text direction to the child */
11493       text_dir = clutter_actor_get_text_direction (self);
11494       clutter_actor_set_text_direction (child, text_dir);
11495     }
11496
11497   if (show_on_set_parent && child->priv->show_on_set_parent)
11498     clutter_actor_show (child);
11499
11500   if (CLUTTER_ACTOR_IS_MAPPED (child))
11501     clutter_actor_queue_redraw (child);
11502
11503   /* maintain the invariant that if an actor needs layout,
11504    * its parents do as well
11505    */
11506   if (child->priv->needs_width_request ||
11507       child->priv->needs_height_request ||
11508       child->priv->needs_allocation)
11509     {
11510       /* we work around the short-circuiting we do
11511        * in clutter_actor_queue_relayout() since we
11512        * want to force a relayout
11513        */
11514       child->priv->needs_width_request = TRUE;
11515       child->priv->needs_height_request = TRUE;
11516       child->priv->needs_allocation = TRUE;
11517
11518       clutter_actor_queue_relayout (child->priv->parent);
11519     }
11520
11521   if (emit_actor_added)
11522     g_signal_emit_by_name (self, "actor-added", child);
11523
11524   if (notify_first_last)
11525     {
11526       if (old_first_child != self->priv->first_child)
11527         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11528
11529       if (old_last_child != self->priv->last_child)
11530         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11531     }
11532
11533   g_object_thaw_notify (G_OBJECT (self));
11534 }
11535
11536 /**
11537  * clutter_actor_add_child:
11538  * @self: a #ClutterActor
11539  * @child: a #ClutterActor
11540  *
11541  * Adds @child to the children of @self.
11542  *
11543  * This function will acquire a reference on @child that will only
11544  * be released when calling clutter_actor_remove_child().
11545  *
11546  * This function will take into consideration the #ClutterActor:depth
11547  * of @child, and will keep the list of children sorted.
11548  *
11549  * This function will emit the #ClutterContainer::actor-added signal
11550  * on @self.
11551  *
11552  * Since: 1.10
11553  */
11554 void
11555 clutter_actor_add_child (ClutterActor *self,
11556                          ClutterActor *child)
11557 {
11558   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11559   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11560   g_return_if_fail (self != child);
11561   g_return_if_fail (child->priv->parent == NULL);
11562
11563   clutter_actor_add_child_internal (self, child,
11564                                     ADD_CHILD_DEFAULT_FLAGS,
11565                                     insert_child_at_depth,
11566                                     NULL);
11567 }
11568
11569 /**
11570  * clutter_actor_insert_child_at_index:
11571  * @self: a #ClutterActor
11572  * @child: a #ClutterActor
11573  * @index_: the index
11574  *
11575  * Inserts @child into the list of children of @self, using the
11576  * given @index_. If @index_ is greater than the number of children
11577  * in @self, or is less than 0, then the new child is added at the end.
11578  *
11579  * This function will acquire a reference on @child that will only
11580  * be released when calling clutter_actor_remove_child().
11581  *
11582  * This function will not take into consideration the #ClutterActor:depth
11583  * of @child.
11584  *
11585  * This function will emit the #ClutterContainer::actor-added signal
11586  * on @self.
11587  *
11588  * Since: 1.10
11589  */
11590 void
11591 clutter_actor_insert_child_at_index (ClutterActor *self,
11592                                      ClutterActor *child,
11593                                      gint          index_)
11594 {
11595   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11596   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11597   g_return_if_fail (self != child);
11598   g_return_if_fail (child->priv->parent == NULL);
11599
11600   clutter_actor_add_child_internal (self, child,
11601                                     ADD_CHILD_DEFAULT_FLAGS,
11602                                     insert_child_at_index,
11603                                     GINT_TO_POINTER (index_));
11604 }
11605
11606 /**
11607  * clutter_actor_insert_child_above:
11608  * @self: a #ClutterActor
11609  * @child: a #ClutterActor
11610  * @sibling: (allow-none): a child of @self, or %NULL
11611  *
11612  * Inserts @child into the list of children of @self, above another
11613  * child of @self or, if @sibling is %NULL, above all the children
11614  * of @self.
11615  *
11616  * This function will acquire a reference on @child that will only
11617  * be released when calling clutter_actor_remove_child().
11618  *
11619  * This function will not take into consideration the #ClutterActor:depth
11620  * of @child.
11621  *
11622  * This function will emit the #ClutterContainer::actor-added signal
11623  * on @self.
11624  *
11625  * Since: 1.10
11626  */
11627 void
11628 clutter_actor_insert_child_above (ClutterActor *self,
11629                                   ClutterActor *child,
11630                                   ClutterActor *sibling)
11631 {
11632   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11633   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11634   g_return_if_fail (self != child);
11635   g_return_if_fail (child != sibling);
11636   g_return_if_fail (child->priv->parent == NULL);
11637   g_return_if_fail (sibling == NULL ||
11638                     (CLUTTER_IS_ACTOR (sibling) &&
11639                      sibling->priv->parent == self));
11640
11641   clutter_actor_add_child_internal (self, child,
11642                                     ADD_CHILD_DEFAULT_FLAGS,
11643                                     insert_child_above,
11644                                     sibling);
11645 }
11646
11647 /**
11648  * clutter_actor_insert_child_below:
11649  * @self: a #ClutterActor
11650  * @child: a #ClutterActor
11651  * @sibling: (allow-none): a child of @self, or %NULL
11652  *
11653  * Inserts @child into the list of children of @self, below another
11654  * child of @self or, if @sibling is %NULL, below all the children
11655  * of @self.
11656  *
11657  * This function will acquire a reference on @child that will only
11658  * be released when calling clutter_actor_remove_child().
11659  *
11660  * This function will not take into consideration the #ClutterActor:depth
11661  * of @child.
11662  *
11663  * This function will emit the #ClutterContainer::actor-added signal
11664  * on @self.
11665  *
11666  * Since: 1.10
11667  */
11668 void
11669 clutter_actor_insert_child_below (ClutterActor *self,
11670                                   ClutterActor *child,
11671                                   ClutterActor *sibling)
11672 {
11673   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11674   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11675   g_return_if_fail (self != child);
11676   g_return_if_fail (child != sibling);
11677   g_return_if_fail (child->priv->parent == NULL);
11678   g_return_if_fail (sibling == NULL ||
11679                     (CLUTTER_IS_ACTOR (sibling) &&
11680                      sibling->priv->parent == self));
11681
11682   clutter_actor_add_child_internal (self, child,
11683                                     ADD_CHILD_DEFAULT_FLAGS,
11684                                     insert_child_below,
11685                                     sibling);
11686 }
11687
11688 /**
11689  * clutter_actor_set_parent:
11690  * @self: A #ClutterActor
11691  * @parent: A new #ClutterActor parent
11692  *
11693  * Sets the parent of @self to @parent.
11694  *
11695  * This function will result in @parent acquiring a reference on @self,
11696  * eventually by sinking its floating reference first. The reference
11697  * will be released by clutter_actor_unparent().
11698  *
11699  * This function should only be called by legacy #ClutterActor<!-- -->s
11700  * implementing the #ClutterContainer interface.
11701  *
11702  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11703  */
11704 void
11705 clutter_actor_set_parent (ClutterActor *self,
11706                           ClutterActor *parent)
11707 {
11708   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11709   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11710   g_return_if_fail (self != parent);
11711   g_return_if_fail (self->priv->parent == NULL);
11712
11713   /* as this function will be called inside ClutterContainer::add
11714    * implementations or when building up a composite actor, we have
11715    * to preserve the old behaviour, and not create child meta or
11716    * emit the ::actor-added signal, to avoid recursion or double
11717    * emissions
11718    */
11719   clutter_actor_add_child_internal (parent, self,
11720                                     ADD_CHILD_LEGACY_FLAGS,
11721                                     insert_child_at_depth,
11722                                     NULL);
11723 }
11724
11725 /**
11726  * clutter_actor_get_parent:
11727  * @self: A #ClutterActor
11728  *
11729  * Retrieves the parent of @self.
11730  *
11731  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11732  *  if no parent is set
11733  */
11734 ClutterActor *
11735 clutter_actor_get_parent (ClutterActor *self)
11736 {
11737   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11738
11739   return self->priv->parent;
11740 }
11741
11742 /**
11743  * clutter_actor_get_paint_visibility:
11744  * @self: A #ClutterActor
11745  *
11746  * Retrieves the 'paint' visibility of an actor recursively checking for non
11747  * visible parents.
11748  *
11749  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11750  *
11751  * Return Value: %TRUE if the actor is visibile and will be painted.
11752  *
11753  * Since: 0.8.4
11754  */
11755 gboolean
11756 clutter_actor_get_paint_visibility (ClutterActor *actor)
11757 {
11758   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11759
11760   return CLUTTER_ACTOR_IS_MAPPED (actor);
11761 }
11762
11763 /**
11764  * clutter_actor_remove_child:
11765  * @self: a #ClutterActor
11766  * @child: a #ClutterActor
11767  *
11768  * Removes @child from the children of @self.
11769  *
11770  * This function will release the reference added by
11771  * clutter_actor_add_child(), so if you want to keep using @child
11772  * you will have to acquire a referenced on it before calling this
11773  * function.
11774  *
11775  * This function will emit the #ClutterContainer::actor-removed
11776  * signal on @self.
11777  *
11778  * Since: 1.10
11779  */
11780 void
11781 clutter_actor_remove_child (ClutterActor *self,
11782                             ClutterActor *child)
11783 {
11784   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11785   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11786   g_return_if_fail (self != child);
11787   g_return_if_fail (child->priv->parent != NULL);
11788   g_return_if_fail (child->priv->parent == self);
11789
11790   clutter_actor_remove_child_internal (self, child,
11791                                        REMOVE_CHILD_DEFAULT_FLAGS);
11792 }
11793
11794 /**
11795  * clutter_actor_remove_all_children:
11796  * @self: a #ClutterActor
11797  *
11798  * Removes all children of @self.
11799  *
11800  * This function releases the reference added by inserting a child actor
11801  * in the list of children of @self.
11802  *
11803  * If the reference count of a child drops to zero, the child will be
11804  * destroyed. If you want to ensure the destruction of all the children
11805  * of @self, use clutter_actor_destroy_all_children().
11806  *
11807  * Since: 1.10
11808  */
11809 void
11810 clutter_actor_remove_all_children (ClutterActor *self)
11811 {
11812   ClutterActorIter iter;
11813
11814   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11815
11816   if (self->priv->n_children == 0)
11817     return;
11818
11819   g_object_freeze_notify (G_OBJECT (self));
11820
11821   clutter_actor_iter_init (&iter, self);
11822   while (clutter_actor_iter_next (&iter, NULL))
11823     clutter_actor_iter_remove (&iter);
11824
11825   g_object_thaw_notify (G_OBJECT (self));
11826
11827   /* sanity check */
11828   g_assert (self->priv->first_child == NULL);
11829   g_assert (self->priv->last_child == NULL);
11830   g_assert (self->priv->n_children == 0);
11831 }
11832
11833 /**
11834  * clutter_actor_destroy_all_children:
11835  * @self: a #ClutterActor
11836  *
11837  * Destroys all children of @self.
11838  *
11839  * This function releases the reference added by inserting a child
11840  * actor in the list of children of @self, and ensures that the
11841  * #ClutterActor::destroy signal is emitted on each child of the
11842  * actor.
11843  *
11844  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11845  * when its reference count drops to 0; the default handler of the
11846  * #ClutterActor::destroy signal will destroy all the children of an
11847  * actor. This function ensures that all children are destroyed, instead
11848  * of just removed from @self, unlike clutter_actor_remove_all_children()
11849  * which will merely release the reference and remove each child.
11850  *
11851  * Unless you acquired an additional reference on each child of @self
11852  * prior to calling clutter_actor_remove_all_children() and want to reuse
11853  * the actors, you should use clutter_actor_destroy_all_children() in
11854  * order to make sure that children are destroyed and signal handlers
11855  * are disconnected even in cases where circular references prevent this
11856  * from automatically happening through reference counting alone.
11857  *
11858  * Since: 1.10
11859  */
11860 void
11861 clutter_actor_destroy_all_children (ClutterActor *self)
11862 {
11863   ClutterActorIter iter;
11864
11865   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11866
11867   if (self->priv->n_children == 0)
11868     return;
11869
11870   g_object_freeze_notify (G_OBJECT (self));
11871
11872   clutter_actor_iter_init (&iter, self);
11873   while (clutter_actor_iter_next (&iter, NULL))
11874     clutter_actor_iter_destroy (&iter);
11875
11876   g_object_thaw_notify (G_OBJECT (self));
11877
11878   /* sanity check */
11879   g_assert (self->priv->first_child == NULL);
11880   g_assert (self->priv->last_child == NULL);
11881   g_assert (self->priv->n_children == 0);
11882 }
11883
11884 typedef struct _InsertBetweenData {
11885   ClutterActor *prev_sibling;
11886   ClutterActor *next_sibling;
11887 } InsertBetweenData;
11888
11889 static void
11890 insert_child_between (ClutterActor *self,
11891                       ClutterActor *child,
11892                       gpointer      data_)
11893 {
11894   InsertBetweenData *data = data_;
11895   ClutterActor *prev_sibling = data->prev_sibling;
11896   ClutterActor *next_sibling = data->next_sibling;
11897
11898   child->priv->parent = self;
11899   child->priv->prev_sibling = prev_sibling;
11900   child->priv->next_sibling = next_sibling;
11901
11902   if (prev_sibling != NULL)
11903     prev_sibling->priv->next_sibling = child;
11904
11905   if (next_sibling != NULL)
11906     next_sibling->priv->prev_sibling = child;
11907
11908   if (child->priv->prev_sibling == NULL)
11909     self->priv->first_child = child;
11910
11911   if (child->priv->next_sibling == NULL)
11912     self->priv->last_child = child;
11913 }
11914
11915 /**
11916  * clutter_actor_replace_child:
11917  * @self: a #ClutterActor
11918  * @old_child: the child of @self to replace
11919  * @new_child: the #ClutterActor to replace @old_child
11920  *
11921  * Replaces @old_child with @new_child in the list of children of @self.
11922  *
11923  * Since: 1.10
11924  */
11925 void
11926 clutter_actor_replace_child (ClutterActor *self,
11927                              ClutterActor *old_child,
11928                              ClutterActor *new_child)
11929 {
11930   ClutterActor *prev_sibling, *next_sibling;
11931   InsertBetweenData clos;
11932
11933   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11934   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11935   g_return_if_fail (old_child->priv->parent == self);
11936   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11937   g_return_if_fail (old_child != new_child);
11938   g_return_if_fail (new_child != self);
11939   g_return_if_fail (new_child->priv->parent == NULL);
11940
11941   prev_sibling = old_child->priv->prev_sibling;
11942   next_sibling = old_child->priv->next_sibling;
11943   clutter_actor_remove_child_internal (self, old_child,
11944                                        REMOVE_CHILD_DEFAULT_FLAGS);
11945
11946   clos.prev_sibling = prev_sibling;
11947   clos.next_sibling = next_sibling;
11948   clutter_actor_add_child_internal (self, new_child,
11949                                     ADD_CHILD_DEFAULT_FLAGS,
11950                                     insert_child_between,
11951                                     &clos);
11952 }
11953
11954 /**
11955  * clutter_actor_unparent:
11956  * @self: a #ClutterActor
11957  *
11958  * Removes the parent of @self.
11959  *
11960  * This will cause the parent of @self to release the reference
11961  * acquired when calling clutter_actor_set_parent(), so if you
11962  * want to keep @self you will have to acquire a reference of
11963  * your own, through g_object_ref().
11964  *
11965  * This function should only be called by legacy #ClutterActor<!-- -->s
11966  * implementing the #ClutterContainer interface.
11967  *
11968  * Since: 0.1.1
11969  *
11970  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11971  */
11972 void
11973 clutter_actor_unparent (ClutterActor *self)
11974 {
11975   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11976
11977   if (self->priv->parent == NULL)
11978     return;
11979
11980   clutter_actor_remove_child_internal (self->priv->parent, self,
11981                                        REMOVE_CHILD_LEGACY_FLAGS);
11982 }
11983
11984 /**
11985  * clutter_actor_reparent:
11986  * @self: a #ClutterActor
11987  * @new_parent: the new #ClutterActor parent
11988  *
11989  * Resets the parent actor of @self.
11990  *
11991  * This function is logically equivalent to calling clutter_actor_unparent()
11992  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11993  * ensures the child is not finalized when unparented, and emits the
11994  * #ClutterActor::parent-set signal only once.
11995  *
11996  * In reality, calling this function is less useful than it sounds, as some
11997  * application code may rely on changes in the intermediate state between
11998  * removal and addition of the actor from its old parent to the @new_parent.
11999  * Thus, it is strongly encouraged to avoid using this function in application
12000  * code.
12001  *
12002  * Since: 0.2
12003  *
12004  * Deprecated: 1.10: Use clutter_actor_remove_child() and
12005  *   clutter_actor_add_child() instead; remember to take a reference on
12006  *   the actor being removed before calling clutter_actor_remove_child()
12007  *   to avoid the reference count dropping to zero and the actor being
12008  *   destroyed.
12009  */
12010 void
12011 clutter_actor_reparent (ClutterActor *self,
12012                         ClutterActor *new_parent)
12013 {
12014   ClutterActorPrivate *priv;
12015
12016   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12017   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
12018   g_return_if_fail (self != new_parent);
12019
12020   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
12021     {
12022       g_warning ("Cannot set a parent on a toplevel actor");
12023       return;
12024     }
12025
12026   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
12027     {
12028       g_warning ("Cannot set a parent currently being destroyed");
12029       return;
12030     }
12031
12032   priv = self->priv;
12033
12034   if (priv->parent != new_parent)
12035     {
12036       ClutterActor *old_parent;
12037
12038       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12039
12040       old_parent = priv->parent;
12041
12042       g_object_ref (self);
12043
12044       if (old_parent != NULL)
12045         {
12046          /* go through the Container implementation if this is a regular
12047           * child and not an internal one
12048           */
12049          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12050            {
12051              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
12052
12053              /* this will have to call unparent() */
12054              clutter_container_remove_actor (parent, self);
12055            }
12056          else
12057            clutter_actor_remove_child_internal (old_parent, self,
12058                                                 REMOVE_CHILD_LEGACY_FLAGS);
12059         }
12060
12061       /* Note, will call set_parent() */
12062       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12063         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
12064       else
12065         clutter_actor_add_child_internal (new_parent, self,
12066                                           ADD_CHILD_LEGACY_FLAGS,
12067                                           insert_child_at_depth,
12068                                           NULL);
12069
12070       /* we emit the ::parent-set signal once */
12071       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
12072
12073       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12074
12075       /* the IN_REPARENT flag suspends state updates */
12076       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
12077
12078       g_object_unref (self);
12079    }
12080 }
12081
12082 /**
12083  * clutter_actor_contains:
12084  * @self: A #ClutterActor
12085  * @descendant: A #ClutterActor, possibly contained in @self
12086  *
12087  * Determines if @descendant is contained inside @self (either as an
12088  * immediate child, or as a deeper descendant). If @self and
12089  * @descendant point to the same actor then it will also return %TRUE.
12090  *
12091  * Return value: whether @descendent is contained within @self
12092  *
12093  * Since: 1.4
12094  */
12095 gboolean
12096 clutter_actor_contains (ClutterActor *self,
12097                         ClutterActor *descendant)
12098 {
12099   ClutterActor *actor;
12100
12101   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12102   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12103
12104   for (actor = descendant; actor; actor = actor->priv->parent)
12105     if (actor == self)
12106       return TRUE;
12107
12108   return FALSE;
12109 }
12110
12111 /**
12112  * clutter_actor_set_child_above_sibling:
12113  * @self: a #ClutterActor
12114  * @child: a #ClutterActor child of @self
12115  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12116  *
12117  * Sets @child to be above @sibling in the list of children of @self.
12118  *
12119  * If @sibling is %NULL, @child will be the new last child of @self.
12120  *
12121  * This function is logically equivalent to removing @child and using
12122  * clutter_actor_insert_child_above(), but it will not emit signals
12123  * or change state on @child.
12124  *
12125  * Since: 1.10
12126  */
12127 void
12128 clutter_actor_set_child_above_sibling (ClutterActor *self,
12129                                        ClutterActor *child,
12130                                        ClutterActor *sibling)
12131 {
12132   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12133   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12134   g_return_if_fail (child->priv->parent == self);
12135   g_return_if_fail (child != sibling);
12136   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12137
12138   if (sibling != NULL)
12139     g_return_if_fail (sibling->priv->parent == self);
12140
12141   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12142       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12143       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12144     return;
12145
12146   /* we don't want to change the state of child, or emit signals, or
12147    * regenerate ChildMeta instances here, but we still want to follow
12148    * the correct sequence of steps encoded in remove_child() and
12149    * add_child(), so that correctness is ensured, and we only go
12150    * through one known code path.
12151    */
12152   g_object_ref (child);
12153   clutter_actor_remove_child_internal (self, child, 0);
12154   clutter_actor_add_child_internal (self, child,
12155                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12156                                     insert_child_above,
12157                                     sibling);
12158
12159   clutter_actor_queue_relayout (self);
12160 }
12161
12162 /**
12163  * clutter_actor_set_child_below_sibling:
12164  * @self: a #ClutterActor
12165  * @child: a #ClutterActor child of @self
12166  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12167  *
12168  * Sets @child to be below @sibling in the list of children of @self.
12169  *
12170  * If @sibling is %NULL, @child will be the new first child of @self.
12171  *
12172  * This function is logically equivalent to removing @self and using
12173  * clutter_actor_insert_child_below(), but it will not emit signals
12174  * or change state on @child.
12175  *
12176  * Since: 1.10
12177  */
12178 void
12179 clutter_actor_set_child_below_sibling (ClutterActor *self,
12180                                        ClutterActor *child,
12181                                        ClutterActor *sibling)
12182 {
12183   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12184   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12185   g_return_if_fail (child->priv->parent == self);
12186   g_return_if_fail (child != sibling);
12187   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12188
12189   if (sibling != NULL)
12190     g_return_if_fail (sibling->priv->parent == self);
12191
12192   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12193       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12194       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12195     return;
12196
12197   /* see the comment in set_child_above_sibling() */
12198   g_object_ref (child);
12199   clutter_actor_remove_child_internal (self, child, 0);
12200   clutter_actor_add_child_internal (self, child,
12201                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12202                                     insert_child_below,
12203                                     sibling);
12204
12205   clutter_actor_queue_relayout (self);
12206 }
12207
12208 /**
12209  * clutter_actor_set_child_at_index:
12210  * @self: a #ClutterActor
12211  * @child: a #ClutterActor child of @self
12212  * @index_: the new index for @child
12213  *
12214  * Changes the index of @child in the list of children of @self.
12215  *
12216  * This function is logically equivalent to removing @child and
12217  * calling clutter_actor_insert_child_at_index(), but it will not
12218  * emit signals or change state on @child.
12219  *
12220  * Since: 1.10
12221  */
12222 void
12223 clutter_actor_set_child_at_index (ClutterActor *self,
12224                                   ClutterActor *child,
12225                                   gint          index_)
12226 {
12227   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12228   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12229   g_return_if_fail (child->priv->parent == self);
12230   g_return_if_fail (index_ <= self->priv->n_children);
12231
12232   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12233       CLUTTER_ACTOR_IN_DESTRUCTION (child))
12234     return;
12235
12236   g_object_ref (child);
12237   clutter_actor_remove_child_internal (self, child, 0);
12238   clutter_actor_add_child_internal (self, child,
12239                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12240                                     insert_child_at_index,
12241                                     GINT_TO_POINTER (index_));
12242
12243   clutter_actor_queue_relayout (self);
12244 }
12245
12246 /**
12247  * clutter_actor_raise:
12248  * @self: A #ClutterActor
12249  * @below: (allow-none): A #ClutterActor to raise above.
12250  *
12251  * Puts @self above @below.
12252  *
12253  * Both actors must have the same parent, and the parent must implement
12254  * the #ClutterContainer interface
12255  *
12256  * This function calls clutter_container_raise_child() internally.
12257  *
12258  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12259  */
12260 void
12261 clutter_actor_raise (ClutterActor *self,
12262                      ClutterActor *below)
12263 {
12264   ClutterActor *parent;
12265
12266   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12267
12268   parent = clutter_actor_get_parent (self);
12269   if (parent == NULL)
12270     {
12271       g_warning ("%s: Actor '%s' is not inside a container",
12272                  G_STRFUNC,
12273                  _clutter_actor_get_debug_name (self));
12274       return;
12275     }
12276
12277   if (below != NULL)
12278     {
12279       if (parent != clutter_actor_get_parent (below))
12280         {
12281           g_warning ("%s Actor '%s' is not in the same container as "
12282                      "actor '%s'",
12283                      G_STRFUNC,
12284                      _clutter_actor_get_debug_name (self),
12285                      _clutter_actor_get_debug_name (below));
12286           return;
12287         }
12288     }
12289
12290   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12291 }
12292
12293 /**
12294  * clutter_actor_lower:
12295  * @self: A #ClutterActor
12296  * @above: (allow-none): A #ClutterActor to lower below
12297  *
12298  * Puts @self below @above.
12299  *
12300  * Both actors must have the same parent, and the parent must implement
12301  * the #ClutterContainer interface.
12302  *
12303  * This function calls clutter_container_lower_child() internally.
12304  *
12305  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12306  */
12307 void
12308 clutter_actor_lower (ClutterActor *self,
12309                      ClutterActor *above)
12310 {
12311   ClutterActor *parent;
12312
12313   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12314
12315   parent = clutter_actor_get_parent (self);
12316   if (parent == NULL)
12317     {
12318       g_warning ("%s: Actor of type %s is not inside a container",
12319                  G_STRFUNC,
12320                  _clutter_actor_get_debug_name (self));
12321       return;
12322     }
12323
12324   if (above)
12325     {
12326       if (parent != clutter_actor_get_parent (above))
12327         {
12328           g_warning ("%s: Actor '%s' is not in the same container as "
12329                      "actor '%s'",
12330                      G_STRFUNC,
12331                      _clutter_actor_get_debug_name (self),
12332                      _clutter_actor_get_debug_name (above));
12333           return;
12334         }
12335     }
12336
12337   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12338 }
12339
12340 /**
12341  * clutter_actor_raise_top:
12342  * @self: A #ClutterActor
12343  *
12344  * Raises @self to the top.
12345  *
12346  * This function calls clutter_actor_raise() internally.
12347  *
12348  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12349  *   a %NULL sibling, instead.
12350  */
12351 void
12352 clutter_actor_raise_top (ClutterActor *self)
12353 {
12354   clutter_actor_raise (self, NULL);
12355 }
12356
12357 /**
12358  * clutter_actor_lower_bottom:
12359  * @self: A #ClutterActor
12360  *
12361  * Lowers @self to the bottom.
12362  *
12363  * This function calls clutter_actor_lower() internally.
12364  *
12365  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12366  *   a %NULL sibling, instead.
12367  */
12368 void
12369 clutter_actor_lower_bottom (ClutterActor *self)
12370 {
12371   clutter_actor_lower (self, NULL);
12372 }
12373
12374 /*
12375  * Event handling
12376  */
12377
12378 /**
12379  * clutter_actor_event:
12380  * @actor: a #ClutterActor
12381  * @event: a #ClutterEvent
12382  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12383  *
12384  * This function is used to emit an event on the main stage.
12385  * You should rarely need to use this function, except for
12386  * synthetising events.
12387  *
12388  * Return value: the return value from the signal emission: %TRUE
12389  *   if the actor handled the event, or %FALSE if the event was
12390  *   not handled
12391  *
12392  * Since: 0.6
12393  */
12394 gboolean
12395 clutter_actor_event (ClutterActor *actor,
12396                      ClutterEvent *event,
12397                      gboolean      capture)
12398 {
12399   gboolean retval = FALSE;
12400   gint signal_num = -1;
12401
12402   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12403   g_return_val_if_fail (event != NULL, FALSE);
12404
12405   g_object_ref (actor);
12406
12407   if (capture)
12408     {
12409       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12410                      event,
12411                      &retval);
12412       goto out;
12413     }
12414
12415   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12416
12417   if (!retval)
12418     {
12419       switch (event->type)
12420         {
12421         case CLUTTER_NOTHING:
12422           break;
12423         case CLUTTER_BUTTON_PRESS:
12424           signal_num = BUTTON_PRESS_EVENT;
12425           break;
12426         case CLUTTER_BUTTON_RELEASE:
12427           signal_num = BUTTON_RELEASE_EVENT;
12428           break;
12429         case CLUTTER_SCROLL:
12430           signal_num = SCROLL_EVENT;
12431           break;
12432         case CLUTTER_KEY_PRESS:
12433           signal_num = KEY_PRESS_EVENT;
12434           break;
12435         case CLUTTER_KEY_RELEASE:
12436           signal_num = KEY_RELEASE_EVENT;
12437           break;
12438         case CLUTTER_MOTION:
12439           signal_num = MOTION_EVENT;
12440           break;
12441         case CLUTTER_ENTER:
12442           signal_num = ENTER_EVENT;
12443           break;
12444         case CLUTTER_LEAVE:
12445           signal_num = LEAVE_EVENT;
12446           break;
12447         case CLUTTER_DELETE:
12448         case CLUTTER_DESTROY_NOTIFY:
12449         case CLUTTER_CLIENT_MESSAGE:
12450         default:
12451           signal_num = -1;
12452           break;
12453         }
12454
12455       if (signal_num != -1)
12456         g_signal_emit (actor, actor_signals[signal_num], 0,
12457                        event, &retval);
12458     }
12459
12460 out:
12461   g_object_unref (actor);
12462
12463   return retval;
12464 }
12465
12466 /**
12467  * clutter_actor_set_reactive:
12468  * @actor: a #ClutterActor
12469  * @reactive: whether the actor should be reactive to events
12470  *
12471  * Sets @actor as reactive. Reactive actors will receive events.
12472  *
12473  * Since: 0.6
12474  */
12475 void
12476 clutter_actor_set_reactive (ClutterActor *actor,
12477                             gboolean      reactive)
12478 {
12479   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12480
12481   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12482     return;
12483
12484   if (reactive)
12485     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12486   else
12487     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12488
12489   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12490 }
12491
12492 /**
12493  * clutter_actor_get_reactive:
12494  * @actor: a #ClutterActor
12495  *
12496  * Checks whether @actor is marked as reactive.
12497  *
12498  * Return value: %TRUE if the actor is reactive
12499  *
12500  * Since: 0.6
12501  */
12502 gboolean
12503 clutter_actor_get_reactive (ClutterActor *actor)
12504 {
12505   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12506
12507   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12508 }
12509
12510 /**
12511  * clutter_actor_get_anchor_point:
12512  * @self: a #ClutterActor
12513  * @anchor_x: (out): return location for the X coordinate of the anchor point
12514  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12515  *
12516  * Gets the current anchor point of the @actor in pixels.
12517  *
12518  * Since: 0.6
12519  */
12520 void
12521 clutter_actor_get_anchor_point (ClutterActor *self,
12522                                 gfloat       *anchor_x,
12523                                 gfloat       *anchor_y)
12524 {
12525   const ClutterTransformInfo *info;
12526
12527   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12528
12529   info = _clutter_actor_get_transform_info_or_defaults (self);
12530   clutter_anchor_coord_get_units (self, &info->anchor,
12531                                   anchor_x,
12532                                   anchor_y,
12533                                   NULL);
12534 }
12535
12536 /**
12537  * clutter_actor_set_anchor_point:
12538  * @self: a #ClutterActor
12539  * @anchor_x: X coordinate of the anchor point
12540  * @anchor_y: Y coordinate of the anchor point
12541  *
12542  * Sets an anchor point for @self. The anchor point is a point in the
12543  * coordinate space of an actor to which the actor position within its
12544  * parent is relative; the default is (0, 0), i.e. the top-left corner
12545  * of the actor.
12546  *
12547  * Since: 0.6
12548  */
12549 void
12550 clutter_actor_set_anchor_point (ClutterActor *self,
12551                                 gfloat        anchor_x,
12552                                 gfloat        anchor_y)
12553 {
12554   ClutterTransformInfo *info;
12555   ClutterActorPrivate *priv;
12556   gboolean changed = FALSE;
12557   gfloat old_anchor_x, old_anchor_y;
12558   GObject *obj;
12559
12560   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12561
12562   obj = G_OBJECT (self);
12563   priv = self->priv;
12564   info = _clutter_actor_get_transform_info (self);
12565
12566   g_object_freeze_notify (obj);
12567
12568   clutter_anchor_coord_get_units (self, &info->anchor,
12569                                   &old_anchor_x,
12570                                   &old_anchor_y,
12571                                   NULL);
12572
12573   if (info->anchor.is_fractional)
12574     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12575
12576   if (old_anchor_x != anchor_x)
12577     {
12578       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12579       changed = TRUE;
12580     }
12581
12582   if (old_anchor_y != anchor_y)
12583     {
12584       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12585       changed = TRUE;
12586     }
12587
12588   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12589
12590   if (changed)
12591     {
12592       priv->transform_valid = FALSE;
12593       clutter_actor_queue_redraw (self);
12594     }
12595
12596   g_object_thaw_notify (obj);
12597 }
12598
12599 /**
12600  * clutter_actor_get_anchor_point_gravity:
12601  * @self: a #ClutterActor
12602  *
12603  * Retrieves the anchor position expressed as a #ClutterGravity. If
12604  * the anchor point was specified using pixels or units this will
12605  * return %CLUTTER_GRAVITY_NONE.
12606  *
12607  * Return value: the #ClutterGravity used by the anchor point
12608  *
12609  * Since: 1.0
12610  */
12611 ClutterGravity
12612 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12613 {
12614   const ClutterTransformInfo *info;
12615
12616   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12617
12618   info = _clutter_actor_get_transform_info_or_defaults (self);
12619
12620   return clutter_anchor_coord_get_gravity (&info->anchor);
12621 }
12622
12623 /**
12624  * clutter_actor_move_anchor_point:
12625  * @self: a #ClutterActor
12626  * @anchor_x: X coordinate of the anchor point
12627  * @anchor_y: Y coordinate of the anchor point
12628  *
12629  * Sets an anchor point for the actor, and adjusts the actor postion so that
12630  * the relative position of the actor toward its parent remains the same.
12631  *
12632  * Since: 0.6
12633  */
12634 void
12635 clutter_actor_move_anchor_point (ClutterActor *self,
12636                                  gfloat        anchor_x,
12637                                  gfloat        anchor_y)
12638 {
12639   gfloat old_anchor_x, old_anchor_y;
12640   const ClutterTransformInfo *info;
12641
12642   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12643
12644   info = _clutter_actor_get_transform_info (self);
12645   clutter_anchor_coord_get_units (self, &info->anchor,
12646                                   &old_anchor_x,
12647                                   &old_anchor_y,
12648                                   NULL);
12649
12650   g_object_freeze_notify (G_OBJECT (self));
12651
12652   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12653
12654   if (self->priv->position_set)
12655     clutter_actor_move_by (self,
12656                            anchor_x - old_anchor_x,
12657                            anchor_y - old_anchor_y);
12658
12659   g_object_thaw_notify (G_OBJECT (self));
12660 }
12661
12662 /**
12663  * clutter_actor_move_anchor_point_from_gravity:
12664  * @self: a #ClutterActor
12665  * @gravity: #ClutterGravity.
12666  *
12667  * Sets an anchor point on the actor based on the given gravity, adjusting the
12668  * actor postion so that its relative position within its parent remains
12669  * unchanged.
12670  *
12671  * Since version 1.0 the anchor point will be stored as a gravity so
12672  * that if the actor changes size then the anchor point will move. For
12673  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12674  * and later double the size of the actor, the anchor point will move
12675  * to the bottom right.
12676  *
12677  * Since: 0.6
12678  */
12679 void
12680 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12681                                               ClutterGravity  gravity)
12682 {
12683   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12684   const ClutterTransformInfo *info;
12685   ClutterActorPrivate *priv;
12686
12687   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12688
12689   priv = self->priv;
12690   info = _clutter_actor_get_transform_info (self);
12691
12692   g_object_freeze_notify (G_OBJECT (self));
12693
12694   clutter_anchor_coord_get_units (self, &info->anchor,
12695                                   &old_anchor_x,
12696                                   &old_anchor_y,
12697                                   NULL);
12698   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12699   clutter_anchor_coord_get_units (self, &info->anchor,
12700                                   &new_anchor_x,
12701                                   &new_anchor_y,
12702                                   NULL);
12703
12704   if (priv->position_set)
12705     clutter_actor_move_by (self,
12706                            new_anchor_x - old_anchor_x,
12707                            new_anchor_y - old_anchor_y);
12708
12709   g_object_thaw_notify (G_OBJECT (self));
12710 }
12711
12712 /**
12713  * clutter_actor_set_anchor_point_from_gravity:
12714  * @self: a #ClutterActor
12715  * @gravity: #ClutterGravity.
12716  *
12717  * Sets an anchor point on the actor, based on the given gravity (this is a
12718  * convenience function wrapping clutter_actor_set_anchor_point()).
12719  *
12720  * Since version 1.0 the anchor point will be stored as a gravity so
12721  * that if the actor changes size then the anchor point will move. For
12722  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12723  * and later double the size of the actor, the anchor point will move
12724  * to the bottom right.
12725  *
12726  * Since: 0.6
12727  */
12728 void
12729 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12730                                              ClutterGravity  gravity)
12731 {
12732   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12733
12734   if (gravity == CLUTTER_GRAVITY_NONE)
12735     clutter_actor_set_anchor_point (self, 0, 0);
12736   else
12737     {
12738       GObject *obj = G_OBJECT (self);
12739       ClutterTransformInfo *info;
12740
12741       g_object_freeze_notify (obj);
12742
12743       info = _clutter_actor_get_transform_info (self);
12744       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12745
12746       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12747       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12748       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12749
12750       self->priv->transform_valid = FALSE;
12751
12752       clutter_actor_queue_redraw (self);
12753
12754       g_object_thaw_notify (obj);
12755     }
12756 }
12757
12758 static void
12759 clutter_actor_store_content_box (ClutterActor *self,
12760                                  const ClutterActorBox *box)
12761 {
12762   if (box != NULL)
12763     {
12764       self->priv->content_box = *box;
12765       self->priv->content_box_valid = TRUE;
12766     }
12767   else
12768     self->priv->content_box_valid = FALSE;
12769
12770   clutter_actor_queue_redraw (self);
12771
12772   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12773 }
12774
12775 static void
12776 clutter_container_iface_init (ClutterContainerIface *iface)
12777 {
12778   /* we don't override anything, as ClutterContainer already has a default
12779    * implementation that we can use, and which calls into our own API.
12780    */
12781 }
12782
12783 typedef enum
12784 {
12785   PARSE_X,
12786   PARSE_Y,
12787   PARSE_WIDTH,
12788   PARSE_HEIGHT,
12789   PARSE_ANCHOR_X,
12790   PARSE_ANCHOR_Y
12791 } ParseDimension;
12792
12793 static gfloat
12794 parse_units (ClutterActor   *self,
12795              ParseDimension  dimension,
12796              JsonNode       *node)
12797 {
12798   GValue value = G_VALUE_INIT;
12799   gfloat retval = 0;
12800
12801   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12802     return 0;
12803
12804   json_node_get_value (node, &value);
12805
12806   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12807     {
12808       retval = (gfloat) g_value_get_int64 (&value);
12809     }
12810   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12811     {
12812       retval = g_value_get_double (&value);
12813     }
12814   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12815     {
12816       ClutterUnits units;
12817       gboolean res;
12818
12819       res = clutter_units_from_string (&units, g_value_get_string (&value));
12820       if (res)
12821         retval = clutter_units_to_pixels (&units);
12822       else
12823         {
12824           g_warning ("Invalid value '%s': integers, strings or floating point "
12825                      "values can be used for the x, y, width and height "
12826                      "properties. Valid modifiers for strings are 'px', 'mm', "
12827                      "'pt' and 'em'.",
12828                      g_value_get_string (&value));
12829           retval = 0;
12830         }
12831     }
12832   else
12833     {
12834       g_warning ("Invalid value of type '%s': integers, strings of floating "
12835                  "point values can be used for the x, y, width, height "
12836                  "anchor-x and anchor-y properties.",
12837                  g_type_name (G_VALUE_TYPE (&value)));
12838     }
12839
12840   g_value_unset (&value);
12841
12842   return retval;
12843 }
12844
12845 typedef struct {
12846   ClutterRotateAxis axis;
12847
12848   gdouble angle;
12849
12850   gfloat center_x;
12851   gfloat center_y;
12852   gfloat center_z;
12853 } RotationInfo;
12854
12855 static inline gboolean
12856 parse_rotation_array (ClutterActor *actor,
12857                       JsonArray    *array,
12858                       RotationInfo *info)
12859 {
12860   JsonNode *element;
12861
12862   if (json_array_get_length (array) != 2)
12863     return FALSE;
12864
12865   /* angle */
12866   element = json_array_get_element (array, 0);
12867   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12868     info->angle = json_node_get_double (element);
12869   else
12870     return FALSE;
12871
12872   /* center */
12873   element = json_array_get_element (array, 1);
12874   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12875     {
12876       JsonArray *center = json_node_get_array (element);
12877
12878       if (json_array_get_length (center) != 2)
12879         return FALSE;
12880
12881       switch (info->axis)
12882         {
12883         case CLUTTER_X_AXIS:
12884           info->center_y = parse_units (actor, PARSE_Y,
12885                                         json_array_get_element (center, 0));
12886           info->center_z = parse_units (actor, PARSE_Y,
12887                                         json_array_get_element (center, 1));
12888           return TRUE;
12889
12890         case CLUTTER_Y_AXIS:
12891           info->center_x = parse_units (actor, PARSE_X,
12892                                         json_array_get_element (center, 0));
12893           info->center_z = parse_units (actor, PARSE_X,
12894                                         json_array_get_element (center, 1));
12895           return TRUE;
12896
12897         case CLUTTER_Z_AXIS:
12898           info->center_x = parse_units (actor, PARSE_X,
12899                                         json_array_get_element (center, 0));
12900           info->center_y = parse_units (actor, PARSE_Y,
12901                                         json_array_get_element (center, 1));
12902           return TRUE;
12903         }
12904     }
12905
12906   return FALSE;
12907 }
12908
12909 static gboolean
12910 parse_rotation (ClutterActor *actor,
12911                 JsonNode     *node,
12912                 RotationInfo *info)
12913 {
12914   JsonArray *array;
12915   guint len, i;
12916   gboolean retval = FALSE;
12917
12918   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12919     {
12920       g_warning ("Invalid node of type '%s' found, expecting an array",
12921                  json_node_type_name (node));
12922       return FALSE;
12923     }
12924
12925   array = json_node_get_array (node);
12926   len = json_array_get_length (array);
12927
12928   for (i = 0; i < len; i++)
12929     {
12930       JsonNode *element = json_array_get_element (array, i);
12931       JsonObject *object;
12932       JsonNode *member;
12933
12934       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12935         {
12936           g_warning ("Invalid node of type '%s' found, expecting an object",
12937                      json_node_type_name (element));
12938           return FALSE;
12939         }
12940
12941       object = json_node_get_object (element);
12942
12943       if (json_object_has_member (object, "x-axis"))
12944         {
12945           member = json_object_get_member (object, "x-axis");
12946
12947           info->axis = CLUTTER_X_AXIS;
12948
12949           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12950             {
12951               info->angle = json_node_get_double (member);
12952               retval = TRUE;
12953             }
12954           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12955             retval = parse_rotation_array (actor,
12956                                            json_node_get_array (member),
12957                                            info);
12958           else
12959             retval = FALSE;
12960         }
12961       else if (json_object_has_member (object, "y-axis"))
12962         {
12963           member = json_object_get_member (object, "y-axis");
12964
12965           info->axis = CLUTTER_Y_AXIS;
12966
12967           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12968             {
12969               info->angle = json_node_get_double (member);
12970               retval = TRUE;
12971             }
12972           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12973             retval = parse_rotation_array (actor,
12974                                            json_node_get_array (member),
12975                                            info);
12976           else
12977             retval = FALSE;
12978         }
12979       else if (json_object_has_member (object, "z-axis"))
12980         {
12981           member = json_object_get_member (object, "z-axis");
12982
12983           info->axis = CLUTTER_Z_AXIS;
12984
12985           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12986             {
12987               info->angle = json_node_get_double (member);
12988               retval = TRUE;
12989             }
12990           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12991             retval = parse_rotation_array (actor,
12992                                            json_node_get_array (member),
12993                                            info);
12994           else
12995             retval = FALSE;
12996         }
12997     }
12998
12999   return retval;
13000 }
13001
13002 static GSList *
13003 parse_actor_metas (ClutterScript *script,
13004                    ClutterActor  *actor,
13005                    JsonNode      *node)
13006 {
13007   GList *elements, *l;
13008   GSList *retval = NULL;
13009
13010   if (!JSON_NODE_HOLDS_ARRAY (node))
13011     return NULL;
13012
13013   elements = json_array_get_elements (json_node_get_array (node));
13014
13015   for (l = elements; l != NULL; l = l->next)
13016     {
13017       JsonNode *element = l->data;
13018       const gchar *id_ = _clutter_script_get_id_from_node (element);
13019       GObject *meta;
13020
13021       if (id_ == NULL || *id_ == '\0')
13022         continue;
13023
13024       meta = clutter_script_get_object (script, id_);
13025       if (meta == NULL)
13026         continue;
13027
13028       retval = g_slist_prepend (retval, meta);
13029     }
13030
13031   g_list_free (elements);
13032
13033   return g_slist_reverse (retval);
13034 }
13035
13036 static GSList *
13037 parse_behaviours (ClutterScript *script,
13038                   ClutterActor  *actor,
13039                   JsonNode      *node)
13040 {
13041   GList *elements, *l;
13042   GSList *retval = NULL;
13043
13044   if (!JSON_NODE_HOLDS_ARRAY (node))
13045     return NULL;
13046
13047   elements = json_array_get_elements (json_node_get_array (node));
13048
13049   for (l = elements; l != NULL; l = l->next)
13050     {
13051       JsonNode *element = l->data;
13052       const gchar *id_ = _clutter_script_get_id_from_node (element);
13053       GObject *behaviour;
13054
13055       if (id_ == NULL || *id_ == '\0')
13056         continue;
13057
13058       behaviour = clutter_script_get_object (script, id_);
13059       if (behaviour == NULL)
13060         continue;
13061
13062       retval = g_slist_prepend (retval, behaviour);
13063     }
13064
13065   g_list_free (elements);
13066
13067   return g_slist_reverse (retval);
13068 }
13069
13070 static ClutterMargin *
13071 parse_margin (ClutterActor *self,
13072               JsonNode     *node)
13073 {
13074   ClutterMargin *margin;
13075   JsonArray *array;
13076
13077   if (!JSON_NODE_HOLDS_ARRAY (node))
13078     {
13079       g_warning ("The margin property must be an array of 1 to 4 elements");
13080       return NULL;
13081     }
13082
13083   margin = clutter_margin_new ();
13084   array = json_node_get_array (node);
13085   switch (json_array_get_length (array))
13086     {
13087     case 1:
13088       margin->top = margin->right = margin->bottom = margin->left =
13089         parse_units (self, 0, json_array_get_element (array, 0));
13090       break;
13091
13092     case 2:
13093       margin->top = margin->bottom =
13094         parse_units (self, 0, json_array_get_element (array, 0));
13095       margin->right = margin->left =
13096         parse_units (self, 0, json_array_get_element (array, 1));
13097       break;
13098
13099     case 3:
13100       margin->top =
13101         parse_units (self, 0, json_array_get_element (array, 0));
13102       margin->right = margin->left =
13103         parse_units (self, 0, json_array_get_element (array, 1));
13104       margin->bottom =
13105         parse_units (self, 0, json_array_get_element (array, 2));
13106       break;
13107
13108     case 4:
13109       margin->top =
13110         parse_units (self, 0, json_array_get_element (array, 0));
13111       margin->right =
13112         parse_units (self, 0, json_array_get_element (array, 1));
13113       margin->bottom =
13114         parse_units (self, 0, json_array_get_element (array, 2));
13115       margin->left =
13116         parse_units (self, 0, json_array_get_element (array, 3));
13117       break;
13118
13119     default:
13120       g_warning ("The margin property must be an array of 1 to 4 elements");
13121       clutter_margin_free (margin);
13122       return NULL;
13123     }
13124   return margin;
13125 }
13126
13127 static gboolean
13128 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
13129                                  ClutterScript     *script,
13130                                  GValue            *value,
13131                                  const gchar       *name,
13132                                  JsonNode          *node)
13133 {
13134   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13135   gboolean retval = FALSE;
13136
13137   if ((name[0] == 'x' && name[1] == '\0') ||
13138       (name[0] == 'y' && name[1] == '\0') ||
13139       (strcmp (name, "width") == 0) ||
13140       (strcmp (name, "height") == 0) ||
13141       (strcmp (name, "anchor_x") == 0) ||
13142       (strcmp (name, "anchor_y") == 0))
13143     {
13144       ParseDimension dimension;
13145       gfloat units;
13146
13147       if (name[0] == 'x')
13148         dimension = PARSE_X;
13149       else if (name[0] == 'y')
13150         dimension = PARSE_Y;
13151       else if (name[0] == 'w')
13152         dimension = PARSE_WIDTH;
13153       else if (name[0] == 'h')
13154         dimension = PARSE_HEIGHT;
13155       else if (name[0] == 'a' && name[7] == 'x')
13156         dimension = PARSE_ANCHOR_X;
13157       else if (name[0] == 'a' && name[7] == 'y')
13158         dimension = PARSE_ANCHOR_Y;
13159       else
13160         return FALSE;
13161
13162       units = parse_units (actor, dimension, node);
13163
13164       /* convert back to pixels: all properties are pixel-based */
13165       g_value_init (value, G_TYPE_FLOAT);
13166       g_value_set_float (value, units);
13167
13168       retval = TRUE;
13169     }
13170   else if (strcmp (name, "rotation") == 0)
13171     {
13172       RotationInfo *info;
13173
13174       info = g_slice_new0 (RotationInfo);
13175       retval = parse_rotation (actor, node, info);
13176
13177       if (retval)
13178         {
13179           g_value_init (value, G_TYPE_POINTER);
13180           g_value_set_pointer (value, info);
13181         }
13182       else
13183         g_slice_free (RotationInfo, info);
13184     }
13185   else if (strcmp (name, "behaviours") == 0)
13186     {
13187       GSList *l;
13188
13189 #ifdef CLUTTER_ENABLE_DEBUG
13190       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13191         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13192                                      "and it should not be used in newly "
13193                                      "written ClutterScript definitions.");
13194 #endif
13195
13196       l = parse_behaviours (script, actor, node);
13197
13198       g_value_init (value, G_TYPE_POINTER);
13199       g_value_set_pointer (value, l);
13200
13201       retval = TRUE;
13202     }
13203   else if (strcmp (name, "actions") == 0 ||
13204            strcmp (name, "constraints") == 0 ||
13205            strcmp (name, "effects") == 0)
13206     {
13207       GSList *l;
13208
13209       l = parse_actor_metas (script, actor, node);
13210
13211       g_value_init (value, G_TYPE_POINTER);
13212       g_value_set_pointer (value, l);
13213
13214       retval = TRUE;
13215     }
13216   else if (strcmp (name, "margin") == 0)
13217     {
13218       ClutterMargin *margin = parse_margin (actor, node);
13219
13220       if (margin)
13221         {
13222           g_value_init (value, CLUTTER_TYPE_MARGIN);
13223           g_value_set_boxed (value, margin);
13224           retval = TRUE;
13225         }
13226     }
13227
13228   return retval;
13229 }
13230
13231 static void
13232 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13233                                    ClutterScript     *script,
13234                                    const gchar       *name,
13235                                    const GValue      *value)
13236 {
13237   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13238
13239 #ifdef CLUTTER_ENABLE_DEBUG
13240   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13241     {
13242       gchar *tmp = g_strdup_value_contents (value);
13243
13244       CLUTTER_NOTE (SCRIPT,
13245                     "in ClutterActor::set_custom_property('%s') = %s",
13246                     name,
13247                     tmp);
13248
13249       g_free (tmp);
13250     }
13251 #endif /* CLUTTER_ENABLE_DEBUG */
13252
13253   if (strcmp (name, "rotation") == 0)
13254     {
13255       RotationInfo *info;
13256
13257       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13258         return;
13259
13260       info = g_value_get_pointer (value);
13261
13262       clutter_actor_set_rotation (actor,
13263                                   info->axis, info->angle,
13264                                   info->center_x,
13265                                   info->center_y,
13266                                   info->center_z);
13267
13268       g_slice_free (RotationInfo, info);
13269
13270       return;
13271     }
13272
13273   if (strcmp (name, "behaviours") == 0)
13274     {
13275       GSList *behaviours, *l;
13276
13277       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13278         return;
13279
13280       behaviours = g_value_get_pointer (value);
13281       for (l = behaviours; l != NULL; l = l->next)
13282         {
13283           ClutterBehaviour *behaviour = l->data;
13284
13285           clutter_behaviour_apply (behaviour, actor);
13286         }
13287
13288       g_slist_free (behaviours);
13289
13290       return;
13291     }
13292
13293   if (strcmp (name, "actions") == 0 ||
13294       strcmp (name, "constraints") == 0 ||
13295       strcmp (name, "effects") == 0)
13296     {
13297       GSList *metas, *l;
13298
13299       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13300         return;
13301
13302       metas = g_value_get_pointer (value);
13303       for (l = metas; l != NULL; l = l->next)
13304         {
13305           if (name[0] == 'a')
13306             clutter_actor_add_action (actor, l->data);
13307
13308           if (name[0] == 'c')
13309             clutter_actor_add_constraint (actor, l->data);
13310
13311           if (name[0] == 'e')
13312             clutter_actor_add_effect (actor, l->data);
13313         }
13314
13315       g_slist_free (metas);
13316
13317       return;
13318     }
13319   if (strcmp (name, "margin") == 0)
13320     {
13321       clutter_actor_set_margin (actor, g_value_get_boxed (value));
13322       return;
13323     }
13324
13325   g_object_set_property (G_OBJECT (scriptable), name, value);
13326 }
13327
13328 static void
13329 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13330 {
13331   iface->parse_custom_node = clutter_actor_parse_custom_node;
13332   iface->set_custom_property = clutter_actor_set_custom_property;
13333 }
13334
13335 static ClutterActorMeta *
13336 get_meta_from_animation_property (ClutterActor  *actor,
13337                                   const gchar   *name,
13338                                   gchar        **name_p)
13339 {
13340   ClutterActorPrivate *priv = actor->priv;
13341   ClutterActorMeta *meta = NULL;
13342   gchar **tokens;
13343
13344   /* if this is not a special property, fall through */
13345   if (name[0] != '@')
13346     return NULL;
13347
13348   /* detect the properties named using the following spec:
13349    *
13350    *   @<section>.<meta-name>.<property-name>
13351    *
13352    * where <section> can be one of the following:
13353    *
13354    *   - actions
13355    *   - constraints
13356    *   - effects
13357    *
13358    * and <meta-name> is the name set on a specific ActorMeta
13359    */
13360
13361   tokens = g_strsplit (name + 1, ".", -1);
13362   if (tokens == NULL || g_strv_length (tokens) != 3)
13363     {
13364       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13365                     name + 1);
13366       g_strfreev (tokens);
13367       return NULL;
13368     }
13369
13370   if (strcmp (tokens[0], "actions") == 0)
13371     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13372
13373   if (strcmp (tokens[0], "constraints") == 0)
13374     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13375
13376   if (strcmp (tokens[0], "effects") == 0)
13377     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13378
13379   if (name_p != NULL)
13380     *name_p = g_strdup (tokens[2]);
13381
13382   CLUTTER_NOTE (ANIMATION,
13383                 "Looking for property '%s' of object '%s' in section '%s'",
13384                 tokens[2],
13385                 tokens[1],
13386                 tokens[0]);
13387
13388   g_strfreev (tokens);
13389
13390   return meta;
13391 }
13392
13393 static GParamSpec *
13394 clutter_actor_find_property (ClutterAnimatable *animatable,
13395                              const gchar       *property_name)
13396 {
13397   ClutterActorMeta *meta = NULL;
13398   GObjectClass *klass = NULL;
13399   GParamSpec *pspec = NULL;
13400   gchar *p_name = NULL;
13401
13402   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13403                                            property_name,
13404                                            &p_name);
13405
13406   if (meta != NULL)
13407     {
13408       klass = G_OBJECT_GET_CLASS (meta);
13409
13410       pspec = g_object_class_find_property (klass, p_name);
13411     }
13412   else
13413     {
13414       klass = G_OBJECT_GET_CLASS (animatable);
13415
13416       pspec = g_object_class_find_property (klass, property_name);
13417     }
13418
13419   g_free (p_name);
13420
13421   return pspec;
13422 }
13423
13424 static void
13425 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13426                                  const gchar       *property_name,
13427                                  GValue            *initial)
13428 {
13429   ClutterActorMeta *meta = NULL;
13430   gchar *p_name = NULL;
13431
13432   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13433                                            property_name,
13434                                            &p_name);
13435
13436   if (meta != NULL)
13437     g_object_get_property (G_OBJECT (meta), p_name, initial);
13438   else
13439     g_object_get_property (G_OBJECT (animatable), property_name, initial);
13440
13441   g_free (p_name);
13442 }
13443
13444 /*
13445  * clutter_actor_set_animatable_property:
13446  * @actor: a #ClutterActor
13447  * @prop_id: the paramspec id
13448  * @value: the value to set
13449  * @pspec: the paramspec
13450  *
13451  * Sets values of animatable properties.
13452  *
13453  * This is a variant of clutter_actor_set_property() that gets called
13454  * by the #ClutterAnimatable implementation of #ClutterActor for the
13455  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13456  * #GParamSpec.
13457  *
13458  * Unlike the implementation of #GObjectClass.set_property(), this
13459  * function will not update the interval if a transition involving an
13460  * animatable property is in progress - this avoids cycles with the
13461  * transition API calling the public API.
13462  */
13463 static void
13464 clutter_actor_set_animatable_property (ClutterActor *actor,
13465                                        guint         prop_id,
13466                                        const GValue *value,
13467                                        GParamSpec   *pspec)
13468 {
13469   GObject *obj = G_OBJECT (actor);
13470
13471   g_object_freeze_notify (obj);
13472
13473   switch (prop_id)
13474     {
13475     case PROP_X:
13476       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13477       break;
13478
13479     case PROP_Y:
13480       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13481       break;
13482
13483     case PROP_POSITION:
13484       clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13485       break;
13486
13487     case PROP_WIDTH:
13488       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13489       break;
13490
13491     case PROP_HEIGHT:
13492       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13493       break;
13494
13495     case PROP_SIZE:
13496       clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13497       break;
13498
13499     case PROP_ALLOCATION:
13500       clutter_actor_allocate_internal (actor,
13501                                        g_value_get_boxed (value),
13502                                        actor->priv->allocation_flags);
13503       break;
13504
13505     case PROP_DEPTH:
13506       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13507       break;
13508
13509     case PROP_OPACITY:
13510       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13511       break;
13512
13513     case PROP_BACKGROUND_COLOR:
13514       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13515       break;
13516
13517     case PROP_SCALE_X:
13518       clutter_actor_set_scale_factor_internal (actor,
13519                                                g_value_get_double (value),
13520                                                pspec);
13521       break;
13522
13523     case PROP_SCALE_Y:
13524       clutter_actor_set_scale_factor_internal (actor,
13525                                                g_value_get_double (value),
13526                                                pspec);
13527       break;
13528
13529     case PROP_ROTATION_ANGLE_X:
13530       clutter_actor_set_rotation_angle_internal (actor,
13531                                                  CLUTTER_X_AXIS,
13532                                                  g_value_get_double (value));
13533       break;
13534
13535     case PROP_ROTATION_ANGLE_Y:
13536       clutter_actor_set_rotation_angle_internal (actor,
13537                                                  CLUTTER_Y_AXIS,
13538                                                  g_value_get_double (value));
13539       break;
13540
13541     case PROP_ROTATION_ANGLE_Z:
13542       clutter_actor_set_rotation_angle_internal (actor,
13543                                                  CLUTTER_Z_AXIS,
13544                                                  g_value_get_double (value));
13545       break;
13546
13547     case PROP_CONTENT_BOX:
13548       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13549       break;
13550
13551     default:
13552       g_object_set_property (obj, pspec->name, value);
13553       break;
13554     }
13555
13556   g_object_thaw_notify (obj);
13557 }
13558
13559 static void
13560 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13561                                const gchar       *property_name,
13562                                const GValue      *final)
13563 {
13564   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13565   ClutterActorMeta *meta = NULL;
13566   gchar *p_name = NULL;
13567
13568   meta = get_meta_from_animation_property (actor,
13569                                            property_name,
13570                                            &p_name);
13571   if (meta != NULL)
13572     g_object_set_property (G_OBJECT (meta), p_name, final);
13573   else
13574     {
13575       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13576       GParamSpec *pspec;
13577
13578       pspec = g_object_class_find_property (obj_class, property_name);
13579
13580       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13581         {
13582           /* XXX - I'm going to the special hell for this */
13583           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13584         }
13585       else
13586         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13587     }
13588
13589   g_free (p_name);
13590 }
13591
13592 static void
13593 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13594 {
13595   iface->find_property = clutter_actor_find_property;
13596   iface->get_initial_state = clutter_actor_get_initial_state;
13597   iface->set_final_state = clutter_actor_set_final_state;
13598 }
13599
13600 /**
13601  * clutter_actor_transform_stage_point:
13602  * @self: A #ClutterActor
13603  * @x: (in): x screen coordinate of the point to unproject
13604  * @y: (in): y screen coordinate of the point to unproject
13605  * @x_out: (out): return location for the unprojected x coordinance
13606  * @y_out: (out): return location for the unprojected y coordinance
13607  *
13608  * This function translates screen coordinates (@x, @y) to
13609  * coordinates relative to the actor. For example, it can be used to translate
13610  * screen events from global screen coordinates into actor-local coordinates.
13611  *
13612  * The conversion can fail, notably if the transform stack results in the
13613  * actor being projected on the screen as a mere line.
13614  *
13615  * The conversion should not be expected to be pixel-perfect due to the
13616  * nature of the operation. In general the error grows when the skewing
13617  * of the actor rectangle on screen increases.
13618  *
13619  * <note><para>This function can be computationally intensive.</para></note>
13620  *
13621  * <note><para>This function only works when the allocation is up-to-date,
13622  * i.e. inside of paint().</para></note>
13623  *
13624  * Return value: %TRUE if conversion was successful.
13625  *
13626  * Since: 0.6
13627  */
13628 gboolean
13629 clutter_actor_transform_stage_point (ClutterActor *self,
13630                                      gfloat        x,
13631                                      gfloat        y,
13632                                      gfloat       *x_out,
13633                                      gfloat       *y_out)
13634 {
13635   ClutterVertex v[4];
13636   float ST[3][3];
13637   float RQ[3][3];
13638   int du, dv, xi, yi;
13639   float px, py;
13640   float xf, yf, wf, det;
13641   ClutterActorPrivate *priv;
13642
13643   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13644
13645   priv = self->priv;
13646
13647   /* This implementation is based on the quad -> quad projection algorithm
13648    * described by Paul Heckbert in:
13649    *
13650    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13651    *
13652    * and the sample implementation at:
13653    *
13654    *   http://www.cs.cmu.edu/~ph/src/texfund/
13655    *
13656    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13657    * quad to rectangle only, which significantly simplifies things; the
13658    * function calls have been unrolled, and most of the math is done in fixed
13659    * point.
13660    */
13661
13662   clutter_actor_get_abs_allocation_vertices (self, v);
13663
13664   /* Keeping these as ints simplifies the multiplication (no significant
13665    * loss of precision here).
13666    */
13667   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13668   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13669
13670   if (!du || !dv)
13671     return FALSE;
13672
13673 #define UX2FP(x)        (x)
13674 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13675
13676   /* First, find mapping from unit uv square to xy quadrilateral; this
13677    * equivalent to the pmap_square_quad() functions in the sample
13678    * implementation, which we can simplify, since our target is always
13679    * a rectangle.
13680    */
13681   px = v[0].x - v[1].x + v[3].x - v[2].x;
13682   py = v[0].y - v[1].y + v[3].y - v[2].y;
13683
13684   if (!px && !py)
13685     {
13686       /* affine transform */
13687       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13688       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13689       RQ[2][0] = UX2FP (v[0].x);
13690       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13691       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13692       RQ[2][1] = UX2FP (v[0].y);
13693       RQ[0][2] = 0;
13694       RQ[1][2] = 0;
13695       RQ[2][2] = 1.0;
13696     }
13697   else
13698     {
13699       /* projective transform */
13700       double dx1, dx2, dy1, dy2, del;
13701
13702       dx1 = UX2FP (v[1].x - v[3].x);
13703       dx2 = UX2FP (v[2].x - v[3].x);
13704       dy1 = UX2FP (v[1].y - v[3].y);
13705       dy2 = UX2FP (v[2].y - v[3].y);
13706
13707       del = DET2FP (dx1, dx2, dy1, dy2);
13708       if (!del)
13709         return FALSE;
13710
13711       /*
13712        * The division here needs to be done in floating point for
13713        * precisions reasons.
13714        */
13715       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13716       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13717       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13718       RQ[2][2] = 1.0;
13719       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13720       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13721       RQ[2][0] = UX2FP (v[0].x);
13722       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13723       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13724       RQ[2][1] = UX2FP (v[0].y);
13725     }
13726
13727   /*
13728    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13729    * square. Since our rectangle is based at 0,0 we only need to scale.
13730    */
13731   RQ[0][0] /= du;
13732   RQ[1][0] /= dv;
13733   RQ[0][1] /= du;
13734   RQ[1][1] /= dv;
13735   RQ[0][2] /= du;
13736   RQ[1][2] /= dv;
13737
13738   /*
13739    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13740    * inverse of that.
13741    */
13742   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13743   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13744   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13745   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13746   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13747   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13748   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13749   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13750   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13751
13752   /*
13753    * Check the resulting matrix is OK.
13754    */
13755   det = (RQ[0][0] * ST[0][0])
13756       + (RQ[0][1] * ST[0][1])
13757       + (RQ[0][2] * ST[0][2]);
13758   if (!det)
13759     return FALSE;
13760
13761   /*
13762    * Now transform our point with the ST matrix; the notional w
13763    * coordinate is 1, hence the last part is simply added.
13764    */
13765   xi = (int) x;
13766   yi = (int) y;
13767
13768   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13769   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13770   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13771
13772   if (x_out)
13773     *x_out = xf / wf;
13774
13775   if (y_out)
13776     *y_out = yf / wf;
13777
13778 #undef UX2FP
13779 #undef DET2FP
13780
13781   return TRUE;
13782 }
13783
13784 /**
13785  * clutter_actor_is_rotated:
13786  * @self: a #ClutterActor
13787  *
13788  * Checks whether any rotation is applied to the actor.
13789  *
13790  * Return value: %TRUE if the actor is rotated.
13791  *
13792  * Since: 0.6
13793  */
13794 gboolean
13795 clutter_actor_is_rotated (ClutterActor *self)
13796 {
13797   const ClutterTransformInfo *info;
13798
13799   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13800
13801   info = _clutter_actor_get_transform_info_or_defaults (self);
13802
13803   if (info->rx_angle || info->ry_angle || info->rz_angle)
13804     return TRUE;
13805
13806   return FALSE;
13807 }
13808
13809 /**
13810  * clutter_actor_is_scaled:
13811  * @self: a #ClutterActor
13812  *
13813  * Checks whether the actor is scaled in either dimension.
13814  *
13815  * Return value: %TRUE if the actor is scaled.
13816  *
13817  * Since: 0.6
13818  */
13819 gboolean
13820 clutter_actor_is_scaled (ClutterActor *self)
13821 {
13822   const ClutterTransformInfo *info;
13823
13824   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13825
13826   info = _clutter_actor_get_transform_info_or_defaults (self);
13827
13828   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13829     return TRUE;
13830
13831   return FALSE;
13832 }
13833
13834 ClutterActor *
13835 _clutter_actor_get_stage_internal (ClutterActor *actor)
13836 {
13837   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13838     actor = actor->priv->parent;
13839
13840   return actor;
13841 }
13842
13843 /**
13844  * clutter_actor_get_stage:
13845  * @actor: a #ClutterActor
13846  *
13847  * Retrieves the #ClutterStage where @actor is contained.
13848  *
13849  * Return value: (transfer none) (type Clutter.Stage): the stage
13850  *   containing the actor, or %NULL
13851  *
13852  * Since: 0.8
13853  */
13854 ClutterActor *
13855 clutter_actor_get_stage (ClutterActor *actor)
13856 {
13857   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13858
13859   return _clutter_actor_get_stage_internal (actor);
13860 }
13861
13862 /**
13863  * clutter_actor_allocate_available_size:
13864  * @self: a #ClutterActor
13865  * @x: the actor's X coordinate
13866  * @y: the actor's Y coordinate
13867  * @available_width: the maximum available width, or -1 to use the
13868  *   actor's natural width
13869  * @available_height: the maximum available height, or -1 to use the
13870  *   actor's natural height
13871  * @flags: flags controlling the allocation
13872  *
13873  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13874  * preferred size, but limiting it to the maximum available width
13875  * and height provided.
13876  *
13877  * This function will do the right thing when dealing with the
13878  * actor's request mode.
13879  *
13880  * The implementation of this function is equivalent to:
13881  *
13882  * |[
13883  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13884  *     {
13885  *       clutter_actor_get_preferred_width (self, available_height,
13886  *                                          &amp;min_width,
13887  *                                          &amp;natural_width);
13888  *       width = CLAMP (natural_width, min_width, available_width);
13889  *
13890  *       clutter_actor_get_preferred_height (self, width,
13891  *                                           &amp;min_height,
13892  *                                           &amp;natural_height);
13893  *       height = CLAMP (natural_height, min_height, available_height);
13894  *     }
13895  *   else
13896  *     {
13897  *       clutter_actor_get_preferred_height (self, available_width,
13898  *                                           &amp;min_height,
13899  *                                           &amp;natural_height);
13900  *       height = CLAMP (natural_height, min_height, available_height);
13901  *
13902  *       clutter_actor_get_preferred_width (self, height,
13903  *                                          &amp;min_width,
13904  *                                          &amp;natural_width);
13905  *       width = CLAMP (natural_width, min_width, available_width);
13906  *     }
13907  *
13908  *   box.x1 = x; box.y1 = y;
13909  *   box.x2 = box.x1 + available_width;
13910  *   box.y2 = box.y1 + available_height;
13911  *   clutter_actor_allocate (self, &amp;box, flags);
13912  * ]|
13913  *
13914  * This function can be used by fluid layout managers to allocate
13915  * an actor's preferred size without making it bigger than the area
13916  * available for the container.
13917  *
13918  * Since: 1.0
13919  */
13920 void
13921 clutter_actor_allocate_available_size (ClutterActor           *self,
13922                                        gfloat                  x,
13923                                        gfloat                  y,
13924                                        gfloat                  available_width,
13925                                        gfloat                  available_height,
13926                                        ClutterAllocationFlags  flags)
13927 {
13928   ClutterActorPrivate *priv;
13929   gfloat width, height;
13930   gfloat min_width, min_height;
13931   gfloat natural_width, natural_height;
13932   ClutterActorBox box;
13933
13934   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13935
13936   priv = self->priv;
13937
13938   width = height = 0.0;
13939
13940   switch (priv->request_mode)
13941     {
13942     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13943       clutter_actor_get_preferred_width (self, available_height,
13944                                          &min_width,
13945                                          &natural_width);
13946       width  = CLAMP (natural_width, min_width, available_width);
13947
13948       clutter_actor_get_preferred_height (self, width,
13949                                           &min_height,
13950                                           &natural_height);
13951       height = CLAMP (natural_height, min_height, available_height);
13952       break;
13953
13954     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13955       clutter_actor_get_preferred_height (self, available_width,
13956                                           &min_height,
13957                                           &natural_height);
13958       height = CLAMP (natural_height, min_height, available_height);
13959
13960       clutter_actor_get_preferred_width (self, height,
13961                                          &min_width,
13962                                          &natural_width);
13963       width  = CLAMP (natural_width, min_width, available_width);
13964       break;
13965     }
13966
13967
13968   box.x1 = x;
13969   box.y1 = y;
13970   box.x2 = box.x1 + width;
13971   box.y2 = box.y1 + height;
13972   clutter_actor_allocate (self, &box, flags);
13973 }
13974
13975 /**
13976  * clutter_actor_allocate_preferred_size:
13977  * @self: a #ClutterActor
13978  * @flags: flags controlling the allocation
13979  *
13980  * Allocates the natural size of @self.
13981  *
13982  * This function is a utility call for #ClutterActor implementations
13983  * that allocates the actor's preferred natural size. It can be used
13984  * by fixed layout managers (like #ClutterGroup or so called
13985  * 'composite actors') inside the ClutterActor::allocate
13986  * implementation to give each child exactly how much space it
13987  * requires.
13988  *
13989  * This function is not meant to be used by applications. It is also
13990  * not meant to be used outside the implementation of the
13991  * ClutterActor::allocate virtual function.
13992  *
13993  * Since: 0.8
13994  */
13995 void
13996 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13997                                        ClutterAllocationFlags  flags)
13998 {
13999   gfloat actor_x, actor_y;
14000   gfloat natural_width, natural_height;
14001   ClutterActorBox actor_box;
14002
14003   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14004
14005   actor_x = clutter_actor_get_x (self);
14006   actor_y = clutter_actor_get_y (self);
14007
14008   clutter_actor_get_preferred_size (self,
14009                                     NULL, NULL,
14010                                     &natural_width,
14011                                     &natural_height);
14012
14013   actor_box.x1 = actor_x;
14014   actor_box.y1 = actor_y;
14015   actor_box.x2 = actor_box.x1 + natural_width;
14016   actor_box.y2 = actor_box.y1 + natural_height;
14017
14018   clutter_actor_allocate (self, &actor_box, flags);
14019 }
14020
14021 /**
14022  * clutter_actor_allocate_align_fill:
14023  * @self: a #ClutterActor
14024  * @box: a #ClutterActorBox, containing the available width and height
14025  * @x_align: the horizontal alignment, between 0 and 1
14026  * @y_align: the vertical alignment, between 0 and 1
14027  * @x_fill: whether the actor should fill horizontally
14028  * @y_fill: whether the actor should fill vertically
14029  * @flags: allocation flags to be passed to clutter_actor_allocate()
14030  *
14031  * Allocates @self by taking into consideration the available allocation
14032  * area; an alignment factor on either axis; and whether the actor should
14033  * fill the allocation on either axis.
14034  *
14035  * The @box should contain the available allocation width and height;
14036  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
14037  * allocation will be offset by their value.
14038  *
14039  * This function takes into consideration the geometry request specified by
14040  * the #ClutterActor:request-mode property, and the text direction.
14041  *
14042  * This function is useful for fluid layout managers, like #ClutterBinLayout
14043  * or #ClutterTableLayout
14044  *
14045  * Since: 1.4
14046  */
14047 void
14048 clutter_actor_allocate_align_fill (ClutterActor           *self,
14049                                    const ClutterActorBox  *box,
14050                                    gdouble                 x_align,
14051                                    gdouble                 y_align,
14052                                    gboolean                x_fill,
14053                                    gboolean                y_fill,
14054                                    ClutterAllocationFlags  flags)
14055 {
14056   ClutterActorPrivate *priv;
14057   ClutterActorBox allocation = { 0, };
14058   gfloat x_offset, y_offset;
14059   gfloat available_width, available_height;
14060   gfloat child_width, child_height;
14061
14062   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14063   g_return_if_fail (box != NULL);
14064   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
14065   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
14066
14067   priv = self->priv;
14068
14069   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
14070   clutter_actor_box_get_size (box, &available_width, &available_height);
14071
14072   if (available_width < 0)
14073     available_width = 0;
14074
14075   if (available_height < 0)
14076     available_height = 0;
14077
14078   if (x_fill)
14079     {
14080       allocation.x1 = x_offset;
14081       allocation.x2 = allocation.x1 + available_width;
14082     }
14083
14084   if (y_fill)
14085     {
14086       allocation.y1 = y_offset;
14087       allocation.y2 = allocation.y1 + available_height;
14088     }
14089
14090   /* if we are filling horizontally and vertically then we're done */
14091   if (x_fill && y_fill)
14092     goto out;
14093
14094   child_width = child_height = 0.0f;
14095
14096   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
14097     {
14098       gfloat min_width, natural_width;
14099       gfloat min_height, natural_height;
14100
14101       clutter_actor_get_preferred_width (self, available_height,
14102                                          &min_width,
14103                                          &natural_width);
14104
14105       child_width = CLAMP (natural_width, min_width, available_width);
14106
14107       if (!y_fill)
14108         {
14109           clutter_actor_get_preferred_height (self, child_width,
14110                                               &min_height,
14111                                               &natural_height);
14112
14113           child_height = CLAMP (natural_height, min_height, available_height);
14114         }
14115     }
14116   else
14117     {
14118       gfloat min_width, natural_width;
14119       gfloat min_height, natural_height;
14120
14121       clutter_actor_get_preferred_height (self, available_width,
14122                                           &min_height,
14123                                           &natural_height);
14124
14125       child_height = CLAMP (natural_height, min_height, available_height);
14126
14127       if (!x_fill)
14128         {
14129           clutter_actor_get_preferred_width (self, child_height,
14130                                              &min_width,
14131                                              &natural_width);
14132
14133           child_width = CLAMP (natural_width, min_width, available_width);
14134         }
14135     }
14136
14137   /* invert the horizontal alignment for RTL languages */
14138   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
14139     x_align = 1.0 - x_align;
14140
14141   if (!x_fill)
14142     {
14143       allocation.x1 = x_offset
14144                     + ((available_width - child_width) * x_align);
14145       allocation.x2 = allocation.x1 + child_width;
14146     }
14147
14148   if (!y_fill)
14149     {
14150       allocation.y1 = y_offset
14151                     + ((available_height - child_height) * y_align);
14152       allocation.y2 = allocation.y1 + child_height;
14153     }
14154
14155 out:
14156   clutter_actor_box_clamp_to_pixel (&allocation);
14157   clutter_actor_allocate (self, &allocation, flags);
14158 }
14159
14160 /**
14161  * clutter_actor_grab_key_focus:
14162  * @self: a #ClutterActor
14163  *
14164  * Sets the key focus of the #ClutterStage including @self
14165  * to this #ClutterActor.
14166  *
14167  * Since: 1.0
14168  */
14169 void
14170 clutter_actor_grab_key_focus (ClutterActor *self)
14171 {
14172   ClutterActor *stage;
14173
14174   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14175
14176   stage = _clutter_actor_get_stage_internal (self);
14177   if (stage != NULL)
14178     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14179 }
14180
14181 /**
14182  * clutter_actor_get_pango_context:
14183  * @self: a #ClutterActor
14184  *
14185  * Retrieves the #PangoContext for @self. The actor's #PangoContext
14186  * is already configured using the appropriate font map, resolution
14187  * and font options.
14188  *
14189  * Unlike clutter_actor_create_pango_context(), this context is owend
14190  * by the #ClutterActor and it will be updated each time the options
14191  * stored by the #ClutterBackend change.
14192  *
14193  * You can use the returned #PangoContext to create a #PangoLayout
14194  * and render text using cogl_pango_render_layout() to reuse the
14195  * glyphs cache also used by Clutter.
14196  *
14197  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14198  *   The returned #PangoContext is owned by the actor and should not be
14199  *   unreferenced by the application code
14200  *
14201  * Since: 1.0
14202  */
14203 PangoContext *
14204 clutter_actor_get_pango_context (ClutterActor *self)
14205 {
14206   ClutterActorPrivate *priv;
14207
14208   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14209
14210   priv = self->priv;
14211
14212   if (priv->pango_context != NULL)
14213     return priv->pango_context;
14214
14215   priv->pango_context = _clutter_context_get_pango_context ();
14216   g_object_ref (priv->pango_context);
14217
14218   return priv->pango_context;
14219 }
14220
14221 /**
14222  * clutter_actor_create_pango_context:
14223  * @self: a #ClutterActor
14224  *
14225  * Creates a #PangoContext for the given actor. The #PangoContext
14226  * is already configured using the appropriate font map, resolution
14227  * and font options.
14228  *
14229  * See also clutter_actor_get_pango_context().
14230  *
14231  * Return value: (transfer full): the newly created #PangoContext.
14232  *   Use g_object_unref() on the returned value to deallocate its
14233  *   resources
14234  *
14235  * Since: 1.0
14236  */
14237 PangoContext *
14238 clutter_actor_create_pango_context (ClutterActor *self)
14239 {
14240   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14241
14242   return _clutter_context_create_pango_context ();
14243 }
14244
14245 /**
14246  * clutter_actor_create_pango_layout:
14247  * @self: a #ClutterActor
14248  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14249  *
14250  * Creates a new #PangoLayout from the same #PangoContext used
14251  * by the #ClutterActor. The #PangoLayout is already configured
14252  * with the font map, resolution and font options, and the
14253  * given @text.
14254  *
14255  * If you want to keep around a #PangoLayout created by this
14256  * function you will have to connect to the #ClutterBackend::font-changed
14257  * and #ClutterBackend::resolution-changed signals, and call
14258  * pango_layout_context_changed() in response to them.
14259  *
14260  * Return value: (transfer full): the newly created #PangoLayout.
14261  *   Use g_object_unref() when done
14262  *
14263  * Since: 1.0
14264  */
14265 PangoLayout *
14266 clutter_actor_create_pango_layout (ClutterActor *self,
14267                                    const gchar  *text)
14268 {
14269   PangoContext *context;
14270   PangoLayout *layout;
14271
14272   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14273
14274   context = clutter_actor_get_pango_context (self);
14275   layout = pango_layout_new (context);
14276
14277   if (text)
14278     pango_layout_set_text (layout, text, -1);
14279
14280   return layout;
14281 }
14282
14283 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14284  * ClutterOffscreenEffect.
14285  */
14286 void
14287 _clutter_actor_set_opacity_override (ClutterActor *self,
14288                                      gint          opacity)
14289 {
14290   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14291
14292   self->priv->opacity_override = opacity;
14293 }
14294
14295 gint
14296 _clutter_actor_get_opacity_override (ClutterActor *self)
14297 {
14298   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14299
14300   return self->priv->opacity_override;
14301 }
14302
14303 /* Allows you to disable applying the actors model view transform during
14304  * a paint. Used by ClutterClone. */
14305 void
14306 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14307                                                 gboolean      enable)
14308 {
14309   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14310
14311   self->priv->enable_model_view_transform = enable;
14312 }
14313
14314 void
14315 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14316                                           gboolean      enable)
14317 {
14318   ClutterActorPrivate *priv;
14319
14320   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14321
14322   priv = self->priv;
14323
14324   priv->enable_paint_unmapped = enable;
14325
14326   if (priv->enable_paint_unmapped)
14327     {
14328       /* Make sure that the parents of the widget are realized first;
14329        * otherwise checks in clutter_actor_update_map_state() will
14330        * fail.
14331        */
14332       clutter_actor_realize (self);
14333
14334       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14335     }
14336   else
14337     {
14338       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14339     }
14340 }
14341
14342 static void
14343 clutter_anchor_coord_get_units (ClutterActor      *self,
14344                                 const AnchorCoord *coord,
14345                                 gfloat            *x,
14346                                 gfloat            *y,
14347                                 gfloat            *z)
14348 {
14349   if (coord->is_fractional)
14350     {
14351       gfloat actor_width, actor_height;
14352
14353       clutter_actor_get_size (self, &actor_width, &actor_height);
14354
14355       if (x)
14356         *x = actor_width * coord->v.fraction.x;
14357
14358       if (y)
14359         *y = actor_height * coord->v.fraction.y;
14360
14361       if (z)
14362         *z = 0;
14363     }
14364   else
14365     {
14366       if (x)
14367         *x = coord->v.units.x;
14368
14369       if (y)
14370         *y = coord->v.units.y;
14371
14372       if (z)
14373         *z = coord->v.units.z;
14374     }
14375 }
14376
14377 static void
14378 clutter_anchor_coord_set_units (AnchorCoord *coord,
14379                                 gfloat       x,
14380                                 gfloat       y,
14381                                 gfloat       z)
14382 {
14383   coord->is_fractional = FALSE;
14384   coord->v.units.x = x;
14385   coord->v.units.y = y;
14386   coord->v.units.z = z;
14387 }
14388
14389 static ClutterGravity
14390 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14391 {
14392   if (coord->is_fractional)
14393     {
14394       if (coord->v.fraction.x == 0.0)
14395         {
14396           if (coord->v.fraction.y == 0.0)
14397             return CLUTTER_GRAVITY_NORTH_WEST;
14398           else if (coord->v.fraction.y == 0.5)
14399             return CLUTTER_GRAVITY_WEST;
14400           else if (coord->v.fraction.y == 1.0)
14401             return CLUTTER_GRAVITY_SOUTH_WEST;
14402           else
14403             return CLUTTER_GRAVITY_NONE;
14404         }
14405       else if (coord->v.fraction.x == 0.5)
14406         {
14407           if (coord->v.fraction.y == 0.0)
14408             return CLUTTER_GRAVITY_NORTH;
14409           else if (coord->v.fraction.y == 0.5)
14410             return CLUTTER_GRAVITY_CENTER;
14411           else if (coord->v.fraction.y == 1.0)
14412             return CLUTTER_GRAVITY_SOUTH;
14413           else
14414             return CLUTTER_GRAVITY_NONE;
14415         }
14416       else if (coord->v.fraction.x == 1.0)
14417         {
14418           if (coord->v.fraction.y == 0.0)
14419             return CLUTTER_GRAVITY_NORTH_EAST;
14420           else if (coord->v.fraction.y == 0.5)
14421             return CLUTTER_GRAVITY_EAST;
14422           else if (coord->v.fraction.y == 1.0)
14423             return CLUTTER_GRAVITY_SOUTH_EAST;
14424           else
14425             return CLUTTER_GRAVITY_NONE;
14426         }
14427       else
14428         return CLUTTER_GRAVITY_NONE;
14429     }
14430   else
14431     return CLUTTER_GRAVITY_NONE;
14432 }
14433
14434 static void
14435 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14436                                   ClutterGravity  gravity)
14437 {
14438   switch (gravity)
14439     {
14440     case CLUTTER_GRAVITY_NORTH:
14441       coord->v.fraction.x = 0.5;
14442       coord->v.fraction.y = 0.0;
14443       break;
14444
14445     case CLUTTER_GRAVITY_NORTH_EAST:
14446       coord->v.fraction.x = 1.0;
14447       coord->v.fraction.y = 0.0;
14448       break;
14449
14450     case CLUTTER_GRAVITY_EAST:
14451       coord->v.fraction.x = 1.0;
14452       coord->v.fraction.y = 0.5;
14453       break;
14454
14455     case CLUTTER_GRAVITY_SOUTH_EAST:
14456       coord->v.fraction.x = 1.0;
14457       coord->v.fraction.y = 1.0;
14458       break;
14459
14460     case CLUTTER_GRAVITY_SOUTH:
14461       coord->v.fraction.x = 0.5;
14462       coord->v.fraction.y = 1.0;
14463       break;
14464
14465     case CLUTTER_GRAVITY_SOUTH_WEST:
14466       coord->v.fraction.x = 0.0;
14467       coord->v.fraction.y = 1.0;
14468       break;
14469
14470     case CLUTTER_GRAVITY_WEST:
14471       coord->v.fraction.x = 0.0;
14472       coord->v.fraction.y = 0.5;
14473       break;
14474
14475     case CLUTTER_GRAVITY_NORTH_WEST:
14476       coord->v.fraction.x = 0.0;
14477       coord->v.fraction.y = 0.0;
14478       break;
14479
14480     case CLUTTER_GRAVITY_CENTER:
14481       coord->v.fraction.x = 0.5;
14482       coord->v.fraction.y = 0.5;
14483       break;
14484
14485     default:
14486       coord->v.fraction.x = 0.0;
14487       coord->v.fraction.y = 0.0;
14488       break;
14489     }
14490
14491   coord->is_fractional = TRUE;
14492 }
14493
14494 static gboolean
14495 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14496 {
14497   if (coord->is_fractional)
14498     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14499   else
14500     return (coord->v.units.x == 0.0
14501             && coord->v.units.y == 0.0
14502             && coord->v.units.z == 0.0);
14503 }
14504
14505 /**
14506  * clutter_actor_get_flags:
14507  * @self: a #ClutterActor
14508  *
14509  * Retrieves the flags set on @self
14510  *
14511  * Return value: a bitwise or of #ClutterActorFlags or 0
14512  *
14513  * Since: 1.0
14514  */
14515 ClutterActorFlags
14516 clutter_actor_get_flags (ClutterActor *self)
14517 {
14518   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14519
14520   return self->flags;
14521 }
14522
14523 /**
14524  * clutter_actor_set_flags:
14525  * @self: a #ClutterActor
14526  * @flags: the flags to set
14527  *
14528  * Sets @flags on @self
14529  *
14530  * This function will emit notifications for the changed properties
14531  *
14532  * Since: 1.0
14533  */
14534 void
14535 clutter_actor_set_flags (ClutterActor      *self,
14536                          ClutterActorFlags  flags)
14537 {
14538   ClutterActorFlags old_flags;
14539   GObject *obj;
14540   gboolean was_reactive_set, reactive_set;
14541   gboolean was_realized_set, realized_set;
14542   gboolean was_mapped_set, mapped_set;
14543   gboolean was_visible_set, visible_set;
14544
14545   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14546
14547   if (self->flags == flags)
14548     return;
14549
14550   obj = G_OBJECT (self);
14551   g_object_ref (obj);
14552   g_object_freeze_notify (obj);
14553
14554   old_flags = self->flags;
14555
14556   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14557   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14558   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14559   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14560
14561   self->flags |= flags;
14562
14563   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14564   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14565   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14566   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14567
14568   if (reactive_set != was_reactive_set)
14569     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14570
14571   if (realized_set != was_realized_set)
14572     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14573
14574   if (mapped_set != was_mapped_set)
14575     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14576
14577   if (visible_set != was_visible_set)
14578     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14579
14580   g_object_thaw_notify (obj);
14581   g_object_unref (obj);
14582 }
14583
14584 /**
14585  * clutter_actor_unset_flags:
14586  * @self: a #ClutterActor
14587  * @flags: the flags to unset
14588  *
14589  * Unsets @flags on @self
14590  *
14591  * This function will emit notifications for the changed properties
14592  *
14593  * Since: 1.0
14594  */
14595 void
14596 clutter_actor_unset_flags (ClutterActor      *self,
14597                            ClutterActorFlags  flags)
14598 {
14599   ClutterActorFlags old_flags;
14600   GObject *obj;
14601   gboolean was_reactive_set, reactive_set;
14602   gboolean was_realized_set, realized_set;
14603   gboolean was_mapped_set, mapped_set;
14604   gboolean was_visible_set, visible_set;
14605
14606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14607
14608   obj = G_OBJECT (self);
14609   g_object_freeze_notify (obj);
14610
14611   old_flags = self->flags;
14612
14613   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14614   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14615   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14616   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14617
14618   self->flags &= ~flags;
14619
14620   if (self->flags == old_flags)
14621     return;
14622
14623   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14624   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14625   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14626   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14627
14628   if (reactive_set != was_reactive_set)
14629     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14630
14631   if (realized_set != was_realized_set)
14632     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14633
14634   if (mapped_set != was_mapped_set)
14635     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14636
14637   if (visible_set != was_visible_set)
14638     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14639
14640   g_object_thaw_notify (obj);
14641 }
14642
14643 /**
14644  * clutter_actor_get_transformation_matrix:
14645  * @self: a #ClutterActor
14646  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14647  *
14648  * Retrieves the transformations applied to @self relative to its
14649  * parent.
14650  *
14651  * Since: 1.0
14652  */
14653 void
14654 clutter_actor_get_transformation_matrix (ClutterActor *self,
14655                                          CoglMatrix   *matrix)
14656 {
14657   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14658
14659   cogl_matrix_init_identity (matrix);
14660
14661   _clutter_actor_apply_modelview_transform (self, matrix);
14662 }
14663
14664 void
14665 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14666                                    gboolean      is_in_clone_paint)
14667 {
14668   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14669   self->priv->in_clone_paint = is_in_clone_paint;
14670 }
14671
14672 /**
14673  * clutter_actor_is_in_clone_paint:
14674  * @self: a #ClutterActor
14675  *
14676  * Checks whether @self is being currently painted by a #ClutterClone
14677  *
14678  * This function is useful only inside the ::paint virtual function
14679  * implementations or within handlers for the #ClutterActor::paint
14680  * signal
14681  *
14682  * This function should not be used by applications
14683  *
14684  * Return value: %TRUE if the #ClutterActor is currently being painted
14685  *   by a #ClutterClone, and %FALSE otherwise
14686  *
14687  * Since: 1.0
14688  */
14689 gboolean
14690 clutter_actor_is_in_clone_paint (ClutterActor *self)
14691 {
14692   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14693
14694   return self->priv->in_clone_paint;
14695 }
14696
14697 static gboolean
14698 set_direction_recursive (ClutterActor *actor,
14699                          gpointer      user_data)
14700 {
14701   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14702
14703   clutter_actor_set_text_direction (actor, text_dir);
14704
14705   return TRUE;
14706 }
14707
14708 /**
14709  * clutter_actor_set_text_direction:
14710  * @self: a #ClutterActor
14711  * @text_dir: the text direction for @self
14712  *
14713  * Sets the #ClutterTextDirection for an actor
14714  *
14715  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14716  *
14717  * If @self implements #ClutterContainer then this function will recurse
14718  * inside all the children of @self (including the internal ones).
14719  *
14720  * Composite actors not implementing #ClutterContainer, or actors requiring
14721  * special handling when the text direction changes, should connect to
14722  * the #GObject::notify signal for the #ClutterActor:text-direction property
14723  *
14724  * Since: 1.2
14725  */
14726 void
14727 clutter_actor_set_text_direction (ClutterActor         *self,
14728                                   ClutterTextDirection  text_dir)
14729 {
14730   ClutterActorPrivate *priv;
14731
14732   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14733   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14734
14735   priv = self->priv;
14736
14737   if (priv->text_direction != text_dir)
14738     {
14739       priv->text_direction = text_dir;
14740
14741       /* we need to emit the notify::text-direction first, so that
14742        * the sub-classes can catch that and do specific handling of
14743        * the text direction; see clutter_text_direction_changed_cb()
14744        * inside clutter-text.c
14745        */
14746       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14747
14748       _clutter_actor_foreach_child (self, set_direction_recursive,
14749                                     GINT_TO_POINTER (text_dir));
14750
14751       clutter_actor_queue_relayout (self);
14752     }
14753 }
14754
14755 void
14756 _clutter_actor_set_has_pointer (ClutterActor *self,
14757                                 gboolean      has_pointer)
14758 {
14759   ClutterActorPrivate *priv = self->priv;
14760
14761   if (priv->has_pointer != has_pointer)
14762     {
14763       priv->has_pointer = has_pointer;
14764
14765       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14766     }
14767 }
14768
14769 /**
14770  * clutter_actor_get_text_direction:
14771  * @self: a #ClutterActor
14772  *
14773  * Retrieves the value set using clutter_actor_set_text_direction()
14774  *
14775  * If no text direction has been previously set, the default text
14776  * direction, as returned by clutter_get_default_text_direction(), will
14777  * be returned instead
14778  *
14779  * Return value: the #ClutterTextDirection for the actor
14780  *
14781  * Since: 1.2
14782  */
14783 ClutterTextDirection
14784 clutter_actor_get_text_direction (ClutterActor *self)
14785 {
14786   ClutterActorPrivate *priv;
14787
14788   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14789                         CLUTTER_TEXT_DIRECTION_LTR);
14790
14791   priv = self->priv;
14792
14793   /* if no direction has been set yet use the default */
14794   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14795     priv->text_direction = clutter_get_default_text_direction ();
14796
14797   return priv->text_direction;
14798 }
14799
14800 /**
14801  * clutter_actor_push_internal:
14802  * @self: a #ClutterActor
14803  *
14804  * Should be used by actors implementing the #ClutterContainer and with
14805  * internal children added through clutter_actor_set_parent(), for instance:
14806  *
14807  * |[
14808  *   static void
14809  *   my_actor_init (MyActor *self)
14810  *   {
14811  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14812  *
14813  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14814  *
14815  *     /&ast; calling clutter_actor_set_parent() now will result in
14816  *      &ast; the internal flag being set on a child of MyActor
14817  *      &ast;/
14818  *
14819  *     /&ast; internal child - a background texture &ast;/
14820  *     self->priv->background_tex = clutter_texture_new ();
14821  *     clutter_actor_set_parent (self->priv->background_tex,
14822  *                               CLUTTER_ACTOR (self));
14823  *
14824  *     /&ast; internal child - a label &ast;/
14825  *     self->priv->label = clutter_text_new ();
14826  *     clutter_actor_set_parent (self->priv->label,
14827  *                               CLUTTER_ACTOR (self));
14828  *
14829  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14830  *
14831  *     /&ast; calling clutter_actor_set_parent() now will not result in
14832  *      &ast; the internal flag being set on a child of MyActor
14833  *      &ast;/
14834  *   }
14835  * ]|
14836  *
14837  * This function will be used by Clutter to toggle an "internal child"
14838  * flag whenever clutter_actor_set_parent() is called; internal children
14839  * are handled differently by Clutter, specifically when destroying their
14840  * parent.
14841  *
14842  * Call clutter_actor_pop_internal() when you finished adding internal
14843  * children.
14844  *
14845  * Nested calls to clutter_actor_push_internal() are allowed, but each
14846  * one must by followed by a clutter_actor_pop_internal() call.
14847  *
14848  * Since: 1.2
14849  *
14850  * Deprecated: 1.10: All children of an actor are accessible through
14851  *   the #ClutterActor API, and #ClutterActor implements the
14852  *   #ClutterContainer interface, so this function is only useful
14853  *   for legacy containers overriding the default implementation.
14854  */
14855 void
14856 clutter_actor_push_internal (ClutterActor *self)
14857 {
14858   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14859
14860   self->priv->internal_child += 1;
14861 }
14862
14863 /**
14864  * clutter_actor_pop_internal:
14865  * @self: a #ClutterActor
14866  *
14867  * Disables the effects of clutter_actor_push_internal().
14868  *
14869  * Since: 1.2
14870  *
14871  * Deprecated: 1.10: All children of an actor are accessible through
14872  *   the #ClutterActor API. This function is only useful for legacy
14873  *   containers overriding the default implementation of the
14874  *   #ClutterContainer interface.
14875  */
14876 void
14877 clutter_actor_pop_internal (ClutterActor *self)
14878 {
14879   ClutterActorPrivate *priv;
14880
14881   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14882
14883   priv = self->priv;
14884
14885   if (priv->internal_child == 0)
14886     {
14887       g_warning ("Mismatched %s: you need to call "
14888                  "clutter_actor_push_composite() at least once before "
14889                  "calling this function", G_STRFUNC);
14890       return;
14891     }
14892
14893   priv->internal_child -= 1;
14894 }
14895
14896 /**
14897  * clutter_actor_has_pointer:
14898  * @self: a #ClutterActor
14899  *
14900  * Checks whether an actor contains the pointer of a
14901  * #ClutterInputDevice
14902  *
14903  * Return value: %TRUE if the actor contains the pointer, and
14904  *   %FALSE otherwise
14905  *
14906  * Since: 1.2
14907  */
14908 gboolean
14909 clutter_actor_has_pointer (ClutterActor *self)
14910 {
14911   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14912
14913   return self->priv->has_pointer;
14914 }
14915
14916 /* XXX: This is a workaround for not being able to break the ABI of
14917  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14918  * clutter_actor_queue_clipped_redraw() for details.
14919  */
14920 ClutterPaintVolume *
14921 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14922 {
14923   return g_object_get_data (G_OBJECT (self),
14924                             "-clutter-actor-queue-redraw-clip");
14925 }
14926
14927 void
14928 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14929                                       ClutterPaintVolume *clip)
14930 {
14931   g_object_set_data (G_OBJECT (self),
14932                      "-clutter-actor-queue-redraw-clip",
14933                      clip);
14934 }
14935
14936 /**
14937  * clutter_actor_has_allocation:
14938  * @self: a #ClutterActor
14939  *
14940  * Checks if the actor has an up-to-date allocation assigned to
14941  * it. This means that the actor should have an allocation: it's
14942  * visible and has a parent. It also means that there is no
14943  * outstanding relayout request in progress for the actor or its
14944  * children (There might be other outstanding layout requests in
14945  * progress that will cause the actor to get a new allocation
14946  * when the stage is laid out, however).
14947  *
14948  * If this function returns %FALSE, then the actor will normally
14949  * be allocated before it is next drawn on the screen.
14950  *
14951  * Return value: %TRUE if the actor has an up-to-date allocation
14952  *
14953  * Since: 1.4
14954  */
14955 gboolean
14956 clutter_actor_has_allocation (ClutterActor *self)
14957 {
14958   ClutterActorPrivate *priv;
14959
14960   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14961
14962   priv = self->priv;
14963
14964   return priv->parent != NULL &&
14965          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14966          !priv->needs_allocation;
14967 }
14968
14969 /**
14970  * clutter_actor_add_action:
14971  * @self: a #ClutterActor
14972  * @action: a #ClutterAction
14973  *
14974  * Adds @action to the list of actions applied to @self
14975  *
14976  * A #ClutterAction can only belong to one actor at a time
14977  *
14978  * The #ClutterActor will hold a reference on @action until either
14979  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14980  * is called
14981  *
14982  * Since: 1.4
14983  */
14984 void
14985 clutter_actor_add_action (ClutterActor  *self,
14986                           ClutterAction *action)
14987 {
14988   ClutterActorPrivate *priv;
14989
14990   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14991   g_return_if_fail (CLUTTER_IS_ACTION (action));
14992
14993   priv = self->priv;
14994
14995   if (priv->actions == NULL)
14996     {
14997       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14998       priv->actions->actor = self;
14999     }
15000
15001   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
15002
15003   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15004 }
15005
15006 /**
15007  * clutter_actor_add_action_with_name:
15008  * @self: a #ClutterActor
15009  * @name: the name to set on the action
15010  * @action: a #ClutterAction
15011  *
15012  * A convenience function for setting the name of a #ClutterAction
15013  * while adding it to the list of actions applied to @self
15014  *
15015  * This function is the logical equivalent of:
15016  *
15017  * |[
15018  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15019  *   clutter_actor_add_action (self, action);
15020  * ]|
15021  *
15022  * Since: 1.4
15023  */
15024 void
15025 clutter_actor_add_action_with_name (ClutterActor  *self,
15026                                     const gchar   *name,
15027                                     ClutterAction *action)
15028 {
15029   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15030   g_return_if_fail (name != NULL);
15031   g_return_if_fail (CLUTTER_IS_ACTION (action));
15032
15033   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15034   clutter_actor_add_action (self, action);
15035 }
15036
15037 /**
15038  * clutter_actor_remove_action:
15039  * @self: a #ClutterActor
15040  * @action: a #ClutterAction
15041  *
15042  * Removes @action from the list of actions applied to @self
15043  *
15044  * The reference held by @self on the #ClutterAction will be released
15045  *
15046  * Since: 1.4
15047  */
15048 void
15049 clutter_actor_remove_action (ClutterActor  *self,
15050                              ClutterAction *action)
15051 {
15052   ClutterActorPrivate *priv;
15053
15054   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15055   g_return_if_fail (CLUTTER_IS_ACTION (action));
15056
15057   priv = self->priv;
15058
15059   if (priv->actions == NULL)
15060     return;
15061
15062   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
15063
15064   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
15065     g_clear_object (&priv->actions);
15066
15067   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15068 }
15069
15070 /**
15071  * clutter_actor_remove_action_by_name:
15072  * @self: a #ClutterActor
15073  * @name: the name of the action to remove
15074  *
15075  * Removes the #ClutterAction with the given name from the list
15076  * of actions applied to @self
15077  *
15078  * Since: 1.4
15079  */
15080 void
15081 clutter_actor_remove_action_by_name (ClutterActor *self,
15082                                      const gchar  *name)
15083 {
15084   ClutterActorPrivate *priv;
15085   ClutterActorMeta *meta;
15086
15087   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15088   g_return_if_fail (name != NULL);
15089
15090   priv = self->priv;
15091
15092   if (priv->actions == NULL)
15093     return;
15094
15095   meta = _clutter_meta_group_get_meta (priv->actions, name);
15096   if (meta == NULL)
15097     return;
15098
15099   _clutter_meta_group_remove_meta (priv->actions, meta);
15100
15101   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15102 }
15103
15104 /**
15105  * clutter_actor_get_actions:
15106  * @self: a #ClutterActor
15107  *
15108  * Retrieves the list of actions applied to @self
15109  *
15110  * Return value: (transfer container) (element-type Clutter.Action): a copy
15111  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
15112  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15113  *   allocated by the returned #GList
15114  *
15115  * Since: 1.4
15116  */
15117 GList *
15118 clutter_actor_get_actions (ClutterActor *self)
15119 {
15120   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15121
15122   if (self->priv->actions == NULL)
15123     return NULL;
15124
15125   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
15126 }
15127
15128 /**
15129  * clutter_actor_get_action:
15130  * @self: a #ClutterActor
15131  * @name: the name of the action to retrieve
15132  *
15133  * Retrieves the #ClutterAction with the given name in the list
15134  * of actions applied to @self
15135  *
15136  * Return value: (transfer none): a #ClutterAction for the given
15137  *   name, or %NULL. The returned #ClutterAction is owned by the
15138  *   actor and it should not be unreferenced directly
15139  *
15140  * Since: 1.4
15141  */
15142 ClutterAction *
15143 clutter_actor_get_action (ClutterActor *self,
15144                           const gchar  *name)
15145 {
15146   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15147   g_return_val_if_fail (name != NULL, NULL);
15148
15149   if (self->priv->actions == NULL)
15150     return NULL;
15151
15152   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
15153 }
15154
15155 /**
15156  * clutter_actor_clear_actions:
15157  * @self: a #ClutterActor
15158  *
15159  * Clears the list of actions applied to @self
15160  *
15161  * Since: 1.4
15162  */
15163 void
15164 clutter_actor_clear_actions (ClutterActor *self)
15165 {
15166   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15167
15168   if (self->priv->actions == NULL)
15169     return;
15170
15171   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15172 }
15173
15174 /**
15175  * clutter_actor_add_constraint:
15176  * @self: a #ClutterActor
15177  * @constraint: a #ClutterConstraint
15178  *
15179  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15180  * to @self
15181  *
15182  * The #ClutterActor will hold a reference on the @constraint until
15183  * either clutter_actor_remove_constraint() or
15184  * clutter_actor_clear_constraints() is called.
15185  *
15186  * Since: 1.4
15187  */
15188 void
15189 clutter_actor_add_constraint (ClutterActor      *self,
15190                               ClutterConstraint *constraint)
15191 {
15192   ClutterActorPrivate *priv;
15193
15194   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15195   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15196
15197   priv = self->priv;
15198
15199   if (priv->constraints == NULL)
15200     {
15201       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15202       priv->constraints->actor = self;
15203     }
15204
15205   _clutter_meta_group_add_meta (priv->constraints,
15206                                 CLUTTER_ACTOR_META (constraint));
15207   clutter_actor_queue_relayout (self);
15208
15209   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15210 }
15211
15212 /**
15213  * clutter_actor_add_constraint_with_name:
15214  * @self: a #ClutterActor
15215  * @name: the name to set on the constraint
15216  * @constraint: a #ClutterConstraint
15217  *
15218  * A convenience function for setting the name of a #ClutterConstraint
15219  * while adding it to the list of constraints applied to @self
15220  *
15221  * This function is the logical equivalent of:
15222  *
15223  * |[
15224  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15225  *   clutter_actor_add_constraint (self, constraint);
15226  * ]|
15227  *
15228  * Since: 1.4
15229  */
15230 void
15231 clutter_actor_add_constraint_with_name (ClutterActor      *self,
15232                                         const gchar       *name,
15233                                         ClutterConstraint *constraint)
15234 {
15235   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15236   g_return_if_fail (name != NULL);
15237   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15238
15239   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15240   clutter_actor_add_constraint (self, constraint);
15241 }
15242
15243 /**
15244  * clutter_actor_remove_constraint:
15245  * @self: a #ClutterActor
15246  * @constraint: a #ClutterConstraint
15247  *
15248  * Removes @constraint from the list of constraints applied to @self
15249  *
15250  * The reference held by @self on the #ClutterConstraint will be released
15251  *
15252  * Since: 1.4
15253  */
15254 void
15255 clutter_actor_remove_constraint (ClutterActor      *self,
15256                                  ClutterConstraint *constraint)
15257 {
15258   ClutterActorPrivate *priv;
15259
15260   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15261   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15262
15263   priv = self->priv;
15264
15265   if (priv->constraints == NULL)
15266     return;
15267
15268   _clutter_meta_group_remove_meta (priv->constraints,
15269                                    CLUTTER_ACTOR_META (constraint));
15270
15271   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15272     g_clear_object (&priv->constraints);
15273
15274   clutter_actor_queue_relayout (self);
15275
15276   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15277 }
15278
15279 /**
15280  * clutter_actor_remove_constraint_by_name:
15281  * @self: a #ClutterActor
15282  * @name: the name of the constraint to remove
15283  *
15284  * Removes the #ClutterConstraint with the given name from the list
15285  * of constraints applied to @self
15286  *
15287  * Since: 1.4
15288  */
15289 void
15290 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15291                                          const gchar  *name)
15292 {
15293   ClutterActorPrivate *priv;
15294   ClutterActorMeta *meta;
15295
15296   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15297   g_return_if_fail (name != NULL);
15298
15299   priv = self->priv;
15300
15301   if (priv->constraints == NULL)
15302     return;
15303
15304   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15305   if (meta == NULL)
15306     return;
15307
15308   _clutter_meta_group_remove_meta (priv->constraints, meta);
15309   clutter_actor_queue_relayout (self);
15310 }
15311
15312 /**
15313  * clutter_actor_get_constraints:
15314  * @self: a #ClutterActor
15315  *
15316  * Retrieves the list of constraints applied to @self
15317  *
15318  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15319  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15320  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15321  *   allocated by the returned #GList
15322  *
15323  * Since: 1.4
15324  */
15325 GList *
15326 clutter_actor_get_constraints (ClutterActor *self)
15327 {
15328   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15329
15330   if (self->priv->constraints == NULL)
15331     return NULL;
15332
15333   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15334 }
15335
15336 /**
15337  * clutter_actor_get_constraint:
15338  * @self: a #ClutterActor
15339  * @name: the name of the constraint to retrieve
15340  *
15341  * Retrieves the #ClutterConstraint with the given name in the list
15342  * of constraints applied to @self
15343  *
15344  * Return value: (transfer none): a #ClutterConstraint for the given
15345  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15346  *   actor and it should not be unreferenced directly
15347  *
15348  * Since: 1.4
15349  */
15350 ClutterConstraint *
15351 clutter_actor_get_constraint (ClutterActor *self,
15352                               const gchar  *name)
15353 {
15354   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15355   g_return_val_if_fail (name != NULL, NULL);
15356
15357   if (self->priv->constraints == NULL)
15358     return NULL;
15359
15360   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15361 }
15362
15363 /**
15364  * clutter_actor_clear_constraints:
15365  * @self: a #ClutterActor
15366  *
15367  * Clears the list of constraints applied to @self
15368  *
15369  * Since: 1.4
15370  */
15371 void
15372 clutter_actor_clear_constraints (ClutterActor *self)
15373 {
15374   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15375
15376   if (self->priv->constraints == NULL)
15377     return;
15378
15379   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15380
15381   clutter_actor_queue_relayout (self);
15382 }
15383
15384 /**
15385  * clutter_actor_set_clip_to_allocation:
15386  * @self: a #ClutterActor
15387  * @clip_set: %TRUE to apply a clip tracking the allocation
15388  *
15389  * Sets whether @self should be clipped to the same size as its
15390  * allocation
15391  *
15392  * Since: 1.4
15393  */
15394 void
15395 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15396                                       gboolean      clip_set)
15397 {
15398   ClutterActorPrivate *priv;
15399
15400   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15401
15402   clip_set = !!clip_set;
15403
15404   priv = self->priv;
15405
15406   if (priv->clip_to_allocation != clip_set)
15407     {
15408       priv->clip_to_allocation = clip_set;
15409
15410       clutter_actor_queue_redraw (self);
15411
15412       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15413     }
15414 }
15415
15416 /**
15417  * clutter_actor_get_clip_to_allocation:
15418  * @self: a #ClutterActor
15419  *
15420  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15421  *
15422  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15423  *
15424  * Since: 1.4
15425  */
15426 gboolean
15427 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15428 {
15429   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15430
15431   return self->priv->clip_to_allocation;
15432 }
15433
15434 /**
15435  * clutter_actor_add_effect:
15436  * @self: a #ClutterActor
15437  * @effect: a #ClutterEffect
15438  *
15439  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15440  *
15441  * The #ClutterActor will hold a reference on the @effect until either
15442  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15443  * called.
15444  *
15445  * Since: 1.4
15446  */
15447 void
15448 clutter_actor_add_effect (ClutterActor  *self,
15449                           ClutterEffect *effect)
15450 {
15451   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15452   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15453
15454   _clutter_actor_add_effect_internal (self, effect);
15455
15456   clutter_actor_queue_redraw (self);
15457
15458   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15459 }
15460
15461 /**
15462  * clutter_actor_add_effect_with_name:
15463  * @self: a #ClutterActor
15464  * @name: the name to set on the effect
15465  * @effect: a #ClutterEffect
15466  *
15467  * A convenience function for setting the name of a #ClutterEffect
15468  * while adding it to the list of effectss applied to @self
15469  *
15470  * This function is the logical equivalent of:
15471  *
15472  * |[
15473  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15474  *   clutter_actor_add_effect (self, effect);
15475  * ]|
15476  *
15477  * Since: 1.4
15478  */
15479 void
15480 clutter_actor_add_effect_with_name (ClutterActor  *self,
15481                                     const gchar   *name,
15482                                     ClutterEffect *effect)
15483 {
15484   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15485   g_return_if_fail (name != NULL);
15486   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15487
15488   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15489   clutter_actor_add_effect (self, effect);
15490 }
15491
15492 /**
15493  * clutter_actor_remove_effect:
15494  * @self: a #ClutterActor
15495  * @effect: a #ClutterEffect
15496  *
15497  * Removes @effect from the list of effects applied to @self
15498  *
15499  * The reference held by @self on the #ClutterEffect will be released
15500  *
15501  * Since: 1.4
15502  */
15503 void
15504 clutter_actor_remove_effect (ClutterActor  *self,
15505                              ClutterEffect *effect)
15506 {
15507   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15508   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15509
15510   _clutter_actor_remove_effect_internal (self, effect);
15511
15512   clutter_actor_queue_redraw (self);
15513
15514   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15515 }
15516
15517 /**
15518  * clutter_actor_remove_effect_by_name:
15519  * @self: a #ClutterActor
15520  * @name: the name of the effect to remove
15521  *
15522  * Removes the #ClutterEffect with the given name from the list
15523  * of effects applied to @self
15524  *
15525  * Since: 1.4
15526  */
15527 void
15528 clutter_actor_remove_effect_by_name (ClutterActor *self,
15529                                      const gchar  *name)
15530 {
15531   ClutterActorPrivate *priv;
15532   ClutterActorMeta *meta;
15533
15534   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15535   g_return_if_fail (name != NULL);
15536
15537   priv = self->priv;
15538
15539   if (priv->effects == NULL)
15540     return;
15541
15542   meta = _clutter_meta_group_get_meta (priv->effects, name);
15543   if (meta == NULL)
15544     return;
15545
15546   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15547 }
15548
15549 /**
15550  * clutter_actor_get_effects:
15551  * @self: a #ClutterActor
15552  *
15553  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15554  *
15555  * Return value: (transfer container) (element-type Clutter.Effect): a list
15556  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15557  *   list are owned by Clutter and they should not be freed. You should
15558  *   free the returned list using g_list_free() when done
15559  *
15560  * Since: 1.4
15561  */
15562 GList *
15563 clutter_actor_get_effects (ClutterActor *self)
15564 {
15565   ClutterActorPrivate *priv;
15566
15567   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15568
15569   priv = self->priv;
15570
15571   if (priv->effects == NULL)
15572     return NULL;
15573
15574   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15575 }
15576
15577 /**
15578  * clutter_actor_get_effect:
15579  * @self: a #ClutterActor
15580  * @name: the name of the effect to retrieve
15581  *
15582  * Retrieves the #ClutterEffect with the given name in the list
15583  * of effects applied to @self
15584  *
15585  * Return value: (transfer none): a #ClutterEffect for the given
15586  *   name, or %NULL. The returned #ClutterEffect is owned by the
15587  *   actor and it should not be unreferenced directly
15588  *
15589  * Since: 1.4
15590  */
15591 ClutterEffect *
15592 clutter_actor_get_effect (ClutterActor *self,
15593                           const gchar  *name)
15594 {
15595   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15596   g_return_val_if_fail (name != NULL, NULL);
15597
15598   if (self->priv->effects == NULL)
15599     return NULL;
15600
15601   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15602 }
15603
15604 /**
15605  * clutter_actor_clear_effects:
15606  * @self: a #ClutterActor
15607  *
15608  * Clears the list of effects applied to @self
15609  *
15610  * Since: 1.4
15611  */
15612 void
15613 clutter_actor_clear_effects (ClutterActor *self)
15614 {
15615   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15616
15617   if (self->priv->effects == NULL)
15618     return;
15619
15620   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15621
15622   clutter_actor_queue_redraw (self);
15623 }
15624
15625 /**
15626  * clutter_actor_has_key_focus:
15627  * @self: a #ClutterActor
15628  *
15629  * Checks whether @self is the #ClutterActor that has key focus
15630  *
15631  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15632  *
15633  * Since: 1.4
15634  */
15635 gboolean
15636 clutter_actor_has_key_focus (ClutterActor *self)
15637 {
15638   ClutterActor *stage;
15639
15640   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15641
15642   stage = _clutter_actor_get_stage_internal (self);
15643   if (stage == NULL)
15644     return FALSE;
15645
15646   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15647 }
15648
15649 static gboolean
15650 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15651                                       ClutterPaintVolume *pv)
15652 {
15653   ClutterActorPrivate *priv = self->priv;
15654
15655   /* Actors are only expected to report a valid paint volume
15656    * while they have a valid allocation. */
15657   if (G_UNLIKELY (priv->needs_allocation))
15658     {
15659       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15660                     "Actor needs allocation",
15661                     _clutter_actor_get_debug_name (self));
15662       return FALSE;
15663     }
15664
15665   /* Check if there are any handlers connected to the paint
15666    * signal. If there are then all bets are off for what the paint
15667    * volume for this actor might possibly be!
15668    *
15669    * XXX: It's expected that this is going to end up being quite a
15670    * costly check to have to do here, but we haven't come up with
15671    * another solution that can reliably catch paint signal handlers at
15672    * the right time to either avoid artefacts due to invalid stage
15673    * clipping or due to incorrect culling.
15674    *
15675    * Previously we checked in clutter_actor_paint(), but at that time
15676    * we may already be using a stage clip that could be derived from
15677    * an invalid paint-volume. We used to try and handle that by
15678    * queuing a follow up, unclipped, redraw but still the previous
15679    * checking wasn't enough to catch invalid volumes involved in
15680    * culling (considering that containers may derive their volume from
15681    * children that haven't yet been painted)
15682    *
15683    * Longer term, improved solutions could be:
15684    * - Disallow painting in the paint signal, only allow using it
15685    *   for tracking when paints happen. We can add another API that
15686    *   allows monkey patching the paint of arbitrary actors but in a
15687    *   more controlled way and that also supports modifying the
15688    *   paint-volume.
15689    * - If we could be notified somehow when signal handlers are
15690    *   connected we wouldn't have to poll for handlers like this.
15691    */
15692   if (g_signal_has_handler_pending (self,
15693                                     actor_signals[PAINT],
15694                                     0,
15695                                     TRUE))
15696     {
15697       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15698                     "Actor has \"paint\" signal handlers",
15699                     _clutter_actor_get_debug_name (self));
15700       return FALSE;
15701     }
15702
15703   _clutter_paint_volume_init_static (pv, self);
15704
15705   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15706     {
15707       clutter_paint_volume_free (pv);
15708       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15709                     "Actor failed to report a volume",
15710                     _clutter_actor_get_debug_name (self));
15711       return FALSE;
15712     }
15713
15714   /* since effects can modify the paint volume, we allow them to actually
15715    * do this by making get_paint_volume() "context sensitive"
15716    */
15717   if (priv->effects != NULL)
15718     {
15719       if (priv->current_effect != NULL)
15720         {
15721           const GList *effects, *l;
15722
15723           /* if we are being called from within the paint sequence of
15724            * an actor, get the paint volume up to the current effect
15725            */
15726           effects = _clutter_meta_group_peek_metas (priv->effects);
15727           for (l = effects;
15728                l != NULL || (l != NULL && l->data != priv->current_effect);
15729                l = l->next)
15730             {
15731               if (!_clutter_effect_get_paint_volume (l->data, pv))
15732                 {
15733                   clutter_paint_volume_free (pv);
15734                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15735                                 "Effect (%s) failed to report a volume",
15736                                 _clutter_actor_get_debug_name (self),
15737                                 _clutter_actor_meta_get_debug_name (l->data));
15738                   return FALSE;
15739                 }
15740             }
15741         }
15742       else
15743         {
15744           const GList *effects, *l;
15745
15746           /* otherwise, get the cumulative volume */
15747           effects = _clutter_meta_group_peek_metas (priv->effects);
15748           for (l = effects; l != NULL; l = l->next)
15749             if (!_clutter_effect_get_paint_volume (l->data, pv))
15750               {
15751                 clutter_paint_volume_free (pv);
15752                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15753                               "Effect (%s) failed to report a volume",
15754                               _clutter_actor_get_debug_name (self),
15755                               _clutter_actor_meta_get_debug_name (l->data));
15756                 return FALSE;
15757               }
15758         }
15759     }
15760
15761   return TRUE;
15762 }
15763
15764 /* The public clutter_actor_get_paint_volume API returns a const
15765  * pointer since we return a pointer directly to the cached
15766  * PaintVolume associated with the actor and don't want the user to
15767  * inadvertently modify it, but for internal uses we sometimes need
15768  * access to the same PaintVolume but need to apply some book-keeping
15769  * modifications to it so we don't want a const pointer.
15770  */
15771 static ClutterPaintVolume *
15772 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15773 {
15774   ClutterActorPrivate *priv;
15775
15776   priv = self->priv;
15777
15778   if (priv->paint_volume_valid)
15779     clutter_paint_volume_free (&priv->paint_volume);
15780
15781   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15782     {
15783       priv->paint_volume_valid = TRUE;
15784       return &priv->paint_volume;
15785     }
15786   else
15787     {
15788       priv->paint_volume_valid = FALSE;
15789       return NULL;
15790     }
15791 }
15792
15793 /**
15794  * clutter_actor_get_paint_volume:
15795  * @self: a #ClutterActor
15796  *
15797  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15798  * when a paint volume can't be determined.
15799  *
15800  * The paint volume is defined as the 3D space occupied by an actor
15801  * when being painted.
15802  *
15803  * This function will call the <function>get_paint_volume()</function>
15804  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15805  * should not usually care about overriding the default implementation,
15806  * unless they are, for instance: painting outside their allocation, or
15807  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15808  * 3D depth).
15809  *
15810  * <note>2D actors overriding <function>get_paint_volume()</function>
15811  * ensure their volume has a depth of 0. (This will be true so long as
15812  * you don't call clutter_paint_volume_set_depth().)</note>
15813  *
15814  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15815  *   or %NULL if no volume could be determined. The returned pointer
15816  *   is not guaranteed to be valid across multiple frames; if you want
15817  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15818  *
15819  * Since: 1.6
15820  */
15821 const ClutterPaintVolume *
15822 clutter_actor_get_paint_volume (ClutterActor *self)
15823 {
15824   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15825
15826   return _clutter_actor_get_paint_volume_mutable (self);
15827 }
15828
15829 /**
15830  * clutter_actor_get_transformed_paint_volume:
15831  * @self: a #ClutterActor
15832  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15833  *    (or %NULL for the stage)
15834  *
15835  * Retrieves the 3D paint volume of an actor like
15836  * clutter_actor_get_paint_volume() does (Please refer to the
15837  * documentation of clutter_actor_get_paint_volume() for more
15838  * details.) and it additionally transforms the paint volume into the
15839  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15840  * is passed for @relative_to_ancestor)
15841  *
15842  * This can be used by containers that base their paint volume on
15843  * the volume of their children. Such containers can query the
15844  * transformed paint volume of all of its children and union them
15845  * together using clutter_paint_volume_union().
15846  *
15847  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15848  *   or %NULL if no volume could be determined. The returned pointer is
15849  *   not guaranteed to be valid across multiple frames; if you wish to
15850  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15851  *
15852  * Since: 1.6
15853  */
15854 const ClutterPaintVolume *
15855 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15856                                             ClutterActor *relative_to_ancestor)
15857 {
15858   const ClutterPaintVolume *volume;
15859   ClutterActor *stage;
15860   ClutterPaintVolume *transformed_volume;
15861
15862   stage = _clutter_actor_get_stage_internal (self);
15863   if (G_UNLIKELY (stage == NULL))
15864     return NULL;
15865
15866   if (relative_to_ancestor == NULL)
15867     relative_to_ancestor = stage;
15868
15869   volume = clutter_actor_get_paint_volume (self);
15870   if (volume == NULL)
15871     return NULL;
15872
15873   transformed_volume =
15874     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15875
15876   _clutter_paint_volume_copy_static (volume, transformed_volume);
15877
15878   _clutter_paint_volume_transform_relative (transformed_volume,
15879                                             relative_to_ancestor);
15880
15881   return transformed_volume;
15882 }
15883
15884 /**
15885  * clutter_actor_get_paint_box:
15886  * @self: a #ClutterActor
15887  * @box: (out): return location for a #ClutterActorBox
15888  *
15889  * Retrieves the paint volume of the passed #ClutterActor, and
15890  * transforms it into a 2D bounding box in stage coordinates.
15891  *
15892  * This function is useful to determine the on screen area occupied by
15893  * the actor. The box is only an approximation and may often be
15894  * considerably larger due to the optimizations used to calculate the
15895  * box. The box is never smaller though, so it can reliably be used
15896  * for culling.
15897  *
15898  * There are times when a 2D paint box can't be determined, e.g.
15899  * because the actor isn't yet parented under a stage or because
15900  * the actor is unable to determine a paint volume.
15901  *
15902  * Return value: %TRUE if a 2D paint box could be determined, else
15903  * %FALSE.
15904  *
15905  * Since: 1.6
15906  */
15907 gboolean
15908 clutter_actor_get_paint_box (ClutterActor    *self,
15909                              ClutterActorBox *box)
15910 {
15911   ClutterActor *stage;
15912   ClutterPaintVolume *pv;
15913
15914   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15915   g_return_val_if_fail (box != NULL, FALSE);
15916
15917   stage = _clutter_actor_get_stage_internal (self);
15918   if (G_UNLIKELY (!stage))
15919     return FALSE;
15920
15921   pv = _clutter_actor_get_paint_volume_mutable (self);
15922   if (G_UNLIKELY (!pv))
15923     return FALSE;
15924
15925   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15926
15927   return TRUE;
15928 }
15929
15930 /**
15931  * clutter_actor_has_overlaps:
15932  * @self: A #ClutterActor
15933  *
15934  * Asks the actor's implementation whether it may contain overlapping
15935  * primitives.
15936  *
15937  * For example; Clutter may use this to determine whether the painting
15938  * should be redirected to an offscreen buffer to correctly implement
15939  * the opacity property.
15940  *
15941  * Custom actors can override the default response by implementing the
15942  * #ClutterActor <function>has_overlaps</function> virtual function. See
15943  * clutter_actor_set_offscreen_redirect() for more information.
15944  *
15945  * Return value: %TRUE if the actor may have overlapping primitives, and
15946  *   %FALSE otherwise
15947  *
15948  * Since: 1.8
15949  */
15950 gboolean
15951 clutter_actor_has_overlaps (ClutterActor *self)
15952 {
15953   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15954
15955   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15956 }
15957
15958 /**
15959  * clutter_actor_has_effects:
15960  * @self: A #ClutterActor
15961  *
15962  * Returns whether the actor has any effects applied.
15963  *
15964  * Return value: %TRUE if the actor has any effects,
15965  *   %FALSE otherwise
15966  *
15967  * Since: 1.10
15968  */
15969 gboolean
15970 clutter_actor_has_effects (ClutterActor *self)
15971 {
15972   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15973
15974   if (self->priv->effects == NULL)
15975     return FALSE;
15976
15977   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15978 }
15979
15980 /**
15981  * clutter_actor_has_constraints:
15982  * @self: A #ClutterActor
15983  *
15984  * Returns whether the actor has any constraints applied.
15985  *
15986  * Return value: %TRUE if the actor has any constraints,
15987  *   %FALSE otherwise
15988  *
15989  * Since: 1.10
15990  */
15991 gboolean
15992 clutter_actor_has_constraints (ClutterActor *self)
15993 {
15994   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15995
15996   return self->priv->constraints != NULL;
15997 }
15998
15999 /**
16000  * clutter_actor_has_actions:
16001  * @self: A #ClutterActor
16002  *
16003  * Returns whether the actor has any actions applied.
16004  *
16005  * Return value: %TRUE if the actor has any actions,
16006  *   %FALSE otherwise
16007  *
16008  * Since: 1.10
16009  */
16010 gboolean
16011 clutter_actor_has_actions (ClutterActor *self)
16012 {
16013   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16014
16015   return self->priv->actions != NULL;
16016 }
16017
16018 /**
16019  * clutter_actor_get_n_children:
16020  * @self: a #ClutterActor
16021  *
16022  * Retrieves the number of children of @self.
16023  *
16024  * Return value: the number of children of an actor
16025  *
16026  * Since: 1.10
16027  */
16028 gint
16029 clutter_actor_get_n_children (ClutterActor *self)
16030 {
16031   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
16032
16033   return self->priv->n_children;
16034 }
16035
16036 /**
16037  * clutter_actor_get_child_at_index:
16038  * @self: a #ClutterActor
16039  * @index_: the position in the list of children
16040  *
16041  * Retrieves the actor at the given @index_ inside the list of
16042  * children of @self.
16043  *
16044  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16045  *
16046  * Since: 1.10
16047  */
16048 ClutterActor *
16049 clutter_actor_get_child_at_index (ClutterActor *self,
16050                                   gint          index_)
16051 {
16052   ClutterActor *iter;
16053   int i;
16054
16055   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16056   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
16057
16058   for (iter = self->priv->first_child, i = 0;
16059        iter != NULL && i < index_;
16060        iter = iter->priv->next_sibling, i += 1)
16061     ;
16062
16063   return iter;
16064 }
16065
16066 /*< private >
16067  * _clutter_actor_foreach_child:
16068  * @actor: The actor whos children you want to iterate
16069  * @callback: The function to call for each child
16070  * @user_data: Private data to pass to @callback
16071  *
16072  * Calls a given @callback once for each child of the specified @actor and
16073  * passing the @user_data pointer each time.
16074  *
16075  * Return value: returns %TRUE if all children were iterated, else
16076  *    %FALSE if a callback broke out of iteration early.
16077  */
16078 gboolean
16079 _clutter_actor_foreach_child (ClutterActor           *self,
16080                               ClutterForeachCallback  callback,
16081                               gpointer                user_data)
16082 {
16083   ClutterActor *iter;
16084   gboolean cont;
16085
16086   if (self->priv->first_child == NULL)
16087     return TRUE;
16088
16089   cont = TRUE;
16090   iter = self->priv->first_child;
16091
16092   /* we use this form so that it's safe to change the children
16093    * list while iterating it
16094    */
16095   while (cont && iter != NULL)
16096     {
16097       ClutterActor *next = iter->priv->next_sibling;
16098
16099       cont = callback (iter, user_data);
16100
16101       iter = next;
16102     }
16103
16104   return cont;
16105 }
16106
16107 #if 0
16108 /* For debugging purposes this gives us a simple way to print out
16109  * the scenegraph e.g in gdb using:
16110  * [|
16111  *   _clutter_actor_traverse (stage,
16112  *                            0,
16113  *                            clutter_debug_print_actor_cb,
16114  *                            NULL,
16115  *                            NULL);
16116  * |]
16117  */
16118 static ClutterActorTraverseVisitFlags
16119 clutter_debug_print_actor_cb (ClutterActor *actor,
16120                               int depth,
16121                               void *user_data)
16122 {
16123   g_print ("%*s%s:%p\n",
16124            depth * 2, "",
16125            _clutter_actor_get_debug_name (actor),
16126            actor);
16127
16128   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16129 }
16130 #endif
16131
16132 static void
16133 _clutter_actor_traverse_breadth (ClutterActor           *actor,
16134                                  ClutterTraverseCallback callback,
16135                                  gpointer                user_data)
16136 {
16137   GQueue *queue = g_queue_new ();
16138   ClutterActor dummy;
16139   int current_depth = 0;
16140
16141   g_queue_push_tail (queue, actor);
16142   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
16143
16144   while ((actor = g_queue_pop_head (queue)))
16145     {
16146       ClutterActorTraverseVisitFlags flags;
16147
16148       if (actor == &dummy)
16149         {
16150           current_depth++;
16151           g_queue_push_tail (queue, &dummy);
16152           continue;
16153         }
16154
16155       flags = callback (actor, current_depth, user_data);
16156       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16157         break;
16158       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16159         {
16160           ClutterActor *iter;
16161
16162           for (iter = actor->priv->first_child;
16163                iter != NULL;
16164                iter = iter->priv->next_sibling)
16165             {
16166               g_queue_push_tail (queue, iter);
16167             }
16168         }
16169     }
16170
16171   g_queue_free (queue);
16172 }
16173
16174 static ClutterActorTraverseVisitFlags
16175 _clutter_actor_traverse_depth (ClutterActor           *actor,
16176                                ClutterTraverseCallback before_children_callback,
16177                                ClutterTraverseCallback after_children_callback,
16178                                int                     current_depth,
16179                                gpointer                user_data)
16180 {
16181   ClutterActorTraverseVisitFlags flags;
16182
16183   flags = before_children_callback (actor, current_depth, user_data);
16184   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16185     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16186
16187   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16188     {
16189       ClutterActor *iter;
16190
16191       for (iter = actor->priv->first_child;
16192            iter != NULL;
16193            iter = iter->priv->next_sibling)
16194         {
16195           flags = _clutter_actor_traverse_depth (iter,
16196                                                  before_children_callback,
16197                                                  after_children_callback,
16198                                                  current_depth + 1,
16199                                                  user_data);
16200
16201           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16202             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16203         }
16204     }
16205
16206   if (after_children_callback)
16207     return after_children_callback (actor, current_depth, user_data);
16208   else
16209     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16210 }
16211
16212 /* _clutter_actor_traverse:
16213  * @actor: The actor to start traversing the graph from
16214  * @flags: These flags may affect how the traversal is done
16215  * @before_children_callback: A function to call before visiting the
16216  *   children of the current actor.
16217  * @after_children_callback: A function to call after visiting the
16218  *   children of the current actor. (Ignored if
16219  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16220  * @user_data: The private data to pass to the callbacks
16221  *
16222  * Traverses the scenegraph starting at the specified @actor and
16223  * descending through all its children and its children's children.
16224  * For each actor traversed @before_children_callback and
16225  * @after_children_callback are called with the specified
16226  * @user_data, before and after visiting that actor's children.
16227  *
16228  * The callbacks can return flags that affect the ongoing traversal
16229  * such as by skipping over an actors children or bailing out of
16230  * any further traversing.
16231  */
16232 void
16233 _clutter_actor_traverse (ClutterActor              *actor,
16234                          ClutterActorTraverseFlags  flags,
16235                          ClutterTraverseCallback    before_children_callback,
16236                          ClutterTraverseCallback    after_children_callback,
16237                          gpointer                   user_data)
16238 {
16239   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16240     _clutter_actor_traverse_breadth (actor,
16241                                      before_children_callback,
16242                                      user_data);
16243   else /* DEPTH_FIRST */
16244     _clutter_actor_traverse_depth (actor,
16245                                    before_children_callback,
16246                                    after_children_callback,
16247                                    0, /* start depth */
16248                                    user_data);
16249 }
16250
16251 static void
16252 on_layout_manager_changed (ClutterLayoutManager *manager,
16253                            ClutterActor         *self)
16254 {
16255   clutter_actor_queue_relayout (self);
16256 }
16257
16258 /**
16259  * clutter_actor_set_layout_manager:
16260  * @self: a #ClutterActor
16261  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16262  *
16263  * Sets the #ClutterLayoutManager delegate object that will be used to
16264  * lay out the children of @self.
16265  *
16266  * The #ClutterActor will take a reference on the passed @manager which
16267  * will be released either when the layout manager is removed, or when
16268  * the actor is destroyed.
16269  *
16270  * Since: 1.10
16271  */
16272 void
16273 clutter_actor_set_layout_manager (ClutterActor         *self,
16274                                   ClutterLayoutManager *manager)
16275 {
16276   ClutterActorPrivate *priv;
16277
16278   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16279   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16280
16281   priv = self->priv;
16282
16283   if (priv->layout_manager != NULL)
16284     {
16285       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16286                                             G_CALLBACK (on_layout_manager_changed),
16287                                             self);
16288       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16289       g_clear_object (&priv->layout_manager);
16290     }
16291
16292   priv->layout_manager = manager;
16293
16294   if (priv->layout_manager != NULL)
16295     {
16296       g_object_ref_sink (priv->layout_manager);
16297       clutter_layout_manager_set_container (priv->layout_manager,
16298                                             CLUTTER_CONTAINER (self));
16299       g_signal_connect (priv->layout_manager, "layout-changed",
16300                         G_CALLBACK (on_layout_manager_changed),
16301                         self);
16302     }
16303
16304   clutter_actor_queue_relayout (self);
16305
16306   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16307 }
16308
16309 /**
16310  * clutter_actor_get_layout_manager:
16311  * @self: a #ClutterActor
16312  *
16313  * Retrieves the #ClutterLayoutManager used by @self.
16314  *
16315  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16316  *   or %NULL
16317  *
16318  * Since: 1.10
16319  */
16320 ClutterLayoutManager *
16321 clutter_actor_get_layout_manager (ClutterActor *self)
16322 {
16323   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16324
16325   return self->priv->layout_manager;
16326 }
16327
16328 static const ClutterLayoutInfo default_layout_info = {
16329   CLUTTER_POINT_INIT_ZERO,      /* fixed-pos */
16330   { 0, 0, 0, 0 },               /* margin */
16331   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16332   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16333   FALSE, FALSE,                 /* expand */
16334   CLUTTER_SIZE_INIT_ZERO,       /* minimum */
16335   CLUTTER_SIZE_INIT_ZERO,       /* natural */
16336 };
16337
16338 static void
16339 layout_info_free (gpointer data)
16340 {
16341   if (G_LIKELY (data != NULL))
16342     g_slice_free (ClutterLayoutInfo, data);
16343 }
16344
16345 /*< private >
16346  * _clutter_actor_get_layout_info:
16347  * @self: a #ClutterActor
16348  *
16349  * Retrieves a pointer to the ClutterLayoutInfo structure.
16350  *
16351  * If the actor does not have a ClutterLayoutInfo associated to it, one
16352  * will be created and initialized to the default values.
16353  *
16354  * This function should be used for setters.
16355  *
16356  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16357  * instead.
16358  *
16359  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16360  */
16361 ClutterLayoutInfo *
16362 _clutter_actor_get_layout_info (ClutterActor *self)
16363 {
16364   ClutterLayoutInfo *retval;
16365
16366   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16367   if (retval == NULL)
16368     {
16369       retval = g_slice_new (ClutterLayoutInfo);
16370
16371       *retval = default_layout_info;
16372
16373       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16374                                retval,
16375                                layout_info_free);
16376     }
16377
16378   return retval;
16379 }
16380
16381 /*< private >
16382  * _clutter_actor_get_layout_info_or_defaults:
16383  * @self: a #ClutterActor
16384  *
16385  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16386  *
16387  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16388  * then the default structure will be returned.
16389  *
16390  * This function should only be used for getters.
16391  *
16392  * Return value: a const pointer to the ClutterLayoutInfo structure
16393  */
16394 const ClutterLayoutInfo *
16395 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16396 {
16397   const ClutterLayoutInfo *info;
16398
16399   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16400   if (info == NULL)
16401     return &default_layout_info;
16402
16403   return info;
16404 }
16405
16406 /**
16407  * clutter_actor_set_x_align:
16408  * @self: a #ClutterActor
16409  * @x_align: the horizontal alignment policy
16410  *
16411  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16412  * actor received extra horizontal space.
16413  *
16414  * See also the #ClutterActor:x-align property.
16415  *
16416  * Since: 1.10
16417  */
16418 void
16419 clutter_actor_set_x_align (ClutterActor      *self,
16420                            ClutterActorAlign  x_align)
16421 {
16422   ClutterLayoutInfo *info;
16423
16424   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16425
16426   info = _clutter_actor_get_layout_info (self);
16427
16428   if (info->x_align != x_align)
16429     {
16430       info->x_align = x_align;
16431
16432       clutter_actor_queue_relayout (self);
16433
16434       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16435     }
16436 }
16437
16438 /**
16439  * clutter_actor_get_x_align:
16440  * @self: a #ClutterActor
16441  *
16442  * Retrieves the horizontal alignment policy set using
16443  * clutter_actor_set_x_align().
16444  *
16445  * Return value: the horizontal alignment policy.
16446  *
16447  * Since: 1.10
16448  */
16449 ClutterActorAlign
16450 clutter_actor_get_x_align (ClutterActor *self)
16451 {
16452   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16453
16454   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16455 }
16456
16457 /**
16458  * clutter_actor_set_y_align:
16459  * @self: a #ClutterActor
16460  * @y_align: the vertical alignment policy
16461  *
16462  * Sets the vertical alignment policy of a #ClutterActor, in case the
16463  * actor received extra vertical space.
16464  *
16465  * See also the #ClutterActor:y-align property.
16466  *
16467  * Since: 1.10
16468  */
16469 void
16470 clutter_actor_set_y_align (ClutterActor      *self,
16471                            ClutterActorAlign  y_align)
16472 {
16473   ClutterLayoutInfo *info;
16474
16475   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16476
16477   info = _clutter_actor_get_layout_info (self);
16478
16479   if (info->y_align != y_align)
16480     {
16481       info->y_align = y_align;
16482
16483       clutter_actor_queue_relayout (self);
16484
16485       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16486     }
16487 }
16488
16489 /**
16490  * clutter_actor_get_y_align:
16491  * @self: a #ClutterActor
16492  *
16493  * Retrieves the vertical alignment policy set using
16494  * clutter_actor_set_y_align().
16495  *
16496  * Return value: the vertical alignment policy.
16497  *
16498  * Since: 1.10
16499  */
16500 ClutterActorAlign
16501 clutter_actor_get_y_align (ClutterActor *self)
16502 {
16503   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16504
16505   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16506 }
16507
16508 /**
16509  * clutter_actor_set_margin:
16510  * @self: a #ClutterActor
16511  * @margin: a #ClutterMargin
16512  *
16513  * Sets all the components of the margin of a #ClutterActor.
16514  *
16515  * Since: 1.10
16516  */
16517 void
16518 clutter_actor_set_margin (ClutterActor        *self,
16519                           const ClutterMargin *margin)
16520 {
16521   ClutterLayoutInfo *info;
16522   gboolean changed;
16523   GObject *obj;
16524
16525   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16526   g_return_if_fail (margin != NULL);
16527
16528   obj = G_OBJECT (self);
16529   changed = FALSE;
16530
16531   g_object_freeze_notify (obj);
16532
16533   info = _clutter_actor_get_layout_info (self);
16534
16535   if (info->margin.top != margin->top)
16536     {
16537       info->margin.top = margin->top;
16538       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16539       changed = TRUE;
16540     }
16541
16542   if (info->margin.right != margin->right)
16543     {
16544       info->margin.right = margin->right;
16545       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16546       changed = TRUE;
16547     }
16548
16549   if (info->margin.bottom != margin->bottom)
16550     {
16551       info->margin.bottom = margin->bottom;
16552       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16553       changed = TRUE;
16554     }
16555
16556   if (info->margin.left != margin->left)
16557     {
16558       info->margin.left = margin->left;
16559       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16560       changed = TRUE;
16561     }
16562
16563   if (changed)
16564     clutter_actor_queue_relayout (self);
16565
16566   g_object_thaw_notify (obj);
16567 }
16568
16569 /**
16570  * clutter_actor_get_margin:
16571  * @self: a #ClutterActor
16572  * @margin: (out caller-allocates): return location for a #ClutterMargin
16573  *
16574  * Retrieves all the components of the margin of a #ClutterActor.
16575  *
16576  * Since: 1.10
16577  */
16578 void
16579 clutter_actor_get_margin (ClutterActor  *self,
16580                           ClutterMargin *margin)
16581 {
16582   const ClutterLayoutInfo *info;
16583
16584   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16585   g_return_if_fail (margin != NULL);
16586
16587   info = _clutter_actor_get_layout_info_or_defaults (self);
16588
16589   *margin = info->margin;
16590 }
16591
16592 /**
16593  * clutter_actor_set_margin_top:
16594  * @self: a #ClutterActor
16595  * @margin: the top margin
16596  *
16597  * Sets the margin from the top of a #ClutterActor.
16598  *
16599  * Since: 1.10
16600  */
16601 void
16602 clutter_actor_set_margin_top (ClutterActor *self,
16603                               gfloat        margin)
16604 {
16605   ClutterLayoutInfo *info;
16606
16607   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16608   g_return_if_fail (margin >= 0.f);
16609
16610   info = _clutter_actor_get_layout_info (self);
16611
16612   if (info->margin.top == margin)
16613     return;
16614
16615   info->margin.top = margin;
16616
16617   clutter_actor_queue_relayout (self);
16618
16619   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16620 }
16621
16622 /**
16623  * clutter_actor_get_margin_top:
16624  * @self: a #ClutterActor
16625  *
16626  * Retrieves the top margin of a #ClutterActor.
16627  *
16628  * Return value: the top margin
16629  *
16630  * Since: 1.10
16631  */
16632 gfloat
16633 clutter_actor_get_margin_top (ClutterActor *self)
16634 {
16635   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16636
16637   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16638 }
16639
16640 /**
16641  * clutter_actor_set_margin_bottom:
16642  * @self: a #ClutterActor
16643  * @margin: the bottom margin
16644  *
16645  * Sets the margin from the bottom of a #ClutterActor.
16646  *
16647  * Since: 1.10
16648  */
16649 void
16650 clutter_actor_set_margin_bottom (ClutterActor *self,
16651                                  gfloat        margin)
16652 {
16653   ClutterLayoutInfo *info;
16654
16655   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16656   g_return_if_fail (margin >= 0.f);
16657
16658   info = _clutter_actor_get_layout_info (self);
16659
16660   if (info->margin.bottom == margin)
16661     return;
16662
16663   info->margin.bottom = margin;
16664
16665   clutter_actor_queue_relayout (self);
16666
16667   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16668 }
16669
16670 /**
16671  * clutter_actor_get_margin_bottom:
16672  * @self: a #ClutterActor
16673  *
16674  * Retrieves the bottom margin of a #ClutterActor.
16675  *
16676  * Return value: the bottom margin
16677  *
16678  * Since: 1.10
16679  */
16680 gfloat
16681 clutter_actor_get_margin_bottom (ClutterActor *self)
16682 {
16683   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16684
16685   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16686 }
16687
16688 /**
16689  * clutter_actor_set_margin_left:
16690  * @self: a #ClutterActor
16691  * @margin: the left margin
16692  *
16693  * Sets the margin from the left of a #ClutterActor.
16694  *
16695  * Since: 1.10
16696  */
16697 void
16698 clutter_actor_set_margin_left (ClutterActor *self,
16699                                gfloat        margin)
16700 {
16701   ClutterLayoutInfo *info;
16702
16703   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16704   g_return_if_fail (margin >= 0.f);
16705
16706   info = _clutter_actor_get_layout_info (self);
16707
16708   if (info->margin.left == margin)
16709     return;
16710
16711   info->margin.left = margin;
16712
16713   clutter_actor_queue_relayout (self);
16714
16715   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16716 }
16717
16718 /**
16719  * clutter_actor_get_margin_left:
16720  * @self: a #ClutterActor
16721  *
16722  * Retrieves the left margin of a #ClutterActor.
16723  *
16724  * Return value: the left margin
16725  *
16726  * Since: 1.10
16727  */
16728 gfloat
16729 clutter_actor_get_margin_left (ClutterActor *self)
16730 {
16731   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16732
16733   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16734 }
16735
16736 /**
16737  * clutter_actor_set_margin_right:
16738  * @self: a #ClutterActor
16739  * @margin: the right margin
16740  *
16741  * Sets the margin from the right of a #ClutterActor.
16742  *
16743  * Since: 1.10
16744  */
16745 void
16746 clutter_actor_set_margin_right (ClutterActor *self,
16747                                 gfloat        margin)
16748 {
16749   ClutterLayoutInfo *info;
16750
16751   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16752   g_return_if_fail (margin >= 0.f);
16753
16754   info = _clutter_actor_get_layout_info (self);
16755
16756   if (info->margin.right == margin)
16757     return;
16758
16759   info->margin.right = margin;
16760
16761   clutter_actor_queue_relayout (self);
16762
16763   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16764 }
16765
16766 /**
16767  * clutter_actor_get_margin_right:
16768  * @self: a #ClutterActor
16769  *
16770  * Retrieves the right margin of a #ClutterActor.
16771  *
16772  * Return value: the right margin
16773  *
16774  * Since: 1.10
16775  */
16776 gfloat
16777 clutter_actor_get_margin_right (ClutterActor *self)
16778 {
16779   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16780
16781   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16782 }
16783
16784 static inline void
16785 clutter_actor_set_background_color_internal (ClutterActor *self,
16786                                              const ClutterColor *color)
16787 {
16788   ClutterActorPrivate *priv = self->priv;
16789   GObject *obj;
16790
16791   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16792     return;
16793
16794   obj = G_OBJECT (self);
16795
16796   priv->bg_color = *color;
16797   priv->bg_color_set = TRUE;
16798
16799   clutter_actor_queue_redraw (self);
16800
16801   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16802   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16803 }
16804
16805 /**
16806  * clutter_actor_set_background_color:
16807  * @self: a #ClutterActor
16808  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16809  *  set color
16810  *
16811  * Sets the background color of a #ClutterActor.
16812  *
16813  * The background color will be used to cover the whole allocation of the
16814  * actor. The default background color of an actor is transparent.
16815  *
16816  * To check whether an actor has a background color, you can use the
16817  * #ClutterActor:background-color-set actor property.
16818  *
16819  * The #ClutterActor:background-color property is animatable.
16820  *
16821  * Since: 1.10
16822  */
16823 void
16824 clutter_actor_set_background_color (ClutterActor       *self,
16825                                     const ClutterColor *color)
16826 {
16827   ClutterActorPrivate *priv;
16828   GObject *obj;
16829   GParamSpec *bg_color_pspec;
16830
16831   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16832
16833   obj = G_OBJECT (self);
16834
16835   priv = self->priv;
16836
16837   if (color == NULL)
16838     {
16839       priv->bg_color_set = FALSE;
16840       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16841       clutter_actor_queue_redraw (self);
16842       return;
16843     }
16844
16845   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16846   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16847     {
16848       _clutter_actor_create_transition (self, bg_color_pspec,
16849                                         &priv->bg_color,
16850                                         color);
16851     }
16852   else
16853     _clutter_actor_update_transition (self, bg_color_pspec, color);
16854
16855   clutter_actor_queue_redraw (self);
16856 }
16857
16858 /**
16859  * clutter_actor_get_background_color:
16860  * @self: a #ClutterActor
16861  * @color: (out caller-allocates): return location for a #ClutterColor
16862  *
16863  * Retrieves the color set using clutter_actor_set_background_color().
16864  *
16865  * Since: 1.10
16866  */
16867 void
16868 clutter_actor_get_background_color (ClutterActor *self,
16869                                     ClutterColor *color)
16870 {
16871   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16872   g_return_if_fail (color != NULL);
16873
16874   *color = self->priv->bg_color;
16875 }
16876
16877 /**
16878  * clutter_actor_get_previous_sibling:
16879  * @self: a #ClutterActor
16880  *
16881  * Retrieves the sibling of @self that comes before it in the list
16882  * of children of @self's parent.
16883  *
16884  * The returned pointer is only valid until the scene graph changes; it
16885  * is not safe to modify the list of children of @self while iterating
16886  * it.
16887  *
16888  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16889  *
16890  * Since: 1.10
16891  */
16892 ClutterActor *
16893 clutter_actor_get_previous_sibling (ClutterActor *self)
16894 {
16895   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16896
16897   return self->priv->prev_sibling;
16898 }
16899
16900 /**
16901  * clutter_actor_get_next_sibling:
16902  * @self: a #ClutterActor
16903  *
16904  * Retrieves the sibling of @self that comes after it in the list
16905  * of children of @self's parent.
16906  *
16907  * The returned pointer is only valid until the scene graph changes; it
16908  * is not safe to modify the list of children of @self while iterating
16909  * it.
16910  *
16911  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16912  *
16913  * Since: 1.10
16914  */
16915 ClutterActor *
16916 clutter_actor_get_next_sibling (ClutterActor *self)
16917 {
16918   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16919
16920   return self->priv->next_sibling;
16921 }
16922
16923 /**
16924  * clutter_actor_get_first_child:
16925  * @self: a #ClutterActor
16926  *
16927  * Retrieves the first child of @self.
16928  *
16929  * The returned pointer is only valid until the scene graph changes; it
16930  * is not safe to modify the list of children of @self while iterating
16931  * it.
16932  *
16933  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16934  *
16935  * Since: 1.10
16936  */
16937 ClutterActor *
16938 clutter_actor_get_first_child (ClutterActor *self)
16939 {
16940   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16941
16942   return self->priv->first_child;
16943 }
16944
16945 /**
16946  * clutter_actor_get_last_child:
16947  * @self: a #ClutterActor
16948  *
16949  * Retrieves the last child of @self.
16950  *
16951  * The returned pointer is only valid until the scene graph changes; it
16952  * is not safe to modify the list of children of @self while iterating
16953  * it.
16954  *
16955  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16956  *
16957  * Since: 1.10
16958  */
16959 ClutterActor *
16960 clutter_actor_get_last_child (ClutterActor *self)
16961 {
16962   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16963
16964   return self->priv->last_child;
16965 }
16966
16967 /* easy way to have properly named fields instead of the dummy ones
16968  * we use in the public structure
16969  */
16970 typedef struct _RealActorIter
16971 {
16972   ClutterActor *root;           /* dummy1 */
16973   ClutterActor *current;        /* dummy2 */
16974   gpointer padding_1;           /* dummy3 */
16975   gint age;                     /* dummy4 */
16976   gpointer padding_2;           /* dummy5 */
16977 } RealActorIter;
16978
16979 /**
16980  * clutter_actor_iter_init:
16981  * @iter: a #ClutterActorIter
16982  * @root: a #ClutterActor
16983  *
16984  * Initializes a #ClutterActorIter, which can then be used to iterate
16985  * efficiently over a section of the scene graph, and associates it
16986  * with @root.
16987  *
16988  * Modifying the scene graph section that contains @root will invalidate
16989  * the iterator.
16990  *
16991  * |[
16992  *   ClutterActorIter iter;
16993  *   ClutterActor *child;
16994  *
16995  *   clutter_actor_iter_init (&iter, container);
16996  *   while (clutter_actor_iter_next (&iter, &child))
16997  *     {
16998  *       /&ast; do something with child &ast;/
16999  *     }
17000  * ]|
17001  *
17002  * Since: 1.10
17003  */
17004 void
17005 clutter_actor_iter_init (ClutterActorIter *iter,
17006                          ClutterActor     *root)
17007 {
17008   RealActorIter *ri = (RealActorIter *) iter;
17009
17010   g_return_if_fail (iter != NULL);
17011   g_return_if_fail (CLUTTER_IS_ACTOR (root));
17012
17013   ri->root = root;
17014   ri->current = NULL;
17015   ri->age = root->priv->age;
17016 }
17017
17018 /**
17019  * clutter_actor_iter_next:
17020  * @iter: a #ClutterActorIter
17021  * @child: (out): return location for a #ClutterActor
17022  *
17023  * Advances the @iter and retrieves the next child of the root #ClutterActor
17024  * that was used to initialize the #ClutterActorIterator.
17025  *
17026  * If the iterator can advance, this function returns %TRUE and sets the
17027  * @child argument.
17028  *
17029  * If the iterator cannot advance, this function returns %FALSE, and
17030  * the contents of @child are undefined.
17031  *
17032  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17033  *
17034  * Since: 1.10
17035  */
17036 gboolean
17037 clutter_actor_iter_next (ClutterActorIter  *iter,
17038                          ClutterActor     **child)
17039 {
17040   RealActorIter *ri = (RealActorIter *) iter;
17041
17042   g_return_val_if_fail (iter != NULL, FALSE);
17043   g_return_val_if_fail (ri->root != NULL, FALSE);
17044 #ifndef G_DISABLE_ASSERT
17045   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17046 #endif
17047
17048   if (ri->current == NULL)
17049     ri->current = ri->root->priv->first_child;
17050   else
17051     ri->current = ri->current->priv->next_sibling;
17052
17053   if (child != NULL)
17054     *child = ri->current;
17055
17056   return ri->current != NULL;
17057 }
17058
17059 /**
17060  * clutter_actor_iter_prev:
17061  * @iter: a #ClutterActorIter
17062  * @child: (out): return location for a #ClutterActor
17063  *
17064  * Advances the @iter and retrieves the previous child of the root
17065  * #ClutterActor that was used to initialize the #ClutterActorIterator.
17066  *
17067  * If the iterator can advance, this function returns %TRUE and sets the
17068  * @child argument.
17069  *
17070  * If the iterator cannot advance, this function returns %FALSE, and
17071  * the contents of @child are undefined.
17072  *
17073  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17074  *
17075  * Since: 1.10
17076  */
17077 gboolean
17078 clutter_actor_iter_prev (ClutterActorIter  *iter,
17079                          ClutterActor     **child)
17080 {
17081   RealActorIter *ri = (RealActorIter *) iter;
17082
17083   g_return_val_if_fail (iter != NULL, FALSE);
17084   g_return_val_if_fail (ri->root != NULL, FALSE);
17085 #ifndef G_DISABLE_ASSERT
17086   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17087 #endif
17088
17089   if (ri->current == NULL)
17090     ri->current = ri->root->priv->last_child;
17091   else
17092     ri->current = ri->current->priv->prev_sibling;
17093
17094   if (child != NULL)
17095     *child = ri->current;
17096
17097   return ri->current != NULL;
17098 }
17099
17100 /**
17101  * clutter_actor_iter_remove:
17102  * @iter: a #ClutterActorIter
17103  *
17104  * Safely removes the #ClutterActor currently pointer to by the iterator
17105  * from its parent.
17106  *
17107  * This function can only be called after clutter_actor_iter_next() or
17108  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17109  * than once for the same actor.
17110  *
17111  * This function will call clutter_actor_remove_child() internally.
17112  *
17113  * Since: 1.10
17114  */
17115 void
17116 clutter_actor_iter_remove (ClutterActorIter *iter)
17117 {
17118   RealActorIter *ri = (RealActorIter *) iter;
17119   ClutterActor *cur;
17120
17121   g_return_if_fail (iter != NULL);
17122   g_return_if_fail (ri->root != NULL);
17123 #ifndef G_DISABLE_ASSERT
17124   g_return_if_fail (ri->age == ri->root->priv->age);
17125 #endif
17126   g_return_if_fail (ri->current != NULL);
17127
17128   cur = ri->current;
17129
17130   if (cur != NULL)
17131     {
17132       ri->current = cur->priv->prev_sibling;
17133
17134       clutter_actor_remove_child_internal (ri->root, cur,
17135                                            REMOVE_CHILD_DEFAULT_FLAGS);
17136
17137       ri->age += 1;
17138     }
17139 }
17140
17141 /**
17142  * clutter_actor_iter_destroy:
17143  * @iter: a #ClutterActorIter
17144  *
17145  * Safely destroys the #ClutterActor currently pointer to by the iterator
17146  * from its parent.
17147  *
17148  * This function can only be called after clutter_actor_iter_next() or
17149  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17150  * than once for the same actor.
17151  *
17152  * This function will call clutter_actor_destroy() internally.
17153  *
17154  * Since: 1.10
17155  */
17156 void
17157 clutter_actor_iter_destroy (ClutterActorIter *iter)
17158 {
17159   RealActorIter *ri = (RealActorIter *) iter;
17160   ClutterActor *cur;
17161
17162   g_return_if_fail (iter != NULL);
17163   g_return_if_fail (ri->root != NULL);
17164 #ifndef G_DISABLE_ASSERT
17165   g_return_if_fail (ri->age == ri->root->priv->age);
17166 #endif
17167   g_return_if_fail (ri->current != NULL);
17168
17169   cur = ri->current;
17170
17171   if (cur != NULL)
17172     {
17173       ri->current = cur->priv->prev_sibling;
17174
17175       clutter_actor_destroy (cur);
17176
17177       ri->age += 1;
17178     }
17179 }
17180
17181 static const ClutterAnimationInfo default_animation_info = {
17182   NULL,         /* transitions */
17183   NULL,         /* states */
17184   NULL,         /* cur_state */
17185 };
17186
17187 static void
17188 clutter_animation_info_free (gpointer data)
17189 {
17190   if (data != NULL)
17191     {
17192       ClutterAnimationInfo *info = data;
17193
17194       if (info->transitions != NULL)
17195         g_hash_table_unref (info->transitions);
17196
17197       if (info->states != NULL)
17198         g_array_unref (info->states);
17199
17200       g_slice_free (ClutterAnimationInfo, info);
17201     }
17202 }
17203
17204 const ClutterAnimationInfo *
17205 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17206 {
17207   const ClutterAnimationInfo *res;
17208   GObject *obj = G_OBJECT (self);
17209
17210   res = g_object_get_qdata (obj, quark_actor_animation_info);
17211   if (res != NULL)
17212     return res;
17213
17214   return &default_animation_info;
17215 }
17216
17217 ClutterAnimationInfo *
17218 _clutter_actor_get_animation_info (ClutterActor *self)
17219 {
17220   GObject *obj = G_OBJECT (self);
17221   ClutterAnimationInfo *res;
17222
17223   res = g_object_get_qdata (obj, quark_actor_animation_info);
17224   if (res == NULL)
17225     {
17226       res = g_slice_new (ClutterAnimationInfo);
17227
17228       *res = default_animation_info;
17229
17230       g_object_set_qdata_full (obj, quark_actor_animation_info,
17231                                res,
17232                                clutter_animation_info_free);
17233     }
17234
17235   return res;
17236 }
17237
17238 ClutterTransition *
17239 _clutter_actor_get_transition (ClutterActor *actor,
17240                                GParamSpec   *pspec)
17241 {
17242   const ClutterAnimationInfo *info;
17243
17244   info = _clutter_actor_get_animation_info_or_defaults (actor);
17245
17246   if (info->transitions == NULL)
17247     return NULL;
17248
17249   return g_hash_table_lookup (info->transitions, pspec->name);
17250 }
17251
17252 static void
17253 transition_closure_free (gpointer data)
17254 {
17255   if (G_LIKELY (data != NULL))
17256     {
17257       TransitionClosure *clos = data;
17258       ClutterTimeline *timeline;
17259
17260       timeline = CLUTTER_TIMELINE (clos->transition);
17261
17262       if (clutter_timeline_is_playing (timeline))
17263         clutter_timeline_stop (timeline);
17264
17265       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17266
17267       g_object_unref (clos->transition);
17268       g_free (clos->name);
17269
17270       g_slice_free (TransitionClosure, clos);
17271     }
17272 }
17273
17274 static void
17275 on_transition_stopped (ClutterTransition *transition,
17276                        gboolean           is_finished,
17277                        TransitionClosure *clos)
17278 {
17279   ClutterActor *actor = clos->actor;
17280   ClutterAnimationInfo *info;
17281
17282   /* reset the caches used by animations */
17283   clutter_actor_store_content_box (actor, NULL);
17284
17285   if (!is_finished)
17286     return;
17287
17288   info = _clutter_actor_get_animation_info (actor);
17289
17290   /* we take a reference here because removing the closure
17291    * will release the reference on the transition, and we
17292    * want the transition to survive the signal emission;
17293    * the master clock will release the last reference at
17294    * the end of the frame processing.
17295    */
17296   g_object_ref (transition);
17297   g_hash_table_remove (info->transitions, clos->name);
17298
17299   /* if it's the last transition then we clean up */
17300   if (g_hash_table_size (info->transitions) == 0)
17301     {
17302       g_hash_table_unref (info->transitions);
17303       info->transitions = NULL;
17304
17305       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17306                     _clutter_actor_get_debug_name (actor));
17307
17308       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17309     }
17310 }
17311
17312 void
17313 _clutter_actor_update_transition (ClutterActor *actor,
17314                                   GParamSpec   *pspec,
17315                                   ...)
17316 {
17317   TransitionClosure *clos;
17318   ClutterTimeline *timeline;
17319   ClutterInterval *interval;
17320   const ClutterAnimationInfo *info;
17321   va_list var_args;
17322   GType ptype;
17323   GValue initial = G_VALUE_INIT;
17324   GValue final = G_VALUE_INIT;
17325   char *error = NULL;
17326
17327   info = _clutter_actor_get_animation_info_or_defaults (actor);
17328
17329   if (info->transitions == NULL)
17330     return;
17331
17332   clos = g_hash_table_lookup (info->transitions, pspec->name);
17333   if (clos == NULL)
17334     return;
17335
17336   timeline = CLUTTER_TIMELINE (clos->transition);
17337
17338   va_start (var_args, pspec);
17339
17340   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17341
17342   g_value_init (&initial, ptype);
17343   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17344                                         pspec->name,
17345                                         &initial);
17346
17347   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17348   if (error != NULL)
17349     {
17350       g_critical ("%s: %s", G_STRLOC, error);
17351       g_free (error);
17352       goto out;
17353     }
17354
17355   interval = clutter_transition_get_interval (clos->transition);
17356   clutter_interval_set_initial_value (interval, &initial);
17357   clutter_interval_set_final_value (interval, &final);
17358
17359   /* if we're updating with an easing duration of zero milliseconds,
17360    * we just jump the timeline to the end and let it run its course
17361    */
17362   if (info->cur_state != NULL &&
17363       info->cur_state->easing_duration != 0)
17364     {
17365       guint cur_duration = clutter_timeline_get_duration (timeline);
17366       ClutterAnimationMode cur_mode =
17367         clutter_timeline_get_progress_mode (timeline);
17368
17369       if (cur_duration != info->cur_state->easing_duration)
17370         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17371
17372       if (cur_mode != info->cur_state->easing_mode)
17373         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17374
17375       clutter_timeline_rewind (timeline);
17376     }
17377   else
17378     {
17379       guint duration = clutter_timeline_get_duration (timeline);
17380
17381       clutter_timeline_advance (timeline, duration);
17382     }
17383
17384 out:
17385   g_value_unset (&initial);
17386   g_value_unset (&final);
17387
17388   va_end (var_args);
17389 }
17390
17391 /*< private >*
17392  * _clutter_actor_create_transition:
17393  * @actor: a #ClutterActor
17394  * @pspec: the property used for the transition
17395  * @...: initial and final state
17396  *
17397  * Creates a #ClutterTransition for the property represented by @pspec.
17398  *
17399  * Return value: a #ClutterTransition
17400  */
17401 ClutterTransition *
17402 _clutter_actor_create_transition (ClutterActor *actor,
17403                                   GParamSpec   *pspec,
17404                                   ...)
17405 {
17406   ClutterAnimationInfo *info;
17407   ClutterTransition *res = NULL;
17408   gboolean call_restore = FALSE;
17409   TransitionClosure *clos;
17410   va_list var_args;
17411
17412   info = _clutter_actor_get_animation_info (actor);
17413
17414   /* XXX - this will go away in 2.0
17415    *
17416    * if no state has been pushed, we assume that the easing state is
17417    * in "compatibility mode": all transitions have a duration of 0
17418    * msecs, which means that they happen immediately. in Clutter 2.0
17419    * this will turn into a g_assert(info->states != NULL), as every
17420    * actor will start with a predefined easing state
17421    */
17422   if (info->states == NULL)
17423     {
17424       clutter_actor_save_easing_state (actor);
17425       clutter_actor_set_easing_duration (actor, 0);
17426       call_restore = TRUE;
17427     }
17428
17429   if (info->transitions == NULL)
17430     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17431                                                NULL,
17432                                                transition_closure_free);
17433
17434   va_start (var_args, pspec);
17435
17436   clos = g_hash_table_lookup (info->transitions, pspec->name);
17437   if (clos == NULL)
17438     {
17439       ClutterTimeline *timeline;
17440       ClutterInterval *interval;
17441       GValue initial = G_VALUE_INIT;
17442       GValue final = G_VALUE_INIT;
17443       GType ptype;
17444       char *error;
17445
17446       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17447
17448       G_VALUE_COLLECT_INIT (&initial, ptype,
17449                             var_args, 0,
17450                             &error);
17451       if (error != NULL)
17452         {
17453           g_critical ("%s: %s", G_STRLOC, error);
17454           g_free (error);
17455           goto out;
17456         }
17457
17458       G_VALUE_COLLECT_INIT (&final, ptype,
17459                             var_args, 0,
17460                             &error);
17461
17462       if (error != NULL)
17463         {
17464           g_critical ("%s: %s", G_STRLOC, error);
17465           g_value_unset (&initial);
17466           g_free (error);
17467           goto out;
17468         }
17469
17470       /* if the current easing state has a duration of 0, then we don't
17471        * bother to create the transition, and we just set the final value
17472        * directly on the actor; we don't go through the Animatable
17473        * interface because we know we got here through an animatable
17474        * property.
17475        */
17476       if (info->cur_state->easing_duration == 0)
17477         {
17478           clutter_actor_set_animatable_property (actor,
17479                                                  pspec->param_id,
17480                                                  &final,
17481                                                  pspec);
17482           g_value_unset (&initial);
17483           g_value_unset (&final);
17484
17485           goto out;
17486         }
17487
17488       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17489
17490       g_value_unset (&initial);
17491       g_value_unset (&final);
17492
17493       res = clutter_property_transition_new (pspec->name);
17494
17495       clutter_transition_set_interval (res, interval);
17496       clutter_transition_set_remove_on_complete (res, TRUE);
17497
17498       timeline = CLUTTER_TIMELINE (res);
17499       clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17500       clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17501       clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17502
17503       /* this will start the transition as well */
17504       clutter_actor_add_transition (actor, pspec->name, res);
17505
17506       /* the actor now owns the transition */
17507       g_object_unref (res);
17508     }
17509   else
17510     res = clos->transition;
17511
17512 out:
17513   if (call_restore)
17514     clutter_actor_restore_easing_state (actor);
17515
17516   va_end (var_args);
17517
17518   return res;
17519 }
17520
17521 /**
17522  * clutter_actor_add_transition:
17523  * @self: a #ClutterActor
17524  * @name: the name of the transition to add
17525  * @transition: the #ClutterTransition to add
17526  *
17527  * Adds a @transition to the #ClutterActor's list of animations.
17528  *
17529  * The @name string is a per-actor unique identifier of the @transition: only
17530  * one #ClutterTransition can be associated to the specified @name.
17531  *
17532  * The @transition will be started once added.
17533  *
17534  * This function will take a reference on the @transition.
17535  *
17536  * This function is usually called implicitly when modifying an animatable
17537  * property.
17538  *
17539  * Since: 1.10
17540  */
17541 void
17542 clutter_actor_add_transition (ClutterActor      *self,
17543                               const char        *name,
17544                               ClutterTransition *transition)
17545 {
17546   ClutterTimeline *timeline;
17547   TransitionClosure *clos;
17548   ClutterAnimationInfo *info;
17549
17550   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17551   g_return_if_fail (name != NULL);
17552   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17553
17554   info = _clutter_actor_get_animation_info (self);
17555
17556   if (info->transitions == NULL)
17557     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17558                                                NULL,
17559                                                transition_closure_free);
17560
17561   if (g_hash_table_lookup (info->transitions, name) != NULL)
17562     {
17563       g_warning ("A transition with name '%s' already exists for "
17564                  "the actor '%s'",
17565                  name,
17566                  _clutter_actor_get_debug_name (self));
17567       return;
17568     }
17569
17570   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17571
17572   timeline = CLUTTER_TIMELINE (transition);
17573
17574   clos = g_slice_new (TransitionClosure);
17575   clos->actor = self;
17576   clos->transition = g_object_ref (transition);
17577   clos->name = g_strdup (name);
17578   clos->completed_id = g_signal_connect (timeline, "stopped",
17579                                          G_CALLBACK (on_transition_stopped),
17580                                          clos);
17581
17582   CLUTTER_NOTE (ANIMATION,
17583                 "Adding transition '%s' [%p] to actor '%s'",
17584                 clos->name,
17585                 clos->transition,
17586                 _clutter_actor_get_debug_name (self));
17587
17588   g_hash_table_insert (info->transitions, clos->name, clos);
17589   clutter_timeline_start (timeline);
17590 }
17591
17592 /**
17593  * clutter_actor_remove_transition:
17594  * @self: a #ClutterActor
17595  * @name: the name of the transition to remove
17596  *
17597  * Removes the transition stored inside a #ClutterActor using @name
17598  * identifier.
17599  *
17600  * If the transition is currently in progress, it will be stopped.
17601  *
17602  * This function releases the reference acquired when the transition
17603  * was added to the #ClutterActor.
17604  *
17605  * Since: 1.10
17606  */
17607 void
17608 clutter_actor_remove_transition (ClutterActor *self,
17609                                  const char   *name)
17610 {
17611   const ClutterAnimationInfo *info;
17612
17613   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17614   g_return_if_fail (name != NULL);
17615
17616   info = _clutter_actor_get_animation_info_or_defaults (self);
17617
17618   if (info->transitions == NULL)
17619     return;
17620
17621   g_hash_table_remove (info->transitions, name);
17622 }
17623
17624 /**
17625  * clutter_actor_remove_all_transitions:
17626  * @self: a #ClutterActor
17627  *
17628  * Removes all transitions associated to @self.
17629  *
17630  * Since: 1.10
17631  */
17632 void
17633 clutter_actor_remove_all_transitions (ClutterActor *self)
17634 {
17635   const ClutterAnimationInfo *info;
17636
17637   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17638
17639   info = _clutter_actor_get_animation_info_or_defaults (self);
17640   if (info->transitions == NULL)
17641     return;
17642
17643   g_hash_table_remove_all (info->transitions);
17644 }
17645
17646 /**
17647  * clutter_actor_set_easing_duration:
17648  * @self: a #ClutterActor
17649  * @msecs: the duration of the easing, or %NULL
17650  *
17651  * Sets the duration of the tweening for animatable properties
17652  * of @self for the current easing state.
17653  *
17654  * Since: 1.10
17655  */
17656 void
17657 clutter_actor_set_easing_duration (ClutterActor *self,
17658                                    guint         msecs)
17659 {
17660   ClutterAnimationInfo *info;
17661
17662   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17663
17664   info = _clutter_actor_get_animation_info (self);
17665
17666   if (info->cur_state == NULL)
17667     {
17668       g_warning ("You must call clutter_actor_save_easing_state() prior "
17669                  "to calling clutter_actor_set_easing_duration().");
17670       return;
17671     }
17672
17673   if (info->cur_state->easing_duration != msecs)
17674     info->cur_state->easing_duration = msecs;
17675 }
17676
17677 /**
17678  * clutter_actor_get_easing_duration:
17679  * @self: a #ClutterActor
17680  *
17681  * Retrieves the duration of the tweening for animatable
17682  * properties of @self for the current easing state.
17683  *
17684  * Return value: the duration of the tweening, in milliseconds
17685  *
17686  * Since: 1.10
17687  */
17688 guint
17689 clutter_actor_get_easing_duration (ClutterActor *self)
17690 {
17691   const ClutterAnimationInfo *info;
17692
17693   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17694
17695   info = _clutter_actor_get_animation_info_or_defaults (self);
17696
17697   if (info->cur_state != NULL)
17698     return info->cur_state->easing_duration;
17699
17700   return 0;
17701 }
17702
17703 /**
17704  * clutter_actor_set_easing_mode:
17705  * @self: a #ClutterActor
17706  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17707  *
17708  * Sets the easing mode for the tweening of animatable properties
17709  * of @self.
17710  *
17711  * Since: 1.10
17712  */
17713 void
17714 clutter_actor_set_easing_mode (ClutterActor         *self,
17715                                ClutterAnimationMode  mode)
17716 {
17717   ClutterAnimationInfo *info;
17718
17719   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17720   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17721   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17722
17723   info = _clutter_actor_get_animation_info (self);
17724
17725   if (info->cur_state == NULL)
17726     {
17727       g_warning ("You must call clutter_actor_save_easing_state() prior "
17728                  "to calling clutter_actor_set_easing_mode().");
17729       return;
17730     }
17731
17732   if (info->cur_state->easing_mode != mode)
17733     info->cur_state->easing_mode = mode;
17734 }
17735
17736 /**
17737  * clutter_actor_get_easing_mode:
17738  * @self: a #ClutterActor
17739  *
17740  * Retrieves the easing mode for the tweening of animatable properties
17741  * of @self for the current easing state.
17742  *
17743  * Return value: an easing mode
17744  *
17745  * Since: 1.10
17746  */
17747 ClutterAnimationMode
17748 clutter_actor_get_easing_mode (ClutterActor *self)
17749 {
17750   const ClutterAnimationInfo *info;
17751
17752   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17753
17754   info = _clutter_actor_get_animation_info_or_defaults (self);
17755
17756   if (info->cur_state != NULL)
17757     return info->cur_state->easing_mode;
17758
17759   return CLUTTER_EASE_OUT_CUBIC;
17760 }
17761
17762 /**
17763  * clutter_actor_set_easing_delay:
17764  * @self: a #ClutterActor
17765  * @msecs: the delay before the start of the tweening, in milliseconds
17766  *
17767  * Sets the delay that should be applied before tweening animatable
17768  * properties.
17769  *
17770  * Since: 1.10
17771  */
17772 void
17773 clutter_actor_set_easing_delay (ClutterActor *self,
17774                                 guint         msecs)
17775 {
17776   ClutterAnimationInfo *info;
17777
17778   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17779
17780   info = _clutter_actor_get_animation_info (self);
17781
17782   if (info->cur_state == NULL)
17783     {
17784       g_warning ("You must call clutter_actor_save_easing_state() prior "
17785                  "to calling clutter_actor_set_easing_delay().");
17786       return;
17787     }
17788
17789   if (info->cur_state->easing_delay != msecs)
17790     info->cur_state->easing_delay = msecs;
17791 }
17792
17793 /**
17794  * clutter_actor_get_easing_delay:
17795  * @self: a #ClutterActor
17796  *
17797  * Retrieves the delay that should be applied when tweening animatable
17798  * properties.
17799  *
17800  * Return value: a delay, in milliseconds
17801  *
17802  * Since: 1.10
17803  */
17804 guint
17805 clutter_actor_get_easing_delay (ClutterActor *self)
17806 {
17807   const ClutterAnimationInfo *info;
17808
17809   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17810
17811   info = _clutter_actor_get_animation_info_or_defaults (self);
17812
17813   if (info->cur_state != NULL)
17814     return info->cur_state->easing_delay;
17815
17816   return 0;
17817 }
17818
17819 /**
17820  * clutter_actor_get_transition:
17821  * @self: a #ClutterActor
17822  * @name: the name of the transition
17823  *
17824  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17825  * transition @name.
17826  *
17827  * Transitions created for animatable properties use the name of the
17828  * property itself, for instance the code below:
17829  *
17830  * |[
17831  *   clutter_actor_set_easing_duration (actor, 1000);
17832  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17833  *
17834  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17835  *   g_signal_connect (transition, "stopped",
17836  *                     G_CALLBACK (on_transition_stopped),
17837  *                     actor);
17838  * ]|
17839  *
17840  * will call the <function>on_transition_stopped</function> callback when
17841  * the transition is finished.
17842  *
17843  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17844  *   was found to match the passed name; the returned instance is owned
17845  *   by Clutter and it should not be freed
17846  *
17847  * Since: 1.10
17848  */
17849 ClutterTransition *
17850 clutter_actor_get_transition (ClutterActor *self,
17851                               const char   *name)
17852 {
17853   TransitionClosure *clos;
17854   const ClutterAnimationInfo *info;
17855
17856   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17857   g_return_val_if_fail (name != NULL, NULL);
17858
17859   info = _clutter_actor_get_animation_info_or_defaults (self);
17860   if (info->transitions == NULL)
17861     return NULL;
17862
17863   clos = g_hash_table_lookup (info->transitions, name);
17864   if (clos == NULL)
17865     return NULL;
17866
17867   return clos->transition;
17868 }
17869
17870 /**
17871  * clutter_actor_save_easing_state:
17872  * @self: a #ClutterActor
17873  *
17874  * Saves the current easing state for animatable properties, and creates
17875  * a new state with the default values for easing mode and duration.
17876  *
17877  * Since: 1.10
17878  */
17879 void
17880 clutter_actor_save_easing_state (ClutterActor *self)
17881 {
17882   ClutterAnimationInfo *info;
17883   AState new_state;
17884
17885   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17886
17887   info = _clutter_actor_get_animation_info (self);
17888
17889   if (info->states == NULL)
17890     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17891
17892   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17893   new_state.easing_duration = 250;
17894   new_state.easing_delay = 0;
17895
17896   g_array_append_val (info->states, new_state);
17897
17898   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17899 }
17900
17901 /**
17902  * clutter_actor_restore_easing_state:
17903  * @self: a #ClutterActor
17904  *
17905  * Restores the easing state as it was prior to a call to
17906  * clutter_actor_save_easing_state().
17907  *
17908  * Since: 1.10
17909  */
17910 void
17911 clutter_actor_restore_easing_state (ClutterActor *self)
17912 {
17913   ClutterAnimationInfo *info;
17914
17915   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17916
17917   info = _clutter_actor_get_animation_info (self);
17918
17919   if (info->states == NULL)
17920     {
17921       g_critical ("The function clutter_actor_restore_easing_state() has "
17922                   "called without a previous call to "
17923                   "clutter_actor_save_easing_state().");
17924       return;
17925     }
17926
17927   g_array_remove_index (info->states, info->states->len - 1);
17928
17929   if (info->states->len > 0)
17930     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17931   else
17932     {
17933       g_array_unref (info->states);
17934       info->states = NULL;
17935       info->cur_state = NULL;
17936     }
17937 }
17938
17939 /**
17940  * clutter_actor_set_content:
17941  * @self: a #ClutterActor
17942  * @content: (allow-none): a #ClutterContent, or %NULL
17943  *
17944  * Sets the contents of a #ClutterActor.
17945  *
17946  * Since: 1.10
17947  */
17948 void
17949 clutter_actor_set_content (ClutterActor   *self,
17950                            ClutterContent *content)
17951 {
17952   ClutterActorPrivate *priv;
17953
17954   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17955   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17956
17957   priv = self->priv;
17958
17959   if (priv->content != NULL)
17960     {
17961       _clutter_content_detached (priv->content, self);
17962       g_clear_object (&priv->content);
17963     }
17964
17965   priv->content = content;
17966
17967   if (priv->content != NULL)
17968     {
17969       g_object_ref (priv->content);
17970       _clutter_content_attached (priv->content, self);
17971     }
17972
17973   /* given that the content is always painted within the allocation,
17974    * we only need to queue a redraw here
17975    */
17976   clutter_actor_queue_redraw (self);
17977
17978   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17979
17980   /* if the content gravity is not resize-fill, and the new content has a
17981    * different preferred size than the previous one, then the content box
17982    * may have been changed. since we compute that lazily, we just notify
17983    * here, and let whomever watches :content-box do whatever they need to
17984    * do.
17985    */
17986   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17987     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17988 }
17989
17990 /**
17991  * clutter_actor_get_content:
17992  * @self: a #ClutterActor
17993  *
17994  * Retrieves the contents of @self.
17995  *
17996  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17997  *   or %NULL if none was set
17998  *
17999  * Since: 1.10
18000  */
18001 ClutterContent *
18002 clutter_actor_get_content (ClutterActor *self)
18003 {
18004   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
18005
18006   return self->priv->content;
18007 }
18008
18009 /**
18010  * clutter_actor_set_content_gravity:
18011  * @self: a #ClutterActor
18012  * @gravity: the #ClutterContentGravity
18013  *
18014  * Sets the gravity of the #ClutterContent used by @self.
18015  *
18016  * See the description of the #ClutterActor:content-gravity property for
18017  * more information.
18018  *
18019  * The #ClutterActor:content-gravity property is animatable.
18020  *
18021  * Since: 1.10
18022  */
18023 void
18024 clutter_actor_set_content_gravity (ClutterActor *self,
18025                                    ClutterContentGravity  gravity)
18026 {
18027   ClutterActorPrivate *priv;
18028
18029   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18030
18031   priv = self->priv;
18032
18033   if (priv->content_gravity == gravity)
18034     return;
18035
18036   priv->content_box_valid = FALSE;
18037
18038   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
18039     {
18040       ClutterActorBox from_box, to_box;
18041
18042       clutter_actor_get_content_box (self, &from_box);
18043
18044       priv->content_gravity = gravity;
18045
18046       clutter_actor_get_content_box (self, &to_box);
18047
18048       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
18049                                         &from_box,
18050                                         &to_box);
18051     }
18052   else
18053     {
18054       ClutterActorBox to_box;
18055
18056       priv->content_gravity = gravity;
18057
18058       clutter_actor_get_content_box (self, &to_box);
18059
18060       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
18061                                         &to_box);
18062     }
18063
18064   clutter_actor_queue_redraw (self);
18065
18066   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
18067 }
18068
18069 /**
18070  * clutter_actor_get_content_gravity:
18071  * @self: a #ClutterActor
18072  *
18073  * Retrieves the content gravity as set using
18074  * clutter_actor_get_content_gravity().
18075  *
18076  * Return value: the content gravity
18077  *
18078  * Since: 1.10
18079  */
18080 ClutterContentGravity
18081 clutter_actor_get_content_gravity (ClutterActor *self)
18082 {
18083   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
18084                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
18085
18086   return self->priv->content_gravity;
18087 }
18088
18089 /**
18090  * clutter_actor_get_content_box:
18091  * @self: a #ClutterActor
18092  * @box: (out caller-allocates): the return location for the bounding
18093  *   box for the #ClutterContent
18094  *
18095  * Retrieves the bounding box for the #ClutterContent of @self.
18096  *
18097  * The bounding box is relative to the actor's allocation.
18098  *
18099  * If no #ClutterContent is set for @self, or if @self has not been
18100  * allocated yet, then the result is undefined.
18101  *
18102  * The content box is guaranteed to be, at most, as big as the allocation
18103  * of the #ClutterActor.
18104  *
18105  * If the #ClutterContent used by the actor has a preferred size, then
18106  * it is possible to modify the content box by using the
18107  * #ClutterActor:content-gravity property.
18108  *
18109  * Since: 1.10
18110  */
18111 void
18112 clutter_actor_get_content_box (ClutterActor    *self,
18113                                ClutterActorBox *box)
18114 {
18115   ClutterActorPrivate *priv;
18116   gfloat content_w, content_h;
18117   gfloat alloc_w, alloc_h;
18118
18119   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18120   g_return_if_fail (box != NULL);
18121
18122   priv = self->priv;
18123
18124   box->x1 = 0.f;
18125   box->y1 = 0.f;
18126   box->x2 = priv->allocation.x2 - priv->allocation.x1;
18127   box->y2 = priv->allocation.y2 - priv->allocation.y1;
18128
18129   if (priv->content_box_valid)
18130     {
18131       *box = priv->content_box;
18132       return;
18133     }
18134
18135   /* no need to do any more work */
18136   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18137     return;
18138
18139   if (priv->content == NULL)
18140     return;
18141
18142   /* if the content does not have a preferred size then there is
18143    * no point in computing the content box
18144    */
18145   if (!clutter_content_get_preferred_size (priv->content,
18146                                            &content_w,
18147                                            &content_h))
18148     return;
18149
18150   alloc_w = box->x2;
18151   alloc_h = box->y2;
18152
18153   switch (priv->content_gravity)
18154     {
18155     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18156       box->x2 = box->x1 + MIN (content_w, alloc_w);
18157       box->y2 = box->y1 + MIN (content_h, alloc_h);
18158       break;
18159
18160     case CLUTTER_CONTENT_GRAVITY_TOP:
18161       if (alloc_w > content_w)
18162         {
18163           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18164           box->x2 = box->x1 + content_w;
18165         }
18166       box->y2 = box->y1 + MIN (content_h, alloc_h);
18167       break;
18168
18169     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18170       if (alloc_w > content_w)
18171         {
18172           box->x1 += (alloc_w - content_w);
18173           box->x2 = box->x1 + content_w;
18174         }
18175       box->y2 = box->y1 + MIN (content_h, alloc_h);
18176       break;
18177
18178     case CLUTTER_CONTENT_GRAVITY_LEFT:
18179       box->x2 = box->x1 + MIN (content_w, alloc_w);
18180       if (alloc_h > content_h)
18181         {
18182           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18183           box->y2 = box->y1 + content_h;
18184         }
18185       break;
18186
18187     case CLUTTER_CONTENT_GRAVITY_CENTER:
18188       if (alloc_w > content_w)
18189         {
18190           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18191           box->x2 = box->x1 + content_w;
18192         }
18193       if (alloc_h > content_h)
18194         {
18195           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18196           box->y2 = box->y1 + content_h;
18197         }
18198       break;
18199
18200     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18201       if (alloc_w > content_w)
18202         {
18203           box->x1 += (alloc_w - content_w);
18204           box->x2 = box->x1 + content_w;
18205         }
18206       if (alloc_h > content_h)
18207         {
18208           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18209           box->y2 = box->y1 + content_h;
18210         }
18211       break;
18212
18213     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18214       box->x2 = box->x1 + MIN (content_w, alloc_w);
18215       if (alloc_h > content_h)
18216         {
18217           box->y1 += (alloc_h - content_h);
18218           box->y2 = box->y1 + content_h;
18219         }
18220       break;
18221
18222     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18223       if (alloc_w > content_w)
18224         {
18225           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18226           box->x2 = box->x1 + content_w;
18227         }
18228       if (alloc_h > content_h)
18229         {
18230           box->y1 += (alloc_h - content_h);
18231           box->y2 = box->y1 + content_h;
18232         }
18233       break;
18234
18235     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18236       if (alloc_w > content_w)
18237         {
18238           box->x1 += (alloc_w - content_w);
18239           box->x2 = box->x1 + content_w;
18240         }
18241       if (alloc_h > content_h)
18242         {
18243           box->y1 += (alloc_h - content_h);
18244           box->y2 = box->y1 + content_h;
18245         }
18246       break;
18247
18248     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18249       g_assert_not_reached ();
18250       break;
18251
18252     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18253       {
18254         double r_c = content_w / content_h;
18255
18256         if (r_c >= 1.0)
18257           {
18258             if ((alloc_w / r_c) > alloc_h)
18259               {
18260                 box->x1 = 0.f;
18261                 box->x2 = alloc_w;
18262
18263                 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18264                 box->y2 = box->y1 + (alloc_w / r_c);
18265               }
18266             else
18267               {
18268                 box->y1 = 0.f;
18269                 box->y2 = alloc_h;
18270
18271                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18272                 box->x2 = box->x1 + (alloc_h * r_c);
18273               }
18274           }
18275         else
18276           {
18277             if ((alloc_w / r_c) > alloc_h)
18278               {
18279                 box->y1 = 0.f;
18280                 box->y2 = alloc_h;
18281
18282                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18283                 box->x2 = box->x1 + (alloc_h * r_c);
18284               }
18285             else
18286               {
18287                 box->x1 = 0.f;
18288                 box->x2 = alloc_w;
18289
18290                 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18291                 box->y2 = box->y1 + (alloc_w / r_c);
18292               }
18293           }
18294
18295         CLUTTER_NOTE (LAYOUT,
18296                       "r_c: %.3f, r_a: %.3f\t"
18297                       "a: [%.2fx%.2f], c: [%.2fx%.2f]\t"
18298                       "b: [%.2f, %.2f, %.2f, %.2f]",
18299                       r_c, alloc_w / alloc_h,
18300                       alloc_w, alloc_h,
18301                       content_w, content_h,
18302                       box->x1, box->y1, box->x2, box->y2);
18303       }
18304       break;
18305     }
18306 }
18307
18308 /**
18309  * clutter_actor_set_content_scaling_filters:
18310  * @self: a #ClutterActor
18311  * @min_filter: the minification filter for the content
18312  * @mag_filter: the magnification filter for the content
18313  *
18314  * Sets the minification and magnification filter to be applied when
18315  * scaling the #ClutterActor:content of a #ClutterActor.
18316  *
18317  * The #ClutterActor:minification-filter will be used when reducing
18318  * the size of the content; the #ClutterActor:magnification-filter
18319  * will be used when increasing the size of the content.
18320  *
18321  * Since: 1.10
18322  */
18323 void
18324 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18325                                            ClutterScalingFilter  min_filter,
18326                                            ClutterScalingFilter  mag_filter)
18327 {
18328   ClutterActorPrivate *priv;
18329   gboolean changed;
18330   GObject *obj;
18331
18332   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18333
18334   priv = self->priv;
18335   obj = G_OBJECT (self);
18336
18337   g_object_freeze_notify (obj);
18338
18339   changed = FALSE;
18340
18341   if (priv->min_filter != min_filter)
18342     {
18343       priv->min_filter = min_filter;
18344       changed = TRUE;
18345
18346       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18347     }
18348
18349   if (priv->mag_filter != mag_filter)
18350     {
18351       priv->mag_filter = mag_filter;
18352       changed = TRUE;
18353
18354       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18355     }
18356
18357   if (changed)
18358     clutter_actor_queue_redraw (self);
18359
18360   g_object_thaw_notify (obj);
18361 }
18362
18363 /**
18364  * clutter_actor_get_content_scaling_filters:
18365  * @self: a #ClutterActor
18366  * @min_filter: (out) (allow-none): return location for the minification
18367  *   filter, or %NULL
18368  * @mag_filter: (out) (allow-none): return location for the magnification
18369  *   filter, or %NULL
18370  *
18371  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18372  *
18373  * Since: 1.10
18374  */
18375 void
18376 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18377                                            ClutterScalingFilter *min_filter,
18378                                            ClutterScalingFilter *mag_filter)
18379 {
18380   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18381
18382   if (min_filter != NULL)
18383     *min_filter = self->priv->min_filter;
18384
18385   if (mag_filter != NULL)
18386     *mag_filter = self->priv->mag_filter;
18387 }
18388
18389 /*
18390  * clutter_actor_queue_compute_expand:
18391  * @self: a #ClutterActor
18392  *
18393  * Invalidates the needs_x_expand and needs_y_expand flags on @self
18394  * and its parents up to the top-level actor.
18395  *
18396  * This function also queues a relayout if anything changed.
18397  */
18398 static inline void
18399 clutter_actor_queue_compute_expand (ClutterActor *self)
18400 {
18401   ClutterActor *parent;
18402   gboolean changed;
18403
18404   if (self->priv->needs_compute_expand)
18405     return;
18406
18407   changed = FALSE;
18408   parent = self;
18409   while (parent != NULL)
18410     {
18411       if (!parent->priv->needs_compute_expand)
18412         {
18413           parent->priv->needs_compute_expand = TRUE;
18414           changed = TRUE;
18415         }
18416
18417       parent = parent->priv->parent;
18418     }
18419
18420   if (changed)
18421     clutter_actor_queue_relayout (self);
18422 }
18423
18424 /**
18425  * clutter_actor_set_x_expand:
18426  * @self: a #ClutterActor
18427  * @expand: whether the actor should expand horizontally
18428  *
18429  * Sets whether a #ClutterActor should expand horizontally; this means
18430  * that layout manager should allocate extra space for the actor, if
18431  * possible.
18432  *
18433  * Setting an actor to expand will also make all its parent expand, so
18434  * that it's possible to build an actor tree and only set this flag on
18435  * its leaves and not on every single actor.
18436  *
18437  * Since: 1.12
18438  */
18439 void
18440 clutter_actor_set_x_expand (ClutterActor *self,
18441                             gboolean      expand)
18442 {
18443   ClutterLayoutInfo *info;
18444
18445   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18446
18447   expand = !!expand;
18448
18449   info = _clutter_actor_get_layout_info (self);
18450   if (info->x_expand != expand)
18451     {
18452       info->x_expand = expand;
18453
18454       self->priv->x_expand_set = TRUE;
18455
18456       clutter_actor_queue_compute_expand (self);
18457
18458       g_object_notify_by_pspec (G_OBJECT (self),
18459                                 obj_props[PROP_X_EXPAND]);
18460     }
18461 }
18462
18463 /**
18464  * clutter_actor_get_x_expand:
18465  * @self: a #ClutterActor
18466  *
18467  * Retrieves the value set with clutter_actor_set_x_expand().
18468  *
18469  * See also: clutter_actor_needs_expand()
18470  *
18471  * Return value: %TRUE if the actor has been set to expand
18472  *
18473  * Since: 1.12
18474  */
18475 gboolean
18476 clutter_actor_get_x_expand (ClutterActor *self)
18477 {
18478   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18479
18480   return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18481 }
18482
18483 /**
18484  * clutter_actor_set_y_expand:
18485  * @self: a #ClutterActor
18486  * @expand: whether the actor should expand vertically
18487  *
18488  * Sets whether a #ClutterActor should expand horizontally; this means
18489  * that layout manager should allocate extra space for the actor, if
18490  * possible.
18491  *
18492  * Setting an actor to expand will also make all its parent expand, so
18493  * that it's possible to build an actor tree and only set this flag on
18494  * its leaves and not on every single actor.
18495  *
18496  * Since: 1.12
18497  */
18498 void
18499 clutter_actor_set_y_expand (ClutterActor *self,
18500                             gboolean      expand)
18501 {
18502   ClutterLayoutInfo *info;
18503
18504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18505
18506   expand = !!expand;
18507
18508   info = _clutter_actor_get_layout_info (self);
18509   if (info->y_expand != expand)
18510     {
18511       info->y_expand = expand;
18512
18513       self->priv->y_expand_set = TRUE;
18514
18515       clutter_actor_queue_compute_expand (self);
18516
18517       g_object_notify_by_pspec (G_OBJECT (self),
18518                                 obj_props[PROP_Y_EXPAND]);
18519     }
18520 }
18521
18522 /**
18523  * clutter_actor_get_y_expand:
18524  * @self: a #ClutterActor
18525  *
18526  * Retrieves the value set with clutter_actor_set_y_expand().
18527  *
18528  * See also: clutter_actor_needs_expand()
18529  *
18530  * Return value: %TRUE if the actor has been set to expand
18531  *
18532  * Since: 1.12
18533  */
18534 gboolean
18535 clutter_actor_get_y_expand (ClutterActor *self)
18536 {
18537   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18538
18539   return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18540 }
18541
18542 static void
18543 clutter_actor_compute_expand_recursive (ClutterActor *self,
18544                                         gboolean     *x_expand_p,
18545                                         gboolean     *y_expand_p)
18546 {
18547   ClutterActorIter iter;
18548   ClutterActor *child;
18549   gboolean x_expand, y_expand;
18550
18551   x_expand = y_expand = FALSE;
18552
18553   /* note that we don't recurse into children if we're already set to expand;
18554    * this avoids traversing the whole actor tree, even if it may lead to some
18555    * child left with the needs_compute_expand flag set.
18556    */
18557   clutter_actor_iter_init (&iter, self);
18558   while (clutter_actor_iter_next (&iter, &child))
18559     {
18560       x_expand = x_expand ||
18561         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18562
18563       y_expand = y_expand ||
18564         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18565     }
18566
18567   *x_expand_p = x_expand;
18568   *y_expand_p = y_expand;
18569 }
18570
18571 static void
18572 clutter_actor_compute_expand (ClutterActor *self)
18573 {
18574   if (self->priv->needs_compute_expand)
18575     {
18576       const ClutterLayoutInfo *info;
18577       gboolean x_expand, y_expand;
18578
18579       info = _clutter_actor_get_layout_info_or_defaults (self);
18580
18581       if (self->priv->x_expand_set)
18582         x_expand = info->x_expand;
18583       else
18584         x_expand = FALSE;
18585
18586       if (self->priv->y_expand_set)
18587         y_expand = info->y_expand;
18588       else
18589         y_expand = FALSE;
18590
18591       /* we don't need to recurse down to the children if the
18592        * actor has been forcibly set to expand
18593        */
18594       if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18595         {
18596           if (self->priv->n_children != 0)
18597             {
18598               gboolean *x_expand_p, *y_expand_p;
18599               gboolean ignored = FALSE;
18600
18601               x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18602               y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18603
18604               clutter_actor_compute_expand_recursive (self,
18605                                                       x_expand_p,
18606                                                       y_expand_p);
18607             }
18608         }
18609
18610       self->priv->needs_compute_expand = FALSE;
18611       self->priv->needs_x_expand = (x_expand != FALSE);
18612       self->priv->needs_y_expand = (y_expand != FALSE);
18613     }
18614 }
18615
18616 /**
18617  * clutter_actor_needs_expand:
18618  * @self: a #ClutterActor
18619  * @orientation: the direction of expansion
18620  *
18621  * Checks whether an actor, or any of its children, is set to expand
18622  * horizontally or vertically.
18623  *
18624  * This function should only be called by layout managers that can
18625  * assign extra space to their children.
18626  *
18627  * If you want to know whether the actor was explicitly set to expand,
18628  * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18629  *
18630  * Return value: %TRUE if the actor should expand
18631  *
18632  * Since: 1.12
18633  */
18634 gboolean
18635 clutter_actor_needs_expand (ClutterActor       *self,
18636                             ClutterOrientation  orientation)
18637 {
18638   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18639
18640   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18641     return FALSE;
18642
18643   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18644     return FALSE;
18645
18646   clutter_actor_compute_expand (self);
18647
18648   switch (orientation)
18649     {
18650     case CLUTTER_ORIENTATION_HORIZONTAL:
18651       return self->priv->needs_x_expand;
18652
18653     case CLUTTER_ORIENTATION_VERTICAL:
18654       return self->priv->needs_y_expand;
18655     }
18656
18657   return FALSE;
18658 }