actor: Invalidate the current state when popping easing states
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: The basic element of the scene graph 
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-animation">
217  *   <title>Animation</title>
218  *   <para>Animation is a core concept of modern user interfaces; Clutter
219  *   provides a complete and powerful animation framework that automatically
220  *   tweens the actor's state without requiring direct, frame by frame
221  *   manipulation from your application code.</para>
222  *   <formalpara>
223  *     <title>Implicit animations</title>
224  *     <para>The implicit animation model of Clutter assumes that all the
225  *     changes in an actor state should be gradual and asynchronous; Clutter
226  *     will automatically transition an actor's property change between the
227  *     current state and the desired one without manual intervention.</para>
228  *     <para>By default, in the 1.0 API series, the transition happens with
229  *     a duration of zero milliseconds, and the implicit animation is an
230  *     opt in feature to retain backwards compatibility. In order to enable
231  *     implicit animations, it is necessary to change the easing state of
232  *     an actor by using clutter_actor_save_easing_state():</para>
233  *     <informalexample><programlisting>
234  * /&ast; assume that the actor is currently positioned at (100, 100) &ast;/
235  * clutter_actor_save_easing_state (actor);
236  * clutter_actor_set_position (actor, 500, 500);
237  * clutter_actor_restore_easing_state (actor);
238  *     </programlisting></informalexample>
239  *     <para>The example above will trigger an implicit animation of the
240  *     actor between its current position to a new position.</para>
241  *     <para>It is possible to animate multiple properties of an actor
242  *     at the same time, and you can animate multiple actors at the same
243  *     time as well, for instance:</para>
244  *     <informalexample><programlisting>
245  * /&ast; animate the actor's opacity and depth &ast;/
246  * clutter_actor_save_easing_state (actor);
247  * clutter_actor_set_opacity (actor, 0);
248  * clutter_actor_set_depth (actor, -100);
249  * clutter_actor_restore_easing_state (actor);
250  *
251  * /&ast; animate another actor's opacity &ast;/
252  * clutter_actor_save_easing_state (another_actor);
253  * clutter_actor_set_opacity (another_actor, 255);
254  * clutter_actor_set_depth (another_actor, 100);
255  * clutter_actor_restore_easing_state (another_actor);
256  *     </programlisting></informalexample>
257  *     <para>Implicit animations use a default duration of 250 milliseconds,
258  *     and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259  *     clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260  *     after changing the easing state of the actor.</para>
261  *   </formalpara>
262  *   <formalpara>
263  *     <title>Explicit animations</title>
264  *     <para>The explicit animation model supported by Clutter requires that
265  *     you create a #ClutterTransition object, and set the initial and
266  *     final values. The transition will not start unless you add it to the
267  *     #ClutterActor.</para>
268  *     <informalexample><programlisting>
269  * ClutterTransition *transition;
270  *
271  * transition = clutter_property_transition_new ("opacity");
272  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
273  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
274  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
275  * clutter_transition_set_interval (transition, clutter_interval_new (G_TYPE_UINT, 255, 0));
276  *
277  * clutter_actor_add_transition (actor, "animate-opacity", transition);
278  *     </programlisting></informalexample>
279  *     <para>The example above will animate the #ClutterActor:opacity property
280  *     of an actor between fully opaque and fully transparent, and back, over
281  *     a span of 3 seconds. The animation does not begin until it is added to
282  *     the actor.</para>
283  *     <para>The explicit animation API should also be used when using custom
284  *     animatable properties for #ClutterAction, #ClutterConstraint, and
285  *     #ClutterEffect instances associated to an actor; see the section on
286  *     <ulink linkend="ClutterActor-custom-animatable-properties">custom
287  *     animatable properties below</ulink> for an example.</para>
288  *     <para>Finally, explicit animations are useful for creating animations
289  *     that run continuously, for instance:</para>
290  *     <informalexample><programlisting>
291  * /&ast; this animation will pulse the actor's opacity continuously &ast;/
292  * ClutterTransition *transition;
293  * ClutterInterval *interval;
294  *
295  * transition = clutter_property_transition_new ("opacity");
296  *
297  * /&ast; we want to animate the opacity between 0 and 255 &ast;/
298  * internal = clutter_interval_new (G_TYPE_UINT, 0, 255);
299  * clutter_transition_set_interval (transition, interval);
300  *
301  * /&ast; over a one second duration, running an infinite amount of times &ast;/
302  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
303  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
304  *
305  * /&ast; we want to fade in and out, so we need to auto-reverse the transition &ast;/
306  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
307  *
308  * /&ast; and we want to use an easing function that eases both in and out &ast;/
309  * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
310  *                                     CLUTTER_EASE_IN_OUT_CUBIC);
311  *
312  * /&ast; add the transition to the desired actor; this will
313  *  &ast; start the animation.
314  *  &ast;/
315  * clutter_actor_add_transition (actor, "opacityAnimation", transition);
316  *     </programlisting></informalexample>
317  *   </formalpara>
318  * </refsect2>
319  *
320  * <refsect2 id="ClutterActor-subclassing">
321  *   <title>Implementing an actor</title>
322  *   <para>Careful consideration should be given when deciding to implement
323  *   a #ClutterActor sub-class. It is generally recommended to implement a
324  *   sub-class of #ClutterActor only for actors that should be used as leaf
325  *   nodes of a scene graph.</para>
326  *   <para>If your actor should be painted in a custom way, you should
327  *   override the #ClutterActor::paint signal class handler. You can either
328  *   opt to chain up to the parent class implementation or decide to fully
329  *   override the default paint implementation; Clutter will set up the
330  *   transformations and clip regions prior to emitting the #ClutterActor::paint
331  *   signal.</para>
332  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
333  *   #ClutterActorClass.get_preferred_height() virtual functions it is
334  *   possible to change or provide the preferred size of an actor; similarly,
335  *   by overriding the #ClutterActorClass.allocate() virtual function it is
336  *   possible to control the layout of the children of an actor. Make sure to
337  *   always chain up to the parent implementation of the
338  *   #ClutterActorClass.allocate() virtual function.</para>
339  *   <para>In general, it is strongly encouraged to use delegation and
340  *   composition instead of direct subclassing.</para>
341  * </refsect2>
342  *
343  * <refsect2 id="ClutterActor-script">
344  *   <title>ClutterActor custom properties for #ClutterScript</title>
345  *   <para>#ClutterActor defines a custom "rotation" property which
346  *   allows a short-hand description of the rotations to be applied
347  *   to an actor.</para>
348  *   <para>The syntax of the "rotation" property is the following:</para>
349  *   <informalexample>
350  *     <programlisting>
351  * "rotation" : [
352  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
353  * ]
354  *     </programlisting>
355  *   </informalexample>
356  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
357  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
358  *   floating point value representing the rotation angle on the given axis,
359  *   in degrees.</para>
360  *   <para>The <emphasis>center</emphasis> array is optional, and if present
361  *   it must contain the center of rotation as described by two coordinates:
362  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
363  *   "z-axis".</para>
364  *   <para>#ClutterActor will also parse every positional and dimensional
365  *   property defined as a string through clutter_units_from_string(); you
366  *   should read the documentation for the #ClutterUnits parser format for
367  *   the valid units and syntax.</para>
368  * </refsect2>
369  *
370  * <refsect2 id="ClutterActor-custom-animatable-properties">
371  *   <title>Custom animatable properties</title>
372  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
373  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
374  *   instance for animation purposes.</para>
375  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
376  *   property it is necessary to set the #ClutterActorMeta:name property on the
377  *   given action or constraint.</para>
378  *   <para>The property can be accessed using the following syntax:</para>
379  *   <informalexample>
380  *     <programlisting>
381  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
382  *     </programlisting>
383  *   </informalexample>
384  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
385  *   <para>The <emphasis>section</emphasis> fragment can be one between
386  *   "actions", "constraints" and "effects".</para>
387  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
388  *   action or constraint, as specified by the #ClutterActorMeta:name
389  *   property.</para>
390  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
391  *   action or constraint property to be animated.</para>
392  *   <para>The example below animates a #ClutterBindConstraint applied to an
393  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
394  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
395  *   its initial state is overlapping the actor to which is bound to.</para>
396  *   <informalexample><programlisting>
397  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
398  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
399  * clutter_actor_add_constraint (rect, constraint);
400  *
401  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
402  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
403  * clutter_actor_add_constraint (rect, constraint);
404  *
405  * clutter_actor_set_reactive (origin, TRUE);
406  *
407  * g_signal_connect (origin, "button-press-event",
408  *                   G_CALLBACK (on_button_press),
409  *                   rect);
410  *   </programlisting></informalexample>
411  *   <para>On button press, the rectangle "slides" from behind the actor to
412  *   which is bound to, using the #ClutterBindConstraint:offset property to
413  *   achieve the effect:</para>
414  *   <informalexample><programlisting>
415  * gboolean
416  * on_button_press (ClutterActor *origin,
417  *                  ClutterEvent *event,
418  *                  ClutterActor *rect)
419  * {
420  *   ClutterTransition *transition;
421  *   ClutterInterval *interval;
422  *
423  *   /&ast; the offset that we want to apply; this will make the actor
424  *    &ast; slide in from behind the origin and rest at the right of
425  *    &ast; the origin, plus a padding value.
426  *    &ast;/
427  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
428  *
429  *   /&ast; the property we wish to animate; the "@constraints" section
430  *    &ast; tells Clutter to check inside the constraints associated
431  *    &ast; with the actor; the "bind-x" section is the name of the
432  *    &ast; constraint; and the "offset" is the name of the property
433  *    &ast; on the constraint.
434  *    &ast;/
435  *   const char *prop = "@constraints.bind-x.offset";
436  *
437  *   /&ast; create a new transition for the given property &ast;/
438  *   transition = clutter_property_transition_new (prop);
439  *
440  *   /&ast; set the easing mode and duration &ast;/
441  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
442  *                                       CLUTTER_EASE_OUT_CUBIC);
443  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
444  *
445  *   /&ast; create the interval with the initial and final values &ast;/
446  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
447  *   clutter_transition_set_interval (transition, interval);
448  *
449  *   /&ast; add the transition to the actor; this causes the animation
450  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
451  *    &ast; the transition later.
452  *    &ast;/
453  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
454  *
455  *   /&ast; we handled the event &ast;/
456  *   return CLUTTER_EVENT_STOP;
457  * }
458  *   </programlisting></informalexample>
459  * </refsect2>
460  */
461
462 /**
463  * CLUTTER_ACTOR_IS_MAPPED:
464  * @a: a #ClutterActor
465  *
466  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
467  *
468  * The mapped state is set when the actor is visible and all its parents up
469  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
470  *
471  * This check can be used to see if an actor is going to be painted, as only
472  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
473  *
474  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
475  * not be checked directly; instead, the recommended usage is to connect a
476  * handler on the #GObject::notify signal for the #ClutterActor:mapped
477  * property of #ClutterActor, and check the presence of
478  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
479  *
480  * It is also important to note that Clutter may delay the changes of
481  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
482  * limitations, or during the reparenting of an actor, to optimize
483  * unnecessary (and potentially expensive) state changes.
484  *
485  * Since: 0.2
486  */
487
488 /**
489  * CLUTTER_ACTOR_IS_REALIZED:
490  * @a: a #ClutterActor
491  *
492  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
493  *
494  * The realized state has an actor-dependant interpretation. If an
495  * actor wants to delay allocating resources until it is attached to a
496  * stage, it may use the realize state to do so. However it is
497  * perfectly acceptable for an actor to allocate Cogl resources before
498  * being realized because there is only one drawing context used by Clutter
499  * so any resources will work on any stage.  If an actor is mapped it
500  * must also be realized, but an actor can be realized and unmapped
501  * (this is so hiding an actor temporarily doesn't do an expensive
502  * unrealize/realize).
503  *
504  * To be realized an actor must be inside a stage, and all its parents
505  * must be realized.
506  *
507  * Since: 0.2
508  */
509
510 /**
511  * CLUTTER_ACTOR_IS_VISIBLE:
512  * @a: a #ClutterActor
513  *
514  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
515  * Equivalent to the ClutterActor::visible object property.
516  *
517  * Note that an actor is only painted onscreen if it's mapped, which
518  * means it's visible, and all its parents are visible, and one of the
519  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
520  *
521  * Since: 0.2
522  */
523
524 /**
525  * CLUTTER_ACTOR_IS_REACTIVE:
526  * @a: a #ClutterActor
527  *
528  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
529  *
530  * Only reactive actors will receive event-related signals.
531  *
532  * Since: 0.6
533  */
534
535 #ifdef HAVE_CONFIG_H
536 #include "config.h"
537 #endif
538
539 #include <math.h>
540
541 #include <gobject/gvaluecollector.h>
542
543 #include <cogl/cogl.h>
544
545 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
546 #define CLUTTER_ENABLE_EXPERIMENTAL_API
547
548 #include "clutter-actor-private.h"
549
550 #include "clutter-action.h"
551 #include "clutter-actor-meta-private.h"
552 #include "clutter-animatable.h"
553 #include "clutter-color-static.h"
554 #include "clutter-color.h"
555 #include "clutter-constraint.h"
556 #include "clutter-container.h"
557 #include "clutter-content-private.h"
558 #include "clutter-debug.h"
559 #include "clutter-effect-private.h"
560 #include "clutter-enum-types.h"
561 #include "clutter-fixed-layout.h"
562 #include "clutter-flatten-effect.h"
563 #include "clutter-interval.h"
564 #include "clutter-main.h"
565 #include "clutter-marshal.h"
566 #include "clutter-paint-nodes.h"
567 #include "clutter-paint-node-private.h"
568 #include "clutter-paint-volume-private.h"
569 #include "clutter-private.h"
570 #include "clutter-profile.h"
571 #include "clutter-property-transition.h"
572 #include "clutter-scriptable.h"
573 #include "clutter-script-private.h"
574 #include "clutter-stage-private.h"
575 #include "clutter-timeline.h"
576 #include "clutter-transition.h"
577 #include "clutter-units.h"
578
579 #include "deprecated/clutter-actor.h"
580 #include "deprecated/clutter-behaviour.h"
581 #include "deprecated/clutter-container.h"
582
583 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
584 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
585
586 /* Internal enum used to control mapped state update.  This is a hint
587  * which indicates when to do something other than just enforce
588  * invariants.
589  */
590 typedef enum {
591   MAP_STATE_CHECK,           /* just enforce invariants. */
592   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
593                               * used when about to unparent.
594                               */
595   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
596                               * used to set mapped on toplevels.
597                               */
598   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
599                               * used just before unmapping parent.
600                               */
601 } MapStateChange;
602
603 /* 3 entries should be a good compromise, few layout managers
604  * will ask for 3 different preferred size in each allocation cycle */
605 #define N_CACHED_SIZE_REQUESTS 3
606
607 struct _ClutterActorPrivate
608 {
609   /* request mode */
610   ClutterRequestMode request_mode;
611
612   /* our cached size requests for different width / height */
613   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
614   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
615
616   /* An age of 0 means the entry is not set */
617   guint cached_height_age;
618   guint cached_width_age;
619
620   /* the bounding box of the actor, relative to the parent's
621    * allocation
622    */
623   ClutterActorBox allocation;
624   ClutterAllocationFlags allocation_flags;
625
626   /* clip, in actor coordinates */
627   cairo_rectangle_t clip;
628
629   /* the cached transformation matrix; see apply_transform() */
630   CoglMatrix transform;
631
632   guint8 opacity;
633   gint opacity_override;
634
635   ClutterOffscreenRedirect offscreen_redirect;
636
637   /* This is an internal effect used to implement the
638      offscreen-redirect property */
639   ClutterEffect *flatten_effect;
640
641   /* scene graph */
642   ClutterActor *parent;
643   ClutterActor *prev_sibling;
644   ClutterActor *next_sibling;
645   ClutterActor *first_child;
646   ClutterActor *last_child;
647
648   gint n_children;
649
650   /* tracks whenever the children of an actor are changed; the
651    * age is incremented by 1 whenever an actor is added or
652    * removed. the age is not incremented when the first or the
653    * last child pointers are changed, or when grandchildren of
654    * an actor are changed.
655    */
656   gint age;
657
658   gchar *name; /* a non-unique name, used for debugging */
659   guint32 id; /* unique id, used for backward compatibility */
660
661   gint32 pick_id; /* per-stage unique id, used for picking */
662
663   /* a back-pointer to the Pango context that we can use
664    * to create pre-configured PangoLayout
665    */
666   PangoContext *pango_context;
667
668   /* the text direction configured for this child - either by
669    * application code, or by the actor's parent
670    */
671   ClutterTextDirection text_direction;
672
673   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
674   gint internal_child;
675
676   /* meta classes */
677   ClutterMetaGroup *actions;
678   ClutterMetaGroup *constraints;
679   ClutterMetaGroup *effects;
680
681   /* delegate object used to allocate the children of this actor */
682   ClutterLayoutManager *layout_manager;
683
684   /* delegate object used to paint the contents of this actor */
685   ClutterContent *content;
686
687   ClutterContentGravity content_gravity;
688   ClutterScalingFilter min_filter;
689   ClutterScalingFilter mag_filter;
690
691   /* used when painting, to update the paint volume */
692   ClutterEffect *current_effect;
693
694   /* This is used to store an effect which needs to be redrawn. A
695      redraw can be queued to start from a particular effect. This is
696      used by parametrised effects that can cache an image of the
697      actor. If a parameter of the effect changes then it only needs to
698      redraw the cached image, not the actual actor. The pointer is
699      only valid if is_dirty == TRUE. If the pointer is NULL then the
700      whole actor is dirty. */
701   ClutterEffect *effect_to_redraw;
702
703   /* This is used when painting effects to implement the
704      clutter_actor_continue_paint() function. It points to the node in
705      the list of effects that is next in the chain */
706   const GList *next_effect_to_paint;
707
708   ClutterPaintVolume paint_volume;
709
710   /* NB: This volume isn't relative to this actor, it is in eye
711    * coordinates so that it can remain valid after the actor changes.
712    */
713   ClutterPaintVolume last_paint_volume;
714
715   ClutterStageQueueRedrawEntry *queue_redraw_entry;
716
717   ClutterColor bg_color;
718
719   /* bitfields */
720
721   /* fixed position and sizes */
722   guint position_set                : 1;
723   guint min_width_set               : 1;
724   guint min_height_set              : 1;
725   guint natural_width_set           : 1;
726   guint natural_height_set          : 1;
727   /* cached request is invalid (implies allocation is too) */
728   guint needs_width_request         : 1;
729   /* cached request is invalid (implies allocation is too) */
730   guint needs_height_request        : 1;
731   /* cached allocation is invalid (request has changed, probably) */
732   guint needs_allocation            : 1;
733   guint show_on_set_parent          : 1;
734   guint has_clip                    : 1;
735   guint clip_to_allocation          : 1;
736   guint enable_model_view_transform : 1;
737   guint enable_paint_unmapped       : 1;
738   guint has_pointer                 : 1;
739   guint propagated_one_redraw       : 1;
740   guint paint_volume_valid          : 1;
741   guint last_paint_volume_valid     : 1;
742   guint in_clone_paint              : 1;
743   guint transform_valid             : 1;
744   /* This is TRUE if anything has queued a redraw since we were last
745      painted. In this case effect_to_redraw will point to an effect
746      the redraw was queued from or it will be NULL if the redraw was
747      queued without an effect. */
748   guint is_dirty                    : 1;
749   guint bg_color_set                : 1;
750 };
751
752 enum
753 {
754   PROP_0,
755
756   PROP_NAME,
757
758   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
759    * when set they force a size request, when gotten they
760    * get the allocation if the allocation is valid, and the
761    * request otherwise
762    */
763   PROP_X,
764   PROP_Y,
765   PROP_WIDTH,
766   PROP_HEIGHT,
767
768   /* Then the rest of these size-related properties are the "actual"
769    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
770    */
771   PROP_FIXED_X,
772   PROP_FIXED_Y,
773
774   PROP_FIXED_POSITION_SET,
775
776   PROP_MIN_WIDTH,
777   PROP_MIN_WIDTH_SET,
778
779   PROP_MIN_HEIGHT,
780   PROP_MIN_HEIGHT_SET,
781
782   PROP_NATURAL_WIDTH,
783   PROP_NATURAL_WIDTH_SET,
784
785   PROP_NATURAL_HEIGHT,
786   PROP_NATURAL_HEIGHT_SET,
787
788   PROP_REQUEST_MODE,
789
790   /* Allocation properties are read-only */
791   PROP_ALLOCATION,
792
793   PROP_DEPTH,
794
795   PROP_CLIP,
796   PROP_HAS_CLIP,
797   PROP_CLIP_TO_ALLOCATION,
798
799   PROP_OPACITY,
800
801   PROP_OFFSCREEN_REDIRECT,
802
803   PROP_VISIBLE,
804   PROP_MAPPED,
805   PROP_REALIZED,
806   PROP_REACTIVE,
807
808   PROP_SCALE_X,
809   PROP_SCALE_Y,
810   PROP_SCALE_CENTER_X,
811   PROP_SCALE_CENTER_Y,
812   PROP_SCALE_GRAVITY,
813
814   PROP_ROTATION_ANGLE_X,
815   PROP_ROTATION_ANGLE_Y,
816   PROP_ROTATION_ANGLE_Z,
817   PROP_ROTATION_CENTER_X,
818   PROP_ROTATION_CENTER_Y,
819   PROP_ROTATION_CENTER_Z,
820   /* This property only makes sense for the z rotation because the
821      others would depend on the actor having a size along the
822      z-axis */
823   PROP_ROTATION_CENTER_Z_GRAVITY,
824
825   PROP_ANCHOR_X,
826   PROP_ANCHOR_Y,
827   PROP_ANCHOR_GRAVITY,
828
829   PROP_SHOW_ON_SET_PARENT,
830
831   PROP_TEXT_DIRECTION,
832   PROP_HAS_POINTER,
833
834   PROP_ACTIONS,
835   PROP_CONSTRAINTS,
836   PROP_EFFECT,
837
838   PROP_LAYOUT_MANAGER,
839
840   PROP_X_ALIGN,
841   PROP_Y_ALIGN,
842   PROP_MARGIN_TOP,
843   PROP_MARGIN_BOTTOM,
844   PROP_MARGIN_LEFT,
845   PROP_MARGIN_RIGHT,
846
847   PROP_BACKGROUND_COLOR,
848   PROP_BACKGROUND_COLOR_SET,
849
850   PROP_FIRST_CHILD,
851   PROP_LAST_CHILD,
852
853   PROP_CONTENT,
854   PROP_CONTENT_GRAVITY,
855   PROP_CONTENT_BOX,
856   PROP_MINIFICATION_FILTER,
857   PROP_MAGNIFICATION_FILTER,
858
859   PROP_LAST
860 };
861
862 static GParamSpec *obj_props[PROP_LAST];
863
864 enum
865 {
866   SHOW,
867   HIDE,
868   DESTROY,
869   PARENT_SET,
870   KEY_FOCUS_IN,
871   KEY_FOCUS_OUT,
872   PAINT,
873   PICK,
874   REALIZE,
875   UNREALIZE,
876   QUEUE_REDRAW,
877   QUEUE_RELAYOUT,
878   EVENT,
879   CAPTURED_EVENT,
880   BUTTON_PRESS_EVENT,
881   BUTTON_RELEASE_EVENT,
882   SCROLL_EVENT,
883   KEY_PRESS_EVENT,
884   KEY_RELEASE_EVENT,
885   MOTION_EVENT,
886   ENTER_EVENT,
887   LEAVE_EVENT,
888   ALLOCATION_CHANGED,
889   TRANSITIONS_COMPLETED,
890
891   LAST_SIGNAL
892 };
893
894 static guint actor_signals[LAST_SIGNAL] = { 0, };
895
896 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
897 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
898 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
899 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
900
901 /* These setters are all static for now, maybe they should be in the
902  * public API, but they are perhaps obscure enough to leave only as
903  * properties
904  */
905 static void clutter_actor_set_min_width          (ClutterActor *self,
906                                                   gfloat        min_width);
907 static void clutter_actor_set_min_height         (ClutterActor *self,
908                                                   gfloat        min_height);
909 static void clutter_actor_set_natural_width      (ClutterActor *self,
910                                                   gfloat        natural_width);
911 static void clutter_actor_set_natural_height     (ClutterActor *self,
912                                                   gfloat        natural_height);
913 static void clutter_actor_set_min_width_set      (ClutterActor *self,
914                                                   gboolean      use_min_width);
915 static void clutter_actor_set_min_height_set     (ClutterActor *self,
916                                                   gboolean      use_min_height);
917 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
918                                                   gboolean  use_natural_width);
919 static void clutter_actor_set_natural_height_set (ClutterActor *self,
920                                                   gboolean  use_natural_height);
921 static void clutter_actor_update_map_state       (ClutterActor  *self,
922                                                   MapStateChange change);
923 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
924
925 /* Helper routines for managing anchor coords */
926 static void clutter_anchor_coord_get_units (ClutterActor      *self,
927                                             const AnchorCoord *coord,
928                                             gfloat            *x,
929                                             gfloat            *y,
930                                             gfloat            *z);
931 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
932                                             gfloat             x,
933                                             gfloat             y,
934                                             gfloat             z);
935
936 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
937 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
938                                                         ClutterGravity     gravity);
939
940 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
941
942 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
943
944 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
945                                                                ClutterActor *ancestor,
946                                                                CoglMatrix *matrix);
947
948 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
949
950 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
951
952 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
953                                                                 const ClutterColor *color);
954
955 static void on_layout_manager_changed (ClutterLayoutManager *manager,
956                                        ClutterActor         *self);
957
958 /* Helper macro which translates by the anchor coord, applies the
959    given transformation and then translates back */
960 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
961   gfloat _tx, _ty, _tz;                                                \
962   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
963   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
964   { _transform; }                                                      \
965   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
966
967 static GQuark quark_shader_data = 0;
968 static GQuark quark_actor_layout_info = 0;
969 static GQuark quark_actor_transform_info = 0;
970 static GQuark quark_actor_animation_info = 0;
971
972 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
973                          clutter_actor,
974                          G_TYPE_INITIALLY_UNOWNED,
975                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
976                                                 clutter_container_iface_init)
977                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
978                                                 clutter_scriptable_iface_init)
979                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
980                                                 clutter_animatable_iface_init)
981                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
982                                                 atk_implementor_iface_init));
983
984 /*< private >
985  * clutter_actor_get_debug_name:
986  * @actor: a #ClutterActor
987  *
988  * Retrieves a printable name of @actor for debugging messages
989  *
990  * Return value: a string with a printable name
991  */
992 const gchar *
993 _clutter_actor_get_debug_name (ClutterActor *actor)
994 {
995   return actor->priv->name != NULL ? actor->priv->name
996                                    : G_OBJECT_TYPE_NAME (actor);
997 }
998
999 #ifdef CLUTTER_ENABLE_DEBUG
1000 /* XXX - this is for debugging only, remove once working (or leave
1001  * in only in some debug mode). Should leave it for a little while
1002  * until we're confident in the new map/realize/visible handling.
1003  */
1004 static inline void
1005 clutter_actor_verify_map_state (ClutterActor *self)
1006 {
1007   ClutterActorPrivate *priv = self->priv;
1008
1009   if (CLUTTER_ACTOR_IS_REALIZED (self))
1010     {
1011       /* all bets are off during reparent when we're potentially realized,
1012        * but should not be according to invariants
1013        */
1014       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1015         {
1016           if (priv->parent == NULL)
1017             {
1018               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1019                 {
1020                 }
1021               else
1022                 g_warning ("Realized non-toplevel actor '%s' should "
1023                            "have a parent",
1024                            _clutter_actor_get_debug_name (self));
1025             }
1026           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1027             {
1028               g_warning ("Realized actor %s has an unrealized parent %s",
1029                          _clutter_actor_get_debug_name (self),
1030                          _clutter_actor_get_debug_name (priv->parent));
1031             }
1032         }
1033     }
1034
1035   if (CLUTTER_ACTOR_IS_MAPPED (self))
1036     {
1037       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1038         g_warning ("Actor '%s' is mapped but not realized",
1039                    _clutter_actor_get_debug_name (self));
1040
1041       /* remaining bets are off during reparent when we're potentially
1042        * mapped, but should not be according to invariants
1043        */
1044       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1045         {
1046           if (priv->parent == NULL)
1047             {
1048               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1049                 {
1050                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1051                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1052                     {
1053                       g_warning ("Toplevel actor '%s' is mapped "
1054                                  "but not visible",
1055                                  _clutter_actor_get_debug_name (self));
1056                     }
1057                 }
1058               else
1059                 {
1060                   g_warning ("Mapped actor '%s' should have a parent",
1061                              _clutter_actor_get_debug_name (self));
1062                 }
1063             }
1064           else
1065             {
1066               ClutterActor *iter = self;
1067
1068               /* check for the enable_paint_unmapped flag on the actor
1069                * and parents; if the flag is enabled at any point of this
1070                * branch of the scene graph then all the later checks
1071                * become pointless
1072                */
1073               while (iter != NULL)
1074                 {
1075                   if (iter->priv->enable_paint_unmapped)
1076                     return;
1077
1078                   iter = iter->priv->parent;
1079                 }
1080
1081               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1082                 {
1083                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1084                              "is not visible",
1085                              _clutter_actor_get_debug_name (self),
1086                              _clutter_actor_get_debug_name (priv->parent));
1087                 }
1088
1089               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1090                 {
1091                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1092                              "is not realized",
1093                              _clutter_actor_get_debug_name (self),
1094                              _clutter_actor_get_debug_name (priv->parent));
1095                 }
1096
1097               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1098                 {
1099                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1100                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1101                                "parent '%s' is not mapped",
1102                                _clutter_actor_get_debug_name (self),
1103                                _clutter_actor_get_debug_name (priv->parent));
1104                 }
1105             }
1106         }
1107     }
1108 }
1109
1110 #endif /* CLUTTER_ENABLE_DEBUG */
1111
1112 static void
1113 clutter_actor_set_mapped (ClutterActor *self,
1114                           gboolean      mapped)
1115 {
1116   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1117     return;
1118
1119   if (mapped)
1120     {
1121       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1122       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1123     }
1124   else
1125     {
1126       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1127       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1128     }
1129 }
1130
1131 /* this function updates the mapped and realized states according to
1132  * invariants, in the appropriate order.
1133  */
1134 static void
1135 clutter_actor_update_map_state (ClutterActor  *self,
1136                                 MapStateChange change)
1137 {
1138   gboolean was_mapped;
1139
1140   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1141
1142   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1143     {
1144       /* the mapped flag on top-level actors must be set by the
1145        * per-backend implementation because it might be asynchronous.
1146        *
1147        * That is, the MAPPED flag on toplevels currently tracks the X
1148        * server mapped-ness of the window, while the expected behavior
1149        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1150        * This creates some weird complexity by breaking the invariant
1151        * that if we're visible and all ancestors shown then we are
1152        * also mapped - instead, we are mapped if all ancestors
1153        * _possibly excepting_ the stage are mapped. The stage
1154        * will map/unmap for example when it is minimized or
1155        * moved to another workspace.
1156        *
1157        * So, the only invariant on the stage is that if visible it
1158        * should be realized, and that it has to be visible to be
1159        * mapped.
1160        */
1161       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1162         clutter_actor_realize (self);
1163
1164       switch (change)
1165         {
1166         case MAP_STATE_CHECK:
1167           break;
1168
1169         case MAP_STATE_MAKE_MAPPED:
1170           g_assert (!was_mapped);
1171           clutter_actor_set_mapped (self, TRUE);
1172           break;
1173
1174         case MAP_STATE_MAKE_UNMAPPED:
1175           g_assert (was_mapped);
1176           clutter_actor_set_mapped (self, FALSE);
1177           break;
1178
1179         case MAP_STATE_MAKE_UNREALIZED:
1180           /* we only use MAKE_UNREALIZED in unparent,
1181            * and unparenting a stage isn't possible.
1182            * If someone wants to just unrealize a stage
1183            * then clutter_actor_unrealize() doesn't
1184            * go through this codepath.
1185            */
1186           g_warning ("Trying to force unrealize stage is not allowed");
1187           break;
1188         }
1189
1190       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1191           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1192           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1193         {
1194           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1195                      "it is somehow still mapped",
1196                      _clutter_actor_get_debug_name (self));
1197         }
1198     }
1199   else
1200     {
1201       ClutterActorPrivate *priv = self->priv;
1202       ClutterActor *parent = priv->parent;
1203       gboolean should_be_mapped;
1204       gboolean may_be_realized;
1205       gboolean must_be_realized;
1206
1207       should_be_mapped = FALSE;
1208       may_be_realized = TRUE;
1209       must_be_realized = FALSE;
1210
1211       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1212         {
1213           may_be_realized = FALSE;
1214         }
1215       else
1216         {
1217           /* Maintain invariant that if parent is mapped, and we are
1218            * visible, then we are mapped ...  unless parent is a
1219            * stage, in which case we map regardless of parent's map
1220            * state but do require stage to be visible and realized.
1221            *
1222            * If parent is realized, that does not force us to be
1223            * realized; but if parent is unrealized, that does force
1224            * us to be unrealized.
1225            *
1226            * The reason we don't force children to realize with
1227            * parents is _clutter_actor_rerealize(); if we require that
1228            * a realized parent means children are realized, then to
1229            * unrealize an actor we would have to unrealize its
1230            * parents, which would end up meaning unrealizing and
1231            * hiding the entire stage. So we allow unrealizing a
1232            * child (as long as that child is not mapped) while that
1233            * child still has a realized parent.
1234            *
1235            * Also, if we unrealize from leaf nodes to root, and
1236            * realize from root to leaf, the invariants are never
1237            * violated if we allow children to be unrealized
1238            * while parents are realized.
1239            *
1240            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1241            * to force us to unmap, even though parent is still
1242            * mapped. This is because we're unmapping from leaf nodes
1243            * up to root nodes.
1244            */
1245           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1246               change != MAP_STATE_MAKE_UNMAPPED)
1247             {
1248               gboolean parent_is_visible_realized_toplevel;
1249
1250               parent_is_visible_realized_toplevel =
1251                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1252                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1253                  CLUTTER_ACTOR_IS_REALIZED (parent));
1254
1255               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1256                   parent_is_visible_realized_toplevel)
1257                 {
1258                   must_be_realized = TRUE;
1259                   should_be_mapped = TRUE;
1260                 }
1261             }
1262
1263           /* if the actor has been set to be painted even if unmapped
1264            * then we should map it and check for realization as well;
1265            * this is an override for the branch of the scene graph
1266            * which begins with this node
1267            */
1268           if (priv->enable_paint_unmapped)
1269             {
1270               if (priv->parent == NULL)
1271                 g_warning ("Attempting to map an unparented actor '%s'",
1272                            _clutter_actor_get_debug_name (self));
1273
1274               should_be_mapped = TRUE;
1275               must_be_realized = TRUE;
1276             }
1277
1278           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1279             may_be_realized = FALSE;
1280         }
1281
1282       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1283         {
1284           if (parent == NULL)
1285             g_warning ("Attempting to map a child that does not "
1286                        "meet the necessary invariants: the actor '%s' "
1287                        "has no parent",
1288                        _clutter_actor_get_debug_name (self));
1289           else
1290             g_warning ("Attempting to map a child that does not "
1291                        "meet the necessary invariants: the actor '%s' "
1292                        "is parented to an unmapped actor '%s'",
1293                        _clutter_actor_get_debug_name (self),
1294                        _clutter_actor_get_debug_name (priv->parent));
1295         }
1296
1297       /* If in reparent, we temporarily suspend unmap and unrealize.
1298        *
1299        * We want to go in the order "realize, map" and "unmap, unrealize"
1300        */
1301
1302       /* Unmap */
1303       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1304         clutter_actor_set_mapped (self, FALSE);
1305
1306       /* Realize */
1307       if (must_be_realized)
1308         clutter_actor_realize (self);
1309
1310       /* if we must be realized then we may be, presumably */
1311       g_assert (!(must_be_realized && !may_be_realized));
1312
1313       /* Unrealize */
1314       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1315         clutter_actor_unrealize_not_hiding (self);
1316
1317       /* Map */
1318       if (should_be_mapped)
1319         {
1320           if (!must_be_realized)
1321             g_warning ("Somehow we think actor '%s' should be mapped but "
1322                        "not realized, which isn't allowed",
1323                        _clutter_actor_get_debug_name (self));
1324
1325           /* realization is allowed to fail (though I don't know what
1326            * an app is supposed to do about that - shouldn't it just
1327            * be a g_error? anyway, we have to avoid mapping if this
1328            * happens)
1329            */
1330           if (CLUTTER_ACTOR_IS_REALIZED (self))
1331             clutter_actor_set_mapped (self, TRUE);
1332         }
1333     }
1334
1335 #ifdef CLUTTER_ENABLE_DEBUG
1336   /* check all invariants were kept */
1337   clutter_actor_verify_map_state (self);
1338 #endif
1339 }
1340
1341 static void
1342 clutter_actor_real_map (ClutterActor *self)
1343 {
1344   ClutterActorPrivate *priv = self->priv;
1345   ClutterActor *stage, *iter;
1346
1347   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1348
1349   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1350                 _clutter_actor_get_debug_name (self));
1351
1352   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1353
1354   stage = _clutter_actor_get_stage_internal (self);
1355   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1356
1357   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1358                 priv->pick_id,
1359                 _clutter_actor_get_debug_name (self));
1360
1361   /* notify on parent mapped before potentially mapping
1362    * children, so apps see a top-down notification.
1363    */
1364   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1365
1366   for (iter = self->priv->first_child;
1367        iter != NULL;
1368        iter = iter->priv->next_sibling)
1369     {
1370       clutter_actor_map (iter);
1371     }
1372 }
1373
1374 /**
1375  * clutter_actor_map:
1376  * @self: A #ClutterActor
1377  *
1378  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1379  * and realizes its children if they are visible. Does nothing if the
1380  * actor is not visible.
1381  *
1382  * Calling this function is strongly disencouraged: the default
1383  * implementation of #ClutterActorClass.map() will map all the children
1384  * of an actor when mapping its parent.
1385  *
1386  * When overriding map, it is mandatory to chain up to the parent
1387  * implementation.
1388  *
1389  * Since: 1.0
1390  */
1391 void
1392 clutter_actor_map (ClutterActor *self)
1393 {
1394   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1395
1396   if (CLUTTER_ACTOR_IS_MAPPED (self))
1397     return;
1398
1399   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1400     return;
1401
1402   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1403 }
1404
1405 static void
1406 clutter_actor_real_unmap (ClutterActor *self)
1407 {
1408   ClutterActorPrivate *priv = self->priv;
1409   ClutterActor *iter;
1410
1411   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1412
1413   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1414                 _clutter_actor_get_debug_name (self));
1415
1416   for (iter = self->priv->first_child;
1417        iter != NULL;
1418        iter = iter->priv->next_sibling)
1419     {
1420       clutter_actor_unmap (iter);
1421     }
1422
1423   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1424
1425   /* clear the contents of the last paint volume, so that hiding + moving +
1426    * showing will not result in the wrong area being repainted
1427    */
1428   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1429   priv->last_paint_volume_valid = TRUE;
1430
1431   /* notify on parent mapped after potentially unmapping
1432    * children, so apps see a bottom-up notification.
1433    */
1434   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1435
1436   /* relinquish keyboard focus if we were unmapped while owning it */
1437   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1438     {
1439       ClutterStage *stage;
1440
1441       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1442
1443       if (stage != NULL)
1444         _clutter_stage_release_pick_id (stage, priv->pick_id);
1445
1446       priv->pick_id = -1;
1447
1448       if (stage != NULL &&
1449           clutter_stage_get_key_focus (stage) == self)
1450         {
1451           clutter_stage_set_key_focus (stage, NULL);
1452         }
1453     }
1454 }
1455
1456 /**
1457  * clutter_actor_unmap:
1458  * @self: A #ClutterActor
1459  *
1460  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1461  * unmaps its children if they were mapped.
1462  *
1463  * Calling this function is not encouraged: the default #ClutterActor
1464  * implementation of #ClutterActorClass.unmap() will also unmap any
1465  * eventual children by default when their parent is unmapped.
1466  *
1467  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1468  * chain up to the parent implementation.
1469  *
1470  * <note>It is important to note that the implementation of the
1471  * #ClutterActorClass.unmap() virtual function may be called after
1472  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1473  * implementation, but it is guaranteed to be called before the
1474  * #GObjectClass.finalize() implementation.</note>
1475  *
1476  * Since: 1.0
1477  */
1478 void
1479 clutter_actor_unmap (ClutterActor *self)
1480 {
1481   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1482
1483   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1484     return;
1485
1486   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1487 }
1488
1489 static void
1490 clutter_actor_real_show (ClutterActor *self)
1491 {
1492   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1493     {
1494       ClutterActorPrivate *priv = self->priv;
1495
1496       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1497
1498       /* we notify on the "visible" flag in the clutter_actor_show()
1499        * wrapper so the entire show signal emission completes first
1500        * (?)
1501        */
1502       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1503
1504       /* we queue a relayout unless the actor is inside a
1505        * container that explicitly told us not to
1506        */
1507       if (priv->parent != NULL &&
1508           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1509         {
1510           /* While an actor is hidden the parent may not have
1511            * allocated/requested so we need to start from scratch
1512            * and avoid the short-circuiting in
1513            * clutter_actor_queue_relayout().
1514            */
1515           priv->needs_width_request  = FALSE;
1516           priv->needs_height_request = FALSE;
1517           priv->needs_allocation     = FALSE;
1518           clutter_actor_queue_relayout (self);
1519         }
1520     }
1521 }
1522
1523 static inline void
1524 set_show_on_set_parent (ClutterActor *self,
1525                         gboolean      set_show)
1526 {
1527   ClutterActorPrivate *priv = self->priv;
1528
1529   set_show = !!set_show;
1530
1531   if (priv->show_on_set_parent == set_show)
1532     return;
1533
1534   if (priv->parent == NULL)
1535     {
1536       priv->show_on_set_parent = set_show;
1537       g_object_notify_by_pspec (G_OBJECT (self),
1538                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1539     }
1540 }
1541
1542 /**
1543  * clutter_actor_show:
1544  * @self: A #ClutterActor
1545  *
1546  * Flags an actor to be displayed. An actor that isn't shown will not
1547  * be rendered on the stage.
1548  *
1549  * Actors are visible by default.
1550  *
1551  * If this function is called on an actor without a parent, the
1552  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1553  * effect.
1554  */
1555 void
1556 clutter_actor_show (ClutterActor *self)
1557 {
1558   ClutterActorPrivate *priv;
1559
1560   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1561
1562   /* simple optimization */
1563   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1564     {
1565       /* we still need to set the :show-on-set-parent property, in
1566        * case show() is called on an unparented actor
1567        */
1568       set_show_on_set_parent (self, TRUE);
1569       return;
1570     }
1571
1572 #ifdef CLUTTER_ENABLE_DEBUG
1573   clutter_actor_verify_map_state (self);
1574 #endif
1575
1576   priv = self->priv;
1577
1578   g_object_freeze_notify (G_OBJECT (self));
1579
1580   set_show_on_set_parent (self, TRUE);
1581
1582   g_signal_emit (self, actor_signals[SHOW], 0);
1583   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1584
1585   if (priv->parent != NULL)
1586     clutter_actor_queue_redraw (priv->parent);
1587
1588   g_object_thaw_notify (G_OBJECT (self));
1589 }
1590
1591 /**
1592  * clutter_actor_show_all:
1593  * @self: a #ClutterActor
1594  *
1595  * Calls clutter_actor_show() on all children of an actor (if any).
1596  *
1597  * Since: 0.2
1598  *
1599  * Deprecated: 1.10: Actors are visible by default
1600  */
1601 void
1602 clutter_actor_show_all (ClutterActor *self)
1603 {
1604   ClutterActorClass *klass;
1605
1606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1607
1608   klass = CLUTTER_ACTOR_GET_CLASS (self);
1609   if (klass->show_all)
1610     klass->show_all (self);
1611 }
1612
1613 static void
1614 clutter_actor_real_hide (ClutterActor *self)
1615 {
1616   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1617     {
1618       ClutterActorPrivate *priv = self->priv;
1619
1620       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1621
1622       /* we notify on the "visible" flag in the clutter_actor_hide()
1623        * wrapper so the entire hide signal emission completes first
1624        * (?)
1625        */
1626       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1627
1628       /* we queue a relayout unless the actor is inside a
1629        * container that explicitly told us not to
1630        */
1631       if (priv->parent != NULL &&
1632           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1633         clutter_actor_queue_relayout (priv->parent);
1634     }
1635 }
1636
1637 /**
1638  * clutter_actor_hide:
1639  * @self: A #ClutterActor
1640  *
1641  * Flags an actor to be hidden. A hidden actor will not be
1642  * rendered on the stage.
1643  *
1644  * Actors are visible by default.
1645  *
1646  * If this function is called on an actor without a parent, the
1647  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1648  * as a side-effect.
1649  */
1650 void
1651 clutter_actor_hide (ClutterActor *self)
1652 {
1653   ClutterActorPrivate *priv;
1654
1655   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1656
1657   /* simple optimization */
1658   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1659     {
1660       /* we still need to set the :show-on-set-parent property, in
1661        * case hide() is called on an unparented actor
1662        */
1663       set_show_on_set_parent (self, FALSE);
1664       return;
1665     }
1666
1667 #ifdef CLUTTER_ENABLE_DEBUG
1668   clutter_actor_verify_map_state (self);
1669 #endif
1670
1671   priv = self->priv;
1672
1673   g_object_freeze_notify (G_OBJECT (self));
1674
1675   set_show_on_set_parent (self, FALSE);
1676
1677   g_signal_emit (self, actor_signals[HIDE], 0);
1678   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1679
1680   if (priv->parent != NULL)
1681     clutter_actor_queue_redraw (priv->parent);
1682
1683   g_object_thaw_notify (G_OBJECT (self));
1684 }
1685
1686 /**
1687  * clutter_actor_hide_all:
1688  * @self: a #ClutterActor
1689  *
1690  * Calls clutter_actor_hide() on all child actors (if any).
1691  *
1692  * Since: 0.2
1693  *
1694  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1695  *   prevent its children from being painted as well.
1696  */
1697 void
1698 clutter_actor_hide_all (ClutterActor *self)
1699 {
1700   ClutterActorClass *klass;
1701
1702   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1703
1704   klass = CLUTTER_ACTOR_GET_CLASS (self);
1705   if (klass->hide_all)
1706     klass->hide_all (self);
1707 }
1708
1709 /**
1710  * clutter_actor_realize:
1711  * @self: A #ClutterActor
1712  *
1713  * Realization informs the actor that it is attached to a stage. It
1714  * can use this to allocate resources if it wanted to delay allocation
1715  * until it would be rendered. However it is perfectly acceptable for
1716  * an actor to create resources before being realized because Clutter
1717  * only ever has a single rendering context so that actor is free to
1718  * be moved from one stage to another.
1719  *
1720  * This function does nothing if the actor is already realized.
1721  *
1722  * Because a realized actor must have realized parent actors, calling
1723  * clutter_actor_realize() will also realize all parents of the actor.
1724  *
1725  * This function does not realize child actors, except in the special
1726  * case that realizing the stage, when the stage is visible, will
1727  * suddenly map (and thus realize) the children of the stage.
1728  **/
1729 void
1730 clutter_actor_realize (ClutterActor *self)
1731 {
1732   ClutterActorPrivate *priv;
1733
1734   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1735
1736   priv = self->priv;
1737
1738 #ifdef CLUTTER_ENABLE_DEBUG
1739   clutter_actor_verify_map_state (self);
1740 #endif
1741
1742   if (CLUTTER_ACTOR_IS_REALIZED (self))
1743     return;
1744
1745   /* To be realized, our parent actors must be realized first.
1746    * This will only succeed if we're inside a toplevel.
1747    */
1748   if (priv->parent != NULL)
1749     clutter_actor_realize (priv->parent);
1750
1751   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1752     {
1753       /* toplevels can be realized at any time */
1754     }
1755   else
1756     {
1757       /* "Fail" the realization if parent is missing or unrealized;
1758        * this should really be a g_warning() not some kind of runtime
1759        * failure; how can an app possibly recover? Instead it's a bug
1760        * in the app and the app should get an explanatory warning so
1761        * someone can fix it. But for now it's too hard to fix this
1762        * because e.g. ClutterTexture needs reworking.
1763        */
1764       if (priv->parent == NULL ||
1765           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1766         return;
1767     }
1768
1769   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1770
1771   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1772   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1773
1774   g_signal_emit (self, actor_signals[REALIZE], 0);
1775
1776   /* Stage actor is allowed to unset the realized flag again in its
1777    * default signal handler, though that is a pathological situation.
1778    */
1779
1780   /* If realization "failed" we'll have to update child state. */
1781   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1782 }
1783
1784 static void
1785 clutter_actor_real_unrealize (ClutterActor *self)
1786 {
1787   /* we must be unmapped (implying our children are also unmapped) */
1788   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1789 }
1790
1791 /**
1792  * clutter_actor_unrealize:
1793  * @self: A #ClutterActor
1794  *
1795  * Unrealization informs the actor that it may be being destroyed or
1796  * moved to another stage. The actor may want to destroy any
1797  * underlying graphics resources at this point. However it is
1798  * perfectly acceptable for it to retain the resources until the actor
1799  * is destroyed because Clutter only ever uses a single rendering
1800  * context and all of the graphics resources are valid on any stage.
1801  *
1802  * Because mapped actors must be realized, actors may not be
1803  * unrealized if they are mapped. This function hides the actor to be
1804  * sure it isn't mapped, an application-visible side effect that you
1805  * may not be expecting.
1806  *
1807  * This function should not be called by application code.
1808  */
1809 void
1810 clutter_actor_unrealize (ClutterActor *self)
1811 {
1812   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1813   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1814
1815 /* This function should not really be in the public API, because
1816  * there isn't a good reason to call it. ClutterActor will already
1817  * unrealize things for you when it's important to do so.
1818  *
1819  * If you were using clutter_actor_unrealize() in a dispose
1820  * implementation, then don't, just chain up to ClutterActor's
1821  * dispose.
1822  *
1823  * If you were using clutter_actor_unrealize() to implement
1824  * unrealizing children of your container, then don't, ClutterActor
1825  * will already take care of that.
1826  *
1827  * If you were using clutter_actor_unrealize() to re-realize to
1828  * create your resources in a different way, then use
1829  * _clutter_actor_rerealize() (inside Clutter) or just call your
1830  * code that recreates your resources directly (outside Clutter).
1831  */
1832
1833 #ifdef CLUTTER_ENABLE_DEBUG
1834   clutter_actor_verify_map_state (self);
1835 #endif
1836
1837   clutter_actor_hide (self);
1838
1839   clutter_actor_unrealize_not_hiding (self);
1840 }
1841
1842 static ClutterActorTraverseVisitFlags
1843 unrealize_actor_before_children_cb (ClutterActor *self,
1844                                     int depth,
1845                                     void *user_data)
1846 {
1847   /* If an actor is already unrealized we know its children have also
1848    * already been unrealized... */
1849   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1850     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1851
1852   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1853
1854   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1855 }
1856
1857 static ClutterActorTraverseVisitFlags
1858 unrealize_actor_after_children_cb (ClutterActor *self,
1859                                    int depth,
1860                                    void *user_data)
1861 {
1862   /* We want to unset the realized flag only _after_
1863    * child actors are unrealized, to maintain invariants.
1864    */
1865   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1866   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1867   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1868 }
1869
1870 /*
1871  * clutter_actor_unrealize_not_hiding:
1872  * @self: A #ClutterActor
1873  *
1874  * Unrealization informs the actor that it may be being destroyed or
1875  * moved to another stage. The actor may want to destroy any
1876  * underlying graphics resources at this point. However it is
1877  * perfectly acceptable for it to retain the resources until the actor
1878  * is destroyed because Clutter only ever uses a single rendering
1879  * context and all of the graphics resources are valid on any stage.
1880  *
1881  * Because mapped actors must be realized, actors may not be
1882  * unrealized if they are mapped. You must hide the actor or one of
1883  * its parents before attempting to unrealize.
1884  *
1885  * This function is separate from clutter_actor_unrealize() because it
1886  * does not automatically hide the actor.
1887  * Actors need not be hidden to be unrealized, they just need to
1888  * be unmapped. In fact we don't want to mess up the application's
1889  * setting of the "visible" flag, so hiding is very undesirable.
1890  *
1891  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1892  * backward compatibility.
1893  */
1894 static void
1895 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1896 {
1897   _clutter_actor_traverse (self,
1898                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1899                            unrealize_actor_before_children_cb,
1900                            unrealize_actor_after_children_cb,
1901                            NULL);
1902 }
1903
1904 /*
1905  * _clutter_actor_rerealize:
1906  * @self: A #ClutterActor
1907  * @callback: Function to call while unrealized
1908  * @data: data for callback
1909  *
1910  * If an actor is already unrealized, this just calls the callback.
1911  *
1912  * If it is realized, it unrealizes temporarily, calls the callback,
1913  * and then re-realizes the actor.
1914  *
1915  * As a side effect, leaves all children of the actor unrealized if
1916  * the actor was realized but not showing.  This is because when we
1917  * unrealize the actor temporarily we must unrealize its children
1918  * (e.g. children of a stage can't be realized if stage window is
1919  * gone). And we aren't clever enough to save the realization state of
1920  * all children. In most cases this should not matter, because
1921  * the children will automatically realize when they next become mapped.
1922  */
1923 void
1924 _clutter_actor_rerealize (ClutterActor    *self,
1925                           ClutterCallback  callback,
1926                           void            *data)
1927 {
1928   gboolean was_mapped;
1929   gboolean was_showing;
1930   gboolean was_realized;
1931
1932   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1933
1934 #ifdef CLUTTER_ENABLE_DEBUG
1935   clutter_actor_verify_map_state (self);
1936 #endif
1937
1938   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1939   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1940   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1941
1942   /* Must be unmapped to unrealize. Note we only have to hide this
1943    * actor if it was mapped (if all parents were showing).  If actor
1944    * is merely visible (but not mapped), then that's fine, we can
1945    * leave it visible.
1946    */
1947   if (was_mapped)
1948     clutter_actor_hide (self);
1949
1950   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1951
1952   /* unrealize self and all children */
1953   clutter_actor_unrealize_not_hiding (self);
1954
1955   if (callback != NULL)
1956     {
1957       (* callback) (self, data);
1958     }
1959
1960   if (was_showing)
1961     clutter_actor_show (self); /* will realize only if mapping implies it */
1962   else if (was_realized)
1963     clutter_actor_realize (self); /* realize self and all parents */
1964 }
1965
1966 static void
1967 clutter_actor_real_pick (ClutterActor       *self,
1968                          const ClutterColor *color)
1969 {
1970   /* the default implementation is just to paint a rectangle
1971    * with the same size of the actor using the passed color
1972    */
1973   if (clutter_actor_should_pick_paint (self))
1974     {
1975       ClutterActorBox box = { 0, };
1976       float width, height;
1977
1978       clutter_actor_get_allocation_box (self, &box);
1979
1980       width = box.x2 - box.x1;
1981       height = box.y2 - box.y1;
1982
1983       cogl_set_source_color4ub (color->red,
1984                                 color->green,
1985                                 color->blue,
1986                                 color->alpha);
1987
1988       cogl_rectangle (0, 0, width, height);
1989     }
1990
1991   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1992    * with existing container classes that override the pick() virtual
1993    * and chain up to the default implementation - otherwise we'll end up
1994    * painting our children twice.
1995    *
1996    * this has to go away for 2.0; hopefully along the pick() itself.
1997    */
1998   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1999     {
2000       ClutterActor *iter;
2001
2002       for (iter = self->priv->first_child;
2003            iter != NULL;
2004            iter = iter->priv->next_sibling)
2005         clutter_actor_paint (iter);
2006     }
2007 }
2008
2009 /**
2010  * clutter_actor_should_pick_paint:
2011  * @self: A #ClutterActor
2012  *
2013  * Should be called inside the implementation of the
2014  * #ClutterActor::pick virtual function in order to check whether
2015  * the actor should paint itself in pick mode or not.
2016  *
2017  * This function should never be called directly by applications.
2018  *
2019  * Return value: %TRUE if the actor should paint its silhouette,
2020  *   %FALSE otherwise
2021  */
2022 gboolean
2023 clutter_actor_should_pick_paint (ClutterActor *self)
2024 {
2025   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2026
2027   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2028       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2029        CLUTTER_ACTOR_IS_REACTIVE (self)))
2030     return TRUE;
2031
2032   return FALSE;
2033 }
2034
2035 static void
2036 clutter_actor_real_get_preferred_width (ClutterActor *self,
2037                                         gfloat        for_height,
2038                                         gfloat       *min_width_p,
2039                                         gfloat       *natural_width_p)
2040 {
2041   ClutterActorPrivate *priv = self->priv;
2042
2043   if (priv->n_children != 0 &&
2044       priv->layout_manager != NULL)
2045     {
2046       ClutterContainer *container = CLUTTER_CONTAINER (self);
2047
2048       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2049                     "for the preferred width",
2050                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2051                     priv->layout_manager);
2052
2053       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2054                                                   container,
2055                                                   for_height,
2056                                                   min_width_p,
2057                                                   natural_width_p);
2058
2059       return;
2060     }
2061
2062   /* Default implementation is always 0x0, usually an actor
2063    * using this default is relying on someone to set the
2064    * request manually
2065    */
2066   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2067
2068   if (min_width_p)
2069     *min_width_p = 0;
2070
2071   if (natural_width_p)
2072     *natural_width_p = 0;
2073 }
2074
2075 static void
2076 clutter_actor_real_get_preferred_height (ClutterActor *self,
2077                                          gfloat        for_width,
2078                                          gfloat       *min_height_p,
2079                                          gfloat       *natural_height_p)
2080 {
2081   ClutterActorPrivate *priv = self->priv;
2082
2083   if (priv->n_children != 0 &&
2084       priv->layout_manager != NULL)
2085     {
2086       ClutterContainer *container = CLUTTER_CONTAINER (self);
2087
2088       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2089                     "for the preferred height",
2090                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2091                     priv->layout_manager);
2092
2093       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2094                                                    container,
2095                                                    for_width,
2096                                                    min_height_p,
2097                                                    natural_height_p);
2098
2099       return;
2100     }
2101   /* Default implementation is always 0x0, usually an actor
2102    * using this default is relying on someone to set the
2103    * request manually
2104    */
2105   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2106
2107   if (min_height_p)
2108     *min_height_p = 0;
2109
2110   if (natural_height_p)
2111     *natural_height_p = 0;
2112 }
2113
2114 static void
2115 clutter_actor_store_old_geometry (ClutterActor    *self,
2116                                   ClutterActorBox *box)
2117 {
2118   *box = self->priv->allocation;
2119 }
2120
2121 static inline void
2122 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2123                                           const ClutterActorBox *old)
2124 {
2125   ClutterActorPrivate *priv = self->priv;
2126   GObject *obj = G_OBJECT (self);
2127
2128   g_object_freeze_notify (obj);
2129
2130   /* to avoid excessive requisition or allocation cycles we
2131    * use the cached values.
2132    *
2133    * - if we don't have an allocation we assume that we need
2134    *   to notify anyway
2135    * - if we don't have a width or a height request we notify
2136    *   width and height
2137    * - if we have a valid allocation then we check the old
2138    *   bounding box with the current allocation and we notify
2139    *   the changes
2140    */
2141   if (priv->needs_allocation)
2142     {
2143       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2144       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2145       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2146       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2147     }
2148   else if (priv->needs_width_request || priv->needs_height_request)
2149     {
2150       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2151       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2152     }
2153   else
2154     {
2155       gfloat x, y;
2156       gfloat width, height;
2157
2158       x = priv->allocation.x1;
2159       y = priv->allocation.y1;
2160       width = priv->allocation.x2 - priv->allocation.x1;
2161       height = priv->allocation.y2 - priv->allocation.y1;
2162
2163       if (x != old->x1)
2164         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2165
2166       if (y != old->y1)
2167         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2168
2169       if (width != (old->x2 - old->x1))
2170         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2171
2172       if (height != (old->y2 - old->y1))
2173         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2174     }
2175
2176   g_object_thaw_notify (obj);
2177 }
2178
2179 /*< private >
2180  * clutter_actor_set_allocation_internal:
2181  * @self: a #ClutterActor
2182  * @box: a #ClutterActorBox
2183  * @flags: allocation flags
2184  *
2185  * Stores the allocation of @self.
2186  *
2187  * This function only performs basic storage and property notification.
2188  *
2189  * This function should be called by clutter_actor_set_allocation()
2190  * and by the default implementation of #ClutterActorClass.allocate().
2191  *
2192  * Return value: %TRUE if the allocation of the #ClutterActor has been
2193  *   changed, and %FALSE otherwise
2194  */
2195 static inline gboolean
2196 clutter_actor_set_allocation_internal (ClutterActor           *self,
2197                                        const ClutterActorBox  *box,
2198                                        ClutterAllocationFlags  flags)
2199 {
2200   ClutterActorPrivate *priv = self->priv;
2201   GObject *obj;
2202   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2203   gboolean flags_changed;
2204   gboolean retval;
2205   ClutterActorBox old_alloc = { 0, };
2206
2207   obj = G_OBJECT (self);
2208
2209   g_object_freeze_notify (obj);
2210
2211   clutter_actor_store_old_geometry (self, &old_alloc);
2212
2213   x1_changed = priv->allocation.x1 != box->x1;
2214   y1_changed = priv->allocation.y1 != box->y1;
2215   x2_changed = priv->allocation.x2 != box->x2;
2216   y2_changed = priv->allocation.y2 != box->y2;
2217
2218   flags_changed = priv->allocation_flags != flags;
2219
2220   priv->allocation = *box;
2221   priv->allocation_flags = flags;
2222
2223   /* allocation is authoritative */
2224   priv->needs_width_request = FALSE;
2225   priv->needs_height_request = FALSE;
2226   priv->needs_allocation = FALSE;
2227
2228   if (x1_changed || y1_changed ||
2229       x2_changed || y2_changed ||
2230       flags_changed)
2231     {
2232       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2233                     _clutter_actor_get_debug_name (self));
2234
2235       priv->transform_valid = FALSE;
2236
2237       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2238
2239       /* if the allocation changes, so does the content box */
2240       if (priv->content != NULL)
2241         g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2242
2243       retval = TRUE;
2244     }
2245   else
2246     retval = FALSE;
2247
2248   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2249
2250   g_object_thaw_notify (obj);
2251
2252   return retval;
2253 }
2254
2255 static void clutter_actor_real_allocate (ClutterActor           *self,
2256                                          const ClutterActorBox  *box,
2257                                          ClutterAllocationFlags  flags);
2258
2259 static inline void
2260 clutter_actor_maybe_layout_children (ClutterActor           *self,
2261                                      const ClutterActorBox  *allocation,
2262                                      ClutterAllocationFlags  flags)
2263 {
2264   ClutterActorPrivate *priv = self->priv;
2265
2266   /* this is going to be a bit hard to follow, so let's put an explanation
2267    * here.
2268    *
2269    * we want ClutterActor to have a default layout manager if the actor was
2270    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2271    *
2272    * we also want any subclass of ClutterActor that does not override the
2273    * ::allocate() virtual function to delegate to a layout manager.
2274    *
2275    * finally, we want to allow people subclassing ClutterActor and overriding
2276    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2277    *
2278    * on the other hand, we want existing actor subclasses overriding the
2279    * ::allocate() virtual function and chaining up to the parent's
2280    * implementation to continue working without allocating their children
2281    * twice, or without entering an allocation loop.
2282    *
2283    * for the first two points, we check if the class of the actor is
2284    * overridding the ::allocate() virtual function; if it isn't, then we
2285    * follow through with checking whether we have children and a layout
2286    * manager, and eventually calling clutter_layout_manager_allocate().
2287    *
2288    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2289    * allocation flags that we got passed, and if it is present, we continue
2290    * with the check above.
2291    *
2292    * if neither of these two checks yields a positive result, we just
2293    * assume that the ::allocate() virtual function that resulted in this
2294    * function being called will also allocate the children of the actor.
2295    */
2296
2297   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2298     goto check_layout;
2299
2300   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2301     goto check_layout;
2302
2303   return;
2304
2305 check_layout:
2306   if (priv->n_children != 0 &&
2307       priv->layout_manager != NULL)
2308     {
2309       ClutterContainer *container = CLUTTER_CONTAINER (self);
2310       ClutterAllocationFlags children_flags;
2311       ClutterActorBox children_box;
2312
2313       /* normalize the box passed to the layout manager */
2314       children_box.x1 = children_box.y1 = 0.f;
2315       children_box.x2 = (allocation->x2 - allocation->x1);
2316       children_box.y2 = (allocation->y2 - allocation->y1);
2317
2318       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2319        * the actor's children, since it refers only to the current
2320        * actor's allocation.
2321        */
2322       children_flags = flags;
2323       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2324
2325       CLUTTER_NOTE (LAYOUT,
2326                     "Allocating %d children of %s "
2327                     "at { %.2f, %.2f - %.2f x %.2f } "
2328                     "using %s",
2329                     priv->n_children,
2330                     _clutter_actor_get_debug_name (self),
2331                     allocation->x1,
2332                     allocation->y1,
2333                     (allocation->x2 - allocation->x1),
2334                     (allocation->y2 - allocation->y1),
2335                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2336
2337       clutter_layout_manager_allocate (priv->layout_manager,
2338                                        container,
2339                                        &children_box,
2340                                        children_flags);
2341     }
2342 }
2343
2344 static void
2345 clutter_actor_real_allocate (ClutterActor           *self,
2346                              const ClutterActorBox  *box,
2347                              ClutterAllocationFlags  flags)
2348 {
2349   ClutterActorPrivate *priv = self->priv;
2350   gboolean changed;
2351
2352   g_object_freeze_notify (G_OBJECT (self));
2353
2354   changed = clutter_actor_set_allocation_internal (self, box, flags);
2355
2356   /* we allocate our children before we notify changes in our geometry,
2357    * so that people connecting to properties will be able to get valid
2358    * data out of the sub-tree of the scene graph that has this actor at
2359    * the root.
2360    */
2361   clutter_actor_maybe_layout_children (self, box, flags);
2362
2363   if (changed)
2364     {
2365       ClutterActorBox signal_box = priv->allocation;
2366       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2367
2368       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2369                      &signal_box,
2370                      signal_flags);
2371     }
2372
2373   g_object_thaw_notify (G_OBJECT (self));
2374 }
2375
2376 static void
2377 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2378                                     ClutterActor *origin)
2379 {
2380   /* no point in queuing a redraw on a destroyed actor */
2381   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2382     return;
2383
2384   /* NB: We can't bail out early here if the actor is hidden in case
2385    * the actor bas been cloned. In this case the clone will need to
2386    * receive the signal so it can queue its own redraw.
2387    */
2388
2389   /* calls klass->queue_redraw in default handler */
2390   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2391 }
2392
2393 static void
2394 clutter_actor_real_queue_redraw (ClutterActor *self,
2395                                  ClutterActor *origin)
2396 {
2397   ClutterActor *parent;
2398
2399   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2400                 _clutter_actor_get_debug_name (self),
2401                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2402                                : "same actor");
2403
2404   /* no point in queuing a redraw on a destroyed actor */
2405   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2406     return;
2407
2408   /* If the queue redraw is coming from a child then the actor has
2409      become dirty and any queued effect is no longer valid */
2410   if (self != origin)
2411     {
2412       self->priv->is_dirty = TRUE;
2413       self->priv->effect_to_redraw = NULL;
2414     }
2415
2416   /* If the actor isn't visible, we still had to emit the signal
2417    * to allow for a ClutterClone, but the appearance of the parent
2418    * won't change so we don't have to propagate up the hierarchy.
2419    */
2420   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2421     return;
2422
2423   /* Although we could determine here that a full stage redraw
2424    * has already been queued and immediately bail out, we actually
2425    * guarantee that we will propagate a queue-redraw signal to our
2426    * parent at least once so that it's possible to implement a
2427    * container that tracks which of its children have queued a
2428    * redraw.
2429    */
2430   if (self->priv->propagated_one_redraw)
2431     {
2432       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2433       if (stage != NULL &&
2434           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2435         return;
2436     }
2437
2438   self->priv->propagated_one_redraw = TRUE;
2439
2440   /* notify parents, if they are all visible eventually we'll
2441    * queue redraw on the stage, which queues the redraw idle.
2442    */
2443   parent = clutter_actor_get_parent (self);
2444   if (parent != NULL)
2445     {
2446       /* this will go up recursively */
2447       _clutter_actor_signal_queue_redraw (parent, origin);
2448     }
2449 }
2450
2451 static void
2452 clutter_actor_real_queue_relayout (ClutterActor *self)
2453 {
2454   ClutterActorPrivate *priv = self->priv;
2455
2456   /* no point in queueing a redraw on a destroyed actor */
2457   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2458     return;
2459
2460   priv->needs_width_request  = TRUE;
2461   priv->needs_height_request = TRUE;
2462   priv->needs_allocation     = TRUE;
2463
2464   /* reset the cached size requests */
2465   memset (priv->width_requests, 0,
2466           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2467   memset (priv->height_requests, 0,
2468           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2469
2470   /* We need to go all the way up the hierarchy */
2471   if (priv->parent != NULL)
2472     _clutter_actor_queue_only_relayout (priv->parent);
2473 }
2474
2475 /**
2476  * clutter_actor_apply_relative_transform_to_point:
2477  * @self: A #ClutterActor
2478  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2479  *   default #ClutterStage
2480  * @point: A point as #ClutterVertex
2481  * @vertex: (out caller-allocates): The translated #ClutterVertex
2482  *
2483  * Transforms @point in coordinates relative to the actor into
2484  * ancestor-relative coordinates using the relevant transform
2485  * stack (i.e. scale, rotation, etc).
2486  *
2487  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2488  * this case, the coordinates returned will be the coordinates on
2489  * the stage before the projection is applied. This is different from
2490  * the behaviour of clutter_actor_apply_transform_to_point().
2491  *
2492  * Since: 0.6
2493  */
2494 void
2495 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2496                                                  ClutterActor        *ancestor,
2497                                                  const ClutterVertex *point,
2498                                                  ClutterVertex       *vertex)
2499 {
2500   gfloat w;
2501   CoglMatrix matrix;
2502
2503   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2504   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2505   g_return_if_fail (point != NULL);
2506   g_return_if_fail (vertex != NULL);
2507
2508   *vertex = *point;
2509   w = 1.0;
2510
2511   if (ancestor == NULL)
2512     ancestor = _clutter_actor_get_stage_internal (self);
2513
2514   if (ancestor == NULL)
2515     {
2516       *vertex = *point;
2517       return;
2518     }
2519
2520   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2521   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2522 }
2523
2524 static gboolean
2525 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2526                                          const ClutterVertex *vertices_in,
2527                                          ClutterVertex *vertices_out,
2528                                          int n_vertices)
2529 {
2530   ClutterActor *stage;
2531   CoglMatrix modelview;
2532   CoglMatrix projection;
2533   float viewport[4];
2534
2535   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2536
2537   stage = _clutter_actor_get_stage_internal (self);
2538
2539   /* We really can't do anything meaningful in this case so don't try
2540    * to do any transform */
2541   if (stage == NULL)
2542     return FALSE;
2543
2544   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2545    * that gets us to stage coordinates, we want to go all the way to eye
2546    * coordinates */
2547   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2548
2549   /* Fetch the projection and viewport */
2550   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2551   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2552                                &viewport[0],
2553                                &viewport[1],
2554                                &viewport[2],
2555                                &viewport[3]);
2556
2557   _clutter_util_fully_transform_vertices (&modelview,
2558                                           &projection,
2559                                           viewport,
2560                                           vertices_in,
2561                                           vertices_out,
2562                                           n_vertices);
2563
2564   return TRUE;
2565 }
2566
2567 /**
2568  * clutter_actor_apply_transform_to_point:
2569  * @self: A #ClutterActor
2570  * @point: A point as #ClutterVertex
2571  * @vertex: (out caller-allocates): The translated #ClutterVertex
2572  *
2573  * Transforms @point in coordinates relative to the actor
2574  * into screen-relative coordinates with the current actor
2575  * transformation (i.e. scale, rotation, etc)
2576  *
2577  * Since: 0.4
2578  **/
2579 void
2580 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2581                                         const ClutterVertex *point,
2582                                         ClutterVertex       *vertex)
2583 {
2584   g_return_if_fail (point != NULL);
2585   g_return_if_fail (vertex != NULL);
2586   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2587 }
2588
2589 /*
2590  * _clutter_actor_get_relative_transformation_matrix:
2591  * @self: The actor whose coordinate space you want to transform from.
2592  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2593  *            or %NULL if you want to transform all the way to eye coordinates.
2594  * @matrix: A #CoglMatrix to store the transformation
2595  *
2596  * This gets a transformation @matrix that will transform coordinates from the
2597  * coordinate space of @self into the coordinate space of @ancestor.
2598  *
2599  * For example if you need a matrix that can transform the local actor
2600  * coordinates of @self into stage coordinates you would pass the actor's stage
2601  * pointer as the @ancestor.
2602  *
2603  * If you pass %NULL then the transformation will take you all the way through
2604  * to eye coordinates. This can be useful if you want to extract the entire
2605  * modelview transform that Clutter applies before applying the projection
2606  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2607  * using cogl_set_modelview_matrix() for example then you would want a matrix
2608  * that transforms into eye coordinates.
2609  *
2610  * <note><para>This function explicitly initializes the given @matrix. If you just
2611  * want clutter to multiply a relative transformation with an existing matrix
2612  * you can use clutter_actor_apply_relative_transformation_matrix()
2613  * instead.</para></note>
2614  *
2615  */
2616 /* XXX: We should consider caching the stage relative modelview along with
2617  * the actor itself */
2618 static void
2619 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2620                                                    ClutterActor *ancestor,
2621                                                    CoglMatrix *matrix)
2622 {
2623   cogl_matrix_init_identity (matrix);
2624
2625   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2626 }
2627
2628 /* Project the given @box into stage window coordinates, writing the
2629  * transformed vertices to @verts[]. */
2630 static gboolean
2631 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2632                                           const ClutterActorBox *box,
2633                                           ClutterVertex          verts[])
2634 {
2635   ClutterVertex box_vertices[4];
2636
2637   box_vertices[0].x = box->x1;
2638   box_vertices[0].y = box->y1;
2639   box_vertices[0].z = 0;
2640   box_vertices[1].x = box->x2;
2641   box_vertices[1].y = box->y1;
2642   box_vertices[1].z = 0;
2643   box_vertices[2].x = box->x1;
2644   box_vertices[2].y = box->y2;
2645   box_vertices[2].z = 0;
2646   box_vertices[3].x = box->x2;
2647   box_vertices[3].y = box->y2;
2648   box_vertices[3].z = 0;
2649
2650   return
2651     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2652 }
2653
2654 /**
2655  * clutter_actor_get_allocation_vertices:
2656  * @self: A #ClutterActor
2657  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2658  *   against, or %NULL to use the #ClutterStage
2659  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2660  *   location for an array of 4 #ClutterVertex in which to store the result
2661  *
2662  * Calculates the transformed coordinates of the four corners of the
2663  * actor in the plane of @ancestor. The returned vertices relate to
2664  * the #ClutterActorBox coordinates as follows:
2665  * <itemizedlist>
2666  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2667  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2668  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2669  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2670  * </itemizedlist>
2671  *
2672  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2673  * this case, the coordinates returned will be the coordinates on
2674  * the stage before the projection is applied. This is different from
2675  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2676  *
2677  * Since: 0.6
2678  */
2679 void
2680 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2681                                        ClutterActor  *ancestor,
2682                                        ClutterVertex  verts[])
2683 {
2684   ClutterActorPrivate *priv;
2685   ClutterActorBox box;
2686   ClutterVertex vertices[4];
2687   CoglMatrix modelview;
2688
2689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2690   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2691
2692   if (ancestor == NULL)
2693     ancestor = _clutter_actor_get_stage_internal (self);
2694
2695   /* Fallback to a NOP transform if the actor isn't parented under a
2696    * stage. */
2697   if (ancestor == NULL)
2698     ancestor = self;
2699
2700   priv = self->priv;
2701
2702   /* if the actor needs to be allocated we force a relayout, so that
2703    * we will have valid values to use in the transformations */
2704   if (priv->needs_allocation)
2705     {
2706       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2707       if (stage)
2708         _clutter_stage_maybe_relayout (stage);
2709       else
2710         {
2711           box.x1 = box.y1 = 0;
2712           /* The result isn't really meaningful in this case but at
2713            * least try to do something *vaguely* reasonable... */
2714           clutter_actor_get_size (self, &box.x2, &box.y2);
2715         }
2716     }
2717
2718   clutter_actor_get_allocation_box (self, &box);
2719
2720   vertices[0].x = box.x1;
2721   vertices[0].y = box.y1;
2722   vertices[0].z = 0;
2723   vertices[1].x = box.x2;
2724   vertices[1].y = box.y1;
2725   vertices[1].z = 0;
2726   vertices[2].x = box.x1;
2727   vertices[2].y = box.y2;
2728   vertices[2].z = 0;
2729   vertices[3].x = box.x2;
2730   vertices[3].y = box.y2;
2731   vertices[3].z = 0;
2732
2733   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2734                                                      &modelview);
2735
2736   cogl_matrix_transform_points (&modelview,
2737                                 3,
2738                                 sizeof (ClutterVertex),
2739                                 vertices,
2740                                 sizeof (ClutterVertex),
2741                                 vertices,
2742                                 4);
2743 }
2744
2745 /**
2746  * clutter_actor_get_abs_allocation_vertices:
2747  * @self: A #ClutterActor
2748  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2749  *   of 4 #ClutterVertex where to store the result.
2750  *
2751  * Calculates the transformed screen coordinates of the four corners of
2752  * the actor; the returned vertices relate to the #ClutterActorBox
2753  * coordinates  as follows:
2754  * <itemizedlist>
2755  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2756  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2757  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2758  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2759  * </itemizedlist>
2760  *
2761  * Since: 0.4
2762  */
2763 void
2764 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2765                                            ClutterVertex  verts[])
2766 {
2767   ClutterActorPrivate *priv;
2768   ClutterActorBox actor_space_allocation;
2769
2770   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2771
2772   priv = self->priv;
2773
2774   /* if the actor needs to be allocated we force a relayout, so that
2775    * the actor allocation box will be valid for
2776    * _clutter_actor_transform_and_project_box()
2777    */
2778   if (priv->needs_allocation)
2779     {
2780       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2781       /* There's nothing meaningful we can do now */
2782       if (!stage)
2783         return;
2784
2785       _clutter_stage_maybe_relayout (stage);
2786     }
2787
2788   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2789    * own coordinate space... */
2790   actor_space_allocation.x1 = 0;
2791   actor_space_allocation.y1 = 0;
2792   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2793   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2794   _clutter_actor_transform_and_project_box (self,
2795                                             &actor_space_allocation,
2796                                             verts);
2797 }
2798
2799 static void
2800 clutter_actor_real_apply_transform (ClutterActor *self,
2801                                     CoglMatrix   *matrix)
2802 {
2803   ClutterActorPrivate *priv = self->priv;
2804
2805   if (!priv->transform_valid)
2806     {
2807       CoglMatrix *transform = &priv->transform;
2808       const ClutterTransformInfo *info;
2809
2810       info = _clutter_actor_get_transform_info_or_defaults (self);
2811
2812       cogl_matrix_init_identity (transform);
2813
2814       cogl_matrix_translate (transform,
2815                              priv->allocation.x1,
2816                              priv->allocation.y1,
2817                              0.0);
2818
2819       if (info->depth)
2820         cogl_matrix_translate (transform, 0, 0, info->depth);
2821
2822       /*
2823        * because the rotation involves translations, we must scale
2824        * before applying the rotations (if we apply the scale after
2825        * the rotations, the translations included in the rotation are
2826        * not scaled and so the entire object will move on the screen
2827        * as a result of rotating it).
2828        */
2829       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2830         {
2831           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2832                                         &info->scale_center,
2833                                         cogl_matrix_scale (transform,
2834                                                            info->scale_x,
2835                                                            info->scale_y,
2836                                                            1.0));
2837         }
2838
2839       if (info->rz_angle)
2840         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2841                                       &info->rz_center,
2842                                       cogl_matrix_rotate (transform,
2843                                                           info->rz_angle,
2844                                                           0, 0, 1.0));
2845
2846       if (info->ry_angle)
2847         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2848                                       &info->ry_center,
2849                                       cogl_matrix_rotate (transform,
2850                                                           info->ry_angle,
2851                                                           0, 1.0, 0));
2852
2853       if (info->rx_angle)
2854         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2855                                       &info->rx_center,
2856                                       cogl_matrix_rotate (transform,
2857                                                           info->rx_angle,
2858                                                           1.0, 0, 0));
2859
2860       if (!clutter_anchor_coord_is_zero (&info->anchor))
2861         {
2862           gfloat x, y, z;
2863
2864           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2865           cogl_matrix_translate (transform, -x, -y, -z);
2866         }
2867
2868       priv->transform_valid = TRUE;
2869     }
2870
2871   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2872 }
2873
2874 /* Applies the transforms associated with this actor to the given
2875  * matrix. */
2876 void
2877 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2878                                           CoglMatrix *matrix)
2879 {
2880   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2881 }
2882
2883 /*
2884  * clutter_actor_apply_relative_transformation_matrix:
2885  * @self: The actor whose coordinate space you want to transform from.
2886  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2887  *            or %NULL if you want to transform all the way to eye coordinates.
2888  * @matrix: A #CoglMatrix to apply the transformation too.
2889  *
2890  * This multiplies a transform with @matrix that will transform coordinates
2891  * from the coordinate space of @self into the coordinate space of @ancestor.
2892  *
2893  * For example if you need a matrix that can transform the local actor
2894  * coordinates of @self into stage coordinates you would pass the actor's stage
2895  * pointer as the @ancestor.
2896  *
2897  * If you pass %NULL then the transformation will take you all the way through
2898  * to eye coordinates. This can be useful if you want to extract the entire
2899  * modelview transform that Clutter applies before applying the projection
2900  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2901  * using cogl_set_modelview_matrix() for example then you would want a matrix
2902  * that transforms into eye coordinates.
2903  *
2904  * <note>This function doesn't initialize the given @matrix, it simply
2905  * multiplies the requested transformation matrix with the existing contents of
2906  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2907  * before calling this function, or you can use
2908  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2909  */
2910 void
2911 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2912                                                      ClutterActor *ancestor,
2913                                                      CoglMatrix *matrix)
2914 {
2915   ClutterActor *parent;
2916
2917   /* Note we terminate before ever calling stage->apply_transform()
2918    * since that would conceptually be relative to the underlying
2919    * window OpenGL coordinates so we'd need a special @ancestor
2920    * value to represent the fake parent of the stage. */
2921   if (self == ancestor)
2922     return;
2923
2924   parent = clutter_actor_get_parent (self);
2925
2926   if (parent != NULL)
2927     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2928                                                          matrix);
2929
2930   _clutter_actor_apply_modelview_transform (self, matrix);
2931 }
2932
2933 static void
2934 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2935                                        ClutterPaintVolume *pv,
2936                                        const char *label,
2937                                        const CoglColor *color)
2938 {
2939   static CoglPipeline *outline = NULL;
2940   CoglPrimitive *prim;
2941   ClutterVertex line_ends[12 * 2];
2942   int n_vertices;
2943   CoglContext *ctx =
2944     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2945   /* XXX: at some point we'll query this from the stage but we can't
2946    * do that until the osx backend uses Cogl natively. */
2947   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2948
2949   if (outline == NULL)
2950     outline = cogl_pipeline_new (ctx);
2951
2952   _clutter_paint_volume_complete (pv);
2953
2954   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2955
2956   /* Front face */
2957   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2958   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2959   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2960   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2961
2962   if (!pv->is_2d)
2963     {
2964       /* Back face */
2965       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2966       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2967       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2968       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2969
2970       /* Lines connecting front face to back face */
2971       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2972       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2973       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2974       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2975     }
2976
2977   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2978                                 n_vertices,
2979                                 (CoglVertexP3 *)line_ends);
2980
2981   cogl_pipeline_set_color (outline, color);
2982   cogl_framebuffer_draw_primitive (fb, outline, prim);
2983   cogl_object_unref (prim);
2984
2985   if (label)
2986     {
2987       PangoLayout *layout;
2988       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2989       pango_layout_set_text (layout, label, -1);
2990       cogl_pango_render_layout (layout,
2991                                 pv->vertices[0].x,
2992                                 pv->vertices[0].y,
2993                                 color,
2994                                 0);
2995       g_object_unref (layout);
2996     }
2997 }
2998
2999 static void
3000 _clutter_actor_draw_paint_volume (ClutterActor *self)
3001 {
3002   ClutterPaintVolume *pv;
3003   CoglColor color;
3004
3005   pv = _clutter_actor_get_paint_volume_mutable (self);
3006   if (!pv)
3007     {
3008       gfloat width, height;
3009       ClutterPaintVolume fake_pv;
3010
3011       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3012       _clutter_paint_volume_init_static (&fake_pv, stage);
3013
3014       clutter_actor_get_size (self, &width, &height);
3015       clutter_paint_volume_set_width (&fake_pv, width);
3016       clutter_paint_volume_set_height (&fake_pv, height);
3017
3018       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3019       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3020                                              _clutter_actor_get_debug_name (self),
3021                                              &color);
3022
3023       clutter_paint_volume_free (&fake_pv);
3024     }
3025   else
3026     {
3027       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3028       _clutter_actor_draw_paint_volume_full (self, pv,
3029                                              _clutter_actor_get_debug_name (self),
3030                                              &color);
3031     }
3032 }
3033
3034 static void
3035 _clutter_actor_paint_cull_result (ClutterActor *self,
3036                                   gboolean success,
3037                                   ClutterCullResult result)
3038 {
3039   ClutterPaintVolume *pv;
3040   CoglColor color;
3041
3042   if (success)
3043     {
3044       if (result == CLUTTER_CULL_RESULT_IN)
3045         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3046       else if (result == CLUTTER_CULL_RESULT_OUT)
3047         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3048       else
3049         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3050     }
3051   else
3052     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3053
3054   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3055     _clutter_actor_draw_paint_volume_full (self, pv,
3056                                            _clutter_actor_get_debug_name (self),
3057                                            &color);
3058   else
3059     {
3060       PangoLayout *layout;
3061       char *label =
3062         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3063       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3064       cogl_set_source_color (&color);
3065
3066       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3067       pango_layout_set_text (layout, label, -1);
3068       cogl_pango_render_layout (layout,
3069                                 0,
3070                                 0,
3071                                 &color,
3072                                 0);
3073       g_free (label);
3074       g_object_unref (layout);
3075     }
3076 }
3077
3078 static int clone_paint_level = 0;
3079
3080 void
3081 _clutter_actor_push_clone_paint (void)
3082 {
3083   clone_paint_level++;
3084 }
3085
3086 void
3087 _clutter_actor_pop_clone_paint (void)
3088 {
3089   clone_paint_level--;
3090 }
3091
3092 static gboolean
3093 in_clone_paint (void)
3094 {
3095   return clone_paint_level > 0;
3096 }
3097
3098 /* Returns TRUE if the actor can be ignored */
3099 /* FIXME: we should return a ClutterCullResult, and
3100  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3101  * means there's no point in trying to cull descendants of the current
3102  * node. */
3103 static gboolean
3104 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3105 {
3106   ClutterActorPrivate *priv = self->priv;
3107   ClutterActor *stage;
3108   const ClutterPlane *stage_clip;
3109
3110   if (!priv->last_paint_volume_valid)
3111     {
3112       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3113                     "->last_paint_volume_valid == FALSE",
3114                     _clutter_actor_get_debug_name (self));
3115       return FALSE;
3116     }
3117
3118   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3119     return FALSE;
3120
3121   stage = _clutter_actor_get_stage_internal (self);
3122   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3123   if (G_UNLIKELY (!stage_clip))
3124     {
3125       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3126                     "No stage clip set",
3127                     _clutter_actor_get_debug_name (self));
3128       return FALSE;
3129     }
3130
3131   if (cogl_get_draw_framebuffer () !=
3132       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3133     {
3134       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3135                     "Current framebuffer doesn't correspond to stage",
3136                     _clutter_actor_get_debug_name (self));
3137       return FALSE;
3138     }
3139
3140   *result_out =
3141     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3142   return TRUE;
3143 }
3144
3145 static void
3146 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3147 {
3148   ClutterActorPrivate *priv = self->priv;
3149   const ClutterPaintVolume *pv;
3150
3151   if (priv->last_paint_volume_valid)
3152     {
3153       clutter_paint_volume_free (&priv->last_paint_volume);
3154       priv->last_paint_volume_valid = FALSE;
3155     }
3156
3157   pv = clutter_actor_get_paint_volume (self);
3158   if (!pv)
3159     {
3160       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3161                     "Actor failed to report a paint volume",
3162                     _clutter_actor_get_debug_name (self));
3163       return;
3164     }
3165
3166   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3167
3168   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3169                                             NULL); /* eye coordinates */
3170
3171   priv->last_paint_volume_valid = TRUE;
3172 }
3173
3174 static inline gboolean
3175 actor_has_shader_data (ClutterActor *self)
3176 {
3177   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3178 }
3179
3180 guint32
3181 _clutter_actor_get_pick_id (ClutterActor *self)
3182 {
3183   if (self->priv->pick_id < 0)
3184     return 0;
3185
3186   return self->priv->pick_id;
3187 }
3188
3189 /* This is the same as clutter_actor_add_effect except that it doesn't
3190    queue a redraw and it doesn't notify on the effect property */
3191 static void
3192 _clutter_actor_add_effect_internal (ClutterActor  *self,
3193                                     ClutterEffect *effect)
3194 {
3195   ClutterActorPrivate *priv = self->priv;
3196
3197   if (priv->effects == NULL)
3198     {
3199       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3200       priv->effects->actor = self;
3201     }
3202
3203   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3204 }
3205
3206 /* This is the same as clutter_actor_remove_effect except that it doesn't
3207    queue a redraw and it doesn't notify on the effect property */
3208 static void
3209 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3210                                        ClutterEffect *effect)
3211 {
3212   ClutterActorPrivate *priv = self->priv;
3213
3214   if (priv->effects == NULL)
3215     return;
3216
3217   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3218 }
3219
3220 static gboolean
3221 needs_flatten_effect (ClutterActor *self)
3222 {
3223   ClutterActorPrivate *priv = self->priv;
3224
3225   if (G_UNLIKELY (clutter_paint_debug_flags &
3226                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3227     return FALSE;
3228
3229   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3230     return TRUE;
3231   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3232     {
3233       if (clutter_actor_get_paint_opacity (self) < 255 &&
3234           clutter_actor_has_overlaps (self))
3235         return TRUE;
3236     }
3237
3238   return FALSE;
3239 }
3240
3241 static void
3242 add_or_remove_flatten_effect (ClutterActor *self)
3243 {
3244   ClutterActorPrivate *priv = self->priv;
3245
3246   /* Add or remove the flatten effect depending on the
3247      offscreen-redirect property. */
3248   if (needs_flatten_effect (self))
3249     {
3250       if (priv->flatten_effect == NULL)
3251         {
3252           ClutterActorMeta *actor_meta;
3253           gint priority;
3254
3255           priv->flatten_effect = _clutter_flatten_effect_new ();
3256           /* Keep a reference to the effect so that we can queue
3257              redraws from it */
3258           g_object_ref_sink (priv->flatten_effect);
3259
3260           /* Set the priority of the effect to high so that it will
3261              always be applied to the actor first. It uses an internal
3262              priority so that it won't be visible to applications */
3263           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3264           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3265           _clutter_actor_meta_set_priority (actor_meta, priority);
3266
3267           /* This will add the effect without queueing a redraw */
3268           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3269         }
3270     }
3271   else
3272     {
3273       if (priv->flatten_effect != NULL)
3274         {
3275           /* Destroy the effect so that it will lose its fbo cache of
3276              the actor */
3277           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3278           g_clear_object (&priv->flatten_effect);
3279         }
3280     }
3281 }
3282
3283 static void
3284 clutter_actor_real_paint (ClutterActor *actor)
3285 {
3286   ClutterActorPrivate *priv = actor->priv;
3287   ClutterActor *iter;
3288
3289   for (iter = priv->first_child;
3290        iter != NULL;
3291        iter = iter->priv->next_sibling)
3292     {
3293       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3294                     _clutter_actor_get_debug_name (iter),
3295                     _clutter_actor_get_debug_name (actor),
3296                     iter->priv->allocation.x1,
3297                     iter->priv->allocation.y1,
3298                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3299                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3300
3301       clutter_actor_paint (iter);
3302     }
3303 }
3304
3305 static gboolean
3306 clutter_actor_paint_node (ClutterActor     *actor,
3307                           ClutterPaintNode *root)
3308 {
3309   ClutterActorPrivate *priv = actor->priv;
3310
3311   if (root == NULL)
3312     return FALSE;
3313
3314   if (priv->bg_color_set &&
3315       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3316     {
3317       ClutterPaintNode *node;
3318       ClutterColor bg_color;
3319       ClutterActorBox box;
3320
3321       box.x1 = 0.f;
3322       box.y1 = 0.f;
3323       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3324       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3325
3326       bg_color = priv->bg_color;
3327       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3328                      * priv->bg_color.alpha
3329                      / 255;
3330
3331       node = clutter_color_node_new (&bg_color);
3332       clutter_paint_node_set_name (node, "backgroundColor");
3333       clutter_paint_node_add_rectangle (node, &box);
3334       clutter_paint_node_add_child (root, node);
3335       clutter_paint_node_unref (node);
3336     }
3337
3338   if (priv->content != NULL)
3339     _clutter_content_paint_content (priv->content, actor, root);
3340
3341   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3342     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3343
3344   if (clutter_paint_node_get_n_children (root) == 0)
3345     return FALSE;
3346
3347 #ifdef CLUTTER_ENABLE_DEBUG
3348   if (CLUTTER_HAS_DEBUG (PAINT))
3349     {
3350       /* dump the tree only if we have one */
3351       _clutter_paint_node_dump_tree (root);
3352     }
3353 #endif /* CLUTTER_ENABLE_DEBUG */
3354
3355   _clutter_paint_node_paint (root);
3356
3357 #if 0
3358   /* XXX: Uncomment this when we disable emitting the paint signal */
3359   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3360 #endif
3361
3362   return TRUE;
3363 }
3364
3365 /**
3366  * clutter_actor_paint:
3367  * @self: A #ClutterActor
3368  *
3369  * Renders the actor to display.
3370  *
3371  * This function should not be called directly by applications.
3372  * Call clutter_actor_queue_redraw() to queue paints, instead.
3373  *
3374  * This function is context-aware, and will either cause a
3375  * regular paint or a pick paint.
3376  *
3377  * This function will emit the #ClutterActor::paint signal or
3378  * the #ClutterActor::pick signal, depending on the context.
3379  *
3380  * This function does not paint the actor if the actor is set to 0,
3381  * unless it is performing a pick paint.
3382  */
3383 void
3384 clutter_actor_paint (ClutterActor *self)
3385 {
3386   ClutterActorPrivate *priv;
3387   ClutterPickMode pick_mode;
3388   gboolean clip_set = FALSE;
3389   gboolean shader_applied = FALSE;
3390
3391   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3392                           "Actor real-paint counter",
3393                           "Increments each time any actor is painted",
3394                           0 /* no application private data */);
3395   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3396                           "Actor pick-paint counter",
3397                           "Increments each time any actor is painted "
3398                           "for picking",
3399                           0 /* no application private data */);
3400
3401   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3402
3403   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3404     return;
3405
3406   priv = self->priv;
3407
3408   pick_mode = _clutter_context_get_pick_mode ();
3409
3410   if (pick_mode == CLUTTER_PICK_NONE)
3411     priv->propagated_one_redraw = FALSE;
3412
3413   /* It's an important optimization that we consider painting of
3414    * actors with 0 opacity to be a NOP... */
3415   if (pick_mode == CLUTTER_PICK_NONE &&
3416       /* ignore top-levels, since they might be transparent */
3417       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3418       /* Use the override opacity if its been set */
3419       ((priv->opacity_override >= 0) ?
3420        priv->opacity_override : priv->opacity) == 0)
3421     return;
3422
3423   /* if we aren't paintable (not in a toplevel with all
3424    * parents paintable) then do nothing.
3425    */
3426   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3427     return;
3428
3429   /* mark that we are in the paint process */
3430   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3431
3432   cogl_push_matrix();
3433
3434   if (priv->enable_model_view_transform)
3435     {
3436       CoglMatrix matrix;
3437
3438       /* XXX: It could be better to cache the modelview with the actor
3439        * instead of progressively building up the transformations on
3440        * the matrix stack every time we paint. */
3441       cogl_get_modelview_matrix (&matrix);
3442       _clutter_actor_apply_modelview_transform (self, &matrix);
3443
3444 #ifdef CLUTTER_ENABLE_DEBUG
3445       /* Catch when out-of-band transforms have been made by actors not as part
3446        * of an apply_transform vfunc... */
3447       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3448         {
3449           CoglMatrix expected_matrix;
3450
3451           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3452                                                              &expected_matrix);
3453
3454           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3455             {
3456               GString *buf = g_string_sized_new (1024);
3457               ClutterActor *parent;
3458
3459               parent = self;
3460               while (parent != NULL)
3461                 {
3462                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3463
3464                   if (parent->priv->parent != NULL)
3465                     g_string_append (buf, "->");
3466
3467                   parent = parent->priv->parent;
3468                 }
3469
3470               g_warning ("Unexpected transform found when painting actor "
3471                          "\"%s\". This will be caused by one of the actor's "
3472                          "ancestors (%s) using the Cogl API directly to transform "
3473                          "children instead of using ::apply_transform().",
3474                          _clutter_actor_get_debug_name (self),
3475                          buf->str);
3476
3477               g_string_free (buf, TRUE);
3478             }
3479         }
3480 #endif /* CLUTTER_ENABLE_DEBUG */
3481
3482       cogl_set_modelview_matrix (&matrix);
3483     }
3484
3485   if (priv->has_clip)
3486     {
3487       cogl_clip_push_rectangle (priv->clip.x,
3488                                 priv->clip.y,
3489                                 priv->clip.x + priv->clip.width,
3490                                 priv->clip.y + priv->clip.height);
3491       clip_set = TRUE;
3492     }
3493   else if (priv->clip_to_allocation)
3494     {
3495       gfloat width, height;
3496
3497       width  = priv->allocation.x2 - priv->allocation.x1;
3498       height = priv->allocation.y2 - priv->allocation.y1;
3499
3500       cogl_clip_push_rectangle (0, 0, width, height);
3501       clip_set = TRUE;
3502     }
3503
3504   if (pick_mode == CLUTTER_PICK_NONE)
3505     {
3506       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3507
3508       /* We check whether we need to add the flatten effect before
3509          each paint so that we can avoid having a mechanism for
3510          applications to notify when the value of the
3511          has_overlaps virtual changes. */
3512       add_or_remove_flatten_effect (self);
3513     }
3514   else
3515     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3516
3517   /* We save the current paint volume so that the next time the
3518    * actor queues a redraw we can constrain the redraw to just
3519    * cover the union of the new bounding box and the old.
3520    *
3521    * We also fetch the current paint volume to perform culling so
3522    * we can avoid painting actors outside the current clip region.
3523    *
3524    * If we are painting inside a clone, we should neither update
3525    * the paint volume or use it to cull painting, since the paint
3526    * box represents the location of the source actor on the
3527    * screen.
3528    *
3529    * XXX: We are starting to do a lot of vertex transforms on
3530    * the CPU in a typical paint, so at some point we should
3531    * audit these and consider caching some things.
3532    *
3533    * NB: We don't perform culling while picking at this point because
3534    * clutter-stage.c doesn't setup the clipping planes appropriately.
3535    *
3536    * NB: We don't want to update the last-paint-volume during picking
3537    * because the last-paint-volume is used to determine the old screen
3538    * space location of an actor that has moved so we can know the
3539    * minimal region to redraw to clear an old view of the actor. If we
3540    * update this during picking then by the time we come around to
3541    * paint then the last-paint-volume would likely represent the new
3542    * actor position not the old.
3543    */
3544   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3545     {
3546       gboolean success;
3547       /* annoyingly gcc warns if uninitialized even though
3548        * the initialization is redundant :-( */
3549       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3550
3551       if (G_LIKELY ((clutter_paint_debug_flags &
3552                      (CLUTTER_DEBUG_DISABLE_CULLING |
3553                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3554                     (CLUTTER_DEBUG_DISABLE_CULLING |
3555                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3556         _clutter_actor_update_last_paint_volume (self);
3557
3558       success = cull_actor (self, &result);
3559
3560       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3561         _clutter_actor_paint_cull_result (self, success, result);
3562       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3563         goto done;
3564     }
3565
3566   if (priv->effects == NULL)
3567     {
3568       if (pick_mode == CLUTTER_PICK_NONE &&
3569           actor_has_shader_data (self))
3570         {
3571           _clutter_actor_shader_pre_paint (self, FALSE);
3572           shader_applied = TRUE;
3573         }
3574
3575       priv->next_effect_to_paint = NULL;
3576     }
3577   else
3578     priv->next_effect_to_paint =
3579       _clutter_meta_group_peek_metas (priv->effects);
3580
3581   clutter_actor_continue_paint (self);
3582
3583   if (shader_applied)
3584     _clutter_actor_shader_post_paint (self);
3585
3586   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3587                   pick_mode == CLUTTER_PICK_NONE))
3588     _clutter_actor_draw_paint_volume (self);
3589
3590 done:
3591   /* If we make it here then the actor has run through a complete
3592      paint run including all the effects so it's no longer dirty */
3593   if (pick_mode == CLUTTER_PICK_NONE)
3594     priv->is_dirty = FALSE;
3595
3596   if (clip_set)
3597     cogl_clip_pop();
3598
3599   cogl_pop_matrix();
3600
3601   /* paint sequence complete */
3602   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3603 }
3604
3605 /**
3606  * clutter_actor_continue_paint:
3607  * @self: A #ClutterActor
3608  *
3609  * Run the next stage of the paint sequence. This function should only
3610  * be called within the implementation of the ‘run’ virtual of a
3611  * #ClutterEffect. It will cause the run method of the next effect to
3612  * be applied, or it will paint the actual actor if the current effect
3613  * is the last effect in the chain.
3614  *
3615  * Since: 1.8
3616  */
3617 void
3618 clutter_actor_continue_paint (ClutterActor *self)
3619 {
3620   ClutterActorPrivate *priv;
3621
3622   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3623   /* This should only be called from with in the ‘run’ implementation
3624      of a ClutterEffect */
3625   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3626
3627   priv = self->priv;
3628
3629   /* Skip any effects that are disabled */
3630   while (priv->next_effect_to_paint &&
3631          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3632     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3633
3634   /* If this has come from the last effect then we'll just paint the
3635      actual actor */
3636   if (priv->next_effect_to_paint == NULL)
3637     {
3638       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3639         {
3640           ClutterPaintNode *dummy;
3641
3642           /* XXX - this will go away in 2.0, when we can get rid of this
3643            * stuff and switch to a pure retained render tree of PaintNodes
3644            * for the entire frame, starting from the Stage; the paint()
3645            * virtual function can then be called directly.
3646            */
3647           dummy = _clutter_dummy_node_new (self);
3648           clutter_paint_node_set_name (dummy, "Root");
3649
3650           /* XXX - for 1.12, we use the return value of paint_node() to
3651            * decide whether we should emit the ::paint signal.
3652            */
3653           clutter_actor_paint_node (self, dummy);
3654           clutter_paint_node_unref (dummy);
3655
3656           g_signal_emit (self, actor_signals[PAINT], 0);
3657         }
3658       else
3659         {
3660           ClutterColor col = { 0, };
3661
3662           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3663
3664           /* Actor will then paint silhouette of itself in supplied
3665            * color.  See clutter_stage_get_actor_at_pos() for where
3666            * picking is enabled.
3667            */
3668           g_signal_emit (self, actor_signals[PICK], 0, &col);
3669         }
3670     }
3671   else
3672     {
3673       ClutterEffect *old_current_effect;
3674       ClutterEffectPaintFlags run_flags = 0;
3675
3676       /* Cache the current effect so that we can put it back before
3677          returning */
3678       old_current_effect = priv->current_effect;
3679
3680       priv->current_effect = priv->next_effect_to_paint->data;
3681       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3682
3683       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3684         {
3685           if (priv->is_dirty)
3686             {
3687               /* If there's an effect queued with this redraw then all
3688                  effects up to that one will be considered dirty. It
3689                  is expected the queued effect will paint the cached
3690                  image and not call clutter_actor_continue_paint again
3691                  (although it should work ok if it does) */
3692               if (priv->effect_to_redraw == NULL ||
3693                   priv->current_effect != priv->effect_to_redraw)
3694                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3695             }
3696
3697           _clutter_effect_paint (priv->current_effect, run_flags);
3698         }
3699       else
3700         {
3701           /* We can't determine when an actor has been modified since
3702              its last pick so lets just assume it has always been
3703              modified */
3704           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3705
3706           _clutter_effect_pick (priv->current_effect, run_flags);
3707         }
3708
3709       priv->current_effect = old_current_effect;
3710     }
3711 }
3712
3713 static ClutterActorTraverseVisitFlags
3714 invalidate_queue_redraw_entry (ClutterActor *self,
3715                                int           depth,
3716                                gpointer      user_data)
3717 {
3718   ClutterActorPrivate *priv = self->priv;
3719
3720   if (priv->queue_redraw_entry != NULL)
3721     {
3722       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3723       priv->queue_redraw_entry = NULL;
3724     }
3725
3726   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3727 }
3728
3729 static inline void
3730 remove_child (ClutterActor *self,
3731               ClutterActor *child)
3732 {
3733   ClutterActor *prev_sibling, *next_sibling;
3734
3735   prev_sibling = child->priv->prev_sibling;
3736   next_sibling = child->priv->next_sibling;
3737
3738   if (prev_sibling != NULL)
3739     prev_sibling->priv->next_sibling = next_sibling;
3740
3741   if (next_sibling != NULL)
3742     next_sibling->priv->prev_sibling = prev_sibling;
3743
3744   if (self->priv->first_child == child)
3745     self->priv->first_child = next_sibling;
3746
3747   if (self->priv->last_child == child)
3748     self->priv->last_child = prev_sibling;
3749
3750   child->priv->parent = NULL;
3751   child->priv->prev_sibling = NULL;
3752   child->priv->next_sibling = NULL;
3753 }
3754
3755 typedef enum {
3756   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3757   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3758   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3759   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3760   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3761   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3762
3763   /* default flags for public API */
3764   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3765                                     REMOVE_CHILD_EMIT_PARENT_SET |
3766                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3767                                     REMOVE_CHILD_CHECK_STATE |
3768                                     REMOVE_CHILD_FLUSH_QUEUE |
3769                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3770
3771   /* flags for legacy/deprecated API */
3772   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3773                                     REMOVE_CHILD_FLUSH_QUEUE |
3774                                     REMOVE_CHILD_EMIT_PARENT_SET |
3775                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3776 } ClutterActorRemoveChildFlags;
3777
3778 /*< private >
3779  * clutter_actor_remove_child_internal:
3780  * @self: a #ClutterActor
3781  * @child: the child of @self that has to be removed
3782  * @flags: control the removal operations
3783  *
3784  * Removes @child from the list of children of @self.
3785  */
3786 static void
3787 clutter_actor_remove_child_internal (ClutterActor                 *self,
3788                                      ClutterActor                 *child,
3789                                      ClutterActorRemoveChildFlags  flags)
3790 {
3791   ClutterActor *old_first, *old_last;
3792   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3793   gboolean flush_queue;
3794   gboolean notify_first_last;
3795   gboolean was_mapped;
3796
3797   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3798   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3799   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3800   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3801   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3802   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3803
3804   g_object_freeze_notify (G_OBJECT (self));
3805
3806   if (destroy_meta)
3807     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3808
3809   if (check_state)
3810     {
3811       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3812
3813       /* we need to unrealize *before* we set parent_actor to NULL,
3814        * because in an unrealize method actors are dissociating from the
3815        * stage, which means they need to be able to
3816        * clutter_actor_get_stage().
3817        *
3818        * yhis should unmap and unrealize, unless we're reparenting.
3819        */
3820       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3821     }
3822   else
3823     was_mapped = FALSE;
3824
3825   if (flush_queue)
3826     {
3827       /* We take this opportunity to invalidate any queue redraw entry
3828        * associated with the actor and descendants since we won't be able to
3829        * determine the appropriate stage after this.
3830        *
3831        * we do this after we updated the mapped state because actors might
3832        * end up queueing redraws inside their mapped/unmapped virtual
3833        * functions, and if we invalidate the redraw entry we could end up
3834        * with an inconsistent state and weird memory corruption. see
3835        * bugs:
3836        *
3837        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3838        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3839        */
3840       _clutter_actor_traverse (child,
3841                                0,
3842                                invalidate_queue_redraw_entry,
3843                                NULL,
3844                                NULL);
3845     }
3846
3847   old_first = self->priv->first_child;
3848   old_last = self->priv->last_child;
3849
3850   remove_child (self, child);
3851
3852   self->priv->n_children -= 1;
3853
3854   self->priv->age += 1;
3855
3856   /* clutter_actor_reparent() will emit ::parent-set for us */
3857   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3858     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3859
3860   /* if the child was mapped then we need to relayout ourselves to account
3861    * for the removed child
3862    */
3863   if (was_mapped)
3864     clutter_actor_queue_relayout (self);
3865
3866   /* we need to emit the signal before dropping the reference */
3867   if (emit_actor_removed)
3868     g_signal_emit_by_name (self, "actor-removed", child);
3869
3870   if (notify_first_last)
3871     {
3872       if (old_first != self->priv->first_child)
3873         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3874
3875       if (old_last != self->priv->last_child)
3876         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3877     }
3878
3879   g_object_thaw_notify (G_OBJECT (self));
3880
3881   /* remove the reference we acquired in clutter_actor_add_child() */
3882   g_object_unref (child);
3883 }
3884
3885 static const ClutterTransformInfo default_transform_info = {
3886   0.0, { 0, },          /* rotation-x */
3887   0.0, { 0, },          /* rotation-y */
3888   0.0, { 0, },          /* rotation-z */
3889
3890   1.0, 1.0, { 0, },     /* scale */
3891
3892   { 0, },               /* anchor */
3893
3894   0.0,                  /* depth */
3895 };
3896
3897 /*< private >
3898  * _clutter_actor_get_transform_info_or_defaults:
3899  * @self: a #ClutterActor
3900  *
3901  * Retrieves the ClutterTransformInfo structure associated to an actor.
3902  *
3903  * If the actor does not have a ClutterTransformInfo structure associated
3904  * to it, then the default structure will be returned.
3905  *
3906  * This function should only be used for getters.
3907  *
3908  * Return value: a const pointer to the ClutterTransformInfo structure
3909  */
3910 const ClutterTransformInfo *
3911 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3912 {
3913   ClutterTransformInfo *info;
3914
3915   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3916   if (info != NULL)
3917     return info;
3918
3919   return &default_transform_info;
3920 }
3921
3922 static void
3923 clutter_transform_info_free (gpointer data)
3924 {
3925   if (data != NULL)
3926     g_slice_free (ClutterTransformInfo, data);
3927 }
3928
3929 /*< private >
3930  * _clutter_actor_get_transform_info:
3931  * @self: a #ClutterActor
3932  *
3933  * Retrieves a pointer to the ClutterTransformInfo structure.
3934  *
3935  * If the actor does not have a ClutterTransformInfo associated to it, one
3936  * will be created and initialized to the default values.
3937  *
3938  * This function should be used for setters.
3939  *
3940  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3941  * instead.
3942  *
3943  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3944  *   structure
3945  */
3946 ClutterTransformInfo *
3947 _clutter_actor_get_transform_info (ClutterActor *self)
3948 {
3949   ClutterTransformInfo *info;
3950
3951   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3952   if (info == NULL)
3953     {
3954       info = g_slice_new (ClutterTransformInfo);
3955
3956       *info = default_transform_info;
3957
3958       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3959                                info,
3960                                clutter_transform_info_free);
3961     }
3962
3963   return info;
3964 }
3965
3966 /*< private >
3967  * clutter_actor_set_rotation_angle_internal:
3968  * @self: a #ClutterActor
3969  * @axis: the axis of the angle to change
3970  * @angle: the angle of rotation
3971  *
3972  * Sets the rotation angle on the given axis without affecting the
3973  * rotation center point.
3974  */
3975 static inline void
3976 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3977                                            ClutterRotateAxis  axis,
3978                                            gdouble            angle)
3979 {
3980   GObject *obj = G_OBJECT (self);
3981   ClutterTransformInfo *info;
3982
3983   info = _clutter_actor_get_transform_info (self);
3984
3985   g_object_freeze_notify (obj);
3986
3987   switch (axis)
3988     {
3989     case CLUTTER_X_AXIS:
3990       info->rx_angle = angle;
3991       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3992       break;
3993
3994     case CLUTTER_Y_AXIS:
3995       info->ry_angle = angle;
3996       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3997       break;
3998
3999     case CLUTTER_Z_AXIS:
4000       info->rz_angle = angle;
4001       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4002       break;
4003     }
4004
4005   self->priv->transform_valid = FALSE;
4006
4007   g_object_thaw_notify (obj);
4008
4009   clutter_actor_queue_redraw (self);
4010 }
4011
4012 static inline void
4013 clutter_actor_set_rotation_angle (ClutterActor      *self,
4014                                   ClutterRotateAxis  axis,
4015                                   gdouble            angle)
4016 {
4017   const ClutterTransformInfo *info;
4018   const double *cur_angle_p = NULL;
4019   GParamSpec *pspec = NULL;
4020
4021   info = _clutter_actor_get_transform_info_or_defaults (self);
4022
4023   switch (axis)
4024     {
4025     case CLUTTER_X_AXIS:
4026       cur_angle_p = &info->rx_angle;
4027       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4028       break;
4029
4030     case CLUTTER_Y_AXIS:
4031       cur_angle_p = &info->ry_angle;
4032       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4033       break;
4034
4035     case CLUTTER_Z_AXIS:
4036       cur_angle_p = &info->rz_angle;
4037       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4038       break;
4039     }
4040
4041   g_assert (pspec != NULL);
4042   g_assert (cur_angle_p != NULL);
4043
4044   if (_clutter_actor_get_transition (self, pspec) == NULL)
4045     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4046   else
4047     _clutter_actor_update_transition (self, pspec, angle);
4048
4049   clutter_actor_queue_redraw (self);
4050 }
4051
4052 /*< private >
4053  * clutter_actor_set_rotation_center_internal:
4054  * @self: a #ClutterActor
4055  * @axis: the axis of the center to change
4056  * @center: the coordinates of the rotation center
4057  *
4058  * Sets the rotation center on the given axis without affecting the
4059  * rotation angle.
4060  */
4061 static inline void
4062 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4063                                             ClutterRotateAxis    axis,
4064                                             const ClutterVertex *center)
4065 {
4066   GObject *obj = G_OBJECT (self);
4067   ClutterTransformInfo *info;
4068   ClutterVertex v = { 0, 0, 0 };
4069
4070   info = _clutter_actor_get_transform_info (self);
4071
4072   if (center != NULL)
4073     v = *center;
4074
4075   g_object_freeze_notify (obj);
4076
4077   switch (axis)
4078     {
4079     case CLUTTER_X_AXIS:
4080       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4081       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4082       break;
4083
4084     case CLUTTER_Y_AXIS:
4085       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4086       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4087       break;
4088
4089     case CLUTTER_Z_AXIS:
4090       /* if the previously set rotation center was fractional, then
4091        * setting explicit coordinates will have to notify the
4092        * :rotation-center-z-gravity property as well
4093        */
4094       if (info->rz_center.is_fractional)
4095         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4096
4097       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4098       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4099       break;
4100     }
4101
4102   self->priv->transform_valid = FALSE;
4103
4104   g_object_thaw_notify (obj);
4105
4106   clutter_actor_queue_redraw (self);
4107 }
4108
4109 static void
4110 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4111                                          double factor,
4112                                          GParamSpec *pspec)
4113 {
4114   GObject *obj = G_OBJECT (self);
4115   ClutterTransformInfo *info;
4116
4117   info = _clutter_actor_get_transform_info (self);
4118
4119   if (pspec == obj_props[PROP_SCALE_X])
4120     info->scale_x = factor;
4121   else
4122     info->scale_y = factor;
4123
4124   self->priv->transform_valid = FALSE;
4125   clutter_actor_queue_redraw (self);
4126   g_object_notify_by_pspec (obj, pspec);
4127 }
4128
4129 static inline void
4130 clutter_actor_set_scale_factor (ClutterActor      *self,
4131                                 ClutterRotateAxis  axis,
4132                                 gdouble            factor)
4133 {
4134   const ClutterTransformInfo *info;
4135   const double *scale_p = NULL;
4136   GParamSpec *pspec = NULL;
4137
4138   info = _clutter_actor_get_transform_info_or_defaults (self);
4139
4140   switch (axis)
4141     {
4142     case CLUTTER_X_AXIS:
4143       pspec = obj_props[PROP_SCALE_X];
4144       scale_p = &info->scale_x;
4145       break;
4146
4147     case CLUTTER_Y_AXIS:
4148       pspec = obj_props[PROP_SCALE_Y];
4149       scale_p = &info->scale_y;
4150       break;
4151
4152     case CLUTTER_Z_AXIS:
4153       break;
4154     }
4155
4156   g_assert (pspec != NULL);
4157   g_assert (scale_p != NULL);
4158
4159   if (_clutter_actor_get_transition (self, pspec) == NULL)
4160     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4161   else
4162     _clutter_actor_update_transition (self, pspec, factor);
4163
4164   clutter_actor_queue_redraw (self);
4165 }
4166
4167 static inline void
4168 clutter_actor_set_scale_center (ClutterActor      *self,
4169                                 ClutterRotateAxis  axis,
4170                                 gfloat             coord)
4171 {
4172   GObject *obj = G_OBJECT (self);
4173   ClutterTransformInfo *info;
4174   gfloat center_x, center_y;
4175
4176   info = _clutter_actor_get_transform_info (self);
4177
4178   g_object_freeze_notify (obj);
4179
4180   /* get the current scale center coordinates */
4181   clutter_anchor_coord_get_units (self, &info->scale_center,
4182                                   &center_x,
4183                                   &center_y,
4184                                   NULL);
4185
4186   /* we need to notify this too, because setting explicit coordinates will
4187    * change the gravity as a side effect
4188    */
4189   if (info->scale_center.is_fractional)
4190     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4191
4192   switch (axis)
4193     {
4194     case CLUTTER_X_AXIS:
4195       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4196       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4197       break;
4198
4199     case CLUTTER_Y_AXIS:
4200       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4201       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4202       break;
4203
4204     default:
4205       g_assert_not_reached ();
4206     }
4207
4208   self->priv->transform_valid = FALSE;
4209
4210   clutter_actor_queue_redraw (self);
4211
4212   g_object_thaw_notify (obj);
4213 }
4214
4215 static inline void
4216 clutter_actor_set_scale_gravity (ClutterActor   *self,
4217                                  ClutterGravity  gravity)
4218 {
4219   ClutterTransformInfo *info;
4220   GObject *obj;
4221
4222   info = _clutter_actor_get_transform_info (self);
4223   obj = G_OBJECT (self);
4224
4225   if (gravity == CLUTTER_GRAVITY_NONE)
4226     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4227   else
4228     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4229
4230   self->priv->transform_valid = FALSE;
4231
4232   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4233   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4234   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4235
4236   clutter_actor_queue_redraw (self);
4237 }
4238
4239 static inline void
4240 clutter_actor_set_anchor_coord (ClutterActor      *self,
4241                                 ClutterRotateAxis  axis,
4242                                 gfloat             coord)
4243 {
4244   GObject *obj = G_OBJECT (self);
4245   ClutterTransformInfo *info;
4246   gfloat anchor_x, anchor_y;
4247
4248   info = _clutter_actor_get_transform_info (self);
4249
4250   g_object_freeze_notify (obj);
4251
4252   clutter_anchor_coord_get_units (self, &info->anchor,
4253                                   &anchor_x,
4254                                   &anchor_y,
4255                                   NULL);
4256
4257   if (info->anchor.is_fractional)
4258     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4259
4260   switch (axis)
4261     {
4262     case CLUTTER_X_AXIS:
4263       clutter_anchor_coord_set_units (&info->anchor,
4264                                       coord,
4265                                       anchor_y,
4266                                       0.0);
4267       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4268       break;
4269
4270     case CLUTTER_Y_AXIS:
4271       clutter_anchor_coord_set_units (&info->anchor,
4272                                       anchor_x,
4273                                       coord,
4274                                       0.0);
4275       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4276       break;
4277
4278     default:
4279       g_assert_not_reached ();
4280     }
4281
4282   self->priv->transform_valid = FALSE;
4283
4284   clutter_actor_queue_redraw (self);
4285
4286   g_object_thaw_notify (obj);
4287 }
4288
4289 static void
4290 clutter_actor_set_property (GObject      *object,
4291                             guint         prop_id,
4292                             const GValue *value,
4293                             GParamSpec   *pspec)
4294 {
4295   ClutterActor *actor = CLUTTER_ACTOR (object);
4296   ClutterActorPrivate *priv = actor->priv;
4297
4298   switch (prop_id)
4299     {
4300     case PROP_X:
4301       clutter_actor_set_x (actor, g_value_get_float (value));
4302       break;
4303
4304     case PROP_Y:
4305       clutter_actor_set_y (actor, g_value_get_float (value));
4306       break;
4307
4308     case PROP_WIDTH:
4309       clutter_actor_set_width (actor, g_value_get_float (value));
4310       break;
4311
4312     case PROP_HEIGHT:
4313       clutter_actor_set_height (actor, g_value_get_float (value));
4314       break;
4315
4316     case PROP_FIXED_X:
4317       clutter_actor_set_x (actor, g_value_get_float (value));
4318       break;
4319
4320     case PROP_FIXED_Y:
4321       clutter_actor_set_y (actor, g_value_get_float (value));
4322       break;
4323
4324     case PROP_FIXED_POSITION_SET:
4325       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4326       break;
4327
4328     case PROP_MIN_WIDTH:
4329       clutter_actor_set_min_width (actor, g_value_get_float (value));
4330       break;
4331
4332     case PROP_MIN_HEIGHT:
4333       clutter_actor_set_min_height (actor, g_value_get_float (value));
4334       break;
4335
4336     case PROP_NATURAL_WIDTH:
4337       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4338       break;
4339
4340     case PROP_NATURAL_HEIGHT:
4341       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4342       break;
4343
4344     case PROP_MIN_WIDTH_SET:
4345       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4346       break;
4347
4348     case PROP_MIN_HEIGHT_SET:
4349       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4350       break;
4351
4352     case PROP_NATURAL_WIDTH_SET:
4353       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4354       break;
4355
4356     case PROP_NATURAL_HEIGHT_SET:
4357       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4358       break;
4359
4360     case PROP_REQUEST_MODE:
4361       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4362       break;
4363
4364     case PROP_DEPTH:
4365       clutter_actor_set_depth (actor, g_value_get_float (value));
4366       break;
4367
4368     case PROP_OPACITY:
4369       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4370       break;
4371
4372     case PROP_OFFSCREEN_REDIRECT:
4373       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4374       break;
4375
4376     case PROP_NAME:
4377       clutter_actor_set_name (actor, g_value_get_string (value));
4378       break;
4379
4380     case PROP_VISIBLE:
4381       if (g_value_get_boolean (value) == TRUE)
4382         clutter_actor_show (actor);
4383       else
4384         clutter_actor_hide (actor);
4385       break;
4386
4387     case PROP_SCALE_X:
4388       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4389                                       g_value_get_double (value));
4390       break;
4391
4392     case PROP_SCALE_Y:
4393       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4394                                       g_value_get_double (value));
4395       break;
4396
4397     case PROP_SCALE_CENTER_X:
4398       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4399                                       g_value_get_float (value));
4400       break;
4401
4402     case PROP_SCALE_CENTER_Y:
4403       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4404                                       g_value_get_float (value));
4405       break;
4406
4407     case PROP_SCALE_GRAVITY:
4408       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4409       break;
4410
4411     case PROP_CLIP:
4412       {
4413         const ClutterGeometry *geom = g_value_get_boxed (value);
4414
4415         clutter_actor_set_clip (actor,
4416                                 geom->x, geom->y,
4417                                 geom->width, geom->height);
4418       }
4419       break;
4420
4421     case PROP_CLIP_TO_ALLOCATION:
4422       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4423       break;
4424
4425     case PROP_REACTIVE:
4426       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4427       break;
4428
4429     case PROP_ROTATION_ANGLE_X:
4430       clutter_actor_set_rotation_angle (actor,
4431                                         CLUTTER_X_AXIS,
4432                                         g_value_get_double (value));
4433       break;
4434
4435     case PROP_ROTATION_ANGLE_Y:
4436       clutter_actor_set_rotation_angle (actor,
4437                                         CLUTTER_Y_AXIS,
4438                                         g_value_get_double (value));
4439       break;
4440
4441     case PROP_ROTATION_ANGLE_Z:
4442       clutter_actor_set_rotation_angle (actor,
4443                                         CLUTTER_Z_AXIS,
4444                                         g_value_get_double (value));
4445       break;
4446
4447     case PROP_ROTATION_CENTER_X:
4448       clutter_actor_set_rotation_center_internal (actor,
4449                                                   CLUTTER_X_AXIS,
4450                                                   g_value_get_boxed (value));
4451       break;
4452
4453     case PROP_ROTATION_CENTER_Y:
4454       clutter_actor_set_rotation_center_internal (actor,
4455                                                   CLUTTER_Y_AXIS,
4456                                                   g_value_get_boxed (value));
4457       break;
4458
4459     case PROP_ROTATION_CENTER_Z:
4460       clutter_actor_set_rotation_center_internal (actor,
4461                                                   CLUTTER_Z_AXIS,
4462                                                   g_value_get_boxed (value));
4463       break;
4464
4465     case PROP_ROTATION_CENTER_Z_GRAVITY:
4466       {
4467         const ClutterTransformInfo *info;
4468
4469         info = _clutter_actor_get_transform_info_or_defaults (actor);
4470         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4471                                                    g_value_get_enum (value));
4472       }
4473       break;
4474
4475     case PROP_ANCHOR_X:
4476       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4477                                       g_value_get_float (value));
4478       break;
4479
4480     case PROP_ANCHOR_Y:
4481       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4482                                       g_value_get_float (value));
4483       break;
4484
4485     case PROP_ANCHOR_GRAVITY:
4486       clutter_actor_set_anchor_point_from_gravity (actor,
4487                                                    g_value_get_enum (value));
4488       break;
4489
4490     case PROP_SHOW_ON_SET_PARENT:
4491       priv->show_on_set_parent = g_value_get_boolean (value);
4492       break;
4493
4494     case PROP_TEXT_DIRECTION:
4495       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4496       break;
4497
4498     case PROP_ACTIONS:
4499       clutter_actor_add_action (actor, g_value_get_object (value));
4500       break;
4501
4502     case PROP_CONSTRAINTS:
4503       clutter_actor_add_constraint (actor, g_value_get_object (value));
4504       break;
4505
4506     case PROP_EFFECT:
4507       clutter_actor_add_effect (actor, g_value_get_object (value));
4508       break;
4509
4510     case PROP_LAYOUT_MANAGER:
4511       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4512       break;
4513
4514     case PROP_X_ALIGN:
4515       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4516       break;
4517
4518     case PROP_Y_ALIGN:
4519       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4520       break;
4521
4522     case PROP_MARGIN_TOP:
4523       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4524       break;
4525
4526     case PROP_MARGIN_BOTTOM:
4527       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4528       break;
4529
4530     case PROP_MARGIN_LEFT:
4531       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4532       break;
4533
4534     case PROP_MARGIN_RIGHT:
4535       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4536       break;
4537
4538     case PROP_BACKGROUND_COLOR:
4539       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4540       break;
4541
4542     case PROP_CONTENT:
4543       clutter_actor_set_content (actor, g_value_get_object (value));
4544       break;
4545
4546     case PROP_CONTENT_GRAVITY:
4547       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4548       break;
4549
4550     case PROP_MINIFICATION_FILTER:
4551       clutter_actor_set_content_scaling_filters (actor,
4552                                                  g_value_get_enum (value),
4553                                                  actor->priv->mag_filter);
4554       break;
4555
4556     case PROP_MAGNIFICATION_FILTER:
4557       clutter_actor_set_content_scaling_filters (actor,
4558                                                  actor->priv->min_filter,
4559                                                  g_value_get_enum (value));
4560       break;
4561
4562     default:
4563       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4564       break;
4565     }
4566 }
4567
4568 static void
4569 clutter_actor_get_property (GObject    *object,
4570                             guint       prop_id,
4571                             GValue     *value,
4572                             GParamSpec *pspec)
4573 {
4574   ClutterActor *actor = CLUTTER_ACTOR (object);
4575   ClutterActorPrivate *priv = actor->priv;
4576
4577   switch (prop_id)
4578     {
4579     case PROP_X:
4580       g_value_set_float (value, clutter_actor_get_x (actor));
4581       break;
4582
4583     case PROP_Y:
4584       g_value_set_float (value, clutter_actor_get_y (actor));
4585       break;
4586
4587     case PROP_WIDTH:
4588       g_value_set_float (value, clutter_actor_get_width (actor));
4589       break;
4590
4591     case PROP_HEIGHT:
4592       g_value_set_float (value, clutter_actor_get_height (actor));
4593       break;
4594
4595     case PROP_FIXED_X:
4596       {
4597         const ClutterLayoutInfo *info;
4598
4599         info = _clutter_actor_get_layout_info_or_defaults (actor);
4600         g_value_set_float (value, info->fixed_x);
4601       }
4602       break;
4603
4604     case PROP_FIXED_Y:
4605       {
4606         const ClutterLayoutInfo *info;
4607
4608         info = _clutter_actor_get_layout_info_or_defaults (actor);
4609         g_value_set_float (value, info->fixed_y);
4610       }
4611       break;
4612
4613     case PROP_FIXED_POSITION_SET:
4614       g_value_set_boolean (value, priv->position_set);
4615       break;
4616
4617     case PROP_MIN_WIDTH:
4618       {
4619         const ClutterLayoutInfo *info;
4620
4621         info = _clutter_actor_get_layout_info_or_defaults (actor);
4622         g_value_set_float (value, info->min_width);
4623       }
4624       break;
4625
4626     case PROP_MIN_HEIGHT:
4627       {
4628         const ClutterLayoutInfo *info;
4629
4630         info = _clutter_actor_get_layout_info_or_defaults (actor);
4631         g_value_set_float (value, info->min_height);
4632       }
4633       break;
4634
4635     case PROP_NATURAL_WIDTH:
4636       {
4637         const ClutterLayoutInfo *info;
4638
4639         info = _clutter_actor_get_layout_info_or_defaults (actor);
4640         g_value_set_float (value, info->natural_width);
4641       }
4642       break;
4643
4644     case PROP_NATURAL_HEIGHT:
4645       {
4646         const ClutterLayoutInfo *info;
4647
4648         info = _clutter_actor_get_layout_info_or_defaults (actor);
4649         g_value_set_float (value, info->natural_height);
4650       }
4651       break;
4652
4653     case PROP_MIN_WIDTH_SET:
4654       g_value_set_boolean (value, priv->min_width_set);
4655       break;
4656
4657     case PROP_MIN_HEIGHT_SET:
4658       g_value_set_boolean (value, priv->min_height_set);
4659       break;
4660
4661     case PROP_NATURAL_WIDTH_SET:
4662       g_value_set_boolean (value, priv->natural_width_set);
4663       break;
4664
4665     case PROP_NATURAL_HEIGHT_SET:
4666       g_value_set_boolean (value, priv->natural_height_set);
4667       break;
4668
4669     case PROP_REQUEST_MODE:
4670       g_value_set_enum (value, priv->request_mode);
4671       break;
4672
4673     case PROP_ALLOCATION:
4674       g_value_set_boxed (value, &priv->allocation);
4675       break;
4676
4677     case PROP_DEPTH:
4678       g_value_set_float (value, clutter_actor_get_depth (actor));
4679       break;
4680
4681     case PROP_OPACITY:
4682       g_value_set_uint (value, priv->opacity);
4683       break;
4684
4685     case PROP_OFFSCREEN_REDIRECT:
4686       g_value_set_enum (value, priv->offscreen_redirect);
4687       break;
4688
4689     case PROP_NAME:
4690       g_value_set_string (value, priv->name);
4691       break;
4692
4693     case PROP_VISIBLE:
4694       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4695       break;
4696
4697     case PROP_MAPPED:
4698       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4699       break;
4700
4701     case PROP_REALIZED:
4702       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4703       break;
4704
4705     case PROP_HAS_CLIP:
4706       g_value_set_boolean (value, priv->has_clip);
4707       break;
4708
4709     case PROP_CLIP:
4710       {
4711         ClutterGeometry clip;
4712
4713         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4714         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4715         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4716         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4717
4718         g_value_set_boxed (value, &clip);
4719       }
4720       break;
4721
4722     case PROP_CLIP_TO_ALLOCATION:
4723       g_value_set_boolean (value, priv->clip_to_allocation);
4724       break;
4725
4726     case PROP_SCALE_X:
4727       {
4728         const ClutterTransformInfo *info;
4729
4730         info = _clutter_actor_get_transform_info_or_defaults (actor);
4731         g_value_set_double (value, info->scale_x);
4732       }
4733       break;
4734
4735     case PROP_SCALE_Y:
4736       {
4737         const ClutterTransformInfo *info;
4738
4739         info = _clutter_actor_get_transform_info_or_defaults (actor);
4740         g_value_set_double (value, info->scale_y);
4741       }
4742       break;
4743
4744     case PROP_SCALE_CENTER_X:
4745       {
4746         gfloat center;
4747
4748         clutter_actor_get_scale_center (actor, &center, NULL);
4749
4750         g_value_set_float (value, center);
4751       }
4752       break;
4753
4754     case PROP_SCALE_CENTER_Y:
4755       {
4756         gfloat center;
4757
4758         clutter_actor_get_scale_center (actor, NULL, &center);
4759
4760         g_value_set_float (value, center);
4761       }
4762       break;
4763
4764     case PROP_SCALE_GRAVITY:
4765       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4766       break;
4767
4768     case PROP_REACTIVE:
4769       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4770       break;
4771
4772     case PROP_ROTATION_ANGLE_X:
4773       {
4774         const ClutterTransformInfo *info;
4775
4776         info = _clutter_actor_get_transform_info_or_defaults (actor);
4777         g_value_set_double (value, info->rx_angle);
4778       }
4779       break;
4780
4781     case PROP_ROTATION_ANGLE_Y:
4782       {
4783         const ClutterTransformInfo *info;
4784
4785         info = _clutter_actor_get_transform_info_or_defaults (actor);
4786         g_value_set_double (value, info->ry_angle);
4787       }
4788       break;
4789
4790     case PROP_ROTATION_ANGLE_Z:
4791       {
4792         const ClutterTransformInfo *info;
4793
4794         info = _clutter_actor_get_transform_info_or_defaults (actor);
4795         g_value_set_double (value, info->rz_angle);
4796       }
4797       break;
4798
4799     case PROP_ROTATION_CENTER_X:
4800       {
4801         ClutterVertex center;
4802
4803         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4804                                     &center.x,
4805                                     &center.y,
4806                                     &center.z);
4807
4808         g_value_set_boxed (value, &center);
4809       }
4810       break;
4811
4812     case PROP_ROTATION_CENTER_Y:
4813       {
4814         ClutterVertex center;
4815
4816         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4817                                     &center.x,
4818                                     &center.y,
4819                                     &center.z);
4820
4821         g_value_set_boxed (value, &center);
4822       }
4823       break;
4824
4825     case PROP_ROTATION_CENTER_Z:
4826       {
4827         ClutterVertex center;
4828
4829         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4830                                     &center.x,
4831                                     &center.y,
4832                                     &center.z);
4833
4834         g_value_set_boxed (value, &center);
4835       }
4836       break;
4837
4838     case PROP_ROTATION_CENTER_Z_GRAVITY:
4839       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4840       break;
4841
4842     case PROP_ANCHOR_X:
4843       {
4844         const ClutterTransformInfo *info;
4845         gfloat anchor_x;
4846
4847         info = _clutter_actor_get_transform_info_or_defaults (actor);
4848         clutter_anchor_coord_get_units (actor, &info->anchor,
4849                                         &anchor_x,
4850                                         NULL,
4851                                         NULL);
4852         g_value_set_float (value, anchor_x);
4853       }
4854       break;
4855
4856     case PROP_ANCHOR_Y:
4857       {
4858         const ClutterTransformInfo *info;
4859         gfloat anchor_y;
4860
4861         info = _clutter_actor_get_transform_info_or_defaults (actor);
4862         clutter_anchor_coord_get_units (actor, &info->anchor,
4863                                         NULL,
4864                                         &anchor_y,
4865                                         NULL);
4866         g_value_set_float (value, anchor_y);
4867       }
4868       break;
4869
4870     case PROP_ANCHOR_GRAVITY:
4871       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4872       break;
4873
4874     case PROP_SHOW_ON_SET_PARENT:
4875       g_value_set_boolean (value, priv->show_on_set_parent);
4876       break;
4877
4878     case PROP_TEXT_DIRECTION:
4879       g_value_set_enum (value, priv->text_direction);
4880       break;
4881
4882     case PROP_HAS_POINTER:
4883       g_value_set_boolean (value, priv->has_pointer);
4884       break;
4885
4886     case PROP_LAYOUT_MANAGER:
4887       g_value_set_object (value, priv->layout_manager);
4888       break;
4889
4890     case PROP_X_ALIGN:
4891       {
4892         const ClutterLayoutInfo *info;
4893
4894         info = _clutter_actor_get_layout_info_or_defaults (actor);
4895         g_value_set_enum (value, info->x_align);
4896       }
4897       break;
4898
4899     case PROP_Y_ALIGN:
4900       {
4901         const ClutterLayoutInfo *info;
4902
4903         info = _clutter_actor_get_layout_info_or_defaults (actor);
4904         g_value_set_enum (value, info->y_align);
4905       }
4906       break;
4907
4908     case PROP_MARGIN_TOP:
4909       {
4910         const ClutterLayoutInfo *info;
4911
4912         info = _clutter_actor_get_layout_info_or_defaults (actor);
4913         g_value_set_float (value, info->margin.top);
4914       }
4915       break;
4916
4917     case PROP_MARGIN_BOTTOM:
4918       {
4919         const ClutterLayoutInfo *info;
4920
4921         info = _clutter_actor_get_layout_info_or_defaults (actor);
4922         g_value_set_float (value, info->margin.bottom);
4923       }
4924       break;
4925
4926     case PROP_MARGIN_LEFT:
4927       {
4928         const ClutterLayoutInfo *info;
4929
4930         info = _clutter_actor_get_layout_info_or_defaults (actor);
4931         g_value_set_float (value, info->margin.left);
4932       }
4933       break;
4934
4935     case PROP_MARGIN_RIGHT:
4936       {
4937         const ClutterLayoutInfo *info;
4938
4939         info = _clutter_actor_get_layout_info_or_defaults (actor);
4940         g_value_set_float (value, info->margin.right);
4941       }
4942       break;
4943
4944     case PROP_BACKGROUND_COLOR_SET:
4945       g_value_set_boolean (value, priv->bg_color_set);
4946       break;
4947
4948     case PROP_BACKGROUND_COLOR:
4949       g_value_set_boxed (value, &priv->bg_color);
4950       break;
4951
4952     case PROP_FIRST_CHILD:
4953       g_value_set_object (value, priv->first_child);
4954       break;
4955
4956     case PROP_LAST_CHILD:
4957       g_value_set_object (value, priv->last_child);
4958       break;
4959
4960     case PROP_CONTENT:
4961       g_value_set_object (value, priv->content);
4962       break;
4963
4964     case PROP_CONTENT_GRAVITY:
4965       g_value_set_enum (value, priv->content_gravity);
4966       break;
4967
4968     case PROP_CONTENT_BOX:
4969       {
4970         ClutterActorBox box = { 0, };
4971
4972         clutter_actor_get_content_box (actor, &box);
4973         g_value_set_boxed (value, &box);
4974       }
4975       break;
4976
4977     case PROP_MINIFICATION_FILTER:
4978       g_value_set_enum (value, priv->min_filter);
4979       break;
4980
4981     case PROP_MAGNIFICATION_FILTER:
4982       g_value_set_enum (value, priv->mag_filter);
4983       break;
4984
4985     default:
4986       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4987       break;
4988     }
4989 }
4990
4991 static void
4992 clutter_actor_dispose (GObject *object)
4993 {
4994   ClutterActor *self = CLUTTER_ACTOR (object);
4995   ClutterActorPrivate *priv = self->priv;
4996
4997   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4998                 priv->id,
4999                 g_type_name (G_OBJECT_TYPE (self)),
5000                 object->ref_count);
5001
5002   g_signal_emit (self, actor_signals[DESTROY], 0);
5003
5004   /* avoid recursing when called from clutter_actor_destroy() */
5005   if (priv->parent != NULL)
5006     {
5007       ClutterActor *parent = priv->parent;
5008
5009       /* go through the Container implementation unless this
5010        * is an internal child and has been marked as such.
5011        *
5012        * removing the actor from its parent will reset the
5013        * realized and mapped states.
5014        */
5015       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5016         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5017       else
5018         clutter_actor_remove_child_internal (parent, self,
5019                                              REMOVE_CHILD_LEGACY_FLAGS);
5020     }
5021
5022   /* parent must be gone at this point */
5023   g_assert (priv->parent == NULL);
5024
5025   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5026     {
5027       /* can't be mapped or realized with no parent */
5028       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5029       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5030     }
5031
5032   g_clear_object (&priv->pango_context);
5033   g_clear_object (&priv->actions);
5034   g_clear_object (&priv->constraints);
5035   g_clear_object (&priv->effects);
5036   g_clear_object (&priv->flatten_effect);
5037
5038   if (priv->layout_manager != NULL)
5039     {
5040       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5041       g_clear_object (&priv->layout_manager);
5042     }
5043
5044   if (priv->content != NULL)
5045     {
5046       _clutter_content_detached (priv->content, self);
5047       g_clear_object (&priv->content);
5048     }
5049
5050   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5051 }
5052
5053 static void
5054 clutter_actor_finalize (GObject *object)
5055 {
5056   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5057
5058   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5059                 priv->name != NULL ? priv->name : "<none>",
5060                 priv->id,
5061                 g_type_name (G_OBJECT_TYPE (object)));
5062
5063   _clutter_context_release_id (priv->id);
5064
5065   g_free (priv->name);
5066
5067   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5068 }
5069
5070
5071 /**
5072  * clutter_actor_get_accessible:
5073  * @self: a #ClutterActor
5074  *
5075  * Returns the accessible object that describes the actor to an
5076  * assistive technology.
5077  *
5078  * If no class-specific #AtkObject implementation is available for the
5079  * actor instance in question, it will inherit an #AtkObject
5080  * implementation from the first ancestor class for which such an
5081  * implementation is defined.
5082  *
5083  * The documentation of the <ulink
5084  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5085  * library contains more information about accessible objects and
5086  * their uses.
5087  *
5088  * Returns: (transfer none): the #AtkObject associated with @actor
5089  */
5090 AtkObject *
5091 clutter_actor_get_accessible (ClutterActor *self)
5092 {
5093   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5094
5095   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5096 }
5097
5098 static AtkObject *
5099 clutter_actor_real_get_accessible (ClutterActor *actor)
5100 {
5101   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5102 }
5103
5104 static AtkObject *
5105 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5106 {
5107   AtkObject *accessible;
5108
5109   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5110   if (accessible != NULL)
5111     g_object_ref (accessible);
5112
5113   return accessible;
5114 }
5115
5116 static void
5117 atk_implementor_iface_init (AtkImplementorIface *iface)
5118 {
5119   iface->ref_accessible = _clutter_actor_ref_accessible;
5120 }
5121
5122 static gboolean
5123 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5124                                            ClutterPaintVolume *volume)
5125 {
5126   ClutterActorPrivate *priv = self->priv;
5127   gboolean res = FALSE;
5128
5129   /* we start from the allocation */
5130   clutter_paint_volume_set_width (volume,
5131                                   priv->allocation.x2 - priv->allocation.x1);
5132   clutter_paint_volume_set_height (volume,
5133                                    priv->allocation.y2 - priv->allocation.y1);
5134
5135   /* if the actor has a clip set then we have a pretty definite
5136    * size for the paint volume: the actor cannot possibly paint
5137    * outside the clip region.
5138    */
5139   if (priv->clip_to_allocation)
5140     {
5141       /* the allocation has already been set, so we just flip the
5142        * return value
5143        */
5144       res = TRUE;
5145     }
5146   else
5147     {
5148       ClutterActor *child;
5149
5150       if (priv->has_clip &&
5151           priv->clip.width >= 0 &&
5152           priv->clip.height >= 0)
5153         {
5154           ClutterVertex origin;
5155
5156           origin.x = priv->clip.x;
5157           origin.y = priv->clip.y;
5158           origin.z = 0;
5159
5160           clutter_paint_volume_set_origin (volume, &origin);
5161           clutter_paint_volume_set_width (volume, priv->clip.width);
5162           clutter_paint_volume_set_height (volume, priv->clip.height);
5163
5164           res = TRUE;
5165         }
5166
5167       /* if we don't have children we just bail out here... */
5168       if (priv->n_children == 0)
5169         return res;
5170
5171       /* ...but if we have children then we ask for their paint volume in
5172        * our coordinates. if any of our children replies that it doesn't
5173        * have a paint volume, we bail out
5174        */
5175       for (child = priv->first_child;
5176            child != NULL;
5177            child = child->priv->next_sibling)
5178         {
5179           const ClutterPaintVolume *child_volume;
5180
5181           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5182           if (child_volume == NULL)
5183             {
5184               res = FALSE;
5185               break;
5186             }
5187
5188           clutter_paint_volume_union (volume, child_volume);
5189           res = TRUE;
5190         }
5191     }
5192
5193   return res;
5194
5195 }
5196
5197 static gboolean
5198 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5199                                      ClutterPaintVolume *volume)
5200 {
5201   ClutterActorClass *klass;
5202   gboolean res;
5203
5204   klass = CLUTTER_ACTOR_GET_CLASS (self);
5205
5206   /* XXX - this thoroughly sucks, but we don't want to penalize users
5207    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5208    * redraw. This should go away in 2.0.
5209    */
5210   if (klass->paint == clutter_actor_real_paint &&
5211       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5212     {
5213       res = TRUE;
5214     }
5215   else
5216     {
5217       /* this is the default return value: we cannot know if a class
5218        * is going to paint outside its allocation, so we take the
5219        * conservative approach.
5220        */
5221       res = FALSE;
5222     }
5223
5224   if (clutter_actor_update_default_paint_volume (self, volume))
5225     return res;
5226
5227   return FALSE;
5228 }
5229
5230 /**
5231  * clutter_actor_get_default_paint_volume:
5232  * @self: a #ClutterActor
5233  *
5234  * Retrieves the default paint volume for @self.
5235  *
5236  * This function provides the same #ClutterPaintVolume that would be
5237  * computed by the default implementation inside #ClutterActor of the
5238  * #ClutterActorClass.get_paint_volume() virtual function.
5239  *
5240  * This function should only be used by #ClutterActor subclasses that
5241  * cannot chain up to the parent implementation when computing their
5242  * paint volume.
5243  *
5244  * Return value: (transfer none): a pointer to the default
5245  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5246  *   the actor could not compute a valid paint volume. The returned value
5247  *   is not guaranteed to be stable across multiple frames, so if you
5248  *   want to retain it, you will need to copy it using
5249  *   clutter_paint_volume_copy().
5250  *
5251  * Since: 1.10
5252  */
5253 const ClutterPaintVolume *
5254 clutter_actor_get_default_paint_volume (ClutterActor *self)
5255 {
5256   ClutterPaintVolume volume;
5257   ClutterPaintVolume *res;
5258
5259   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5260
5261   res = NULL;
5262   _clutter_paint_volume_init_static (&volume, self);
5263   if (clutter_actor_update_default_paint_volume (self, &volume))
5264     {
5265       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5266
5267       if (stage != NULL)
5268         {
5269           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5270           _clutter_paint_volume_copy_static (&volume, res);
5271         }
5272     }
5273
5274   clutter_paint_volume_free (&volume);
5275
5276   return res;
5277 }
5278
5279 static gboolean
5280 clutter_actor_real_has_overlaps (ClutterActor *self)
5281 {
5282   /* By default we'll assume that all actors need an offscreen redirect to get
5283    * the correct opacity. Actors such as ClutterTexture that would never need
5284    * an offscreen redirect can override this to return FALSE. */
5285   return TRUE;
5286 }
5287
5288 static void
5289 clutter_actor_real_destroy (ClutterActor *actor)
5290 {
5291   ClutterActorIter iter;
5292
5293   g_object_freeze_notify (G_OBJECT (actor));
5294
5295   clutter_actor_iter_init (&iter, actor);
5296   while (clutter_actor_iter_next (&iter, NULL))
5297     clutter_actor_iter_destroy (&iter);
5298
5299   g_object_thaw_notify (G_OBJECT (actor));
5300 }
5301
5302 static GObject *
5303 clutter_actor_constructor (GType gtype,
5304                            guint n_props,
5305                            GObjectConstructParam *props)
5306 {
5307   GObjectClass *gobject_class;
5308   ClutterActor *self;
5309   GObject *retval;
5310
5311   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5312   retval = gobject_class->constructor (gtype, n_props, props);
5313   self = CLUTTER_ACTOR (retval);
5314
5315   if (self->priv->layout_manager == NULL)
5316     {
5317       ClutterLayoutManager *default_layout;
5318
5319       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5320
5321       default_layout = clutter_fixed_layout_new ();
5322       clutter_actor_set_layout_manager (self, default_layout);
5323     }
5324
5325   return retval;
5326 }
5327
5328 static void
5329 clutter_actor_class_init (ClutterActorClass *klass)
5330 {
5331   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5332
5333   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5334   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5335   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5336   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5337
5338   object_class->constructor = clutter_actor_constructor;
5339   object_class->set_property = clutter_actor_set_property;
5340   object_class->get_property = clutter_actor_get_property;
5341   object_class->dispose = clutter_actor_dispose;
5342   object_class->finalize = clutter_actor_finalize;
5343
5344   klass->show = clutter_actor_real_show;
5345   klass->show_all = clutter_actor_show;
5346   klass->hide = clutter_actor_real_hide;
5347   klass->hide_all = clutter_actor_hide;
5348   klass->map = clutter_actor_real_map;
5349   klass->unmap = clutter_actor_real_unmap;
5350   klass->unrealize = clutter_actor_real_unrealize;
5351   klass->pick = clutter_actor_real_pick;
5352   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5353   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5354   klass->allocate = clutter_actor_real_allocate;
5355   klass->queue_redraw = clutter_actor_real_queue_redraw;
5356   klass->queue_relayout = clutter_actor_real_queue_relayout;
5357   klass->apply_transform = clutter_actor_real_apply_transform;
5358   klass->get_accessible = clutter_actor_real_get_accessible;
5359   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5360   klass->has_overlaps = clutter_actor_real_has_overlaps;
5361   klass->paint = clutter_actor_real_paint;
5362   klass->destroy = clutter_actor_real_destroy;
5363
5364   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5365
5366   /**
5367    * ClutterActor:x:
5368    *
5369    * X coordinate of the actor in pixels. If written, forces a fixed
5370    * position for the actor. If read, returns the fixed position if any,
5371    * otherwise the allocation if available, otherwise 0.
5372    *
5373    * The #ClutterActor:x property is animatable.
5374    */
5375   obj_props[PROP_X] =
5376     g_param_spec_float ("x",
5377                         P_("X coordinate"),
5378                         P_("X coordinate of the actor"),
5379                         -G_MAXFLOAT, G_MAXFLOAT,
5380                         0.0,
5381                         G_PARAM_READWRITE |
5382                         G_PARAM_STATIC_STRINGS |
5383                         CLUTTER_PARAM_ANIMATABLE);
5384
5385   /**
5386    * ClutterActor:y:
5387    *
5388    * Y coordinate of the actor in pixels. If written, forces a fixed
5389    * position for the actor.  If read, returns the fixed position if
5390    * any, otherwise the allocation if available, otherwise 0.
5391    *
5392    * The #ClutterActor:y property is animatable.
5393    */
5394   obj_props[PROP_Y] =
5395     g_param_spec_float ("y",
5396                         P_("Y coordinate"),
5397                         P_("Y coordinate of the actor"),
5398                         -G_MAXFLOAT, G_MAXFLOAT,
5399                         0.0,
5400                         G_PARAM_READWRITE |
5401                         G_PARAM_STATIC_STRINGS |
5402                         CLUTTER_PARAM_ANIMATABLE);
5403
5404   /**
5405    * ClutterActor:width:
5406    *
5407    * Width of the actor (in pixels). If written, forces the minimum and
5408    * natural size request of the actor to the given width. If read, returns
5409    * the allocated width if available, otherwise the width request.
5410    *
5411    * The #ClutterActor:width property is animatable.
5412    */
5413   obj_props[PROP_WIDTH] =
5414     g_param_spec_float ("width",
5415                         P_("Width"),
5416                         P_("Width of the actor"),
5417                         0.0, G_MAXFLOAT,
5418                         0.0,
5419                         G_PARAM_READWRITE |
5420                         G_PARAM_STATIC_STRINGS |
5421                         CLUTTER_PARAM_ANIMATABLE);
5422
5423   /**
5424    * ClutterActor:height:
5425    *
5426    * Height of the actor (in pixels).  If written, forces the minimum and
5427    * natural size request of the actor to the given height. If read, returns
5428    * the allocated height if available, otherwise the height request.
5429    *
5430    * The #ClutterActor:height property is animatable.
5431    */
5432   obj_props[PROP_HEIGHT] =
5433     g_param_spec_float ("height",
5434                         P_("Height"),
5435                         P_("Height of the actor"),
5436                         0.0, G_MAXFLOAT,
5437                         0.0,
5438                         G_PARAM_READWRITE |
5439                         G_PARAM_STATIC_STRINGS |
5440                         CLUTTER_PARAM_ANIMATABLE);
5441
5442   /**
5443    * ClutterActor:fixed-x:
5444    *
5445    * The fixed X position of the actor in pixels.
5446    *
5447    * Writing this property sets #ClutterActor:fixed-position-set
5448    * property as well, as a side effect
5449    *
5450    * Since: 0.8
5451    */
5452   obj_props[PROP_FIXED_X] =
5453     g_param_spec_float ("fixed-x",
5454                         P_("Fixed X"),
5455                         P_("Forced X position of the actor"),
5456                         -G_MAXFLOAT, G_MAXFLOAT,
5457                         0.0,
5458                         CLUTTER_PARAM_READWRITE);
5459
5460   /**
5461    * ClutterActor:fixed-y:
5462    *
5463    * The fixed Y position of the actor in pixels.
5464    *
5465    * Writing this property sets the #ClutterActor:fixed-position-set
5466    * property as well, as a side effect
5467    *
5468    * Since: 0.8
5469    */
5470   obj_props[PROP_FIXED_Y] =
5471     g_param_spec_float ("fixed-y",
5472                         P_("Fixed Y"),
5473                         P_("Forced Y position of the actor"),
5474                         -G_MAXFLOAT, G_MAXFLOAT,
5475                         0,
5476                         CLUTTER_PARAM_READWRITE);
5477
5478   /**
5479    * ClutterActor:fixed-position-set:
5480    *
5481    * This flag controls whether the #ClutterActor:fixed-x and
5482    * #ClutterActor:fixed-y properties are used
5483    *
5484    * Since: 0.8
5485    */
5486   obj_props[PROP_FIXED_POSITION_SET] =
5487     g_param_spec_boolean ("fixed-position-set",
5488                           P_("Fixed position set"),
5489                           P_("Whether to use fixed positioning for the actor"),
5490                           FALSE,
5491                           CLUTTER_PARAM_READWRITE);
5492
5493   /**
5494    * ClutterActor:min-width:
5495    *
5496    * A forced minimum width request for the actor, in pixels
5497    *
5498    * Writing this property sets the #ClutterActor:min-width-set property
5499    * as well, as a side effect.
5500    *
5501    *This property overrides the usual width request of the actor.
5502    *
5503    * Since: 0.8
5504    */
5505   obj_props[PROP_MIN_WIDTH] =
5506     g_param_spec_float ("min-width",
5507                         P_("Min Width"),
5508                         P_("Forced minimum width request for the actor"),
5509                         0.0, G_MAXFLOAT,
5510                         0.0,
5511                         CLUTTER_PARAM_READWRITE);
5512
5513   /**
5514    * ClutterActor:min-height:
5515    *
5516    * A forced minimum height request for the actor, in pixels
5517    *
5518    * Writing this property sets the #ClutterActor:min-height-set property
5519    * as well, as a side effect. This property overrides the usual height
5520    * request of the actor.
5521    *
5522    * Since: 0.8
5523    */
5524   obj_props[PROP_MIN_HEIGHT] =
5525     g_param_spec_float ("min-height",
5526                         P_("Min Height"),
5527                         P_("Forced minimum height request for the actor"),
5528                         0.0, G_MAXFLOAT,
5529                         0.0,
5530                         CLUTTER_PARAM_READWRITE);
5531
5532   /**
5533    * ClutterActor:natural-width:
5534    *
5535    * A forced natural width request for the actor, in pixels
5536    *
5537    * Writing this property sets the #ClutterActor:natural-width-set
5538    * property as well, as a side effect. This property overrides the
5539    * usual width request of the actor
5540    *
5541    * Since: 0.8
5542    */
5543   obj_props[PROP_NATURAL_WIDTH] =
5544     g_param_spec_float ("natural-width",
5545                         P_("Natural Width"),
5546                         P_("Forced natural width request for the actor"),
5547                         0.0, G_MAXFLOAT,
5548                         0.0,
5549                         CLUTTER_PARAM_READWRITE);
5550
5551   /**
5552    * ClutterActor:natural-height:
5553    *
5554    * A forced natural height request for the actor, in pixels
5555    *
5556    * Writing this property sets the #ClutterActor:natural-height-set
5557    * property as well, as a side effect. This property overrides the
5558    * usual height request of the actor
5559    *
5560    * Since: 0.8
5561    */
5562   obj_props[PROP_NATURAL_HEIGHT] =
5563     g_param_spec_float ("natural-height",
5564                         P_("Natural Height"),
5565                         P_("Forced natural height request for the actor"),
5566                         0.0, G_MAXFLOAT,
5567                         0.0,
5568                         CLUTTER_PARAM_READWRITE);
5569
5570   /**
5571    * ClutterActor:min-width-set:
5572    *
5573    * This flag controls whether the #ClutterActor:min-width property
5574    * is used
5575    *
5576    * Since: 0.8
5577    */
5578   obj_props[PROP_MIN_WIDTH_SET] =
5579     g_param_spec_boolean ("min-width-set",
5580                           P_("Minimum width set"),
5581                           P_("Whether to use the min-width property"),
5582                           FALSE,
5583                           CLUTTER_PARAM_READWRITE);
5584
5585   /**
5586    * ClutterActor:min-height-set:
5587    *
5588    * This flag controls whether the #ClutterActor:min-height property
5589    * is used
5590    *
5591    * Since: 0.8
5592    */
5593   obj_props[PROP_MIN_HEIGHT_SET] =
5594     g_param_spec_boolean ("min-height-set",
5595                           P_("Minimum height set"),
5596                           P_("Whether to use the min-height property"),
5597                           FALSE,
5598                           CLUTTER_PARAM_READWRITE);
5599
5600   /**
5601    * ClutterActor:natural-width-set:
5602    *
5603    * This flag controls whether the #ClutterActor:natural-width property
5604    * is used
5605    *
5606    * Since: 0.8
5607    */
5608   obj_props[PROP_NATURAL_WIDTH_SET] =
5609     g_param_spec_boolean ("natural-width-set",
5610                           P_("Natural width set"),
5611                           P_("Whether to use the natural-width property"),
5612                           FALSE,
5613                           CLUTTER_PARAM_READWRITE);
5614
5615   /**
5616    * ClutterActor:natural-height-set:
5617    *
5618    * This flag controls whether the #ClutterActor:natural-height property
5619    * is used
5620    *
5621    * Since: 0.8
5622    */
5623   obj_props[PROP_NATURAL_HEIGHT_SET] =
5624     g_param_spec_boolean ("natural-height-set",
5625                           P_("Natural height set"),
5626                           P_("Whether to use the natural-height property"),
5627                           FALSE,
5628                           CLUTTER_PARAM_READWRITE);
5629
5630   /**
5631    * ClutterActor:allocation:
5632    *
5633    * The allocation for the actor, in pixels
5634    *
5635    * This is property is read-only, but you might monitor it to know when an
5636    * actor moves or resizes
5637    *
5638    * Since: 0.8
5639    */
5640   obj_props[PROP_ALLOCATION] =
5641     g_param_spec_boxed ("allocation",
5642                         P_("Allocation"),
5643                         P_("The actor's allocation"),
5644                         CLUTTER_TYPE_ACTOR_BOX,
5645                         CLUTTER_PARAM_READABLE);
5646
5647   /**
5648    * ClutterActor:request-mode:
5649    *
5650    * Request mode for the #ClutterActor. The request mode determines the
5651    * type of geometry management used by the actor, either height for width
5652    * (the default) or width for height.
5653    *
5654    * For actors implementing height for width, the parent container should get
5655    * the preferred width first, and then the preferred height for that width.
5656    *
5657    * For actors implementing width for height, the parent container should get
5658    * the preferred height first, and then the preferred width for that height.
5659    *
5660    * For instance:
5661    *
5662    * |[
5663    *   ClutterRequestMode mode;
5664    *   gfloat natural_width, min_width;
5665    *   gfloat natural_height, min_height;
5666    *
5667    *   mode = clutter_actor_get_request_mode (child);
5668    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5669    *     {
5670    *       clutter_actor_get_preferred_width (child, -1,
5671    *                                          &amp;min_width,
5672    *                                          &amp;natural_width);
5673    *       clutter_actor_get_preferred_height (child, natural_width,
5674    *                                           &amp;min_height,
5675    *                                           &amp;natural_height);
5676    *     }
5677    *   else
5678    *     {
5679    *       clutter_actor_get_preferred_height (child, -1,
5680    *                                           &amp;min_height,
5681    *                                           &amp;natural_height);
5682    *       clutter_actor_get_preferred_width (child, natural_height,
5683    *                                          &amp;min_width,
5684    *                                          &amp;natural_width);
5685    *     }
5686    * ]|
5687    *
5688    * will retrieve the minimum and natural width and height depending on the
5689    * preferred request mode of the #ClutterActor "child".
5690    *
5691    * The clutter_actor_get_preferred_size() function will implement this
5692    * check for you.
5693    *
5694    * Since: 0.8
5695    */
5696   obj_props[PROP_REQUEST_MODE] =
5697     g_param_spec_enum ("request-mode",
5698                        P_("Request Mode"),
5699                        P_("The actor's request mode"),
5700                        CLUTTER_TYPE_REQUEST_MODE,
5701                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5702                        CLUTTER_PARAM_READWRITE);
5703
5704   /**
5705    * ClutterActor:depth:
5706    *
5707    * The position of the actor on the Z axis.
5708    *
5709    * The #ClutterActor:depth property is relative to the parent's
5710    * modelview matrix.
5711    *
5712    * The #ClutterActor:depth property is animatable.
5713    *
5714    * Since: 0.6
5715    */
5716   obj_props[PROP_DEPTH] =
5717     g_param_spec_float ("depth",
5718                         P_("Depth"),
5719                         P_("Position on the Z axis"),
5720                         -G_MAXFLOAT, G_MAXFLOAT,
5721                         0.0,
5722                         G_PARAM_READWRITE |
5723                         G_PARAM_STATIC_STRINGS |
5724                         CLUTTER_PARAM_ANIMATABLE);
5725
5726   /**
5727    * ClutterActor:opacity:
5728    *
5729    * Opacity of an actor, between 0 (fully transparent) and
5730    * 255 (fully opaque)
5731    *
5732    * The #ClutterActor:opacity property is animatable.
5733    */
5734   obj_props[PROP_OPACITY] =
5735     g_param_spec_uint ("opacity",
5736                        P_("Opacity"),
5737                        P_("Opacity of an actor"),
5738                        0, 255,
5739                        255,
5740                        G_PARAM_READWRITE |
5741                        G_PARAM_STATIC_STRINGS |
5742                        CLUTTER_PARAM_ANIMATABLE);
5743
5744   /**
5745    * ClutterActor:offscreen-redirect:
5746    *
5747    * Determines the conditions in which the actor will be redirected
5748    * to an offscreen framebuffer while being painted. For example this
5749    * can be used to cache an actor in a framebuffer or for improved
5750    * handling of transparent actors. See
5751    * clutter_actor_set_offscreen_redirect() for details.
5752    *
5753    * Since: 1.8
5754    */
5755   obj_props[PROP_OFFSCREEN_REDIRECT] =
5756     g_param_spec_flags ("offscreen-redirect",
5757                         P_("Offscreen redirect"),
5758                         P_("Flags controlling when to flatten the actor into a single image"),
5759                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5760                         0,
5761                         CLUTTER_PARAM_READWRITE);
5762
5763   /**
5764    * ClutterActor:visible:
5765    *
5766    * Whether the actor is set to be visible or not
5767    *
5768    * See also #ClutterActor:mapped
5769    */
5770   obj_props[PROP_VISIBLE] =
5771     g_param_spec_boolean ("visible",
5772                           P_("Visible"),
5773                           P_("Whether the actor is visible or not"),
5774                           FALSE,
5775                           CLUTTER_PARAM_READWRITE);
5776
5777   /**
5778    * ClutterActor:mapped:
5779    *
5780    * Whether the actor is mapped (will be painted when the stage
5781    * to which it belongs is mapped)
5782    *
5783    * Since: 1.0
5784    */
5785   obj_props[PROP_MAPPED] =
5786     g_param_spec_boolean ("mapped",
5787                           P_("Mapped"),
5788                           P_("Whether the actor will be painted"),
5789                           FALSE,
5790                           CLUTTER_PARAM_READABLE);
5791
5792   /**
5793    * ClutterActor:realized:
5794    *
5795    * Whether the actor has been realized
5796    *
5797    * Since: 1.0
5798    */
5799   obj_props[PROP_REALIZED] =
5800     g_param_spec_boolean ("realized",
5801                           P_("Realized"),
5802                           P_("Whether the actor has been realized"),
5803                           FALSE,
5804                           CLUTTER_PARAM_READABLE);
5805
5806   /**
5807    * ClutterActor:reactive:
5808    *
5809    * Whether the actor is reactive to events or not
5810    *
5811    * Only reactive actors will emit event-related signals
5812    *
5813    * Since: 0.6
5814    */
5815   obj_props[PROP_REACTIVE] =
5816     g_param_spec_boolean ("reactive",
5817                           P_("Reactive"),
5818                           P_("Whether the actor is reactive to events"),
5819                           FALSE,
5820                           CLUTTER_PARAM_READWRITE);
5821
5822   /**
5823    * ClutterActor:has-clip:
5824    *
5825    * Whether the actor has the #ClutterActor:clip property set or not
5826    */
5827   obj_props[PROP_HAS_CLIP] =
5828     g_param_spec_boolean ("has-clip",
5829                           P_("Has Clip"),
5830                           P_("Whether the actor has a clip set"),
5831                           FALSE,
5832                           CLUTTER_PARAM_READABLE);
5833
5834   /**
5835    * ClutterActor:clip:
5836    *
5837    * The clip region for the actor, in actor-relative coordinates
5838    *
5839    * Every part of the actor outside the clip region will not be
5840    * painted
5841    */
5842   obj_props[PROP_CLIP] =
5843     g_param_spec_boxed ("clip",
5844                         P_("Clip"),
5845                         P_("The clip region for the actor"),
5846                         CLUTTER_TYPE_GEOMETRY,
5847                         CLUTTER_PARAM_READWRITE);
5848
5849   /**
5850    * ClutterActor:name:
5851    *
5852    * The name of the actor
5853    *
5854    * Since: 0.2
5855    */
5856   obj_props[PROP_NAME] =
5857     g_param_spec_string ("name",
5858                          P_("Name"),
5859                          P_("Name of the actor"),
5860                          NULL,
5861                          CLUTTER_PARAM_READWRITE);
5862
5863   /**
5864    * ClutterActor:scale-x:
5865    *
5866    * The horizontal scale of the actor.
5867    *
5868    * The #ClutterActor:scale-x property is animatable.
5869    *
5870    * Since: 0.6
5871    */
5872   obj_props[PROP_SCALE_X] =
5873     g_param_spec_double ("scale-x",
5874                          P_("Scale X"),
5875                          P_("Scale factor on the X axis"),
5876                          0.0, G_MAXDOUBLE,
5877                          1.0,
5878                          G_PARAM_READWRITE |
5879                          G_PARAM_STATIC_STRINGS |
5880                          CLUTTER_PARAM_ANIMATABLE);
5881
5882   /**
5883    * ClutterActor:scale-y:
5884    *
5885    * The vertical scale of the actor.
5886    *
5887    * The #ClutterActor:scale-y property is animatable.
5888    *
5889    * Since: 0.6
5890    */
5891   obj_props[PROP_SCALE_Y] =
5892     g_param_spec_double ("scale-y",
5893                          P_("Scale Y"),
5894                          P_("Scale factor on the Y axis"),
5895                          0.0, G_MAXDOUBLE,
5896                          1.0,
5897                          G_PARAM_READWRITE |
5898                          G_PARAM_STATIC_STRINGS |
5899                          CLUTTER_PARAM_ANIMATABLE);
5900
5901   /**
5902    * ClutterActor:scale-center-x:
5903    *
5904    * The horizontal center point for scaling
5905    *
5906    * Since: 1.0
5907    */
5908   obj_props[PROP_SCALE_CENTER_X] =
5909     g_param_spec_float ("scale-center-x",
5910                         P_("Scale Center X"),
5911                         P_("Horizontal scale center"),
5912                         -G_MAXFLOAT, G_MAXFLOAT,
5913                         0.0,
5914                         CLUTTER_PARAM_READWRITE);
5915
5916   /**
5917    * ClutterActor:scale-center-y:
5918    *
5919    * The vertical center point for scaling
5920    *
5921    * Since: 1.0
5922    */
5923   obj_props[PROP_SCALE_CENTER_Y] =
5924     g_param_spec_float ("scale-center-y",
5925                         P_("Scale Center Y"),
5926                         P_("Vertical scale center"),
5927                         -G_MAXFLOAT, G_MAXFLOAT,
5928                         0.0,
5929                         CLUTTER_PARAM_READWRITE);
5930
5931   /**
5932    * ClutterActor:scale-gravity:
5933    *
5934    * The center point for scaling expressed as a #ClutterGravity
5935    *
5936    * Since: 1.0
5937    */
5938   obj_props[PROP_SCALE_GRAVITY] =
5939     g_param_spec_enum ("scale-gravity",
5940                        P_("Scale Gravity"),
5941                        P_("The center of scaling"),
5942                        CLUTTER_TYPE_GRAVITY,
5943                        CLUTTER_GRAVITY_NONE,
5944                        CLUTTER_PARAM_READWRITE);
5945
5946   /**
5947    * ClutterActor:rotation-angle-x:
5948    *
5949    * The rotation angle on the X axis.
5950    *
5951    * The #ClutterActor:rotation-angle-x property is animatable.
5952    *
5953    * Since: 0.6
5954    */
5955   obj_props[PROP_ROTATION_ANGLE_X] =
5956     g_param_spec_double ("rotation-angle-x",
5957                          P_("Rotation Angle X"),
5958                          P_("The rotation angle on the X axis"),
5959                          -G_MAXDOUBLE, G_MAXDOUBLE,
5960                          0.0,
5961                          G_PARAM_READWRITE |
5962                          G_PARAM_STATIC_STRINGS |
5963                          CLUTTER_PARAM_ANIMATABLE);
5964
5965   /**
5966    * ClutterActor:rotation-angle-y:
5967    *
5968    * The rotation angle on the Y axis
5969    *
5970    * The #ClutterActor:rotation-angle-y property is animatable.
5971    *
5972    * Since: 0.6
5973    */
5974   obj_props[PROP_ROTATION_ANGLE_Y] =
5975     g_param_spec_double ("rotation-angle-y",
5976                          P_("Rotation Angle Y"),
5977                          P_("The rotation angle on the Y axis"),
5978                          -G_MAXDOUBLE, G_MAXDOUBLE,
5979                          0.0,
5980                          G_PARAM_READWRITE |
5981                          G_PARAM_STATIC_STRINGS |
5982                          CLUTTER_PARAM_ANIMATABLE);
5983
5984   /**
5985    * ClutterActor:rotation-angle-z:
5986    *
5987    * The rotation angle on the Z axis
5988    *
5989    * The #ClutterActor:rotation-angle-z property is animatable.
5990    *
5991    * Since: 0.6
5992    */
5993   obj_props[PROP_ROTATION_ANGLE_Z] =
5994     g_param_spec_double ("rotation-angle-z",
5995                          P_("Rotation Angle Z"),
5996                          P_("The rotation angle on the Z axis"),
5997                          -G_MAXDOUBLE, G_MAXDOUBLE,
5998                          0.0,
5999                          G_PARAM_READWRITE |
6000                          G_PARAM_STATIC_STRINGS |
6001                          CLUTTER_PARAM_ANIMATABLE);
6002
6003   /**
6004    * ClutterActor:rotation-center-x:
6005    *
6006    * The rotation center on the X axis.
6007    *
6008    * Since: 0.6
6009    */
6010   obj_props[PROP_ROTATION_CENTER_X] =
6011     g_param_spec_boxed ("rotation-center-x",
6012                         P_("Rotation Center X"),
6013                         P_("The rotation center on the X axis"),
6014                         CLUTTER_TYPE_VERTEX,
6015                         CLUTTER_PARAM_READWRITE);
6016
6017   /**
6018    * ClutterActor:rotation-center-y:
6019    *
6020    * The rotation center on the Y axis.
6021    *
6022    * Since: 0.6
6023    */
6024   obj_props[PROP_ROTATION_CENTER_Y] =
6025     g_param_spec_boxed ("rotation-center-y",
6026                         P_("Rotation Center Y"),
6027                         P_("The rotation center on the Y axis"),
6028                         CLUTTER_TYPE_VERTEX,
6029                         CLUTTER_PARAM_READWRITE);
6030
6031   /**
6032    * ClutterActor:rotation-center-z:
6033    *
6034    * The rotation center on the Z axis.
6035    *
6036    * Since: 0.6
6037    */
6038   obj_props[PROP_ROTATION_CENTER_Z] =
6039     g_param_spec_boxed ("rotation-center-z",
6040                         P_("Rotation Center Z"),
6041                         P_("The rotation center on the Z axis"),
6042                         CLUTTER_TYPE_VERTEX,
6043                         CLUTTER_PARAM_READWRITE);
6044
6045   /**
6046    * ClutterActor:rotation-center-z-gravity:
6047    *
6048    * The rotation center on the Z axis expressed as a #ClutterGravity.
6049    *
6050    * Since: 1.0
6051    */
6052   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6053     g_param_spec_enum ("rotation-center-z-gravity",
6054                        P_("Rotation Center Z Gravity"),
6055                        P_("Center point for rotation around the Z axis"),
6056                        CLUTTER_TYPE_GRAVITY,
6057                        CLUTTER_GRAVITY_NONE,
6058                        CLUTTER_PARAM_READWRITE);
6059
6060   /**
6061    * ClutterActor:anchor-x:
6062    *
6063    * The X coordinate of an actor's anchor point, relative to
6064    * the actor coordinate space, in pixels
6065    *
6066    * Since: 0.8
6067    */
6068   obj_props[PROP_ANCHOR_X] =
6069     g_param_spec_float ("anchor-x",
6070                         P_("Anchor X"),
6071                         P_("X coordinate of the anchor point"),
6072                         -G_MAXFLOAT, G_MAXFLOAT,
6073                         0,
6074                         CLUTTER_PARAM_READWRITE);
6075
6076   /**
6077    * ClutterActor:anchor-y:
6078    *
6079    * The Y coordinate of an actor's anchor point, relative to
6080    * the actor coordinate space, in pixels
6081    *
6082    * Since: 0.8
6083    */
6084   obj_props[PROP_ANCHOR_Y] =
6085     g_param_spec_float ("anchor-y",
6086                         P_("Anchor Y"),
6087                         P_("Y coordinate of the anchor point"),
6088                         -G_MAXFLOAT, G_MAXFLOAT,
6089                         0,
6090                         CLUTTER_PARAM_READWRITE);
6091
6092   /**
6093    * ClutterActor:anchor-gravity:
6094    *
6095    * The anchor point expressed as a #ClutterGravity
6096    *
6097    * Since: 1.0
6098    */
6099   obj_props[PROP_ANCHOR_GRAVITY] =
6100     g_param_spec_enum ("anchor-gravity",
6101                        P_("Anchor Gravity"),
6102                        P_("The anchor point as a ClutterGravity"),
6103                        CLUTTER_TYPE_GRAVITY,
6104                        CLUTTER_GRAVITY_NONE,
6105                        CLUTTER_PARAM_READWRITE);
6106
6107   /**
6108    * ClutterActor:show-on-set-parent:
6109    *
6110    * If %TRUE, the actor is automatically shown when parented.
6111    *
6112    * Calling clutter_actor_hide() on an actor which has not been
6113    * parented will set this property to %FALSE as a side effect.
6114    *
6115    * Since: 0.8
6116    */
6117   obj_props[PROP_SHOW_ON_SET_PARENT] =
6118     g_param_spec_boolean ("show-on-set-parent",
6119                           P_("Show on set parent"),
6120                           P_("Whether the actor is shown when parented"),
6121                           TRUE,
6122                           CLUTTER_PARAM_READWRITE);
6123
6124   /**
6125    * ClutterActor:clip-to-allocation:
6126    *
6127    * Whether the clip region should track the allocated area
6128    * of the actor.
6129    *
6130    * This property is ignored if a clip area has been explicitly
6131    * set using clutter_actor_set_clip().
6132    *
6133    * Since: 1.0
6134    */
6135   obj_props[PROP_CLIP_TO_ALLOCATION] =
6136     g_param_spec_boolean ("clip-to-allocation",
6137                           P_("Clip to Allocation"),
6138                           P_("Sets the clip region to track the actor's allocation"),
6139                           FALSE,
6140                           CLUTTER_PARAM_READWRITE);
6141
6142   /**
6143    * ClutterActor:text-direction:
6144    *
6145    * The direction of the text inside a #ClutterActor.
6146    *
6147    * Since: 1.0
6148    */
6149   obj_props[PROP_TEXT_DIRECTION] =
6150     g_param_spec_enum ("text-direction",
6151                        P_("Text Direction"),
6152                        P_("Direction of the text"),
6153                        CLUTTER_TYPE_TEXT_DIRECTION,
6154                        CLUTTER_TEXT_DIRECTION_LTR,
6155                        CLUTTER_PARAM_READWRITE);
6156
6157   /**
6158    * ClutterActor:has-pointer:
6159    *
6160    * Whether the actor contains the pointer of a #ClutterInputDevice
6161    * or not.
6162    *
6163    * Since: 1.2
6164    */
6165   obj_props[PROP_HAS_POINTER] =
6166     g_param_spec_boolean ("has-pointer",
6167                           P_("Has Pointer"),
6168                           P_("Whether the actor contains the pointer of an input device"),
6169                           FALSE,
6170                           CLUTTER_PARAM_READABLE);
6171
6172   /**
6173    * ClutterActor:actions:
6174    *
6175    * Adds a #ClutterAction to the actor
6176    *
6177    * Since: 1.4
6178    */
6179   obj_props[PROP_ACTIONS] =
6180     g_param_spec_object ("actions",
6181                          P_("Actions"),
6182                          P_("Adds an action to the actor"),
6183                          CLUTTER_TYPE_ACTION,
6184                          CLUTTER_PARAM_WRITABLE);
6185
6186   /**
6187    * ClutterActor:constraints:
6188    *
6189    * Adds a #ClutterConstraint to the actor
6190    *
6191    * Since: 1.4
6192    */
6193   obj_props[PROP_CONSTRAINTS] =
6194     g_param_spec_object ("constraints",
6195                          P_("Constraints"),
6196                          P_("Adds a constraint to the actor"),
6197                          CLUTTER_TYPE_CONSTRAINT,
6198                          CLUTTER_PARAM_WRITABLE);
6199
6200   /**
6201    * ClutterActor:effect:
6202    *
6203    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6204    *
6205    * Since: 1.4
6206    */
6207   obj_props[PROP_EFFECT] =
6208     g_param_spec_object ("effect",
6209                          P_("Effect"),
6210                          P_("Add an effect to be applied on the actor"),
6211                          CLUTTER_TYPE_EFFECT,
6212                          CLUTTER_PARAM_WRITABLE);
6213
6214   /**
6215    * ClutterActor:layout-manager:
6216    *
6217    * A delegate object for controlling the layout of the children of
6218    * an actor.
6219    *
6220    * Since: 1.10
6221    */
6222   obj_props[PROP_LAYOUT_MANAGER] =
6223     g_param_spec_object ("layout-manager",
6224                          P_("Layout Manager"),
6225                          P_("The object controlling the layout of an actor's children"),
6226                          CLUTTER_TYPE_LAYOUT_MANAGER,
6227                          CLUTTER_PARAM_READWRITE);
6228
6229
6230   /**
6231    * ClutterActor:x-align:
6232    *
6233    * The alignment of an actor on the X axis, if the actor has been given
6234    * extra space for its allocation.
6235    *
6236    * Since: 1.10
6237    */
6238   obj_props[PROP_X_ALIGN] =
6239     g_param_spec_enum ("x-align",
6240                        P_("X Alignment"),
6241                        P_("The alignment of the actor on the X axis within its allocation"),
6242                        CLUTTER_TYPE_ACTOR_ALIGN,
6243                        CLUTTER_ACTOR_ALIGN_FILL,
6244                        CLUTTER_PARAM_READWRITE);
6245
6246   /**
6247    * ClutterActor:y-align:
6248    *
6249    * The alignment of an actor on the Y axis, if the actor has been given
6250    * extra space for its allocation.
6251    *
6252    * Since: 1.10
6253    */
6254   obj_props[PROP_Y_ALIGN] =
6255     g_param_spec_enum ("y-align",
6256                        P_("Y Alignment"),
6257                        P_("The alignment of the actor on the Y axis within its allocation"),
6258                        CLUTTER_TYPE_ACTOR_ALIGN,
6259                        CLUTTER_ACTOR_ALIGN_FILL,
6260                        CLUTTER_PARAM_READWRITE);
6261
6262   /**
6263    * ClutterActor:margin-top:
6264    *
6265    * The margin (in pixels) from the top of the actor.
6266    *
6267    * This property adds a margin to the actor's preferred size; the margin
6268    * will be automatically taken into account when allocating the actor.
6269    *
6270    * Since: 1.10
6271    */
6272   obj_props[PROP_MARGIN_TOP] =
6273     g_param_spec_float ("margin-top",
6274                         P_("Margin Top"),
6275                         P_("Extra space at the top"),
6276                         0.0, G_MAXFLOAT,
6277                         0.0,
6278                         CLUTTER_PARAM_READWRITE);
6279
6280   /**
6281    * ClutterActor:margin-bottom:
6282    *
6283    * The margin (in pixels) from the bottom of the actor.
6284    *
6285    * This property adds a margin to the actor's preferred size; the margin
6286    * will be automatically taken into account when allocating the actor.
6287    *
6288    * Since: 1.10
6289    */
6290   obj_props[PROP_MARGIN_BOTTOM] =
6291     g_param_spec_float ("margin-bottom",
6292                         P_("Margin Bottom"),
6293                         P_("Extra space at the bottom"),
6294                         0.0, G_MAXFLOAT,
6295                         0.0,
6296                         CLUTTER_PARAM_READWRITE);
6297
6298   /**
6299    * ClutterActor:margin-left:
6300    *
6301    * The margin (in pixels) from the left of the actor.
6302    *
6303    * This property adds a margin to the actor's preferred size; the margin
6304    * will be automatically taken into account when allocating the actor.
6305    *
6306    * Since: 1.10
6307    */
6308   obj_props[PROP_MARGIN_LEFT] =
6309     g_param_spec_float ("margin-left",
6310                         P_("Margin Left"),
6311                         P_("Extra space at the left"),
6312                         0.0, G_MAXFLOAT,
6313                         0.0,
6314                         CLUTTER_PARAM_READWRITE);
6315
6316   /**
6317    * ClutterActor:margin-right:
6318    *
6319    * The margin (in pixels) from the right of the actor.
6320    *
6321    * This property adds a margin to the actor's preferred size; the margin
6322    * will be automatically taken into account when allocating the actor.
6323    *
6324    * Since: 1.10
6325    */
6326   obj_props[PROP_MARGIN_RIGHT] =
6327     g_param_spec_float ("margin-right",
6328                         P_("Margin Right"),
6329                         P_("Extra space at the right"),
6330                         0.0, G_MAXFLOAT,
6331                         0.0,
6332                         CLUTTER_PARAM_READWRITE);
6333
6334   /**
6335    * ClutterActor:background-color-set:
6336    *
6337    * Whether the #ClutterActor:background-color property has been set.
6338    *
6339    * Since: 1.10
6340    */
6341   obj_props[PROP_BACKGROUND_COLOR_SET] =
6342     g_param_spec_boolean ("background-color-set",
6343                           P_("Background Color Set"),
6344                           P_("Whether the background color is set"),
6345                           FALSE,
6346                           CLUTTER_PARAM_READABLE);
6347
6348   /**
6349    * ClutterActor:background-color:
6350    *
6351    * Paints a solid fill of the actor's allocation using the specified
6352    * color.
6353    *
6354    * The #ClutterActor:background-color property is animatable.
6355    *
6356    * Since: 1.10
6357    */
6358   obj_props[PROP_BACKGROUND_COLOR] =
6359     clutter_param_spec_color ("background-color",
6360                               P_("Background color"),
6361                               P_("The actor's background color"),
6362                               CLUTTER_COLOR_Transparent,
6363                               G_PARAM_READWRITE |
6364                               G_PARAM_STATIC_STRINGS |
6365                               CLUTTER_PARAM_ANIMATABLE);
6366
6367   /**
6368    * ClutterActor:first-child:
6369    *
6370    * The actor's first child.
6371    *
6372    * Since: 1.10
6373    */
6374   obj_props[PROP_FIRST_CHILD] =
6375     g_param_spec_object ("first-child",
6376                          P_("First Child"),
6377                          P_("The actor's first child"),
6378                          CLUTTER_TYPE_ACTOR,
6379                          CLUTTER_PARAM_READABLE);
6380
6381   /**
6382    * ClutterActor:last-child:
6383    *
6384    * The actor's last child.
6385    *
6386    * Since: 1.10
6387    */
6388   obj_props[PROP_LAST_CHILD] =
6389     g_param_spec_object ("last-child",
6390                          P_("Last Child"),
6391                          P_("The actor's last child"),
6392                          CLUTTER_TYPE_ACTOR,
6393                          CLUTTER_PARAM_READABLE);
6394
6395   /**
6396    * ClutterActor:content:
6397    *
6398    * The #ClutterContent implementation that controls the content
6399    * of the actor.
6400    *
6401    * Since: 1.10
6402    */
6403   obj_props[PROP_CONTENT] =
6404     g_param_spec_object ("content",
6405                          P_("Content"),
6406                          P_("Delegate object for painting the actor's content"),
6407                          CLUTTER_TYPE_CONTENT,
6408                          CLUTTER_PARAM_READWRITE);
6409
6410   /**
6411    * ClutterActor:content-gravity:
6412    *
6413    * The alignment that should be honoured by the #ClutterContent
6414    * set with the #ClutterActor:content property.
6415    *
6416    * Changing the value of this property will change the bounding box of
6417    * the content; you can use the #ClutterActor:content-box property to
6418    * get the position and size of the content within the actor's
6419    * allocation.
6420    *
6421    * This property is meaningful only for #ClutterContent implementations
6422    * that have a preferred size, and if the preferred size is smaller than
6423    * the actor's allocation.
6424    *
6425    * Since: 1.10
6426    */
6427   obj_props[PROP_CONTENT_GRAVITY] =
6428     g_param_spec_enum ("content-gravity",
6429                        P_("Content Gravity"),
6430                        P_("Alignment of the actor's content"),
6431                        CLUTTER_TYPE_CONTENT_GRAVITY,
6432                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6433                        CLUTTER_PARAM_READWRITE);
6434
6435   /**
6436    * ClutterActor:content-box:
6437    *
6438    * The bounding box for the #ClutterContent used by the actor.
6439    *
6440    * The value of this property is controlled by the #ClutterActor:allocation
6441    * and #ClutterActor:content-gravity properties of #ClutterActor.
6442    *
6443    * The bounding box for the content is guaranteed to never exceed the
6444    * allocation's of the actor.
6445    *
6446    * Since: 1.10
6447    */
6448   obj_props[PROP_CONTENT_BOX] =
6449     g_param_spec_boxed ("content-box",
6450                         P_("Content Box"),
6451                         P_("The bounding box of the actor's content"),
6452                         CLUTTER_TYPE_ACTOR_BOX,
6453                         CLUTTER_PARAM_READABLE);
6454
6455   obj_props[PROP_MINIFICATION_FILTER] =
6456     g_param_spec_enum ("minification-filter",
6457                        P_("Minification Filter"),
6458                        P_("The filter used when reducing the size of the content"),
6459                        CLUTTER_TYPE_SCALING_FILTER,
6460                        CLUTTER_SCALING_FILTER_LINEAR,
6461                        CLUTTER_PARAM_READWRITE);
6462
6463   obj_props[PROP_MAGNIFICATION_FILTER] =
6464     g_param_spec_enum ("magnification-filter",
6465                        P_("Magnification Filter"),
6466                        P_("The filter used when increasing the size of the content"),
6467                        CLUTTER_TYPE_SCALING_FILTER,
6468                        CLUTTER_SCALING_FILTER_LINEAR,
6469                        CLUTTER_PARAM_READWRITE);
6470
6471   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6472
6473   /**
6474    * ClutterActor::destroy:
6475    * @actor: the #ClutterActor which emitted the signal
6476    *
6477    * The ::destroy signal notifies that all references held on the
6478    * actor which emitted it should be released.
6479    *
6480    * The ::destroy signal should be used by all holders of a reference
6481    * on @actor.
6482    *
6483    * This signal might result in the finalization of the #ClutterActor
6484    * if all references are released.
6485    *
6486    * Composite actors and actors implementing the #ClutterContainer
6487    * interface should override the default implementation of the
6488    * class handler of this signal and call clutter_actor_destroy() on
6489    * their children. When overriding the default class handler, it is
6490    * required to chain up to the parent's implementation.
6491    *
6492    * Since: 0.2
6493    */
6494   actor_signals[DESTROY] =
6495     g_signal_new (I_("destroy"),
6496                   G_TYPE_FROM_CLASS (object_class),
6497                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6498                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6499                   NULL, NULL,
6500                   _clutter_marshal_VOID__VOID,
6501                   G_TYPE_NONE, 0);
6502   /**
6503    * ClutterActor::show:
6504    * @actor: the object which received the signal
6505    *
6506    * The ::show signal is emitted when an actor is visible and
6507    * rendered on the stage.
6508    *
6509    * Since: 0.2
6510    */
6511   actor_signals[SHOW] =
6512     g_signal_new (I_("show"),
6513                   G_TYPE_FROM_CLASS (object_class),
6514                   G_SIGNAL_RUN_FIRST,
6515                   G_STRUCT_OFFSET (ClutterActorClass, show),
6516                   NULL, NULL,
6517                   _clutter_marshal_VOID__VOID,
6518                   G_TYPE_NONE, 0);
6519   /**
6520    * ClutterActor::hide:
6521    * @actor: the object which received the signal
6522    *
6523    * The ::hide signal is emitted when an actor is no longer rendered
6524    * on the stage.
6525    *
6526    * Since: 0.2
6527    */
6528   actor_signals[HIDE] =
6529     g_signal_new (I_("hide"),
6530                   G_TYPE_FROM_CLASS (object_class),
6531                   G_SIGNAL_RUN_FIRST,
6532                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6533                   NULL, NULL,
6534                   _clutter_marshal_VOID__VOID,
6535                   G_TYPE_NONE, 0);
6536   /**
6537    * ClutterActor::parent-set:
6538    * @actor: the object which received the signal
6539    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6540    *
6541    * This signal is emitted when the parent of the actor changes.
6542    *
6543    * Since: 0.2
6544    */
6545   actor_signals[PARENT_SET] =
6546     g_signal_new (I_("parent-set"),
6547                   G_TYPE_FROM_CLASS (object_class),
6548                   G_SIGNAL_RUN_LAST,
6549                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6550                   NULL, NULL,
6551                   _clutter_marshal_VOID__OBJECT,
6552                   G_TYPE_NONE, 1,
6553                   CLUTTER_TYPE_ACTOR);
6554
6555   /**
6556    * ClutterActor::queue-redraw:
6557    * @actor: the actor we're bubbling the redraw request through
6558    * @origin: the actor which initiated the redraw request
6559    *
6560    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6561    * is called on @origin.
6562    *
6563    * The default implementation for #ClutterActor chains up to the
6564    * parent actor and queues a redraw on the parent, thus "bubbling"
6565    * the redraw queue up through the actor graph. The default
6566    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6567    * in a main loop idle handler.
6568    *
6569    * Note that the @origin actor may be the stage, or a container; it
6570    * does not have to be a leaf node in the actor graph.
6571    *
6572    * Toolkits embedding a #ClutterStage which require a redraw and
6573    * relayout cycle can stop the emission of this signal using the
6574    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6575    * themselves, like:
6576    *
6577    * |[
6578    *   static void
6579    *   on_redraw_complete (gpointer data)
6580    *   {
6581    *     ClutterStage *stage = data;
6582    *
6583    *     /&ast; execute the Clutter drawing pipeline &ast;/
6584    *     clutter_stage_ensure_redraw (stage);
6585    *   }
6586    *
6587    *   static void
6588    *   on_stage_queue_redraw (ClutterStage *stage)
6589    *   {
6590    *     /&ast; this prevents the default handler to run &ast;/
6591    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6592    *
6593    *     /&ast; queue a redraw with the host toolkit and call
6594    *      &ast; a function when the redraw has been completed
6595    *      &ast;/
6596    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6597    *   }
6598    * ]|
6599    *
6600    * <note><para>This signal is emitted before the Clutter paint
6601    * pipeline is executed. If you want to know when the pipeline has
6602    * been completed you should connect to the ::paint signal on the
6603    * Stage with g_signal_connect_after().</para></note>
6604    *
6605    * Since: 1.0
6606    */
6607   actor_signals[QUEUE_REDRAW] =
6608     g_signal_new (I_("queue-redraw"),
6609                   G_TYPE_FROM_CLASS (object_class),
6610                   G_SIGNAL_RUN_LAST |
6611                   G_SIGNAL_NO_HOOKS,
6612                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6613                   NULL, NULL,
6614                   _clutter_marshal_VOID__OBJECT,
6615                   G_TYPE_NONE, 1,
6616                   CLUTTER_TYPE_ACTOR);
6617
6618   /**
6619    * ClutterActor::queue-relayout
6620    * @actor: the actor being queued for relayout
6621    *
6622    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6623    * is called on an actor.
6624    *
6625    * The default implementation for #ClutterActor chains up to the
6626    * parent actor and queues a relayout on the parent, thus "bubbling"
6627    * the relayout queue up through the actor graph.
6628    *
6629    * The main purpose of this signal is to allow relayout to be propagated
6630    * properly in the procense of #ClutterClone actors. Applications will
6631    * not normally need to connect to this signal.
6632    *
6633    * Since: 1.2
6634    */
6635   actor_signals[QUEUE_RELAYOUT] =
6636     g_signal_new (I_("queue-relayout"),
6637                   G_TYPE_FROM_CLASS (object_class),
6638                   G_SIGNAL_RUN_LAST |
6639                   G_SIGNAL_NO_HOOKS,
6640                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6641                   NULL, NULL,
6642                   _clutter_marshal_VOID__VOID,
6643                   G_TYPE_NONE, 0);
6644
6645   /**
6646    * ClutterActor::event:
6647    * @actor: the actor which received the event
6648    * @event: a #ClutterEvent
6649    *
6650    * The ::event signal is emitted each time an event is received
6651    * by the @actor. This signal will be emitted on every actor,
6652    * following the hierarchy chain, until it reaches the top-level
6653    * container (the #ClutterStage).
6654    *
6655    * Return value: %TRUE if the event has been handled by the actor,
6656    *   or %FALSE to continue the emission.
6657    *
6658    * Since: 0.6
6659    */
6660   actor_signals[EVENT] =
6661     g_signal_new (I_("event"),
6662                   G_TYPE_FROM_CLASS (object_class),
6663                   G_SIGNAL_RUN_LAST,
6664                   G_STRUCT_OFFSET (ClutterActorClass, event),
6665                   _clutter_boolean_handled_accumulator, NULL,
6666                   _clutter_marshal_BOOLEAN__BOXED,
6667                   G_TYPE_BOOLEAN, 1,
6668                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6669   /**
6670    * ClutterActor::button-press-event:
6671    * @actor: the actor which received the event
6672    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6673    *
6674    * The ::button-press-event signal is emitted each time a mouse button
6675    * is pressed on @actor.
6676    *
6677    * Return value: %TRUE if the event has been handled by the actor,
6678    *   or %FALSE to continue the emission.
6679    *
6680    * Since: 0.6
6681    */
6682   actor_signals[BUTTON_PRESS_EVENT] =
6683     g_signal_new (I_("button-press-event"),
6684                   G_TYPE_FROM_CLASS (object_class),
6685                   G_SIGNAL_RUN_LAST,
6686                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6687                   _clutter_boolean_handled_accumulator, NULL,
6688                   _clutter_marshal_BOOLEAN__BOXED,
6689                   G_TYPE_BOOLEAN, 1,
6690                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6691   /**
6692    * ClutterActor::button-release-event:
6693    * @actor: the actor which received the event
6694    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6695    *
6696    * The ::button-release-event signal is emitted each time a mouse button
6697    * is released on @actor.
6698    *
6699    * Return value: %TRUE if the event has been handled by the actor,
6700    *   or %FALSE to continue the emission.
6701    *
6702    * Since: 0.6
6703    */
6704   actor_signals[BUTTON_RELEASE_EVENT] =
6705     g_signal_new (I_("button-release-event"),
6706                   G_TYPE_FROM_CLASS (object_class),
6707                   G_SIGNAL_RUN_LAST,
6708                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6709                   _clutter_boolean_handled_accumulator, NULL,
6710                   _clutter_marshal_BOOLEAN__BOXED,
6711                   G_TYPE_BOOLEAN, 1,
6712                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6713   /**
6714    * ClutterActor::scroll-event:
6715    * @actor: the actor which received the event
6716    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6717    *
6718    * The ::scroll-event signal is emitted each time the mouse is
6719    * scrolled on @actor
6720    *
6721    * Return value: %TRUE if the event has been handled by the actor,
6722    *   or %FALSE to continue the emission.
6723    *
6724    * Since: 0.6
6725    */
6726   actor_signals[SCROLL_EVENT] =
6727     g_signal_new (I_("scroll-event"),
6728                   G_TYPE_FROM_CLASS (object_class),
6729                   G_SIGNAL_RUN_LAST,
6730                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6731                   _clutter_boolean_handled_accumulator, NULL,
6732                   _clutter_marshal_BOOLEAN__BOXED,
6733                   G_TYPE_BOOLEAN, 1,
6734                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6735   /**
6736    * ClutterActor::key-press-event:
6737    * @actor: the actor which received the event
6738    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6739    *
6740    * The ::key-press-event signal is emitted each time a keyboard button
6741    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6742    *
6743    * Return value: %TRUE if the event has been handled by the actor,
6744    *   or %FALSE to continue the emission.
6745    *
6746    * Since: 0.6
6747    */
6748   actor_signals[KEY_PRESS_EVENT] =
6749     g_signal_new (I_("key-press-event"),
6750                   G_TYPE_FROM_CLASS (object_class),
6751                   G_SIGNAL_RUN_LAST,
6752                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6753                   _clutter_boolean_handled_accumulator, NULL,
6754                   _clutter_marshal_BOOLEAN__BOXED,
6755                   G_TYPE_BOOLEAN, 1,
6756                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6757   /**
6758    * ClutterActor::key-release-event:
6759    * @actor: the actor which received the event
6760    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6761    *
6762    * The ::key-release-event signal is emitted each time a keyboard button
6763    * is released while @actor has key focus (see
6764    * clutter_stage_set_key_focus()).
6765    *
6766    * Return value: %TRUE if the event has been handled by the actor,
6767    *   or %FALSE to continue the emission.
6768    *
6769    * Since: 0.6
6770    */
6771   actor_signals[KEY_RELEASE_EVENT] =
6772     g_signal_new (I_("key-release-event"),
6773                   G_TYPE_FROM_CLASS (object_class),
6774                   G_SIGNAL_RUN_LAST,
6775                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6776                   _clutter_boolean_handled_accumulator, NULL,
6777                   _clutter_marshal_BOOLEAN__BOXED,
6778                   G_TYPE_BOOLEAN, 1,
6779                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6780   /**
6781    * ClutterActor::motion-event:
6782    * @actor: the actor which received the event
6783    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6784    *
6785    * The ::motion-event signal is emitted each time the mouse pointer is
6786    * moved over @actor.
6787    *
6788    * Return value: %TRUE if the event has been handled by the actor,
6789    *   or %FALSE to continue the emission.
6790    *
6791    * Since: 0.6
6792    */
6793   actor_signals[MOTION_EVENT] =
6794     g_signal_new (I_("motion-event"),
6795                   G_TYPE_FROM_CLASS (object_class),
6796                   G_SIGNAL_RUN_LAST,
6797                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6798                   _clutter_boolean_handled_accumulator, NULL,
6799                   _clutter_marshal_BOOLEAN__BOXED,
6800                   G_TYPE_BOOLEAN, 1,
6801                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6802
6803   /**
6804    * ClutterActor::key-focus-in:
6805    * @actor: the actor which now has key focus
6806    *
6807    * The ::key-focus-in signal is emitted when @actor receives key focus.
6808    *
6809    * Since: 0.6
6810    */
6811   actor_signals[KEY_FOCUS_IN] =
6812     g_signal_new (I_("key-focus-in"),
6813                   G_TYPE_FROM_CLASS (object_class),
6814                   G_SIGNAL_RUN_LAST,
6815                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6816                   NULL, NULL,
6817                   _clutter_marshal_VOID__VOID,
6818                   G_TYPE_NONE, 0);
6819
6820   /**
6821    * ClutterActor::key-focus-out:
6822    * @actor: the actor which now has key focus
6823    *
6824    * The ::key-focus-out signal is emitted when @actor loses key focus.
6825    *
6826    * Since: 0.6
6827    */
6828   actor_signals[KEY_FOCUS_OUT] =
6829     g_signal_new (I_("key-focus-out"),
6830                   G_TYPE_FROM_CLASS (object_class),
6831                   G_SIGNAL_RUN_LAST,
6832                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6833                   NULL, NULL,
6834                   _clutter_marshal_VOID__VOID,
6835                   G_TYPE_NONE, 0);
6836
6837   /**
6838    * ClutterActor::enter-event:
6839    * @actor: the actor which the pointer has entered.
6840    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6841    *
6842    * The ::enter-event signal is emitted when the pointer enters the @actor
6843    *
6844    * Return value: %TRUE if the event has been handled by the actor,
6845    *   or %FALSE to continue the emission.
6846    *
6847    * Since: 0.6
6848    */
6849   actor_signals[ENTER_EVENT] =
6850     g_signal_new (I_("enter-event"),
6851                   G_TYPE_FROM_CLASS (object_class),
6852                   G_SIGNAL_RUN_LAST,
6853                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6854                   _clutter_boolean_handled_accumulator, NULL,
6855                   _clutter_marshal_BOOLEAN__BOXED,
6856                   G_TYPE_BOOLEAN, 1,
6857                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6858
6859   /**
6860    * ClutterActor::leave-event:
6861    * @actor: the actor which the pointer has left
6862    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6863    *
6864    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6865    *
6866    * Return value: %TRUE if the event has been handled by the actor,
6867    *   or %FALSE to continue the emission.
6868    *
6869    * Since: 0.6
6870    */
6871   actor_signals[LEAVE_EVENT] =
6872     g_signal_new (I_("leave-event"),
6873                   G_TYPE_FROM_CLASS (object_class),
6874                   G_SIGNAL_RUN_LAST,
6875                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6876                   _clutter_boolean_handled_accumulator, NULL,
6877                   _clutter_marshal_BOOLEAN__BOXED,
6878                   G_TYPE_BOOLEAN, 1,
6879                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6880
6881   /**
6882    * ClutterActor::captured-event:
6883    * @actor: the actor which received the signal
6884    * @event: a #ClutterEvent
6885    *
6886    * The ::captured-event signal is emitted when an event is captured
6887    * by Clutter. This signal will be emitted starting from the top-level
6888    * container (the #ClutterStage) to the actor which received the event
6889    * going down the hierarchy. This signal can be used to intercept every
6890    * event before the specialized events (like
6891    * ClutterActor::button-press-event or ::key-released-event) are
6892    * emitted.
6893    *
6894    * Return value: %TRUE if the event has been handled by the actor,
6895    *   or %FALSE to continue the emission.
6896    *
6897    * Since: 0.6
6898    */
6899   actor_signals[CAPTURED_EVENT] =
6900     g_signal_new (I_("captured-event"),
6901                   G_TYPE_FROM_CLASS (object_class),
6902                   G_SIGNAL_RUN_LAST,
6903                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6904                   _clutter_boolean_handled_accumulator, NULL,
6905                   _clutter_marshal_BOOLEAN__BOXED,
6906                   G_TYPE_BOOLEAN, 1,
6907                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6908
6909   /**
6910    * ClutterActor::paint:
6911    * @actor: the #ClutterActor that received the signal
6912    *
6913    * The ::paint signal is emitted each time an actor is being painted.
6914    *
6915    * Subclasses of #ClutterActor should override the class signal handler
6916    * and paint themselves in that function.
6917    *
6918    * It is possible to connect a handler to the ::paint signal in order
6919    * to set up some custom aspect of a paint.
6920    *
6921    * Since: 0.8
6922    */
6923   actor_signals[PAINT] =
6924     g_signal_new (I_("paint"),
6925                   G_TYPE_FROM_CLASS (object_class),
6926                   G_SIGNAL_RUN_LAST |
6927                   G_SIGNAL_NO_HOOKS,
6928                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6929                   NULL, NULL,
6930                   _clutter_marshal_VOID__VOID,
6931                   G_TYPE_NONE, 0);
6932   /**
6933    * ClutterActor::realize:
6934    * @actor: the #ClutterActor that received the signal
6935    *
6936    * The ::realize signal is emitted each time an actor is being
6937    * realized.
6938    *
6939    * Since: 0.8
6940    */
6941   actor_signals[REALIZE] =
6942     g_signal_new (I_("realize"),
6943                   G_TYPE_FROM_CLASS (object_class),
6944                   G_SIGNAL_RUN_LAST,
6945                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6946                   NULL, NULL,
6947                   _clutter_marshal_VOID__VOID,
6948                   G_TYPE_NONE, 0);
6949   /**
6950    * ClutterActor::unrealize:
6951    * @actor: the #ClutterActor that received the signal
6952    *
6953    * The ::unrealize signal is emitted each time an actor is being
6954    * unrealized.
6955    *
6956    * Since: 0.8
6957    */
6958   actor_signals[UNREALIZE] =
6959     g_signal_new (I_("unrealize"),
6960                   G_TYPE_FROM_CLASS (object_class),
6961                   G_SIGNAL_RUN_LAST,
6962                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6963                   NULL, NULL,
6964                   _clutter_marshal_VOID__VOID,
6965                   G_TYPE_NONE, 0);
6966
6967   /**
6968    * ClutterActor::pick:
6969    * @actor: the #ClutterActor that received the signal
6970    * @color: the #ClutterColor to be used when picking
6971    *
6972    * The ::pick signal is emitted each time an actor is being painted
6973    * in "pick mode". The pick mode is used to identify the actor during
6974    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6975    * The actor should paint its shape using the passed @pick_color.
6976    *
6977    * Subclasses of #ClutterActor should override the class signal handler
6978    * and paint themselves in that function.
6979    *
6980    * It is possible to connect a handler to the ::pick signal in order
6981    * to set up some custom aspect of a paint in pick mode.
6982    *
6983    * Since: 1.0
6984    */
6985   actor_signals[PICK] =
6986     g_signal_new (I_("pick"),
6987                   G_TYPE_FROM_CLASS (object_class),
6988                   G_SIGNAL_RUN_LAST,
6989                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6990                   NULL, NULL,
6991                   _clutter_marshal_VOID__BOXED,
6992                   G_TYPE_NONE, 1,
6993                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6994
6995   /**
6996    * ClutterActor::allocation-changed:
6997    * @actor: the #ClutterActor that emitted the signal
6998    * @box: a #ClutterActorBox with the new allocation
6999    * @flags: #ClutterAllocationFlags for the allocation
7000    *
7001    * The ::allocation-changed signal is emitted when the
7002    * #ClutterActor:allocation property changes. Usually, application
7003    * code should just use the notifications for the :allocation property
7004    * but if you want to track the allocation flags as well, for instance
7005    * to know whether the absolute origin of @actor changed, then you might
7006    * want use this signal instead.
7007    *
7008    * Since: 1.0
7009    */
7010   actor_signals[ALLOCATION_CHANGED] =
7011     g_signal_new (I_("allocation-changed"),
7012                   G_TYPE_FROM_CLASS (object_class),
7013                   G_SIGNAL_RUN_LAST,
7014                   0,
7015                   NULL, NULL,
7016                   _clutter_marshal_VOID__BOXED_FLAGS,
7017                   G_TYPE_NONE, 2,
7018                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7019                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7020
7021   /**
7022    * ClutterActor::transitions-completed:
7023    * @actor: a #ClutterActor
7024    *
7025    * The ::transitions-completed signal is emitted once all transitions
7026    * involving @actor are complete.
7027    *
7028    * Since: 1.10
7029    */
7030   actor_signals[TRANSITIONS_COMPLETED] =
7031     g_signal_new (I_("transitions-completed"),
7032                   G_TYPE_FROM_CLASS (object_class),
7033                   G_SIGNAL_RUN_LAST,
7034                   0,
7035                   NULL, NULL,
7036                   _clutter_marshal_VOID__VOID,
7037                   G_TYPE_NONE, 0);
7038 }
7039
7040 static void
7041 clutter_actor_init (ClutterActor *self)
7042 {
7043   ClutterActorPrivate *priv;
7044
7045   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7046
7047   priv->id = _clutter_context_acquire_id (self);
7048   priv->pick_id = -1;
7049
7050   priv->opacity = 0xff;
7051   priv->show_on_set_parent = TRUE;
7052
7053   priv->needs_width_request = TRUE;
7054   priv->needs_height_request = TRUE;
7055   priv->needs_allocation = TRUE;
7056
7057   priv->cached_width_age = 1;
7058   priv->cached_height_age = 1;
7059
7060   priv->opacity_override = -1;
7061   priv->enable_model_view_transform = TRUE;
7062
7063   /* Initialize an empty paint volume to start with */
7064   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7065   priv->last_paint_volume_valid = TRUE;
7066
7067   priv->transform_valid = FALSE;
7068
7069   /* the default is to stretch the content, to match the
7070    * current behaviour of basically all actors. also, it's
7071    * the easiest thing to compute.
7072    */
7073   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7074   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7075   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7076 }
7077
7078 /**
7079  * clutter_actor_new:
7080  *
7081  * Creates a new #ClutterActor.
7082  *
7083  * A newly created actor has a floating reference, which will be sunk
7084  * when it is added to another actor.
7085  *
7086  * Return value: (transfer full): the newly created #ClutterActor
7087  *
7088  * Since: 1.10
7089  */
7090 ClutterActor *
7091 clutter_actor_new (void)
7092 {
7093   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7094 }
7095
7096 /**
7097  * clutter_actor_destroy:
7098  * @self: a #ClutterActor
7099  *
7100  * Destroys an actor.  When an actor is destroyed, it will break any
7101  * references it holds to other objects.  If the actor is inside a
7102  * container, the actor will be removed.
7103  *
7104  * When you destroy a container, its children will be destroyed as well.
7105  *
7106  * Note: you cannot destroy the #ClutterStage returned by
7107  * clutter_stage_get_default().
7108  */
7109 void
7110 clutter_actor_destroy (ClutterActor *self)
7111 {
7112   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7113
7114   g_object_ref (self);
7115
7116   /* avoid recursion while destroying */
7117   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7118     {
7119       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7120
7121       g_object_run_dispose (G_OBJECT (self));
7122
7123       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7124     }
7125
7126   g_object_unref (self);
7127 }
7128
7129 void
7130 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7131                                     ClutterPaintVolume *clip)
7132 {
7133   ClutterActorPrivate *priv = self->priv;
7134   ClutterPaintVolume *pv;
7135   gboolean clipped;
7136
7137   /* Remove queue entry early in the process, otherwise a new
7138      queue_redraw() during signal handling could put back this
7139      object in the stage redraw list (but the entry is freed as
7140      soon as we return from this function, causing a segfault
7141      later)
7142   */
7143   priv->queue_redraw_entry = NULL;
7144
7145   /* If we've been explicitly passed a clip volume then there's
7146    * nothing more to calculate, but otherwise the only thing we know
7147    * is that the change is constrained to the given actor.
7148    *
7149    * The idea is that if we know the paint volume for where the actor
7150    * was last drawn (in eye coordinates) and we also have the paint
7151    * volume for where it will be drawn next (in actor coordinates)
7152    * then if we queue a redraw for both these volumes that will cover
7153    * everything that needs to be redrawn to clear the old view and
7154    * show the latest view of the actor.
7155    *
7156    * Don't clip this redraw if we don't know what position we had for
7157    * the previous redraw since we don't know where to set the clip so
7158    * it will clear the actor as it is currently.
7159    */
7160   if (clip)
7161     {
7162       _clutter_actor_set_queue_redraw_clip (self, clip);
7163       clipped = TRUE;
7164     }
7165   else if (G_LIKELY (priv->last_paint_volume_valid))
7166     {
7167       pv = _clutter_actor_get_paint_volume_mutable (self);
7168       if (pv)
7169         {
7170           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7171
7172           /* make sure we redraw the actors old position... */
7173           _clutter_actor_set_queue_redraw_clip (stage,
7174                                                 &priv->last_paint_volume);
7175           _clutter_actor_signal_queue_redraw (stage, stage);
7176           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7177
7178           /* XXX: Ideally the redraw signal would take a clip volume
7179            * argument, but that would be an ABI break. Until we can
7180            * break the ABI we pass the argument out-of-band
7181            */
7182
7183           /* setup the clip for the actors new position... */
7184           _clutter_actor_set_queue_redraw_clip (self, pv);
7185           clipped = TRUE;
7186         }
7187       else
7188         clipped = FALSE;
7189     }
7190   else
7191     clipped = FALSE;
7192
7193   _clutter_actor_signal_queue_redraw (self, self);
7194
7195   /* Just in case anyone is manually firing redraw signals without
7196    * using the public queue_redraw() API we are careful to ensure that
7197    * our out-of-band clip member is cleared before returning...
7198    *
7199    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7200    */
7201   if (G_LIKELY (clipped))
7202     _clutter_actor_set_queue_redraw_clip (self, NULL);
7203 }
7204
7205 static void
7206 _clutter_actor_get_allocation_clip (ClutterActor *self,
7207                                     ClutterActorBox *clip)
7208 {
7209   ClutterActorBox allocation;
7210
7211   /* XXX: we don't care if we get an out of date allocation here
7212    * because clutter_actor_queue_redraw_with_clip knows to ignore
7213    * the clip if the actor's allocation is invalid.
7214    *
7215    * This is noted because clutter_actor_get_allocation_box does some
7216    * unnecessary work to support buggy code with a comment suggesting
7217    * that it could be changed later which would be good for this use
7218    * case!
7219    */
7220   clutter_actor_get_allocation_box (self, &allocation);
7221
7222   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7223    * actor's own coordinate space but the allocation is in parent
7224    * coordinates */
7225   clip->x1 = 0;
7226   clip->y1 = 0;
7227   clip->x2 = allocation.x2 - allocation.x1;
7228   clip->y2 = allocation.y2 - allocation.y1;
7229 }
7230
7231 void
7232 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7233                                   ClutterRedrawFlags  flags,
7234                                   ClutterPaintVolume *volume,
7235                                   ClutterEffect      *effect)
7236 {
7237   ClutterActorPrivate *priv = self->priv;
7238   ClutterPaintVolume allocation_pv;
7239   ClutterPaintVolume *pv;
7240   gboolean should_free_pv;
7241   ClutterActor *stage;
7242
7243   /* Here's an outline of the actor queue redraw mechanism:
7244    *
7245    * The process starts in one of the following two functions which
7246    * are wrappers for this function:
7247    * clutter_actor_queue_redraw
7248    * _clutter_actor_queue_redraw_with_clip
7249    *
7250    * additionally, an effect can queue a redraw by wrapping this
7251    * function in clutter_effect_queue_rerun
7252    *
7253    * This functions queues an entry in a list associated with the
7254    * stage which is a list of actors that queued a redraw while
7255    * updating the timelines, performing layouting and processing other
7256    * mainloop sources before the next paint starts.
7257    *
7258    * We aim to minimize the processing done at this point because
7259    * there is a good chance other events will happen while updating
7260    * the scenegraph that would invalidate any expensive work we might
7261    * otherwise try to do here. For example we don't try and resolve
7262    * the screen space bounding box of an actor at this stage so as to
7263    * minimize how much of the screen redraw because it's possible
7264    * something else will happen which will force a full redraw anyway.
7265    *
7266    * When all updates are complete and we come to paint the stage then
7267    * we iterate this list and actually emit the "queue-redraw" signals
7268    * for each of the listed actors which will bubble up to the stage
7269    * for each actor and at that point we will transform the actors
7270    * paint volume into screen coordinates to determine the clip region
7271    * for what needs to be redrawn in the next paint.
7272    *
7273    * Besides minimizing redundant work another reason for this
7274    * deferred design is that it's more likely we will be able to
7275    * determine the paint volume of an actor once we've finished
7276    * updating the scenegraph because its allocation should be up to
7277    * date. NB: If we can't determine an actors paint volume then we
7278    * can't automatically queue a clipped redraw which can make a big
7279    * difference to performance.
7280    *
7281    * So the control flow goes like this:
7282    * One of clutter_actor_queue_redraw,
7283    *        _clutter_actor_queue_redraw_with_clip
7284    *     or clutter_effect_queue_rerun
7285    *
7286    * then control moves to:
7287    *   _clutter_stage_queue_actor_redraw
7288    *
7289    * later during _clutter_stage_do_update, once relayouting is done
7290    * and the scenegraph has been updated we will call:
7291    * _clutter_stage_finish_queue_redraws
7292    *
7293    * _clutter_stage_finish_queue_redraws will call
7294    * _clutter_actor_finish_queue_redraw for each listed actor.
7295    * Note: actors *are* allowed to queue further redraws during this
7296    * process (considering clone actors or texture_new_from_actor which
7297    * respond to their source queueing a redraw by queuing a redraw
7298    * themselves). We repeat the process until the list is empty.
7299    *
7300    * This will result in the "queue-redraw" signal being fired for
7301    * each actor which will pass control to the default signal handler:
7302    * clutter_actor_real_queue_redraw
7303    *
7304    * This will bubble up to the stages handler:
7305    * clutter_stage_real_queue_redraw
7306    *
7307    * clutter_stage_real_queue_redraw will transform the actors paint
7308    * volume into screen space and add it as a clip region for the next
7309    * paint.
7310    */
7311
7312   /* ignore queueing a redraw for actors being destroyed */
7313   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7314     return;
7315
7316   stage = _clutter_actor_get_stage_internal (self);
7317
7318   /* Ignore queueing a redraw for actors not descended from a stage */
7319   if (stage == NULL)
7320     return;
7321
7322   /* ignore queueing a redraw on stages that are being destroyed */
7323   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7324     return;
7325
7326   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7327     {
7328       ClutterActorBox allocation_clip;
7329       ClutterVertex origin;
7330
7331       /* If the actor doesn't have a valid allocation then we will
7332        * queue a full stage redraw. */
7333       if (priv->needs_allocation)
7334         {
7335           /* NB: NULL denotes an undefined clip which will result in a
7336            * full redraw... */
7337           _clutter_actor_set_queue_redraw_clip (self, NULL);
7338           _clutter_actor_signal_queue_redraw (self, self);
7339           return;
7340         }
7341
7342       _clutter_paint_volume_init_static (&allocation_pv, self);
7343       pv = &allocation_pv;
7344
7345       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7346
7347       origin.x = allocation_clip.x1;
7348       origin.y = allocation_clip.y1;
7349       origin.z = 0;
7350       clutter_paint_volume_set_origin (pv, &origin);
7351       clutter_paint_volume_set_width (pv,
7352                                       allocation_clip.x2 - allocation_clip.x1);
7353       clutter_paint_volume_set_height (pv,
7354                                        allocation_clip.y2 -
7355                                        allocation_clip.y1);
7356       should_free_pv = TRUE;
7357     }
7358   else
7359     {
7360       pv = volume;
7361       should_free_pv = FALSE;
7362     }
7363
7364   self->priv->queue_redraw_entry =
7365     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7366                                        priv->queue_redraw_entry,
7367                                        self,
7368                                        pv);
7369
7370   if (should_free_pv)
7371     clutter_paint_volume_free (pv);
7372
7373   /* If this is the first redraw queued then we can directly use the
7374      effect parameter */
7375   if (!priv->is_dirty)
7376     priv->effect_to_redraw = effect;
7377   /* Otherwise we need to merge it with the existing effect parameter */
7378   else if (effect != NULL)
7379     {
7380       /* If there's already an effect then we need to use whichever is
7381          later in the chain of actors. Otherwise a full redraw has
7382          already been queued on the actor so we need to ignore the
7383          effect parameter */
7384       if (priv->effect_to_redraw != NULL)
7385         {
7386           if (priv->effects == NULL)
7387             g_warning ("Redraw queued with an effect that is "
7388                        "not applied to the actor");
7389           else
7390             {
7391               const GList *l;
7392
7393               for (l = _clutter_meta_group_peek_metas (priv->effects);
7394                    l != NULL;
7395                    l = l->next)
7396                 {
7397                   if (l->data == priv->effect_to_redraw ||
7398                       l->data == effect)
7399                     priv->effect_to_redraw = l->data;
7400                 }
7401             }
7402         }
7403     }
7404   else
7405     {
7406       /* If no effect is specified then we need to redraw the whole
7407          actor */
7408       priv->effect_to_redraw = NULL;
7409     }
7410
7411   priv->is_dirty = TRUE;
7412 }
7413
7414 /**
7415  * clutter_actor_queue_redraw:
7416  * @self: A #ClutterActor
7417  *
7418  * Queues up a redraw of an actor and any children. The redraw occurs
7419  * once the main loop becomes idle (after the current batch of events
7420  * has been processed, roughly).
7421  *
7422  * Applications rarely need to call this, as redraws are handled
7423  * automatically by modification functions.
7424  *
7425  * This function will not do anything if @self is not visible, or
7426  * if the actor is inside an invisible part of the scenegraph.
7427  *
7428  * Also be aware that painting is a NOP for actors with an opacity of
7429  * 0
7430  *
7431  * When you are implementing a custom actor you must queue a redraw
7432  * whenever some private state changes that will affect painting or
7433  * picking of your actor.
7434  */
7435 void
7436 clutter_actor_queue_redraw (ClutterActor *self)
7437 {
7438   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7439
7440   _clutter_actor_queue_redraw_full (self,
7441                                     0, /* flags */
7442                                     NULL, /* clip volume */
7443                                     NULL /* effect */);
7444 }
7445
7446 /*< private >
7447  * _clutter_actor_queue_redraw_with_clip:
7448  * @self: A #ClutterActor
7449  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7450  *   this queue redraw.
7451  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7452  *   redrawn or %NULL if you are just using a @flag to state your
7453  *   desired clipping.
7454  *
7455  * Queues up a clipped redraw of an actor and any children. The redraw
7456  * occurs once the main loop becomes idle (after the current batch of
7457  * events has been processed, roughly).
7458  *
7459  * If no flags are given the clip volume is defined by @volume
7460  * specified in actor coordinates and tells Clutter that only content
7461  * within this volume has been changed so Clutter can optionally
7462  * optimize the redraw.
7463  *
7464  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7465  * should be %NULL and this tells Clutter to use the actor's current
7466  * allocation as a clip box. This flag can only be used for 2D actors,
7467  * because any actor with depth may be projected outside its
7468  * allocation.
7469  *
7470  * Applications rarely need to call this, as redraws are handled
7471  * automatically by modification functions.
7472  *
7473  * This function will not do anything if @self is not visible, or if
7474  * the actor is inside an invisible part of the scenegraph.
7475  *
7476  * Also be aware that painting is a NOP for actors with an opacity of
7477  * 0
7478  *
7479  * When you are implementing a custom actor you must queue a redraw
7480  * whenever some private state changes that will affect painting or
7481  * picking of your actor.
7482  */
7483 void
7484 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7485                                        ClutterRedrawFlags  flags,
7486                                        ClutterPaintVolume *volume)
7487 {
7488   _clutter_actor_queue_redraw_full (self,
7489                                     flags, /* flags */
7490                                     volume, /* clip volume */
7491                                     NULL /* effect */);
7492 }
7493
7494 static void
7495 _clutter_actor_queue_only_relayout (ClutterActor *self)
7496 {
7497   ClutterActorPrivate *priv = self->priv;
7498
7499   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7500     return;
7501
7502   if (priv->needs_width_request &&
7503       priv->needs_height_request &&
7504       priv->needs_allocation)
7505     return; /* save some cpu cycles */
7506
7507 #if CLUTTER_ENABLE_DEBUG
7508   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7509     {
7510       g_warning ("The actor '%s' is currently inside an allocation "
7511                  "cycle; calling clutter_actor_queue_relayout() is "
7512                  "not recommended",
7513                  _clutter_actor_get_debug_name (self));
7514     }
7515 #endif /* CLUTTER_ENABLE_DEBUG */
7516
7517   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7518 }
7519
7520 /**
7521  * clutter_actor_queue_redraw_with_clip:
7522  * @self: a #ClutterActor
7523  * @clip: (allow-none): a rectangular clip region, or %NULL
7524  *
7525  * Queues a redraw on @self limited to a specific, actor-relative
7526  * rectangular area.
7527  *
7528  * If @clip is %NULL this function is equivalent to
7529  * clutter_actor_queue_redraw().
7530  *
7531  * Since: 1.10
7532  */
7533 void
7534 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7535                                       const cairo_rectangle_int_t *clip)
7536 {
7537   ClutterPaintVolume volume;
7538   ClutterVertex origin;
7539
7540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7541
7542   if (clip == NULL)
7543     {
7544       clutter_actor_queue_redraw (self);
7545       return;
7546     }
7547
7548   _clutter_paint_volume_init_static (&volume, self);
7549
7550   origin.x = clip->x;
7551   origin.y = clip->y;
7552   origin.z = 0.0f;
7553
7554   clutter_paint_volume_set_origin (&volume, &origin);
7555   clutter_paint_volume_set_width (&volume, clip->width);
7556   clutter_paint_volume_set_height (&volume, clip->height);
7557
7558   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7559
7560   clutter_paint_volume_free (&volume);
7561 }
7562
7563 /**
7564  * clutter_actor_queue_relayout:
7565  * @self: A #ClutterActor
7566  *
7567  * Indicates that the actor's size request or other layout-affecting
7568  * properties may have changed. This function is used inside #ClutterActor
7569  * subclass implementations, not by applications directly.
7570  *
7571  * Queueing a new layout automatically queues a redraw as well.
7572  *
7573  * Since: 0.8
7574  */
7575 void
7576 clutter_actor_queue_relayout (ClutterActor *self)
7577 {
7578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7579
7580   _clutter_actor_queue_only_relayout (self);
7581   clutter_actor_queue_redraw (self);
7582 }
7583
7584 /**
7585  * clutter_actor_get_preferred_size:
7586  * @self: a #ClutterActor
7587  * @min_width_p: (out) (allow-none): return location for the minimum
7588  *   width, or %NULL
7589  * @min_height_p: (out) (allow-none): return location for the minimum
7590  *   height, or %NULL
7591  * @natural_width_p: (out) (allow-none): return location for the natural
7592  *   width, or %NULL
7593  * @natural_height_p: (out) (allow-none): return location for the natural
7594  *   height, or %NULL
7595  *
7596  * Computes the preferred minimum and natural size of an actor, taking into
7597  * account the actor's geometry management (either height-for-width
7598  * or width-for-height).
7599  *
7600  * The width and height used to compute the preferred height and preferred
7601  * width are the actor's natural ones.
7602  *
7603  * If you need to control the height for the preferred width, or the width for
7604  * the preferred height, you should use clutter_actor_get_preferred_width()
7605  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7606  * geometry management using the #ClutterActor:request-mode property.
7607  *
7608  * Since: 0.8
7609  */
7610 void
7611 clutter_actor_get_preferred_size (ClutterActor *self,
7612                                   gfloat       *min_width_p,
7613                                   gfloat       *min_height_p,
7614                                   gfloat       *natural_width_p,
7615                                   gfloat       *natural_height_p)
7616 {
7617   ClutterActorPrivate *priv;
7618   gfloat min_width, min_height;
7619   gfloat natural_width, natural_height;
7620
7621   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7622
7623   priv = self->priv;
7624
7625   min_width = min_height = 0;
7626   natural_width = natural_height = 0;
7627
7628   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7629     {
7630       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7631       clutter_actor_get_preferred_width (self, -1,
7632                                          &min_width,
7633                                          &natural_width);
7634       clutter_actor_get_preferred_height (self, natural_width,
7635                                           &min_height,
7636                                           &natural_height);
7637     }
7638   else
7639     {
7640       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7641       clutter_actor_get_preferred_height (self, -1,
7642                                           &min_height,
7643                                           &natural_height);
7644       clutter_actor_get_preferred_width (self, natural_height,
7645                                          &min_width,
7646                                          &natural_width);
7647     }
7648
7649   if (min_width_p)
7650     *min_width_p = min_width;
7651
7652   if (min_height_p)
7653     *min_height_p = min_height;
7654
7655   if (natural_width_p)
7656     *natural_width_p = natural_width;
7657
7658   if (natural_height_p)
7659     *natural_height_p = natural_height;
7660 }
7661
7662 /*< private >
7663  * effective_align:
7664  * @align: a #ClutterActorAlign
7665  * @direction: a #ClutterTextDirection
7666  *
7667  * Retrieves the correct alignment depending on the text direction
7668  *
7669  * Return value: the effective alignment
7670  */
7671 static ClutterActorAlign
7672 effective_align (ClutterActorAlign    align,
7673                  ClutterTextDirection direction)
7674 {
7675   ClutterActorAlign res;
7676
7677   switch (align)
7678     {
7679     case CLUTTER_ACTOR_ALIGN_START:
7680       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7681           ? CLUTTER_ACTOR_ALIGN_END
7682           : CLUTTER_ACTOR_ALIGN_START;
7683       break;
7684
7685     case CLUTTER_ACTOR_ALIGN_END:
7686       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7687           ? CLUTTER_ACTOR_ALIGN_START
7688           : CLUTTER_ACTOR_ALIGN_END;
7689       break;
7690
7691     default:
7692       res = align;
7693       break;
7694     }
7695
7696   return res;
7697 }
7698
7699 static inline void
7700 adjust_for_margin (float  margin_start,
7701                    float  margin_end,
7702                    float *minimum_size,
7703                    float *natural_size,
7704                    float *allocated_start,
7705                    float *allocated_end)
7706 {
7707   *minimum_size -= (margin_start + margin_end);
7708   *natural_size -= (margin_start + margin_end);
7709   *allocated_start += margin_start;
7710   *allocated_end -= margin_end;
7711 }
7712
7713 static inline void
7714 adjust_for_alignment (ClutterActorAlign  alignment,
7715                       float              natural_size,
7716                       float             *allocated_start,
7717                       float             *allocated_end)
7718 {
7719   float allocated_size = *allocated_end - *allocated_start;
7720
7721   switch (alignment)
7722     {
7723     case CLUTTER_ACTOR_ALIGN_FILL:
7724       /* do nothing */
7725       break;
7726
7727     case CLUTTER_ACTOR_ALIGN_START:
7728       /* keep start */
7729       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7730       break;
7731
7732     case CLUTTER_ACTOR_ALIGN_END:
7733       if (allocated_size > natural_size)
7734         {
7735           *allocated_start += (allocated_size - natural_size);
7736           *allocated_end = *allocated_start + natural_size;
7737         }
7738       break;
7739
7740     case CLUTTER_ACTOR_ALIGN_CENTER:
7741       if (allocated_size > natural_size)
7742         {
7743           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7744           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7745         }
7746       break;
7747     }
7748 }
7749
7750 /*< private >
7751  * clutter_actor_adjust_width:
7752  * @self: a #ClutterActor
7753  * @minimum_width: (inout): the actor's preferred minimum width, which
7754  *   will be adjusted depending on the margin
7755  * @natural_width: (inout): the actor's preferred natural width, which
7756  *   will be adjusted depending on the margin
7757  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7758  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7759  *
7760  * Adjusts the preferred and allocated position and size of an actor,
7761  * depending on the margin and alignment properties.
7762  */
7763 static void
7764 clutter_actor_adjust_width (ClutterActor *self,
7765                             gfloat       *minimum_width,
7766                             gfloat       *natural_width,
7767                             gfloat       *adjusted_x1,
7768                             gfloat       *adjusted_x2)
7769 {
7770   ClutterTextDirection text_dir;
7771   const ClutterLayoutInfo *info;
7772
7773   info = _clutter_actor_get_layout_info_or_defaults (self);
7774   text_dir = clutter_actor_get_text_direction (self);
7775
7776   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7777
7778   /* this will tweak natural_width to remove the margin, so that
7779    * adjust_for_alignment() will use the correct size
7780    */
7781   adjust_for_margin (info->margin.left, info->margin.right,
7782                      minimum_width, natural_width,
7783                      adjusted_x1, adjusted_x2);
7784
7785   adjust_for_alignment (effective_align (info->x_align, text_dir),
7786                         *natural_width,
7787                         adjusted_x1, adjusted_x2);
7788 }
7789
7790 /*< private >
7791  * clutter_actor_adjust_height:
7792  * @self: a #ClutterActor
7793  * @minimum_height: (inout): the actor's preferred minimum height, which
7794  *   will be adjusted depending on the margin
7795  * @natural_height: (inout): the actor's preferred natural height, which
7796  *   will be adjusted depending on the margin
7797  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7798  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7799  *
7800  * Adjusts the preferred and allocated position and size of an actor,
7801  * depending on the margin and alignment properties.
7802  */
7803 static void
7804 clutter_actor_adjust_height (ClutterActor *self,
7805                              gfloat       *minimum_height,
7806                              gfloat       *natural_height,
7807                              gfloat       *adjusted_y1,
7808                              gfloat       *adjusted_y2)
7809 {
7810   const ClutterLayoutInfo *info;
7811
7812   info = _clutter_actor_get_layout_info_or_defaults (self);
7813
7814   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7815
7816   /* this will tweak natural_height to remove the margin, so that
7817    * adjust_for_alignment() will use the correct size
7818    */
7819   adjust_for_margin (info->margin.top, info->margin.bottom,
7820                      minimum_height, natural_height,
7821                      adjusted_y1,
7822                      adjusted_y2);
7823
7824   /* we don't use effective_align() here, because text direction
7825    * only affects the horizontal axis
7826    */
7827   adjust_for_alignment (info->y_align,
7828                         *natural_height,
7829                         adjusted_y1,
7830                         adjusted_y2);
7831
7832 }
7833
7834 /* looks for a cached size request for this for_size. If not
7835  * found, returns the oldest entry so it can be overwritten */
7836 static gboolean
7837 _clutter_actor_get_cached_size_request (gfloat         for_size,
7838                                         SizeRequest   *cached_size_requests,
7839                                         SizeRequest  **result)
7840 {
7841   guint i;
7842
7843   *result = &cached_size_requests[0];
7844
7845   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7846     {
7847       SizeRequest *sr;
7848
7849       sr = &cached_size_requests[i];
7850
7851       if (sr->age > 0 &&
7852           sr->for_size == for_size)
7853         {
7854           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7855           *result = sr;
7856           return TRUE;
7857         }
7858       else if (sr->age < (*result)->age)
7859         {
7860           *result = sr;
7861         }
7862     }
7863
7864   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7865
7866   return FALSE;
7867 }
7868
7869 /**
7870  * clutter_actor_get_preferred_width:
7871  * @self: A #ClutterActor
7872  * @for_height: available height when computing the preferred width,
7873  *   or a negative value to indicate that no height is defined
7874  * @min_width_p: (out) (allow-none): return location for minimum width,
7875  *   or %NULL
7876  * @natural_width_p: (out) (allow-none): return location for the natural
7877  *   width, or %NULL
7878  *
7879  * Computes the requested minimum and natural widths for an actor,
7880  * optionally depending on the specified height, or if they are
7881  * already computed, returns the cached values.
7882  *
7883  * An actor may not get its request - depending on the layout
7884  * manager that's in effect.
7885  *
7886  * A request should not incorporate the actor's scale or anchor point;
7887  * those transformations do not affect layout, only rendering.
7888  *
7889  * Since: 0.8
7890  */
7891 void
7892 clutter_actor_get_preferred_width (ClutterActor *self,
7893                                    gfloat        for_height,
7894                                    gfloat       *min_width_p,
7895                                    gfloat       *natural_width_p)
7896 {
7897   float request_min_width, request_natural_width;
7898   SizeRequest *cached_size_request;
7899   const ClutterLayoutInfo *info;
7900   ClutterActorPrivate *priv;
7901   gboolean found_in_cache;
7902
7903   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7904
7905   priv = self->priv;
7906
7907   info = _clutter_actor_get_layout_info_or_defaults (self);
7908
7909   /* we shortcircuit the case of a fixed size set using set_width() */
7910   if (priv->min_width_set && priv->natural_width_set)
7911     {
7912       if (min_width_p != NULL)
7913         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7914
7915       if (natural_width_p != NULL)
7916         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7917
7918       return;
7919     }
7920
7921   /* the remaining cases are:
7922    *
7923    *   - either min_width or natural_width have been set
7924    *   - neither min_width or natural_width have been set
7925    *
7926    * in both cases, we go through the cache (and through the actor in case
7927    * of cache misses) and determine the authoritative value depending on
7928    * the *_set flags.
7929    */
7930
7931   if (!priv->needs_width_request)
7932     {
7933       found_in_cache =
7934         _clutter_actor_get_cached_size_request (for_height,
7935                                                 priv->width_requests,
7936                                                 &cached_size_request);
7937     }
7938   else
7939     {
7940       /* if the actor needs a width request we use the first slot */
7941       found_in_cache = FALSE;
7942       cached_size_request = &priv->width_requests[0];
7943     }
7944
7945   if (!found_in_cache)
7946     {
7947       gfloat minimum_width, natural_width;
7948       ClutterActorClass *klass;
7949
7950       minimum_width = natural_width = 0;
7951
7952       /* adjust for the margin */
7953       if (for_height >= 0)
7954         {
7955           for_height -= (info->margin.top + info->margin.bottom);
7956           if (for_height < 0)
7957             for_height = 0;
7958         }
7959
7960       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7961
7962       klass = CLUTTER_ACTOR_GET_CLASS (self);
7963       klass->get_preferred_width (self, for_height,
7964                                   &minimum_width,
7965                                   &natural_width);
7966
7967       /* adjust for the margin */
7968       minimum_width += (info->margin.left + info->margin.right);
7969       natural_width += (info->margin.left + info->margin.right);
7970
7971       /* Due to accumulated float errors, it's better not to warn
7972        * on this, but just fix it.
7973        */
7974       if (natural_width < minimum_width)
7975         natural_width = minimum_width;
7976
7977       cached_size_request->min_size = minimum_width;
7978       cached_size_request->natural_size = natural_width;
7979       cached_size_request->for_size = for_height;
7980       cached_size_request->age = priv->cached_width_age;
7981
7982       priv->cached_width_age += 1;
7983       priv->needs_width_request = FALSE;
7984     }
7985
7986   if (!priv->min_width_set)
7987     request_min_width = cached_size_request->min_size;
7988   else
7989     request_min_width = info->min_width;
7990
7991   if (!priv->natural_width_set)
7992     request_natural_width = cached_size_request->natural_size;
7993   else
7994     request_natural_width = info->natural_width;
7995
7996   if (min_width_p)
7997     *min_width_p = request_min_width;
7998
7999   if (natural_width_p)
8000     *natural_width_p = request_natural_width;
8001 }
8002
8003 /**
8004  * clutter_actor_get_preferred_height:
8005  * @self: A #ClutterActor
8006  * @for_width: available width to assume in computing desired height,
8007  *   or a negative value to indicate that no width is defined
8008  * @min_height_p: (out) (allow-none): return location for minimum height,
8009  *   or %NULL
8010  * @natural_height_p: (out) (allow-none): return location for natural
8011  *   height, or %NULL
8012  *
8013  * Computes the requested minimum and natural heights for an actor,
8014  * or if they are already computed, returns the cached values.
8015  *
8016  * An actor may not get its request - depending on the layout
8017  * manager that's in effect.
8018  *
8019  * A request should not incorporate the actor's scale or anchor point;
8020  * those transformations do not affect layout, only rendering.
8021  *
8022  * Since: 0.8
8023  */
8024 void
8025 clutter_actor_get_preferred_height (ClutterActor *self,
8026                                     gfloat        for_width,
8027                                     gfloat       *min_height_p,
8028                                     gfloat       *natural_height_p)
8029 {
8030   float request_min_height, request_natural_height;
8031   SizeRequest *cached_size_request;
8032   const ClutterLayoutInfo *info;
8033   ClutterActorPrivate *priv;
8034   gboolean found_in_cache;
8035
8036   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8037
8038   priv = self->priv;
8039
8040   info = _clutter_actor_get_layout_info_or_defaults (self);
8041
8042   /* we shortcircuit the case of a fixed size set using set_height() */
8043   if (priv->min_height_set && priv->natural_height_set)
8044     {
8045       if (min_height_p != NULL)
8046         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8047
8048       if (natural_height_p != NULL)
8049         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8050
8051       return;
8052     }
8053
8054   /* the remaining cases are:
8055    *
8056    *   - either min_height or natural_height have been set
8057    *   - neither min_height or natural_height have been set
8058    *
8059    * in both cases, we go through the cache (and through the actor in case
8060    * of cache misses) and determine the authoritative value depending on
8061    * the *_set flags.
8062    */
8063
8064   if (!priv->needs_height_request)
8065     {
8066       found_in_cache =
8067         _clutter_actor_get_cached_size_request (for_width,
8068                                                 priv->height_requests,
8069                                                 &cached_size_request);
8070     }
8071   else
8072     {
8073       found_in_cache = FALSE;
8074       cached_size_request = &priv->height_requests[0];
8075     }
8076
8077   if (!found_in_cache)
8078     {
8079       gfloat minimum_height, natural_height;
8080       ClutterActorClass *klass;
8081
8082       minimum_height = natural_height = 0;
8083
8084       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8085
8086       /* adjust for margin */
8087       if (for_width >= 0)
8088         {
8089           for_width -= (info->margin.left + info->margin.right);
8090           if (for_width < 0)
8091             for_width = 0;
8092         }
8093
8094       klass = CLUTTER_ACTOR_GET_CLASS (self);
8095       klass->get_preferred_height (self, for_width,
8096                                    &minimum_height,
8097                                    &natural_height);
8098
8099       /* adjust for margin */
8100       minimum_height += (info->margin.top + info->margin.bottom);
8101       natural_height += (info->margin.top + info->margin.bottom);
8102
8103       /* Due to accumulated float errors, it's better not to warn
8104        * on this, but just fix it.
8105        */
8106       if (natural_height < minimum_height)
8107         natural_height = minimum_height;
8108
8109       cached_size_request->min_size = minimum_height;
8110       cached_size_request->natural_size = natural_height;
8111       cached_size_request->for_size = for_width;
8112       cached_size_request->age = priv->cached_height_age;
8113
8114       priv->cached_height_age += 1;
8115       priv->needs_height_request = FALSE;
8116     }
8117
8118   if (!priv->min_height_set)
8119     request_min_height = cached_size_request->min_size;
8120   else
8121     request_min_height = info->min_height;
8122
8123   if (!priv->natural_height_set)
8124     request_natural_height = cached_size_request->natural_size;
8125   else
8126     request_natural_height = info->natural_height;
8127
8128   if (min_height_p)
8129     *min_height_p = request_min_height;
8130
8131   if (natural_height_p)
8132     *natural_height_p = request_natural_height;
8133 }
8134
8135 /**
8136  * clutter_actor_get_allocation_box:
8137  * @self: A #ClutterActor
8138  * @box: (out): the function fills this in with the actor's allocation
8139  *
8140  * Gets the layout box an actor has been assigned. The allocation can
8141  * only be assumed valid inside a paint() method; anywhere else, it
8142  * may be out-of-date.
8143  *
8144  * An allocation does not incorporate the actor's scale or anchor point;
8145  * those transformations do not affect layout, only rendering.
8146  *
8147  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8148  * of functions inside the implementation of the get_preferred_width()
8149  * or get_preferred_height() virtual functions.</note>
8150  *
8151  * Since: 0.8
8152  */
8153 void
8154 clutter_actor_get_allocation_box (ClutterActor    *self,
8155                                   ClutterActorBox *box)
8156 {
8157   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8158
8159   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8160    * which limits calling get_allocation to inside paint() basically; or
8161    * we can 2) force a layout, which could be expensive if someone calls
8162    * get_allocation somewhere silly; or we can 3) just return the latest
8163    * value, allowing it to be out-of-date, and assume people know what
8164    * they are doing.
8165    *
8166    * The least-surprises approach that keeps existing code working is
8167    * likely to be 2). People can end up doing some inefficient things,
8168    * though, and in general code that requires 2) is probably broken.
8169    */
8170
8171   /* this implements 2) */
8172   if (G_UNLIKELY (self->priv->needs_allocation))
8173     {
8174       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8175
8176       /* do not queue a relayout on an unparented actor */
8177       if (stage)
8178         _clutter_stage_maybe_relayout (stage);
8179     }
8180
8181   /* commenting out the code above and just keeping this assigment
8182    * implements 3)
8183    */
8184   *box = self->priv->allocation;
8185 }
8186
8187 /**
8188  * clutter_actor_get_allocation_geometry:
8189  * @self: A #ClutterActor
8190  * @geom: (out): allocation geometry in pixels
8191  *
8192  * Gets the layout box an actor has been assigned.  The allocation can
8193  * only be assumed valid inside a paint() method; anywhere else, it
8194  * may be out-of-date.
8195  *
8196  * An allocation does not incorporate the actor's scale or anchor point;
8197  * those transformations do not affect layout, only rendering.
8198  *
8199  * The returned rectangle is in pixels.
8200  *
8201  * Since: 0.8
8202  */
8203 void
8204 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8205                                        ClutterGeometry *geom)
8206 {
8207   ClutterActorBox box;
8208
8209   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8210   g_return_if_fail (geom != NULL);
8211
8212   clutter_actor_get_allocation_box (self, &box);
8213
8214   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8215   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8216   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8217   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8218 }
8219
8220 static void
8221 clutter_actor_update_constraints (ClutterActor    *self,
8222                                   ClutterActorBox *allocation)
8223 {
8224   ClutterActorPrivate *priv = self->priv;
8225   const GList *constraints, *l;
8226
8227   if (priv->constraints == NULL)
8228     return;
8229
8230   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8231   for (l = constraints; l != NULL; l = l->next)
8232     {
8233       ClutterConstraint *constraint = l->data;
8234       ClutterActorMeta *meta = l->data;
8235
8236       if (clutter_actor_meta_get_enabled (meta))
8237         {
8238           _clutter_constraint_update_allocation (constraint,
8239                                                  self,
8240                                                  allocation);
8241
8242           CLUTTER_NOTE (LAYOUT,
8243                         "Allocation of '%s' after constraint '%s': "
8244                         "{ %.2f, %.2f, %.2f, %.2f }",
8245                         _clutter_actor_get_debug_name (self),
8246                         _clutter_actor_meta_get_debug_name (meta),
8247                         allocation->x1,
8248                         allocation->y1,
8249                         allocation->x2,
8250                         allocation->y2);
8251         }
8252     }
8253 }
8254
8255 /*< private >
8256  * clutter_actor_adjust_allocation:
8257  * @self: a #ClutterActor
8258  * @allocation: (inout): the allocation to adjust
8259  *
8260  * Adjusts the passed allocation box taking into account the actor's
8261  * layout information, like alignment, expansion, and margin.
8262  */
8263 static void
8264 clutter_actor_adjust_allocation (ClutterActor    *self,
8265                                  ClutterActorBox *allocation)
8266 {
8267   ClutterActorBox adj_allocation;
8268   float alloc_width, alloc_height;
8269   float min_width, min_height;
8270   float nat_width, nat_height;
8271   ClutterRequestMode req_mode;
8272
8273   adj_allocation = *allocation;
8274
8275   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8276
8277   /* we want to hit the cache, so we use the public API */
8278   req_mode = clutter_actor_get_request_mode (self);
8279
8280   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8281     {
8282       clutter_actor_get_preferred_width (self, -1,
8283                                          &min_width,
8284                                          &nat_width);
8285       clutter_actor_get_preferred_height (self, alloc_width,
8286                                           &min_height,
8287                                           &nat_height);
8288     }
8289   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8290     {
8291       clutter_actor_get_preferred_height (self, -1,
8292                                           &min_height,
8293                                           &nat_height);
8294       clutter_actor_get_preferred_height (self, alloc_height,
8295                                           &min_width,
8296                                           &nat_width);
8297     }
8298
8299 #ifdef CLUTTER_ENABLE_DEBUG
8300   /* warn about underallocations */
8301   if (_clutter_diagnostic_enabled () &&
8302       (floorf (min_width - alloc_width) > 0 ||
8303        floorf (min_height - alloc_height) > 0))
8304     {
8305       ClutterActor *parent = clutter_actor_get_parent (self);
8306
8307       /* the only actors that are allowed to be underallocated are the Stage,
8308        * as it doesn't have an implicit size, and Actors that specifically
8309        * told us that they want to opt-out from layout control mechanisms
8310        * through the NO_LAYOUT escape hatch.
8311        */
8312       if (parent != NULL &&
8313           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8314         {
8315           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8316                      "of %.2f x %.2f from its parent actor '%s', but its "
8317                      "requested minimum size is of %.2f x %.2f",
8318                      _clutter_actor_get_debug_name (self),
8319                      alloc_width, alloc_height,
8320                      _clutter_actor_get_debug_name (parent),
8321                      min_width, min_height);
8322         }
8323     }
8324 #endif
8325
8326   clutter_actor_adjust_width (self,
8327                               &min_width,
8328                               &nat_width,
8329                               &adj_allocation.x1,
8330                               &adj_allocation.x2);
8331
8332   clutter_actor_adjust_height (self,
8333                                &min_height,
8334                                &nat_height,
8335                                &adj_allocation.y1,
8336                                &adj_allocation.y2);
8337
8338   /* we maintain the invariant that an allocation cannot be adjusted
8339    * to be outside the parent-given box
8340    */
8341   if (adj_allocation.x1 < allocation->x1 ||
8342       adj_allocation.y1 < allocation->y1 ||
8343       adj_allocation.x2 > allocation->x2 ||
8344       adj_allocation.y2 > allocation->y2)
8345     {
8346       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8347                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8348                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8349                  _clutter_actor_get_debug_name (self),
8350                  adj_allocation.x1, adj_allocation.y1,
8351                  adj_allocation.x2 - adj_allocation.x1,
8352                  adj_allocation.y2 - adj_allocation.y1,
8353                  allocation->x1, allocation->y1,
8354                  allocation->x2 - allocation->x1,
8355                  allocation->y2 - allocation->y1);
8356       return;
8357     }
8358
8359   *allocation = adj_allocation;
8360 }
8361
8362 /**
8363  * clutter_actor_allocate:
8364  * @self: A #ClutterActor
8365  * @box: new allocation of the actor, in parent-relative coordinates
8366  * @flags: flags that control the allocation
8367  *
8368  * Called by the parent of an actor to assign the actor its size.
8369  * Should never be called by applications (except when implementing
8370  * a container or layout manager).
8371  *
8372  * Actors can know from their allocation box whether they have moved
8373  * with respect to their parent actor. The @flags parameter describes
8374  * additional information about the allocation, for instance whether
8375  * the parent has moved with respect to the stage, for example because
8376  * a grandparent's origin has moved.
8377  *
8378  * Since: 0.8
8379  */
8380 void
8381 clutter_actor_allocate (ClutterActor           *self,
8382                         const ClutterActorBox  *box,
8383                         ClutterAllocationFlags  flags)
8384 {
8385   ClutterActorPrivate *priv;
8386   ClutterActorClass *klass;
8387   ClutterActorBox old_allocation, real_allocation;
8388   gboolean origin_changed, child_moved, size_changed;
8389   gboolean stage_allocation_changed;
8390
8391   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8392   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8393     {
8394       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8395                  "which isn't a descendent of the stage!\n",
8396                  self, _clutter_actor_get_debug_name (self));
8397       return;
8398     }
8399
8400   priv = self->priv;
8401
8402   old_allocation = priv->allocation;
8403   real_allocation = *box;
8404
8405   /* constraints are allowed to modify the allocation only here; we do
8406    * this prior to all the other checks so that we can bail out if the
8407    * allocation did not change
8408    */
8409   clutter_actor_update_constraints (self, &real_allocation);
8410
8411   /* adjust the allocation depending on the align/margin properties */
8412   clutter_actor_adjust_allocation (self, &real_allocation);
8413
8414   if (real_allocation.x2 < real_allocation.x1 ||
8415       real_allocation.y2 < real_allocation.y1)
8416     {
8417       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8418                  _clutter_actor_get_debug_name (self),
8419                  real_allocation.x2 - real_allocation.x1,
8420                  real_allocation.y2 - real_allocation.y1);
8421     }
8422
8423   /* we allow 0-sized actors, but not negative-sized ones */
8424   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8425   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8426
8427   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8428
8429   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8430                  real_allocation.y1 != old_allocation.y1);
8431
8432   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8433                   real_allocation.y2 != old_allocation.y2);
8434
8435   if (origin_changed || child_moved || size_changed)
8436     stage_allocation_changed = TRUE;
8437   else
8438     stage_allocation_changed = FALSE;
8439
8440   /* If we get an allocation "out of the blue"
8441    * (we did not queue relayout), then we want to
8442    * ignore it. But if we have needs_allocation set,
8443    * we want to guarantee that allocate() virtual
8444    * method is always called, i.e. that queue_relayout()
8445    * always results in an allocate() invocation on
8446    * an actor.
8447    *
8448    * The optimization here is to avoid re-allocating
8449    * actors that did not queue relayout and were
8450    * not moved.
8451    */
8452   if (!priv->needs_allocation && !stage_allocation_changed)
8453     {
8454       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8455       return;
8456     }
8457
8458   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8459    * clutter_actor_allocate(), it indicates whether the parent has its
8460    * absolute origin moved; when passed in to ClutterActor::allocate()
8461    * virtual method though, it indicates whether the child has its
8462    * absolute origin moved.  So we set it when child_moved is TRUE
8463    */
8464   if (child_moved)
8465     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8466
8467   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8468
8469   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8470                 _clutter_actor_get_debug_name (self));
8471
8472   klass = CLUTTER_ACTOR_GET_CLASS (self);
8473   klass->allocate (self, &real_allocation, flags);
8474
8475   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8476
8477   if (stage_allocation_changed)
8478     clutter_actor_queue_redraw (self);
8479 }
8480
8481 /**
8482  * clutter_actor_set_allocation:
8483  * @self: a #ClutterActor
8484  * @box: a #ClutterActorBox
8485  * @flags: allocation flags
8486  *
8487  * Stores the allocation of @self as defined by @box.
8488  *
8489  * This function can only be called from within the implementation of
8490  * the #ClutterActorClass.allocate() virtual function.
8491  *
8492  * The allocation should have been adjusted to take into account constraints,
8493  * alignment, and margin properties. If you are implementing a #ClutterActor
8494  * subclass that provides its own layout management policy for its children
8495  * instead of using a #ClutterLayoutManager delegate, you should not call
8496  * this function on the children of @self; instead, you should call
8497  * clutter_actor_allocate(), which will adjust the allocation box for
8498  * you.
8499  *
8500  * This function should only be used by subclasses of #ClutterActor
8501  * that wish to store their allocation but cannot chain up to the
8502  * parent's implementation; the default implementation of the
8503  * #ClutterActorClass.allocate() virtual function will call this
8504  * function.
8505  *
8506  * It is important to note that, while chaining up was the recommended
8507  * behaviour for #ClutterActor subclasses prior to the introduction of
8508  * this function, it is recommended to call clutter_actor_set_allocation()
8509  * instead.
8510  *
8511  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8512  * to handle the allocation of its children, this function will call
8513  * the clutter_layout_manager_allocate() function only if the
8514  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8515  * expected that the subclass will call clutter_layout_manager_allocate()
8516  * by itself. For instance, the following code:
8517  *
8518  * |[
8519  * static void
8520  * my_actor_allocate (ClutterActor *actor,
8521  *                    const ClutterActorBox *allocation,
8522  *                    ClutterAllocationFlags flags)
8523  * {
8524  *   ClutterActorBox new_alloc;
8525  *   ClutterAllocationFlags new_flags;
8526  *
8527  *   adjust_allocation (allocation, &amp;new_alloc);
8528  *
8529  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8530  *
8531  *   /&ast; this will use the layout manager set on the actor &ast;/
8532  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8533  * }
8534  * ]|
8535  *
8536  * is equivalent to this:
8537  *
8538  * |[
8539  * static void
8540  * my_actor_allocate (ClutterActor *actor,
8541  *                    const ClutterActorBox *allocation,
8542  *                    ClutterAllocationFlags flags)
8543  * {
8544  *   ClutterLayoutManager *layout;
8545  *   ClutterActorBox new_alloc;
8546  *
8547  *   adjust_allocation (allocation, &amp;new_alloc);
8548  *
8549  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8550  *
8551  *   layout = clutter_actor_get_layout_manager (actor);
8552  *   clutter_layout_manager_allocate (layout,
8553  *                                    CLUTTER_CONTAINER (actor),
8554  *                                    &amp;new_alloc,
8555  *                                    flags);
8556  * }
8557  * ]|
8558  *
8559  * Since: 1.10
8560  */
8561 void
8562 clutter_actor_set_allocation (ClutterActor           *self,
8563                               const ClutterActorBox  *box,
8564                               ClutterAllocationFlags  flags)
8565 {
8566   ClutterActorPrivate *priv;
8567   gboolean changed;
8568
8569   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8570   g_return_if_fail (box != NULL);
8571
8572   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8573     {
8574       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8575                   "can only be called from within the implementation of "
8576                   "the ClutterActor::allocate() virtual function.");
8577       return;
8578     }
8579
8580   priv = self->priv;
8581
8582   g_object_freeze_notify (G_OBJECT (self));
8583
8584   changed = clutter_actor_set_allocation_internal (self, box, flags);
8585
8586   /* we allocate our children before we notify changes in our geometry,
8587    * so that people connecting to properties will be able to get valid
8588    * data out of the sub-tree of the scene graph that has this actor at
8589    * the root.
8590    */
8591   clutter_actor_maybe_layout_children (self, box, flags);
8592
8593   if (changed)
8594     {
8595       ClutterActorBox signal_box = priv->allocation;
8596       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8597
8598       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8599                      &signal_box,
8600                      signal_flags);
8601     }
8602
8603   g_object_thaw_notify (G_OBJECT (self));
8604 }
8605
8606 /**
8607  * clutter_actor_set_geometry:
8608  * @self: A #ClutterActor
8609  * @geometry: A #ClutterGeometry
8610  *
8611  * Sets the actor's fixed position and forces its minimum and natural
8612  * size, in pixels. This means the untransformed actor will have the
8613  * given geometry. This is the same as calling clutter_actor_set_position()
8614  * and clutter_actor_set_size().
8615  *
8616  * Deprecated: 1.10: Use clutter_actor_set_position() and
8617  *   clutter_actor_set_size() instead.
8618  */
8619 void
8620 clutter_actor_set_geometry (ClutterActor          *self,
8621                             const ClutterGeometry *geometry)
8622 {
8623   g_object_freeze_notify (G_OBJECT (self));
8624
8625   clutter_actor_set_position (self, geometry->x, geometry->y);
8626   clutter_actor_set_size (self, geometry->width, geometry->height);
8627
8628   g_object_thaw_notify (G_OBJECT (self));
8629 }
8630
8631 /**
8632  * clutter_actor_get_geometry:
8633  * @self: A #ClutterActor
8634  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8635  *
8636  * Gets the size and position of an actor relative to its parent
8637  * actor. This is the same as calling clutter_actor_get_position() and
8638  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8639  * requested size and position if the actor's allocation is invalid.
8640  *
8641  * Deprecated: 1.10: Use clutter_actor_get_position() and
8642  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8643  *   instead.
8644  */
8645 void
8646 clutter_actor_get_geometry (ClutterActor    *self,
8647                             ClutterGeometry *geometry)
8648 {
8649   gfloat x, y, width, height;
8650
8651   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8652   g_return_if_fail (geometry != NULL);
8653
8654   clutter_actor_get_position (self, &x, &y);
8655   clutter_actor_get_size (self, &width, &height);
8656
8657   geometry->x = (int) x;
8658   geometry->y = (int) y;
8659   geometry->width = (int) width;
8660   geometry->height = (int) height;
8661 }
8662
8663 /**
8664  * clutter_actor_set_position:
8665  * @self: A #ClutterActor
8666  * @x: New left position of actor in pixels.
8667  * @y: New top position of actor in pixels.
8668  *
8669  * Sets the actor's fixed position in pixels relative to any parent
8670  * actor.
8671  *
8672  * If a layout manager is in use, this position will override the
8673  * layout manager and force a fixed position.
8674  */
8675 void
8676 clutter_actor_set_position (ClutterActor *self,
8677                             gfloat        x,
8678                             gfloat        y)
8679 {
8680   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8681
8682   g_object_freeze_notify (G_OBJECT (self));
8683
8684   clutter_actor_set_x (self, x);
8685   clutter_actor_set_y (self, y);
8686
8687   g_object_thaw_notify (G_OBJECT (self));
8688 }
8689
8690 /**
8691  * clutter_actor_get_fixed_position_set:
8692  * @self: A #ClutterActor
8693  *
8694  * Checks whether an actor has a fixed position set (and will thus be
8695  * unaffected by any layout manager).
8696  *
8697  * Return value: %TRUE if the fixed position is set on the actor
8698  *
8699  * Since: 0.8
8700  */
8701 gboolean
8702 clutter_actor_get_fixed_position_set (ClutterActor *self)
8703 {
8704   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8705
8706   return self->priv->position_set;
8707 }
8708
8709 /**
8710  * clutter_actor_set_fixed_position_set:
8711  * @self: A #ClutterActor
8712  * @is_set: whether to use fixed position
8713  *
8714  * Sets whether an actor has a fixed position set (and will thus be
8715  * unaffected by any layout manager).
8716  *
8717  * Since: 0.8
8718  */
8719 void
8720 clutter_actor_set_fixed_position_set (ClutterActor *self,
8721                                       gboolean      is_set)
8722 {
8723   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8724
8725   if (self->priv->position_set == (is_set != FALSE))
8726     return;
8727
8728   self->priv->position_set = is_set != FALSE;
8729   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8730
8731   clutter_actor_queue_relayout (self);
8732 }
8733
8734 /**
8735  * clutter_actor_move_by:
8736  * @self: A #ClutterActor
8737  * @dx: Distance to move Actor on X axis.
8738  * @dy: Distance to move Actor on Y axis.
8739  *
8740  * Moves an actor by the specified distance relative to its current
8741  * position in pixels.
8742  *
8743  * This function modifies the fixed position of an actor and thus removes
8744  * it from any layout management. Another way to move an actor is with an
8745  * anchor point, see clutter_actor_set_anchor_point().
8746  *
8747  * Since: 0.2
8748  */
8749 void
8750 clutter_actor_move_by (ClutterActor *self,
8751                        gfloat        dx,
8752                        gfloat        dy)
8753 {
8754   const ClutterLayoutInfo *info;
8755   gfloat x, y;
8756
8757   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8758
8759   info = _clutter_actor_get_layout_info_or_defaults (self);
8760   x = info->fixed_x;
8761   y = info->fixed_y;
8762
8763   clutter_actor_set_position (self, x + dx, y + dy);
8764 }
8765
8766 static void
8767 clutter_actor_set_min_width (ClutterActor *self,
8768                              gfloat        min_width)
8769 {
8770   ClutterActorPrivate *priv = self->priv;
8771   ClutterActorBox old = { 0, };
8772   ClutterLayoutInfo *info;
8773
8774   /* if we are setting the size on a top-level actor and the
8775    * backend only supports static top-levels (e.g. framebuffers)
8776    * then we ignore the passed value and we override it with
8777    * the stage implementation's preferred size.
8778    */
8779   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8780       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8781     return;
8782
8783   info = _clutter_actor_get_layout_info (self);
8784
8785   if (priv->min_width_set && min_width == info->min_width)
8786     return;
8787
8788   g_object_freeze_notify (G_OBJECT (self));
8789
8790   clutter_actor_store_old_geometry (self, &old);
8791
8792   info->min_width = min_width;
8793   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8794   clutter_actor_set_min_width_set (self, TRUE);
8795
8796   clutter_actor_notify_if_geometry_changed (self, &old);
8797
8798   g_object_thaw_notify (G_OBJECT (self));
8799
8800   clutter_actor_queue_relayout (self);
8801 }
8802
8803 static void
8804 clutter_actor_set_min_height (ClutterActor *self,
8805                               gfloat        min_height)
8806
8807 {
8808   ClutterActorPrivate *priv = self->priv;
8809   ClutterActorBox old = { 0, };
8810   ClutterLayoutInfo *info;
8811
8812   /* if we are setting the size on a top-level actor and the
8813    * backend only supports static top-levels (e.g. framebuffers)
8814    * then we ignore the passed value and we override it with
8815    * the stage implementation's preferred size.
8816    */
8817   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8818       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8819     return;
8820
8821   info = _clutter_actor_get_layout_info (self);
8822
8823   if (priv->min_height_set && min_height == info->min_height)
8824     return;
8825
8826   g_object_freeze_notify (G_OBJECT (self));
8827
8828   clutter_actor_store_old_geometry (self, &old);
8829
8830   info->min_height = min_height;
8831   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8832   clutter_actor_set_min_height_set (self, TRUE);
8833
8834   clutter_actor_notify_if_geometry_changed (self, &old);
8835
8836   g_object_thaw_notify (G_OBJECT (self));
8837
8838   clutter_actor_queue_relayout (self);
8839 }
8840
8841 static void
8842 clutter_actor_set_natural_width (ClutterActor *self,
8843                                  gfloat        natural_width)
8844 {
8845   ClutterActorPrivate *priv = self->priv;
8846   ClutterActorBox old = { 0, };
8847   ClutterLayoutInfo *info;
8848
8849   /* if we are setting the size on a top-level actor and the
8850    * backend only supports static top-levels (e.g. framebuffers)
8851    * then we ignore the passed value and we override it with
8852    * the stage implementation's preferred size.
8853    */
8854   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8855       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8856     return;
8857
8858   info = _clutter_actor_get_layout_info (self);
8859
8860   if (priv->natural_width_set && natural_width == info->natural_width)
8861     return;
8862
8863   g_object_freeze_notify (G_OBJECT (self));
8864
8865   clutter_actor_store_old_geometry (self, &old);
8866
8867   info->natural_width = natural_width;
8868   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8869   clutter_actor_set_natural_width_set (self, TRUE);
8870
8871   clutter_actor_notify_if_geometry_changed (self, &old);
8872
8873   g_object_thaw_notify (G_OBJECT (self));
8874
8875   clutter_actor_queue_relayout (self);
8876 }
8877
8878 static void
8879 clutter_actor_set_natural_height (ClutterActor *self,
8880                                   gfloat        natural_height)
8881 {
8882   ClutterActorPrivate *priv = self->priv;
8883   ClutterActorBox old = { 0, };
8884   ClutterLayoutInfo *info;
8885
8886   /* if we are setting the size on a top-level actor and the
8887    * backend only supports static top-levels (e.g. framebuffers)
8888    * then we ignore the passed value and we override it with
8889    * the stage implementation's preferred size.
8890    */
8891   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8892       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8893     return;
8894
8895   info = _clutter_actor_get_layout_info (self);
8896
8897   if (priv->natural_height_set && natural_height == info->natural_height)
8898     return;
8899
8900   g_object_freeze_notify (G_OBJECT (self));
8901
8902   clutter_actor_store_old_geometry (self, &old);
8903
8904   info->natural_height = natural_height;
8905   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8906   clutter_actor_set_natural_height_set (self, TRUE);
8907
8908   clutter_actor_notify_if_geometry_changed (self, &old);
8909
8910   g_object_thaw_notify (G_OBJECT (self));
8911
8912   clutter_actor_queue_relayout (self);
8913 }
8914
8915 static void
8916 clutter_actor_set_min_width_set (ClutterActor *self,
8917                                  gboolean      use_min_width)
8918 {
8919   ClutterActorPrivate *priv = self->priv;
8920   ClutterActorBox old = { 0, };
8921
8922   if (priv->min_width_set == (use_min_width != FALSE))
8923     return;
8924
8925   clutter_actor_store_old_geometry (self, &old);
8926
8927   priv->min_width_set = use_min_width != FALSE;
8928   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8929
8930   clutter_actor_notify_if_geometry_changed (self, &old);
8931
8932   clutter_actor_queue_relayout (self);
8933 }
8934
8935 static void
8936 clutter_actor_set_min_height_set (ClutterActor *self,
8937                                   gboolean      use_min_height)
8938 {
8939   ClutterActorPrivate *priv = self->priv;
8940   ClutterActorBox old = { 0, };
8941
8942   if (priv->min_height_set == (use_min_height != FALSE))
8943     return;
8944
8945   clutter_actor_store_old_geometry (self, &old);
8946
8947   priv->min_height_set = use_min_height != FALSE;
8948   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8949
8950   clutter_actor_notify_if_geometry_changed (self, &old);
8951
8952   clutter_actor_queue_relayout (self);
8953 }
8954
8955 static void
8956 clutter_actor_set_natural_width_set (ClutterActor *self,
8957                                      gboolean      use_natural_width)
8958 {
8959   ClutterActorPrivate *priv = self->priv;
8960   ClutterActorBox old = { 0, };
8961
8962   if (priv->natural_width_set == (use_natural_width != FALSE))
8963     return;
8964
8965   clutter_actor_store_old_geometry (self, &old);
8966
8967   priv->natural_width_set = use_natural_width != FALSE;
8968   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8969
8970   clutter_actor_notify_if_geometry_changed (self, &old);
8971
8972   clutter_actor_queue_relayout (self);
8973 }
8974
8975 static void
8976 clutter_actor_set_natural_height_set (ClutterActor *self,
8977                                       gboolean      use_natural_height)
8978 {
8979   ClutterActorPrivate *priv = self->priv;
8980   ClutterActorBox old = { 0, };
8981
8982   if (priv->natural_height_set == (use_natural_height != FALSE))
8983     return;
8984
8985   clutter_actor_store_old_geometry (self, &old);
8986
8987   priv->natural_height_set = use_natural_height != FALSE;
8988   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8989
8990   clutter_actor_notify_if_geometry_changed (self, &old);
8991
8992   clutter_actor_queue_relayout (self);
8993 }
8994
8995 /**
8996  * clutter_actor_set_request_mode:
8997  * @self: a #ClutterActor
8998  * @mode: the request mode
8999  *
9000  * Sets the geometry request mode of @self.
9001  *
9002  * The @mode determines the order for invoking
9003  * clutter_actor_get_preferred_width() and
9004  * clutter_actor_get_preferred_height()
9005  *
9006  * Since: 1.2
9007  */
9008 void
9009 clutter_actor_set_request_mode (ClutterActor       *self,
9010                                 ClutterRequestMode  mode)
9011 {
9012   ClutterActorPrivate *priv;
9013
9014   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9015
9016   priv = self->priv;
9017
9018   if (priv->request_mode == mode)
9019     return;
9020
9021   priv->request_mode = mode;
9022
9023   priv->needs_width_request = TRUE;
9024   priv->needs_height_request = TRUE;
9025
9026   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9027
9028   clutter_actor_queue_relayout (self);
9029 }
9030
9031 /**
9032  * clutter_actor_get_request_mode:
9033  * @self: a #ClutterActor
9034  *
9035  * Retrieves the geometry request mode of @self
9036  *
9037  * Return value: the request mode for the actor
9038  *
9039  * Since: 1.2
9040  */
9041 ClutterRequestMode
9042 clutter_actor_get_request_mode (ClutterActor *self)
9043 {
9044   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9045                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9046
9047   return self->priv->request_mode;
9048 }
9049
9050 /* variant of set_width() without checks and without notification
9051  * freeze+thaw, for internal usage only
9052  */
9053 static inline void
9054 clutter_actor_set_width_internal (ClutterActor *self,
9055                                   gfloat        width)
9056 {
9057   if (width >= 0)
9058     {
9059       /* the Stage will use the :min-width to control the minimum
9060        * width to be resized to, so we should not be setting it
9061        * along with the :natural-width
9062        */
9063       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9064         clutter_actor_set_min_width (self, width);
9065
9066       clutter_actor_set_natural_width (self, width);
9067     }
9068   else
9069     {
9070       /* we only unset the :natural-width for the Stage */
9071       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9072         clutter_actor_set_min_width_set (self, FALSE);
9073
9074       clutter_actor_set_natural_width_set (self, FALSE);
9075     }
9076 }
9077
9078 /* variant of set_height() without checks and without notification
9079  * freeze+thaw, for internal usage only
9080  */
9081 static inline void
9082 clutter_actor_set_height_internal (ClutterActor *self,
9083                                    gfloat        height)
9084 {
9085   if (height >= 0)
9086     {
9087       /* see the comment above in set_width_internal() */
9088       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9089         clutter_actor_set_min_height (self, height);
9090
9091       clutter_actor_set_natural_height (self, height);
9092     }
9093   else
9094     {
9095       /* see the comment above in set_width_internal() */
9096       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9097         clutter_actor_set_min_height_set (self, FALSE);
9098
9099       clutter_actor_set_natural_height_set (self, FALSE);
9100     }
9101 }
9102
9103 /**
9104  * clutter_actor_set_size:
9105  * @self: A #ClutterActor
9106  * @width: New width of actor in pixels, or -1
9107  * @height: New height of actor in pixels, or -1
9108  *
9109  * Sets the actor's size request in pixels. This overrides any
9110  * "normal" size request the actor would have. For example
9111  * a text actor might normally request the size of the text;
9112  * this function would force a specific size instead.
9113  *
9114  * If @width and/or @height are -1 the actor will use its
9115  * "normal" size request instead of overriding it, i.e.
9116  * you can "unset" the size with -1.
9117  *
9118  * This function sets or unsets both the minimum and natural size.
9119  */
9120 void
9121 clutter_actor_set_size (ClutterActor *self,
9122                         gfloat        width,
9123                         gfloat        height)
9124 {
9125   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9126
9127   g_object_freeze_notify (G_OBJECT (self));
9128
9129   clutter_actor_set_width (self, width);
9130   clutter_actor_set_height (self, height);
9131
9132   g_object_thaw_notify (G_OBJECT (self));
9133 }
9134
9135 /**
9136  * clutter_actor_get_size:
9137  * @self: A #ClutterActor
9138  * @width: (out) (allow-none): return location for the width, or %NULL.
9139  * @height: (out) (allow-none): return location for the height, or %NULL.
9140  *
9141  * This function tries to "do what you mean" and return
9142  * the size an actor will have. If the actor has a valid
9143  * allocation, the allocation will be returned; otherwise,
9144  * the actors natural size request will be returned.
9145  *
9146  * If you care whether you get the request vs. the allocation, you
9147  * should probably call a different function like
9148  * clutter_actor_get_allocation_box() or
9149  * clutter_actor_get_preferred_width().
9150  *
9151  * Since: 0.2
9152  */
9153 void
9154 clutter_actor_get_size (ClutterActor *self,
9155                         gfloat       *width,
9156                         gfloat       *height)
9157 {
9158   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9159
9160   if (width)
9161     *width = clutter_actor_get_width (self);
9162
9163   if (height)
9164     *height = clutter_actor_get_height (self);
9165 }
9166
9167 /**
9168  * clutter_actor_get_position:
9169  * @self: a #ClutterActor
9170  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9171  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9172  *
9173  * This function tries to "do what you mean" and tell you where the
9174  * actor is, prior to any transformations. Retrieves the fixed
9175  * position of an actor in pixels, if one has been set; otherwise, if
9176  * the allocation is valid, returns the actor's allocated position;
9177  * otherwise, returns 0,0.
9178  *
9179  * The returned position is in pixels.
9180  *
9181  * Since: 0.6
9182  */
9183 void
9184 clutter_actor_get_position (ClutterActor *self,
9185                             gfloat       *x,
9186                             gfloat       *y)
9187 {
9188   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9189
9190   if (x)
9191     *x = clutter_actor_get_x (self);
9192
9193   if (y)
9194     *y = clutter_actor_get_y (self);
9195 }
9196
9197 /**
9198  * clutter_actor_get_transformed_position:
9199  * @self: A #ClutterActor
9200  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9201  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9202  *
9203  * Gets the absolute position of an actor, in pixels relative to the stage.
9204  *
9205  * Since: 0.8
9206  */
9207 void
9208 clutter_actor_get_transformed_position (ClutterActor *self,
9209                                         gfloat       *x,
9210                                         gfloat       *y)
9211 {
9212   ClutterVertex v1;
9213   ClutterVertex v2;
9214
9215   v1.x = v1.y = v1.z = 0;
9216   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9217
9218   if (x)
9219     *x = v2.x;
9220
9221   if (y)
9222     *y = v2.y;
9223 }
9224
9225 /**
9226  * clutter_actor_get_transformed_size:
9227  * @self: A #ClutterActor
9228  * @width: (out) (allow-none): return location for the width, or %NULL
9229  * @height: (out) (allow-none): return location for the height, or %NULL
9230  *
9231  * Gets the absolute size of an actor in pixels, taking into account the
9232  * scaling factors.
9233  *
9234  * If the actor has a valid allocation, the allocated size will be used.
9235  * If the actor has not a valid allocation then the preferred size will
9236  * be transformed and returned.
9237  *
9238  * If you want the transformed allocation, see
9239  * clutter_actor_get_abs_allocation_vertices() instead.
9240  *
9241  * <note>When the actor (or one of its ancestors) is rotated around the
9242  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9243  * as a generic quadrangle; in that case this function returns the size
9244  * of the smallest rectangle that encapsulates the entire quad. Please
9245  * note that in this case no assumptions can be made about the relative
9246  * position of this envelope to the absolute position of the actor, as
9247  * returned by clutter_actor_get_transformed_position(); if you need this
9248  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9249  * to get the coords of the actual quadrangle.</note>
9250  *
9251  * Since: 0.8
9252  */
9253 void
9254 clutter_actor_get_transformed_size (ClutterActor *self,
9255                                     gfloat       *width,
9256                                     gfloat       *height)
9257 {
9258   ClutterActorPrivate *priv;
9259   ClutterVertex v[4];
9260   gfloat x_min, x_max, y_min, y_max;
9261   gint i;
9262
9263   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9264
9265   priv = self->priv;
9266
9267   /* if the actor hasn't been allocated yet, get the preferred
9268    * size and transform that
9269    */
9270   if (priv->needs_allocation)
9271     {
9272       gfloat natural_width, natural_height;
9273       ClutterActorBox box;
9274
9275       /* Make a fake allocation to transform.
9276        *
9277        * NB: _clutter_actor_transform_and_project_box expects a box in
9278        * the actor's coordinate space... */
9279
9280       box.x1 = 0;
9281       box.y1 = 0;
9282
9283       natural_width = natural_height = 0;
9284       clutter_actor_get_preferred_size (self, NULL, NULL,
9285                                         &natural_width,
9286                                         &natural_height);
9287
9288       box.x2 = natural_width;
9289       box.y2 = natural_height;
9290
9291       _clutter_actor_transform_and_project_box (self, &box, v);
9292     }
9293   else
9294     clutter_actor_get_abs_allocation_vertices (self, v);
9295
9296   x_min = x_max = v[0].x;
9297   y_min = y_max = v[0].y;
9298
9299   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9300     {
9301       if (v[i].x < x_min)
9302         x_min = v[i].x;
9303
9304       if (v[i].x > x_max)
9305         x_max = v[i].x;
9306
9307       if (v[i].y < y_min)
9308         y_min = v[i].y;
9309
9310       if (v[i].y > y_max)
9311         y_max = v[i].y;
9312     }
9313
9314   if (width)
9315     *width  = x_max - x_min;
9316
9317   if (height)
9318     *height = y_max - y_min;
9319 }
9320
9321 /**
9322  * clutter_actor_get_width:
9323  * @self: A #ClutterActor
9324  *
9325  * Retrieves the width of a #ClutterActor.
9326  *
9327  * If the actor has a valid allocation, this function will return the
9328  * width of the allocated area given to the actor.
9329  *
9330  * If the actor does not have a valid allocation, this function will
9331  * return the actor's natural width, that is the preferred width of
9332  * the actor.
9333  *
9334  * If you care whether you get the preferred width or the width that
9335  * has been assigned to the actor, you should probably call a different
9336  * function like clutter_actor_get_allocation_box() to retrieve the
9337  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9338  * preferred width.
9339  *
9340  * If an actor has a fixed width, for instance a width that has been
9341  * assigned using clutter_actor_set_width(), the width returned will
9342  * be the same value.
9343  *
9344  * Return value: the width of the actor, in pixels
9345  */
9346 gfloat
9347 clutter_actor_get_width (ClutterActor *self)
9348 {
9349   ClutterActorPrivate *priv;
9350
9351   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9352
9353   priv = self->priv;
9354
9355   if (priv->needs_allocation)
9356     {
9357       gfloat natural_width = 0;
9358
9359       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9360         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9361       else
9362         {
9363           gfloat natural_height = 0;
9364
9365           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9366           clutter_actor_get_preferred_width (self, natural_height,
9367                                              NULL,
9368                                              &natural_width);
9369         }
9370
9371       return natural_width;
9372     }
9373   else
9374     return priv->allocation.x2 - priv->allocation.x1;
9375 }
9376
9377 /**
9378  * clutter_actor_get_height:
9379  * @self: A #ClutterActor
9380  *
9381  * Retrieves the height of a #ClutterActor.
9382  *
9383  * If the actor has a valid allocation, this function will return the
9384  * height of the allocated area given to the actor.
9385  *
9386  * If the actor does not have a valid allocation, this function will
9387  * return the actor's natural height, that is the preferred height of
9388  * the actor.
9389  *
9390  * If you care whether you get the preferred height or the height that
9391  * has been assigned to the actor, you should probably call a different
9392  * function like clutter_actor_get_allocation_box() to retrieve the
9393  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9394  * preferred height.
9395  *
9396  * If an actor has a fixed height, for instance a height that has been
9397  * assigned using clutter_actor_set_height(), the height returned will
9398  * be the same value.
9399  *
9400  * Return value: the height of the actor, in pixels
9401  */
9402 gfloat
9403 clutter_actor_get_height (ClutterActor *self)
9404 {
9405   ClutterActorPrivate *priv;
9406
9407   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9408
9409   priv = self->priv;
9410
9411   if (priv->needs_allocation)
9412     {
9413       gfloat natural_height = 0;
9414
9415       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9416         {
9417           gfloat natural_width = 0;
9418
9419           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9420           clutter_actor_get_preferred_height (self, natural_width,
9421                                               NULL, &natural_height);
9422         }
9423       else
9424         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9425
9426       return natural_height;
9427     }
9428   else
9429     return priv->allocation.y2 - priv->allocation.y1;
9430 }
9431
9432 /**
9433  * clutter_actor_set_width:
9434  * @self: A #ClutterActor
9435  * @width: Requested new width for the actor, in pixels, or -1
9436  *
9437  * Forces a width on an actor, causing the actor's preferred width
9438  * and height (if any) to be ignored.
9439  *
9440  * If @width is -1 the actor will use its preferred width request
9441  * instead of overriding it, i.e. you can "unset" the width with -1.
9442  *
9443  * This function sets both the minimum and natural size of the actor.
9444  *
9445  * since: 0.2
9446  */
9447 void
9448 clutter_actor_set_width (ClutterActor *self,
9449                          gfloat        width)
9450 {
9451   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9452
9453   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9454     {
9455       float cur_size = clutter_actor_get_width (self);
9456
9457       _clutter_actor_create_transition (self,
9458                                         obj_props[PROP_WIDTH],
9459                                         cur_size,
9460                                         width);
9461     }
9462   else
9463     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9464
9465   clutter_actor_queue_relayout (self);
9466 }
9467
9468 /**
9469  * clutter_actor_set_height:
9470  * @self: A #ClutterActor
9471  * @height: Requested new height for the actor, in pixels, or -1
9472  *
9473  * Forces a height on an actor, causing the actor's preferred width
9474  * and height (if any) to be ignored.
9475  *
9476  * If @height is -1 the actor will use its preferred height instead of
9477  * overriding it, i.e. you can "unset" the height with -1.
9478  *
9479  * This function sets both the minimum and natural size of the actor.
9480  *
9481  * since: 0.2
9482  */
9483 void
9484 clutter_actor_set_height (ClutterActor *self,
9485                           gfloat        height)
9486 {
9487   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9488
9489   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9490     {
9491       float cur_size = clutter_actor_get_height (self);
9492
9493       _clutter_actor_create_transition (self,
9494                                         obj_props[PROP_HEIGHT],
9495                                         cur_size,
9496                                         height);
9497     }
9498   else
9499     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9500
9501   clutter_actor_queue_relayout (self);
9502 }
9503
9504 static inline void
9505 clutter_actor_set_x_internal (ClutterActor *self,
9506                               float         x)
9507 {
9508   ClutterActorPrivate *priv = self->priv;
9509   ClutterLayoutInfo *linfo;
9510   ClutterActorBox old = { 0, };
9511
9512   linfo = _clutter_actor_get_layout_info (self);
9513
9514   if (priv->position_set && linfo->fixed_x == x)
9515     return;
9516
9517   clutter_actor_store_old_geometry (self, &old);
9518
9519   linfo->fixed_x = x;
9520   clutter_actor_set_fixed_position_set (self, TRUE);
9521
9522   clutter_actor_notify_if_geometry_changed (self, &old);
9523
9524   clutter_actor_queue_relayout (self);
9525 }
9526
9527 static inline void
9528 clutter_actor_set_y_internal (ClutterActor *self,
9529                               float         y)
9530 {
9531   ClutterActorPrivate *priv = self->priv;
9532   ClutterLayoutInfo *linfo;
9533   ClutterActorBox old = { 0, };
9534
9535   linfo = _clutter_actor_get_layout_info (self);
9536
9537   if (priv->position_set && linfo->fixed_y == y)
9538     return;
9539
9540   clutter_actor_store_old_geometry (self, &old);
9541
9542   linfo->fixed_y = y;
9543   clutter_actor_set_fixed_position_set (self, TRUE);
9544
9545   clutter_actor_notify_if_geometry_changed (self, &old);
9546
9547   clutter_actor_queue_relayout (self);
9548 }
9549
9550 /**
9551  * clutter_actor_set_x:
9552  * @self: a #ClutterActor
9553  * @x: the actor's position on the X axis
9554  *
9555  * Sets the actor's X coordinate, relative to its parent, in pixels.
9556  *
9557  * Overrides any layout manager and forces a fixed position for
9558  * the actor.
9559  *
9560  * The #ClutterActor:x property is animatable.
9561  *
9562  * Since: 0.6
9563  */
9564 void
9565 clutter_actor_set_x (ClutterActor *self,
9566                      gfloat        x)
9567 {
9568   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9569
9570   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9571     {
9572       float cur_position = clutter_actor_get_x (self);
9573
9574       _clutter_actor_create_transition (self, obj_props[PROP_X],
9575                                         cur_position,
9576                                         x);
9577     }
9578   else
9579     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9580
9581   clutter_actor_queue_relayout (self);
9582 }
9583
9584 /**
9585  * clutter_actor_set_y:
9586  * @self: a #ClutterActor
9587  * @y: the actor's position on the Y axis
9588  *
9589  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9590  *
9591  * Overrides any layout manager and forces a fixed position for
9592  * the actor.
9593  *
9594  * The #ClutterActor:y property is animatable.
9595  *
9596  * Since: 0.6
9597  */
9598 void
9599 clutter_actor_set_y (ClutterActor *self,
9600                      gfloat        y)
9601 {
9602   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9603
9604   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9605     {
9606       float cur_position = clutter_actor_get_y (self);
9607
9608       _clutter_actor_create_transition (self, obj_props[PROP_Y],
9609                                         cur_position,
9610                                         y);
9611     }
9612   else
9613     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9614
9615   clutter_actor_queue_relayout (self);
9616 }
9617
9618 /**
9619  * clutter_actor_get_x:
9620  * @self: A #ClutterActor
9621  *
9622  * Retrieves the X coordinate of a #ClutterActor.
9623  *
9624  * This function tries to "do what you mean", by returning the
9625  * correct value depending on the actor's state.
9626  *
9627  * If the actor has a valid allocation, this function will return
9628  * the X coordinate of the origin of the allocation box.
9629  *
9630  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9631  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9632  * function will return that coordinate.
9633  *
9634  * If both the allocation and a fixed position are missing, this function
9635  * will return 0.
9636  *
9637  * Return value: the X coordinate, in pixels, ignoring any
9638  *   transformation (i.e. scaling, rotation)
9639  */
9640 gfloat
9641 clutter_actor_get_x (ClutterActor *self)
9642 {
9643   ClutterActorPrivate *priv;
9644
9645   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9646
9647   priv = self->priv;
9648
9649   if (priv->needs_allocation)
9650     {
9651       if (priv->position_set)
9652         {
9653           const ClutterLayoutInfo *info;
9654
9655           info = _clutter_actor_get_layout_info_or_defaults (self);
9656
9657           return info->fixed_x;
9658         }
9659       else
9660         return 0;
9661     }
9662   else
9663     return priv->allocation.x1;
9664 }
9665
9666 /**
9667  * clutter_actor_get_y:
9668  * @self: A #ClutterActor
9669  *
9670  * Retrieves the Y coordinate of a #ClutterActor.
9671  *
9672  * This function tries to "do what you mean", by returning the
9673  * correct value depending on the actor's state.
9674  *
9675  * If the actor has a valid allocation, this function will return
9676  * the Y coordinate of the origin of the allocation box.
9677  *
9678  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9679  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9680  * function will return that coordinate.
9681  *
9682  * If both the allocation and a fixed position are missing, this function
9683  * will return 0.
9684  *
9685  * Return value: the Y coordinate, in pixels, ignoring any
9686  *   transformation (i.e. scaling, rotation)
9687  */
9688 gfloat
9689 clutter_actor_get_y (ClutterActor *self)
9690 {
9691   ClutterActorPrivate *priv;
9692
9693   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9694
9695   priv = self->priv;
9696
9697   if (priv->needs_allocation)
9698     {
9699       if (priv->position_set)
9700         {
9701           const ClutterLayoutInfo *info;
9702
9703           info = _clutter_actor_get_layout_info_or_defaults (self);
9704
9705           return info->fixed_y;
9706         }
9707       else
9708         return 0;
9709     }
9710   else
9711     return priv->allocation.y1;
9712 }
9713
9714 /**
9715  * clutter_actor_set_scale:
9716  * @self: A #ClutterActor
9717  * @scale_x: double factor to scale actor by horizontally.
9718  * @scale_y: double factor to scale actor by vertically.
9719  *
9720  * Scales an actor with the given factors. The scaling is relative to
9721  * the scale center and the anchor point. The scale center is
9722  * unchanged by this function and defaults to 0,0.
9723  *
9724  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9725  * animatable.
9726  *
9727  * Since: 0.2
9728  */
9729 void
9730 clutter_actor_set_scale (ClutterActor *self,
9731                          gdouble       scale_x,
9732                          gdouble       scale_y)
9733 {
9734   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9735
9736   g_object_freeze_notify (G_OBJECT (self));
9737
9738   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9739   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9740
9741   g_object_thaw_notify (G_OBJECT (self));
9742 }
9743
9744 /**
9745  * clutter_actor_set_scale_full:
9746  * @self: A #ClutterActor
9747  * @scale_x: double factor to scale actor by horizontally.
9748  * @scale_y: double factor to scale actor by vertically.
9749  * @center_x: X coordinate of the center of the scale.
9750  * @center_y: Y coordinate of the center of the scale
9751  *
9752  * Scales an actor with the given factors around the given center
9753  * point. The center point is specified in pixels relative to the
9754  * anchor point (usually the top left corner of the actor).
9755  *
9756  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9757  * are animatable.
9758  *
9759  * Since: 1.0
9760  */
9761 void
9762 clutter_actor_set_scale_full (ClutterActor *self,
9763                               gdouble       scale_x,
9764                               gdouble       scale_y,
9765                               gfloat        center_x,
9766                               gfloat        center_y)
9767 {
9768   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9769
9770   g_object_freeze_notify (G_OBJECT (self));
9771
9772   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9773   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9774   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9775   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9776
9777   g_object_thaw_notify (G_OBJECT (self));
9778 }
9779
9780 /**
9781  * clutter_actor_set_scale_with_gravity:
9782  * @self: A #ClutterActor
9783  * @scale_x: double factor to scale actor by horizontally.
9784  * @scale_y: double factor to scale actor by vertically.
9785  * @gravity: the location of the scale center expressed as a compass
9786  * direction.
9787  *
9788  * Scales an actor with the given factors around the given
9789  * center point. The center point is specified as one of the compass
9790  * directions in #ClutterGravity. For example, setting it to north
9791  * will cause the top of the actor to remain unchanged and the rest of
9792  * the actor to expand left, right and downwards.
9793  *
9794  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9795  * animatable.
9796  *
9797  * Since: 1.0
9798  */
9799 void
9800 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9801                                       gdouble         scale_x,
9802                                       gdouble         scale_y,
9803                                       ClutterGravity  gravity)
9804 {
9805   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9806
9807   g_object_freeze_notify (G_OBJECT (self));
9808
9809   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9810   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9811   clutter_actor_set_scale_gravity (self, gravity);
9812
9813   g_object_thaw_notify (G_OBJECT (self));
9814 }
9815
9816 /**
9817  * clutter_actor_get_scale:
9818  * @self: A #ClutterActor
9819  * @scale_x: (out) (allow-none): Location to store horizonal
9820  *   scale factor, or %NULL.
9821  * @scale_y: (out) (allow-none): Location to store vertical
9822  *   scale factor, or %NULL.
9823  *
9824  * Retrieves an actors scale factors.
9825  *
9826  * Since: 0.2
9827  */
9828 void
9829 clutter_actor_get_scale (ClutterActor *self,
9830                          gdouble      *scale_x,
9831                          gdouble      *scale_y)
9832 {
9833   const ClutterTransformInfo *info;
9834
9835   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9836
9837   info = _clutter_actor_get_transform_info_or_defaults (self);
9838
9839   if (scale_x)
9840     *scale_x = info->scale_x;
9841
9842   if (scale_y)
9843     *scale_y = info->scale_y;
9844 }
9845
9846 /**
9847  * clutter_actor_get_scale_center:
9848  * @self: A #ClutterActor
9849  * @center_x: (out) (allow-none): Location to store the X position
9850  *   of the scale center, or %NULL.
9851  * @center_y: (out) (allow-none): Location to store the Y position
9852  *   of the scale center, or %NULL.
9853  *
9854  * Retrieves the scale center coordinate in pixels relative to the top
9855  * left corner of the actor. If the scale center was specified using a
9856  * #ClutterGravity this will calculate the pixel offset using the
9857  * current size of the actor.
9858  *
9859  * Since: 1.0
9860  */
9861 void
9862 clutter_actor_get_scale_center (ClutterActor *self,
9863                                 gfloat       *center_x,
9864                                 gfloat       *center_y)
9865 {
9866   const ClutterTransformInfo *info;
9867
9868   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9869
9870   info = _clutter_actor_get_transform_info_or_defaults (self);
9871
9872   clutter_anchor_coord_get_units (self, &info->scale_center,
9873                                   center_x,
9874                                   center_y,
9875                                   NULL);
9876 }
9877
9878 /**
9879  * clutter_actor_get_scale_gravity:
9880  * @self: A #ClutterActor
9881  *
9882  * Retrieves the scale center as a compass direction. If the scale
9883  * center was specified in pixels or units this will return
9884  * %CLUTTER_GRAVITY_NONE.
9885  *
9886  * Return value: the scale gravity
9887  *
9888  * Since: 1.0
9889  */
9890 ClutterGravity
9891 clutter_actor_get_scale_gravity (ClutterActor *self)
9892 {
9893   const ClutterTransformInfo *info;
9894
9895   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9896
9897   info = _clutter_actor_get_transform_info_or_defaults (self);
9898
9899   return clutter_anchor_coord_get_gravity (&info->scale_center);
9900 }
9901
9902 static inline void
9903 clutter_actor_set_opacity_internal (ClutterActor *self,
9904                                     guint8        opacity)
9905 {
9906   ClutterActorPrivate *priv = self->priv;
9907
9908   if (priv->opacity != opacity)
9909     {
9910       priv->opacity = opacity;
9911
9912       /* Queue a redraw from the flatten effect so that it can use
9913          its cached image if available instead of having to redraw the
9914          actual actor. If it doesn't end up using the FBO then the
9915          effect is still able to continue the paint anyway. If there
9916          is no flatten effect yet then this is equivalent to queueing
9917          a full redraw */
9918       _clutter_actor_queue_redraw_full (self,
9919                                         0, /* flags */
9920                                         NULL, /* clip */
9921                                         priv->flatten_effect);
9922
9923       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9924     }
9925 }
9926
9927 /**
9928  * clutter_actor_set_opacity:
9929  * @self: A #ClutterActor
9930  * @opacity: New opacity value for the actor.
9931  *
9932  * Sets the actor's opacity, with zero being completely transparent and
9933  * 255 (0xff) being fully opaque.
9934  *
9935  * The #ClutterActor:opacity property is animatable.
9936  */
9937 void
9938 clutter_actor_set_opacity (ClutterActor *self,
9939                            guint8        opacity)
9940 {
9941   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9942
9943   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
9944     {
9945       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
9946                                         self->priv->opacity,
9947                                         opacity);
9948     }
9949   else
9950     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9951
9952   clutter_actor_queue_redraw (self);
9953 }
9954
9955 /*
9956  * clutter_actor_get_paint_opacity_internal:
9957  * @self: a #ClutterActor
9958  *
9959  * Retrieves the absolute opacity of the actor, as it appears on the stage
9960  *
9961  * This function does not do type checks
9962  *
9963  * Return value: the absolute opacity of the actor
9964  */
9965 static guint8
9966 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9967 {
9968   ClutterActorPrivate *priv = self->priv;
9969   ClutterActor *parent;
9970
9971   /* override the top-level opacity to always be 255; even in
9972    * case of ClutterStage:use-alpha being TRUE we want the rest
9973    * of the scene to be painted
9974    */
9975   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9976     return 255;
9977
9978   if (priv->opacity_override >= 0)
9979     return priv->opacity_override;
9980
9981   parent = priv->parent;
9982
9983   /* Factor in the actual actors opacity with parents */
9984   if (parent != NULL)
9985     {
9986       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9987
9988       if (opacity != 0xff)
9989         return (opacity * priv->opacity) / 0xff;
9990     }
9991
9992   return priv->opacity;
9993
9994 }
9995
9996 /**
9997  * clutter_actor_get_paint_opacity:
9998  * @self: A #ClutterActor
9999  *
10000  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10001  *
10002  * This function traverses the hierarchy chain and composites the opacity of
10003  * the actor with that of its parents.
10004  *
10005  * This function is intended for subclasses to use in the paint virtual
10006  * function, to paint themselves with the correct opacity.
10007  *
10008  * Return value: The actor opacity value.
10009  *
10010  * Since: 0.8
10011  */
10012 guint8
10013 clutter_actor_get_paint_opacity (ClutterActor *self)
10014 {
10015   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10016
10017   return clutter_actor_get_paint_opacity_internal (self);
10018 }
10019
10020 /**
10021  * clutter_actor_get_opacity:
10022  * @self: a #ClutterActor
10023  *
10024  * Retrieves the opacity value of an actor, as set by
10025  * clutter_actor_set_opacity().
10026  *
10027  * For retrieving the absolute opacity of the actor inside a paint
10028  * virtual function, see clutter_actor_get_paint_opacity().
10029  *
10030  * Return value: the opacity of the actor
10031  */
10032 guint8
10033 clutter_actor_get_opacity (ClutterActor *self)
10034 {
10035   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10036
10037   return self->priv->opacity;
10038 }
10039
10040 /**
10041  * clutter_actor_set_offscreen_redirect:
10042  * @self: A #ClutterActor
10043  * @redirect: New offscreen redirect flags for the actor.
10044  *
10045  * Defines the circumstances where the actor should be redirected into
10046  * an offscreen image. The offscreen image is used to flatten the
10047  * actor into a single image while painting for two main reasons.
10048  * Firstly, when the actor is painted a second time without any of its
10049  * contents changing it can simply repaint the cached image without
10050  * descending further down the actor hierarchy. Secondly, it will make
10051  * the opacity look correct even if there are overlapping primitives
10052  * in the actor.
10053  *
10054  * Caching the actor could in some cases be a performance win and in
10055  * some cases be a performance lose so it is important to determine
10056  * which value is right for an actor before modifying this value. For
10057  * example, there is never any reason to flatten an actor that is just
10058  * a single texture (such as a #ClutterTexture) because it is
10059  * effectively already cached in an image so the offscreen would be
10060  * redundant. Also if the actor contains primitives that are far apart
10061  * with a large transparent area in the middle (such as a large
10062  * CluterGroup with a small actor in the top left and a small actor in
10063  * the bottom right) then the cached image will contain the entire
10064  * image of the large area and the paint will waste time blending all
10065  * of the transparent pixels in the middle.
10066  *
10067  * The default method of implementing opacity on a container simply
10068  * forwards on the opacity to all of the children. If the children are
10069  * overlapping then it will appear as if they are two separate glassy
10070  * objects and there will be a break in the color where they
10071  * overlap. By redirecting to an offscreen buffer it will be as if the
10072  * two opaque objects are combined into one and then made transparent
10073  * which is usually what is expected.
10074  *
10075  * The image below demonstrates the difference between redirecting and
10076  * not. The image shows two Clutter groups, each containing a red and
10077  * a green rectangle which overlap. The opacity on the group is set to
10078  * 128 (which is 50%). When the offscreen redirect is not used, the
10079  * red rectangle can be seen through the blue rectangle as if the two
10080  * rectangles were separately transparent. When the redirect is used
10081  * the group as a whole is transparent instead so the red rectangle is
10082  * not visible where they overlap.
10083  *
10084  * <figure id="offscreen-redirect">
10085  *   <title>Sample of using an offscreen redirect for transparency</title>
10086  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10087  * </figure>
10088  *
10089  * The default value for this property is 0, so we effectively will
10090  * never redirect an actor offscreen by default. This means that there
10091  * are times that transparent actors may look glassy as described
10092  * above. The reason this is the default is because there is a
10093  * performance trade off between quality and performance here. In many
10094  * cases the default form of glassy opacity looks good enough, but if
10095  * it's not you will need to set the
10096  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10097  * redirection for opacity.
10098  *
10099  * Custom actors that don't contain any overlapping primitives are
10100  * recommended to override the has_overlaps() virtual to return %FALSE
10101  * for maximum efficiency.
10102  *
10103  * Since: 1.8
10104  */
10105 void
10106 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10107                                       ClutterOffscreenRedirect redirect)
10108 {
10109   ClutterActorPrivate *priv;
10110
10111   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10112
10113   priv = self->priv;
10114
10115   if (priv->offscreen_redirect != redirect)
10116     {
10117       priv->offscreen_redirect = redirect;
10118
10119       /* Queue a redraw from the effect so that it can use its cached
10120          image if available instead of having to redraw the actual
10121          actor. If it doesn't end up using the FBO then the effect is
10122          still able to continue the paint anyway. If there is no
10123          effect then this is equivalent to queuing a full redraw */
10124       _clutter_actor_queue_redraw_full (self,
10125                                         0, /* flags */
10126                                         NULL, /* clip */
10127                                         priv->flatten_effect);
10128
10129       g_object_notify_by_pspec (G_OBJECT (self),
10130                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10131     }
10132 }
10133
10134 /**
10135  * clutter_actor_get_offscreen_redirect:
10136  * @self: a #ClutterActor
10137  *
10138  * Retrieves whether to redirect the actor to an offscreen buffer, as
10139  * set by clutter_actor_set_offscreen_redirect().
10140  *
10141  * Return value: the value of the offscreen-redirect property of the actor
10142  *
10143  * Since: 1.8
10144  */
10145 ClutterOffscreenRedirect
10146 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10147 {
10148   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10149
10150   return self->priv->offscreen_redirect;
10151 }
10152
10153 /**
10154  * clutter_actor_set_name:
10155  * @self: A #ClutterActor
10156  * @name: Textual tag to apply to actor
10157  *
10158  * Sets the given name to @self. The name can be used to identify
10159  * a #ClutterActor.
10160  */
10161 void
10162 clutter_actor_set_name (ClutterActor *self,
10163                         const gchar  *name)
10164 {
10165   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10166
10167   g_free (self->priv->name);
10168   self->priv->name = g_strdup (name);
10169
10170   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10171 }
10172
10173 /**
10174  * clutter_actor_get_name:
10175  * @self: A #ClutterActor
10176  *
10177  * Retrieves the name of @self.
10178  *
10179  * Return value: the name of the actor, or %NULL. The returned string is
10180  *   owned by the actor and should not be modified or freed.
10181  */
10182 const gchar *
10183 clutter_actor_get_name (ClutterActor *self)
10184 {
10185   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10186
10187   return self->priv->name;
10188 }
10189
10190 /**
10191  * clutter_actor_get_gid:
10192  * @self: A #ClutterActor
10193  *
10194  * Retrieves the unique id for @self.
10195  *
10196  * Return value: Globally unique value for this object instance.
10197  *
10198  * Since: 0.6
10199  *
10200  * Deprecated: 1.8: The id is not used any longer.
10201  */
10202 guint32
10203 clutter_actor_get_gid (ClutterActor *self)
10204 {
10205   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10206
10207   return self->priv->id;
10208 }
10209
10210 static inline void
10211 clutter_actor_set_depth_internal (ClutterActor *self,
10212                                   float         depth)
10213 {
10214   ClutterTransformInfo *info;
10215
10216   info = _clutter_actor_get_transform_info (self);
10217
10218   if (info->depth != depth)
10219     {
10220       /* Sets Z value - XXX 2.0: should we invert? */
10221       info->depth = depth;
10222
10223       self->priv->transform_valid = FALSE;
10224
10225       /* FIXME - remove this crap; sadly, there are still containers
10226        * in Clutter that depend on this utter brain damage
10227        */
10228       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10229
10230       clutter_actor_queue_redraw (self);
10231
10232       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10233     }
10234 }
10235
10236 /**
10237  * clutter_actor_set_depth:
10238  * @self: a #ClutterActor
10239  * @depth: Z co-ord
10240  *
10241  * Sets the Z coordinate of @self to @depth.
10242  *
10243  * The unit used by @depth is dependant on the perspective setup. See
10244  * also clutter_stage_set_perspective().
10245  */
10246 void
10247 clutter_actor_set_depth (ClutterActor *self,
10248                          gfloat        depth)
10249 {
10250   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10251
10252   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10253     {
10254       const ClutterTransformInfo *info;
10255
10256       info = _clutter_actor_get_transform_info_or_defaults (self);
10257
10258       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10259                                         info->depth,
10260                                         depth);
10261     }
10262   else
10263     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10264
10265   clutter_actor_queue_redraw (self);
10266 }
10267
10268 /**
10269  * clutter_actor_get_depth:
10270  * @self: a #ClutterActor
10271  *
10272  * Retrieves the depth of @self.
10273  *
10274  * Return value: the depth of the actor
10275  */
10276 gfloat
10277 clutter_actor_get_depth (ClutterActor *self)
10278 {
10279   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10280
10281   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10282 }
10283
10284 /**
10285  * clutter_actor_set_rotation:
10286  * @self: a #ClutterActor
10287  * @axis: the axis of rotation
10288  * @angle: the angle of rotation
10289  * @x: X coordinate of the rotation center
10290  * @y: Y coordinate of the rotation center
10291  * @z: Z coordinate of the rotation center
10292  *
10293  * Sets the rotation angle of @self around the given axis.
10294  *
10295  * The rotation center coordinates used depend on the value of @axis:
10296  * <itemizedlist>
10297  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10298  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10299  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10300  * </itemizedlist>
10301  *
10302  * The rotation coordinates are relative to the anchor point of the
10303  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10304  * point is set, the upper left corner is assumed as the origin.
10305  *
10306  * Since: 0.8
10307  */
10308 void
10309 clutter_actor_set_rotation (ClutterActor      *self,
10310                             ClutterRotateAxis  axis,
10311                             gdouble            angle,
10312                             gfloat             x,
10313                             gfloat             y,
10314                             gfloat             z)
10315 {
10316   ClutterVertex v;
10317
10318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10319
10320   v.x = x;
10321   v.y = y;
10322   v.z = z;
10323
10324   g_object_freeze_notify (G_OBJECT (self));
10325
10326   clutter_actor_set_rotation_angle (self, axis, angle);
10327   clutter_actor_set_rotation_center_internal (self, axis, &v);
10328
10329   g_object_thaw_notify (G_OBJECT (self));
10330 }
10331
10332 /**
10333  * clutter_actor_set_z_rotation_from_gravity:
10334  * @self: a #ClutterActor
10335  * @angle: the angle of rotation
10336  * @gravity: the center point of the rotation
10337  *
10338  * Sets the rotation angle of @self around the Z axis using the center
10339  * point specified as a compass point. For example to rotate such that
10340  * the center of the actor remains static you can use
10341  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10342  * will move accordingly.
10343  *
10344  * Since: 1.0
10345  */
10346 void
10347 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10348                                            gdouble         angle,
10349                                            ClutterGravity  gravity)
10350 {
10351   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10352
10353   if (gravity == CLUTTER_GRAVITY_NONE)
10354     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10355   else
10356     {
10357       GObject *obj = G_OBJECT (self);
10358       ClutterTransformInfo *info;
10359
10360       info = _clutter_actor_get_transform_info (self);
10361
10362       g_object_freeze_notify (obj);
10363
10364       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10365
10366       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10367       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10368       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10369
10370       g_object_thaw_notify (obj);
10371     }
10372 }
10373
10374 /**
10375  * clutter_actor_get_rotation:
10376  * @self: a #ClutterActor
10377  * @axis: the axis of rotation
10378  * @x: (out): return value for the X coordinate of the center of rotation
10379  * @y: (out): return value for the Y coordinate of the center of rotation
10380  * @z: (out): return value for the Z coordinate of the center of rotation
10381  *
10382  * Retrieves the angle and center of rotation on the given axis,
10383  * set using clutter_actor_set_rotation().
10384  *
10385  * Return value: the angle of rotation
10386  *
10387  * Since: 0.8
10388  */
10389 gdouble
10390 clutter_actor_get_rotation (ClutterActor      *self,
10391                             ClutterRotateAxis  axis,
10392                             gfloat            *x,
10393                             gfloat            *y,
10394                             gfloat            *z)
10395 {
10396   const ClutterTransformInfo *info;
10397   const AnchorCoord *anchor_coord;
10398   gdouble retval = 0;
10399
10400   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10401
10402   info = _clutter_actor_get_transform_info_or_defaults (self);
10403
10404   switch (axis)
10405     {
10406     case CLUTTER_X_AXIS:
10407       anchor_coord = &info->rx_center;
10408       retval = info->rx_angle;
10409       break;
10410
10411     case CLUTTER_Y_AXIS:
10412       anchor_coord = &info->ry_center;
10413       retval = info->ry_angle;
10414       break;
10415
10416     case CLUTTER_Z_AXIS:
10417       anchor_coord = &info->rz_center;
10418       retval = info->rz_angle;
10419       break;
10420
10421     default:
10422       anchor_coord = NULL;
10423       retval = 0.0;
10424       break;
10425     }
10426
10427   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10428
10429   return retval;
10430 }
10431
10432 /**
10433  * clutter_actor_get_z_rotation_gravity:
10434  * @self: A #ClutterActor
10435  *
10436  * Retrieves the center for the rotation around the Z axis as a
10437  * compass direction. If the center was specified in pixels or units
10438  * this will return %CLUTTER_GRAVITY_NONE.
10439  *
10440  * Return value: the Z rotation center
10441  *
10442  * Since: 1.0
10443  */
10444 ClutterGravity
10445 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10446 {
10447   const ClutterTransformInfo *info;
10448
10449   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10450
10451   info = _clutter_actor_get_transform_info_or_defaults (self);
10452
10453   return clutter_anchor_coord_get_gravity (&info->rz_center);
10454 }
10455
10456 /**
10457  * clutter_actor_set_clip:
10458  * @self: A #ClutterActor
10459  * @xoff: X offset of the clip rectangle
10460  * @yoff: Y offset of the clip rectangle
10461  * @width: Width of the clip rectangle
10462  * @height: Height of the clip rectangle
10463  *
10464  * Sets clip area for @self. The clip area is always computed from the
10465  * upper left corner of the actor, even if the anchor point is set
10466  * otherwise.
10467  *
10468  * Since: 0.6
10469  */
10470 void
10471 clutter_actor_set_clip (ClutterActor *self,
10472                         gfloat        xoff,
10473                         gfloat        yoff,
10474                         gfloat        width,
10475                         gfloat        height)
10476 {
10477   ClutterActorPrivate *priv;
10478
10479   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10480
10481   priv = self->priv;
10482
10483   if (priv->has_clip &&
10484       priv->clip.x == xoff &&
10485       priv->clip.y == yoff &&
10486       priv->clip.width == width &&
10487       priv->clip.height == height)
10488     return;
10489
10490   priv->clip.x = xoff;
10491   priv->clip.y = yoff;
10492   priv->clip.width = width;
10493   priv->clip.height = height;
10494
10495   priv->has_clip = TRUE;
10496
10497   clutter_actor_queue_redraw (self);
10498
10499   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10500   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10501 }
10502
10503 /**
10504  * clutter_actor_remove_clip:
10505  * @self: A #ClutterActor
10506  *
10507  * Removes clip area from @self.
10508  */
10509 void
10510 clutter_actor_remove_clip (ClutterActor *self)
10511 {
10512   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10513
10514   if (!self->priv->has_clip)
10515     return;
10516
10517   self->priv->has_clip = FALSE;
10518
10519   clutter_actor_queue_redraw (self);
10520
10521   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10522 }
10523
10524 /**
10525  * clutter_actor_has_clip:
10526  * @self: a #ClutterActor
10527  *
10528  * Determines whether the actor has a clip area set or not.
10529  *
10530  * Return value: %TRUE if the actor has a clip area set.
10531  *
10532  * Since: 0.1.1
10533  */
10534 gboolean
10535 clutter_actor_has_clip (ClutterActor *self)
10536 {
10537   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10538
10539   return self->priv->has_clip;
10540 }
10541
10542 /**
10543  * clutter_actor_get_clip:
10544  * @self: a #ClutterActor
10545  * @xoff: (out) (allow-none): return location for the X offset of
10546  *   the clip rectangle, or %NULL
10547  * @yoff: (out) (allow-none): return location for the Y offset of
10548  *   the clip rectangle, or %NULL
10549  * @width: (out) (allow-none): return location for the width of
10550  *   the clip rectangle, or %NULL
10551  * @height: (out) (allow-none): return location for the height of
10552  *   the clip rectangle, or %NULL
10553  *
10554  * Gets the clip area for @self, if any is set
10555  *
10556  * Since: 0.6
10557  */
10558 void
10559 clutter_actor_get_clip (ClutterActor *self,
10560                         gfloat       *xoff,
10561                         gfloat       *yoff,
10562                         gfloat       *width,
10563                         gfloat       *height)
10564 {
10565   ClutterActorPrivate *priv;
10566
10567   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10568
10569   priv = self->priv;
10570
10571   if (!priv->has_clip)
10572     return;
10573
10574   if (xoff != NULL)
10575     *xoff = priv->clip.x;
10576
10577   if (yoff != NULL)
10578     *yoff = priv->clip.y;
10579
10580   if (width != NULL)
10581     *width = priv->clip.width;
10582
10583   if (height != NULL)
10584     *height = priv->clip.height;
10585 }
10586
10587 /**
10588  * clutter_actor_get_children:
10589  * @self: a #ClutterActor
10590  *
10591  * Retrieves the list of children of @self.
10592  *
10593  * Return value: (transfer container) (element-type ClutterActor): A newly
10594  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10595  *   done.
10596  *
10597  * Since: 1.10
10598  */
10599 GList *
10600 clutter_actor_get_children (ClutterActor *self)
10601 {
10602   ClutterActor *iter;
10603   GList *res;
10604
10605   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10606
10607   /* we walk the list backward so that we can use prepend(),
10608    * which is O(1)
10609    */
10610   for (iter = self->priv->last_child, res = NULL;
10611        iter != NULL;
10612        iter = iter->priv->prev_sibling)
10613     {
10614       res = g_list_prepend (res, iter);
10615     }
10616
10617   return res;
10618 }
10619
10620 /*< private >
10621  * insert_child_at_depth:
10622  * @self: a #ClutterActor
10623  * @child: a #ClutterActor
10624  *
10625  * Inserts @child inside the list of children held by @self, using
10626  * the depth as the insertion criteria.
10627  *
10628  * This sadly makes the insertion not O(1), but we can keep the
10629  * list sorted so that the painters algorithm we use for painting
10630  * the children will work correctly.
10631  */
10632 static void
10633 insert_child_at_depth (ClutterActor *self,
10634                        ClutterActor *child,
10635                        gpointer      dummy G_GNUC_UNUSED)
10636 {
10637   ClutterActor *iter;
10638   float child_depth;
10639
10640   child->priv->parent = self;
10641
10642   child_depth =
10643     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10644
10645   /* special-case the first child */
10646   if (self->priv->n_children == 0)
10647     {
10648       self->priv->first_child = child;
10649       self->priv->last_child = child;
10650
10651       child->priv->next_sibling = NULL;
10652       child->priv->prev_sibling = NULL;
10653
10654       return;
10655     }
10656
10657   /* Find the right place to insert the child so that it will still be
10658      sorted and the child will be after all of the actors at the same
10659      dept */
10660   for (iter = self->priv->first_child;
10661        iter != NULL;
10662        iter = iter->priv->next_sibling)
10663     {
10664       float iter_depth;
10665
10666       iter_depth =
10667         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10668
10669       if (iter_depth > child_depth)
10670         break;
10671     }
10672
10673   if (iter != NULL)
10674     {
10675       ClutterActor *tmp = iter->priv->prev_sibling;
10676
10677       if (tmp != NULL)
10678         tmp->priv->next_sibling = child;
10679
10680       /* Insert the node before the found one */
10681       child->priv->prev_sibling = iter->priv->prev_sibling;
10682       child->priv->next_sibling = iter;
10683       iter->priv->prev_sibling = child;
10684     }
10685   else
10686     {
10687       ClutterActor *tmp = self->priv->last_child;
10688
10689       if (tmp != NULL)
10690         tmp->priv->next_sibling = child;
10691
10692       /* insert the node at the end of the list */
10693       child->priv->prev_sibling = self->priv->last_child;
10694       child->priv->next_sibling = NULL;
10695     }
10696
10697   if (child->priv->prev_sibling == NULL)
10698     self->priv->first_child = child;
10699
10700   if (child->priv->next_sibling == NULL)
10701     self->priv->last_child = child;
10702 }
10703
10704 static void
10705 insert_child_at_index (ClutterActor *self,
10706                        ClutterActor *child,
10707                        gpointer      data_)
10708 {
10709   gint index_ = GPOINTER_TO_INT (data_);
10710
10711   child->priv->parent = self;
10712
10713   if (index_ == 0)
10714     {
10715       ClutterActor *tmp = self->priv->first_child;
10716
10717       if (tmp != NULL)
10718         tmp->priv->prev_sibling = child;
10719
10720       child->priv->prev_sibling = NULL;
10721       child->priv->next_sibling = tmp;
10722     }
10723   else if (index_ < 0 || index_ >= self->priv->n_children)
10724     {
10725       ClutterActor *tmp = self->priv->last_child;
10726
10727       if (tmp != NULL)
10728         tmp->priv->next_sibling = child;
10729
10730       child->priv->prev_sibling = tmp;
10731       child->priv->next_sibling = NULL;
10732     }
10733   else
10734     {
10735       ClutterActor *iter;
10736       int i;
10737
10738       for (iter = self->priv->first_child, i = 0;
10739            iter != NULL;
10740            iter = iter->priv->next_sibling, i += 1)
10741         {
10742           if (index_ == i)
10743             {
10744               ClutterActor *tmp = iter->priv->prev_sibling;
10745
10746               child->priv->prev_sibling = tmp;
10747               child->priv->next_sibling = iter;
10748
10749               iter->priv->prev_sibling = child;
10750
10751               if (tmp != NULL)
10752                 tmp->priv->next_sibling = child;
10753
10754               break;
10755             }
10756         }
10757     }
10758
10759   if (child->priv->prev_sibling == NULL)
10760     self->priv->first_child = child;
10761
10762   if (child->priv->next_sibling == NULL)
10763     self->priv->last_child = child;
10764 }
10765
10766 static void
10767 insert_child_above (ClutterActor *self,
10768                     ClutterActor *child,
10769                     gpointer      data)
10770 {
10771   ClutterActor *sibling = data;
10772
10773   child->priv->parent = self;
10774
10775   if (sibling == NULL)
10776     sibling = self->priv->last_child;
10777
10778   child->priv->prev_sibling = sibling;
10779
10780   if (sibling != NULL)
10781     {
10782       ClutterActor *tmp = sibling->priv->next_sibling;
10783
10784       child->priv->next_sibling = tmp;
10785
10786       if (tmp != NULL)
10787         tmp->priv->prev_sibling = child;
10788
10789       sibling->priv->next_sibling = child;
10790     }
10791   else
10792     child->priv->next_sibling = NULL;
10793
10794   if (child->priv->prev_sibling == NULL)
10795     self->priv->first_child = child;
10796
10797   if (child->priv->next_sibling == NULL)
10798     self->priv->last_child = child;
10799 }
10800
10801 static void
10802 insert_child_below (ClutterActor *self,
10803                     ClutterActor *child,
10804                     gpointer      data)
10805 {
10806   ClutterActor *sibling = data;
10807
10808   child->priv->parent = self;
10809
10810   if (sibling == NULL)
10811     sibling = self->priv->first_child;
10812
10813   child->priv->next_sibling = sibling;
10814
10815   if (sibling != NULL)
10816     {
10817       ClutterActor *tmp = sibling->priv->prev_sibling;
10818
10819       child->priv->prev_sibling = tmp;
10820
10821       if (tmp != NULL)
10822         tmp->priv->next_sibling = child;
10823
10824       sibling->priv->prev_sibling = child;
10825     }
10826   else
10827     child->priv->prev_sibling = NULL;
10828
10829   if (child->priv->prev_sibling == NULL)
10830     self->priv->first_child = child;
10831
10832   if (child->priv->next_sibling == NULL)
10833     self->priv->last_child = child;
10834 }
10835
10836 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10837                                            ClutterActor *child,
10838                                            gpointer      data);
10839
10840 typedef enum {
10841   ADD_CHILD_CREATE_META       = 1 << 0,
10842   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10843   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10844   ADD_CHILD_CHECK_STATE       = 1 << 3,
10845   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10846
10847   /* default flags for public API */
10848   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10849                                ADD_CHILD_EMIT_PARENT_SET |
10850                                ADD_CHILD_EMIT_ACTOR_ADDED |
10851                                ADD_CHILD_CHECK_STATE |
10852                                ADD_CHILD_NOTIFY_FIRST_LAST,
10853
10854   /* flags for legacy/deprecated API */
10855   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10856                                ADD_CHILD_CHECK_STATE |
10857                                ADD_CHILD_NOTIFY_FIRST_LAST
10858 } ClutterActorAddChildFlags;
10859
10860 /*< private >
10861  * clutter_actor_add_child_internal:
10862  * @self: a #ClutterActor
10863  * @child: a #ClutterActor
10864  * @flags: control flags for actions
10865  * @add_func: delegate function
10866  * @data: (closure): data to pass to @add_func
10867  *
10868  * Adds @child to the list of children of @self.
10869  *
10870  * The actual insertion inside the list is delegated to @add_func: this
10871  * function will just set up the state, perform basic checks, and emit
10872  * signals.
10873  *
10874  * The @flags argument is used to perform additional operations.
10875  */
10876 static inline void
10877 clutter_actor_add_child_internal (ClutterActor              *self,
10878                                   ClutterActor              *child,
10879                                   ClutterActorAddChildFlags  flags,
10880                                   ClutterActorAddChildFunc   add_func,
10881                                   gpointer                   data)
10882 {
10883   ClutterTextDirection text_dir;
10884   gboolean create_meta;
10885   gboolean emit_parent_set, emit_actor_added;
10886   gboolean check_state;
10887   gboolean notify_first_last;
10888   ClutterActor *old_first_child, *old_last_child;
10889
10890   if (child->priv->parent != NULL)
10891     {
10892       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10893                  "use clutter_actor_remove_child() first.",
10894                  _clutter_actor_get_debug_name (child),
10895                  _clutter_actor_get_debug_name (child->priv->parent));
10896       return;
10897     }
10898
10899   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10900     {
10901       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10902                  "a child of another actor.",
10903                  _clutter_actor_get_debug_name (child));
10904       return;
10905     }
10906
10907 #if 0
10908   /* XXX - this check disallows calling methods that change the stacking
10909    * order within the destruction sequence, by triggering a critical
10910    * warning first, and leaving the actor in an undefined state, which
10911    * then ends up being caught by an assertion.
10912    *
10913    * the reproducible sequence is:
10914    *
10915    *   - actor gets destroyed;
10916    *   - another actor, linked to the first, will try to change the
10917    *     stacking order of the first actor;
10918    *   - changing the stacking order is a composite operation composed
10919    *     by the following steps:
10920    *     1. ref() the child;
10921    *     2. remove_child_internal(), which removes the reference;
10922    *     3. add_child_internal(), which adds a reference;
10923    *   - the state of the actor is not changed between (2) and (3), as
10924    *     it could be an expensive recomputation;
10925    *   - if (3) bails out, then the actor is in an undefined state, but
10926    *     still alive;
10927    *   - the destruction sequence terminates, but the actor is unparented
10928    *     while its state indicates being parented instead.
10929    *   - assertion failure.
10930    *
10931    * the obvious fix would be to decompose each set_child_*_sibling()
10932    * method into proper remove_child()/add_child(), with state validation;
10933    * this may cause excessive work, though, and trigger a cascade of other
10934    * bugs in code that assumes that a change in the stacking order is an
10935    * atomic operation.
10936    *
10937    * another potential fix is to just remove this check here, and let
10938    * code doing stacking order changes inside the destruction sequence
10939    * of an actor continue doing the work.
10940    *
10941    * the third fix is to silently bail out early from every
10942    * set_child_*_sibling() and set_child_at_index() method, and avoid
10943    * doing work.
10944    *
10945    * I have a preference for the second solution, since it involves the
10946    * least amount of work, and the least amount of code duplication.
10947    *
10948    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10949    */
10950   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10951     {
10952       g_warning ("The actor '%s' is currently being destroyed, and "
10953                  "cannot be added as a child of another actor.",
10954                  _clutter_actor_get_debug_name (child));
10955       return;
10956     }
10957 #endif
10958
10959   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10960   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10961   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10962   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10963   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10964
10965   old_first_child = self->priv->first_child;
10966   old_last_child = self->priv->last_child;
10967
10968   g_object_freeze_notify (G_OBJECT (self));
10969
10970   if (create_meta)
10971     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10972
10973   g_object_ref_sink (child);
10974   child->priv->parent = NULL;
10975   child->priv->next_sibling = NULL;
10976   child->priv->prev_sibling = NULL;
10977
10978   /* delegate the actual insertion */
10979   add_func (self, child, data);
10980
10981   g_assert (child->priv->parent == self);
10982
10983   self->priv->n_children += 1;
10984
10985   self->priv->age += 1;
10986
10987   /* if push_internal() has been called then we automatically set
10988    * the flag on the actor
10989    */
10990   if (self->priv->internal_child)
10991     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10992
10993   /* clutter_actor_reparent() will emit ::parent-set for us */
10994   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10995     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10996
10997   if (check_state)
10998     {
10999       /* If parent is mapped or realized, we need to also be mapped or
11000        * realized once we're inside the parent.
11001        */
11002       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11003
11004       /* propagate the parent's text direction to the child */
11005       text_dir = clutter_actor_get_text_direction (self);
11006       clutter_actor_set_text_direction (child, text_dir);
11007     }
11008
11009   if (child->priv->show_on_set_parent)
11010     clutter_actor_show (child);
11011
11012   if (CLUTTER_ACTOR_IS_MAPPED (child))
11013     clutter_actor_queue_redraw (child);
11014
11015   /* maintain the invariant that if an actor needs layout,
11016    * its parents do as well
11017    */
11018   if (child->priv->needs_width_request ||
11019       child->priv->needs_height_request ||
11020       child->priv->needs_allocation)
11021     {
11022       /* we work around the short-circuiting we do
11023        * in clutter_actor_queue_relayout() since we
11024        * want to force a relayout
11025        */
11026       child->priv->needs_width_request = TRUE;
11027       child->priv->needs_height_request = TRUE;
11028       child->priv->needs_allocation = TRUE;
11029
11030       clutter_actor_queue_relayout (child->priv->parent);
11031     }
11032
11033   if (emit_actor_added)
11034     g_signal_emit_by_name (self, "actor-added", child);
11035
11036   if (notify_first_last)
11037     {
11038       if (old_first_child != self->priv->first_child)
11039         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11040
11041       if (old_last_child != self->priv->last_child)
11042         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11043     }
11044
11045   g_object_thaw_notify (G_OBJECT (self));
11046 }
11047
11048 /**
11049  * clutter_actor_add_child:
11050  * @self: a #ClutterActor
11051  * @child: a #ClutterActor
11052  *
11053  * Adds @child to the children of @self.
11054  *
11055  * This function will acquire a reference on @child that will only
11056  * be released when calling clutter_actor_remove_child().
11057  *
11058  * This function will take into consideration the #ClutterActor:depth
11059  * of @child, and will keep the list of children sorted.
11060  *
11061  * This function will emit the #ClutterContainer::actor-added signal
11062  * on @self.
11063  *
11064  * Since: 1.10
11065  */
11066 void
11067 clutter_actor_add_child (ClutterActor *self,
11068                          ClutterActor *child)
11069 {
11070   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11071   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11072   g_return_if_fail (self != child);
11073   g_return_if_fail (child->priv->parent == NULL);
11074
11075   clutter_actor_add_child_internal (self, child,
11076                                     ADD_CHILD_DEFAULT_FLAGS,
11077                                     insert_child_at_depth,
11078                                     NULL);
11079 }
11080
11081 /**
11082  * clutter_actor_insert_child_at_index:
11083  * @self: a #ClutterActor
11084  * @child: a #ClutterActor
11085  * @index_: the index
11086  *
11087  * Inserts @child into the list of children of @self, using the
11088  * given @index_. If @index_ is greater than the number of children
11089  * in @self, or is less than 0, then the new child is added at the end.
11090  *
11091  * This function will acquire a reference on @child that will only
11092  * be released when calling clutter_actor_remove_child().
11093  *
11094  * This function will not take into consideration the #ClutterActor:depth
11095  * of @child.
11096  *
11097  * This function will emit the #ClutterContainer::actor-added signal
11098  * on @self.
11099  *
11100  * Since: 1.10
11101  */
11102 void
11103 clutter_actor_insert_child_at_index (ClutterActor *self,
11104                                      ClutterActor *child,
11105                                      gint          index_)
11106 {
11107   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11108   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11109   g_return_if_fail (self != child);
11110   g_return_if_fail (child->priv->parent == NULL);
11111
11112   clutter_actor_add_child_internal (self, child,
11113                                     ADD_CHILD_DEFAULT_FLAGS,
11114                                     insert_child_at_index,
11115                                     GINT_TO_POINTER (index_));
11116 }
11117
11118 /**
11119  * clutter_actor_insert_child_above:
11120  * @self: a #ClutterActor
11121  * @child: a #ClutterActor
11122  * @sibling: (allow-none): a child of @self, or %NULL
11123  *
11124  * Inserts @child into the list of children of @self, above another
11125  * child of @self or, if @sibling is %NULL, above all the children
11126  * of @self.
11127  *
11128  * This function will acquire a reference on @child that will only
11129  * be released when calling clutter_actor_remove_child().
11130  *
11131  * This function will not take into consideration the #ClutterActor:depth
11132  * of @child.
11133  *
11134  * This function will emit the #ClutterContainer::actor-added signal
11135  * on @self.
11136  *
11137  * Since: 1.10
11138  */
11139 void
11140 clutter_actor_insert_child_above (ClutterActor *self,
11141                                   ClutterActor *child,
11142                                   ClutterActor *sibling)
11143 {
11144   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11145   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11146   g_return_if_fail (self != child);
11147   g_return_if_fail (child != sibling);
11148   g_return_if_fail (child->priv->parent == NULL);
11149   g_return_if_fail (sibling == NULL ||
11150                     (CLUTTER_IS_ACTOR (sibling) &&
11151                      sibling->priv->parent == self));
11152
11153   clutter_actor_add_child_internal (self, child,
11154                                     ADD_CHILD_DEFAULT_FLAGS,
11155                                     insert_child_above,
11156                                     sibling);
11157 }
11158
11159 /**
11160  * clutter_actor_insert_child_below:
11161  * @self: a #ClutterActor
11162  * @child: a #ClutterActor
11163  * @sibling: (allow-none): a child of @self, or %NULL
11164  *
11165  * Inserts @child into the list of children of @self, below another
11166  * child of @self or, if @sibling is %NULL, below all the children
11167  * of @self.
11168  *
11169  * This function will acquire a reference on @child that will only
11170  * be released when calling clutter_actor_remove_child().
11171  *
11172  * This function will not take into consideration the #ClutterActor:depth
11173  * of @child.
11174  *
11175  * This function will emit the #ClutterContainer::actor-added signal
11176  * on @self.
11177  *
11178  * Since: 1.10
11179  */
11180 void
11181 clutter_actor_insert_child_below (ClutterActor *self,
11182                                   ClutterActor *child,
11183                                   ClutterActor *sibling)
11184 {
11185   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11186   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11187   g_return_if_fail (self != child);
11188   g_return_if_fail (child != sibling);
11189   g_return_if_fail (child->priv->parent == NULL);
11190   g_return_if_fail (sibling == NULL ||
11191                     (CLUTTER_IS_ACTOR (sibling) &&
11192                      sibling->priv->parent == self));
11193
11194   clutter_actor_add_child_internal (self, child,
11195                                     ADD_CHILD_DEFAULT_FLAGS,
11196                                     insert_child_below,
11197                                     sibling);
11198 }
11199
11200 /**
11201  * clutter_actor_set_parent:
11202  * @self: A #ClutterActor
11203  * @parent: A new #ClutterActor parent
11204  *
11205  * Sets the parent of @self to @parent.
11206  *
11207  * This function will result in @parent acquiring a reference on @self,
11208  * eventually by sinking its floating reference first. The reference
11209  * will be released by clutter_actor_unparent().
11210  *
11211  * This function should only be called by legacy #ClutterActor<!-- -->s
11212  * implementing the #ClutterContainer interface.
11213  *
11214  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11215  */
11216 void
11217 clutter_actor_set_parent (ClutterActor *self,
11218                           ClutterActor *parent)
11219 {
11220   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11221   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11222   g_return_if_fail (self != parent);
11223   g_return_if_fail (self->priv->parent == NULL);
11224
11225   /* as this function will be called inside ClutterContainer::add
11226    * implementations or when building up a composite actor, we have
11227    * to preserve the old behaviour, and not create child meta or
11228    * emit the ::actor-added signal, to avoid recursion or double
11229    * emissions
11230    */
11231   clutter_actor_add_child_internal (parent, self,
11232                                     ADD_CHILD_LEGACY_FLAGS,
11233                                     insert_child_at_depth,
11234                                     NULL);
11235 }
11236
11237 /**
11238  * clutter_actor_get_parent:
11239  * @self: A #ClutterActor
11240  *
11241  * Retrieves the parent of @self.
11242  *
11243  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11244  *  if no parent is set
11245  */
11246 ClutterActor *
11247 clutter_actor_get_parent (ClutterActor *self)
11248 {
11249   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11250
11251   return self->priv->parent;
11252 }
11253
11254 /**
11255  * clutter_actor_get_paint_visibility:
11256  * @self: A #ClutterActor
11257  *
11258  * Retrieves the 'paint' visibility of an actor recursively checking for non
11259  * visible parents.
11260  *
11261  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11262  *
11263  * Return Value: %TRUE if the actor is visibile and will be painted.
11264  *
11265  * Since: 0.8.4
11266  */
11267 gboolean
11268 clutter_actor_get_paint_visibility (ClutterActor *actor)
11269 {
11270   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11271
11272   return CLUTTER_ACTOR_IS_MAPPED (actor);
11273 }
11274
11275 /**
11276  * clutter_actor_remove_child:
11277  * @self: a #ClutterActor
11278  * @child: a #ClutterActor
11279  *
11280  * Removes @child from the children of @self.
11281  *
11282  * This function will release the reference added by
11283  * clutter_actor_add_child(), so if you want to keep using @child
11284  * you will have to acquire a referenced on it before calling this
11285  * function.
11286  *
11287  * This function will emit the #ClutterContainer::actor-removed
11288  * signal on @self.
11289  *
11290  * Since: 1.10
11291  */
11292 void
11293 clutter_actor_remove_child (ClutterActor *self,
11294                             ClutterActor *child)
11295 {
11296   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11297   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11298   g_return_if_fail (self != child);
11299   g_return_if_fail (child->priv->parent != NULL);
11300   g_return_if_fail (child->priv->parent == self);
11301
11302   clutter_actor_remove_child_internal (self, child,
11303                                        REMOVE_CHILD_DEFAULT_FLAGS);
11304 }
11305
11306 /**
11307  * clutter_actor_remove_all_children:
11308  * @self: a #ClutterActor
11309  *
11310  * Removes all children of @self.
11311  *
11312  * This function releases the reference added by inserting a child actor
11313  * in the list of children of @self.
11314  *
11315  * If the reference count of a child drops to zero, the child will be
11316  * destroyed. If you want to ensure the destruction of all the children
11317  * of @self, use clutter_actor_destroy_all_children().
11318  *
11319  * Since: 1.10
11320  */
11321 void
11322 clutter_actor_remove_all_children (ClutterActor *self)
11323 {
11324   ClutterActorIter iter;
11325
11326   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11327
11328   if (self->priv->n_children == 0)
11329     return;
11330
11331   g_object_freeze_notify (G_OBJECT (self));
11332
11333   clutter_actor_iter_init (&iter, self);
11334   while (clutter_actor_iter_next (&iter, NULL))
11335     clutter_actor_iter_remove (&iter);
11336
11337   g_object_thaw_notify (G_OBJECT (self));
11338
11339   /* sanity check */
11340   g_assert (self->priv->first_child == NULL);
11341   g_assert (self->priv->last_child == NULL);
11342   g_assert (self->priv->n_children == 0);
11343 }
11344
11345 /**
11346  * clutter_actor_destroy_all_children:
11347  * @self: a #ClutterActor
11348  *
11349  * Destroys all children of @self.
11350  *
11351  * This function releases the reference added by inserting a child
11352  * actor in the list of children of @self, and ensures that the
11353  * #ClutterActor::destroy signal is emitted on each child of the
11354  * actor.
11355  *
11356  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11357  * when its reference count drops to 0; the default handler of the
11358  * #ClutterActor::destroy signal will destroy all the children of an
11359  * actor. This function ensures that all children are destroyed, instead
11360  * of just removed from @self, unlike clutter_actor_remove_all_children()
11361  * which will merely release the reference and remove each child.
11362  *
11363  * Unless you acquired an additional reference on each child of @self
11364  * prior to calling clutter_actor_remove_all_children() and want to reuse
11365  * the actors, you should use clutter_actor_destroy_all_children() in
11366  * order to make sure that children are destroyed and signal handlers
11367  * are disconnected even in cases where circular references prevent this
11368  * from automatically happening through reference counting alone.
11369  *
11370  * Since: 1.10
11371  */
11372 void
11373 clutter_actor_destroy_all_children (ClutterActor *self)
11374 {
11375   ClutterActorIter iter;
11376
11377   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11378
11379   if (self->priv->n_children == 0)
11380     return;
11381
11382   g_object_freeze_notify (G_OBJECT (self));
11383
11384   clutter_actor_iter_init (&iter, self);
11385   while (clutter_actor_iter_next (&iter, NULL))
11386     clutter_actor_iter_destroy (&iter);
11387
11388   g_object_thaw_notify (G_OBJECT (self));
11389
11390   /* sanity check */
11391   g_assert (self->priv->first_child == NULL);
11392   g_assert (self->priv->last_child == NULL);
11393   g_assert (self->priv->n_children == 0);
11394 }
11395
11396 typedef struct _InsertBetweenData {
11397   ClutterActor *prev_sibling;
11398   ClutterActor *next_sibling;
11399 } InsertBetweenData;
11400
11401 static void
11402 insert_child_between (ClutterActor *self,
11403                       ClutterActor *child,
11404                       gpointer      data_)
11405 {
11406   InsertBetweenData *data = data_;
11407   ClutterActor *prev_sibling = data->prev_sibling;
11408   ClutterActor *next_sibling = data->next_sibling;
11409
11410   child->priv->parent = self;
11411   child->priv->prev_sibling = prev_sibling;
11412   child->priv->next_sibling = next_sibling;
11413
11414   if (prev_sibling != NULL)
11415     prev_sibling->priv->next_sibling = child;
11416
11417   if (next_sibling != NULL)
11418     next_sibling->priv->prev_sibling = child;
11419
11420   if (child->priv->prev_sibling == NULL)
11421     self->priv->first_child = child;
11422
11423   if (child->priv->next_sibling == NULL)
11424     self->priv->last_child = child;
11425 }
11426
11427 /**
11428  * clutter_actor_replace_child:
11429  * @self: a #ClutterActor
11430  * @old_child: the child of @self to replace
11431  * @new_child: the #ClutterActor to replace @old_child
11432  *
11433  * Replaces @old_child with @new_child in the list of children of @self.
11434  *
11435  * Since: 1.10
11436  */
11437 void
11438 clutter_actor_replace_child (ClutterActor *self,
11439                              ClutterActor *old_child,
11440                              ClutterActor *new_child)
11441 {
11442   ClutterActor *prev_sibling, *next_sibling;
11443   InsertBetweenData clos;
11444
11445   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11446   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11447   g_return_if_fail (old_child->priv->parent == self);
11448   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11449   g_return_if_fail (old_child != new_child);
11450   g_return_if_fail (new_child != self);
11451   g_return_if_fail (new_child->priv->parent == NULL);
11452
11453   prev_sibling = old_child->priv->prev_sibling;
11454   next_sibling = old_child->priv->next_sibling;
11455   clutter_actor_remove_child_internal (self, old_child,
11456                                        REMOVE_CHILD_DEFAULT_FLAGS);
11457
11458   clos.prev_sibling = prev_sibling;
11459   clos.next_sibling = next_sibling;
11460   clutter_actor_add_child_internal (self, new_child,
11461                                     ADD_CHILD_DEFAULT_FLAGS,
11462                                     insert_child_between,
11463                                     &clos);
11464 }
11465
11466 /**
11467  * clutter_actor_unparent:
11468  * @self: a #ClutterActor
11469  *
11470  * Removes the parent of @self.
11471  *
11472  * This will cause the parent of @self to release the reference
11473  * acquired when calling clutter_actor_set_parent(), so if you
11474  * want to keep @self you will have to acquire a reference of
11475  * your own, through g_object_ref().
11476  *
11477  * This function should only be called by legacy #ClutterActor<!-- -->s
11478  * implementing the #ClutterContainer interface.
11479  *
11480  * Since: 0.1.1
11481  *
11482  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11483  */
11484 void
11485 clutter_actor_unparent (ClutterActor *self)
11486 {
11487   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11488
11489   if (self->priv->parent == NULL)
11490     return;
11491
11492   clutter_actor_remove_child_internal (self->priv->parent, self,
11493                                        REMOVE_CHILD_LEGACY_FLAGS);
11494 }
11495
11496 /**
11497  * clutter_actor_reparent:
11498  * @self: a #ClutterActor
11499  * @new_parent: the new #ClutterActor parent
11500  *
11501  * Resets the parent actor of @self.
11502  *
11503  * This function is logically equivalent to calling clutter_actor_unparent()
11504  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11505  * ensures the child is not finalized when unparented, and emits the
11506  * #ClutterActor::parent-set signal only once.
11507  *
11508  * In reality, calling this function is less useful than it sounds, as some
11509  * application code may rely on changes in the intermediate state between
11510  * removal and addition of the actor from its old parent to the @new_parent.
11511  * Thus, it is strongly encouraged to avoid using this function in application
11512  * code.
11513  *
11514  * Since: 0.2
11515  *
11516  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11517  *   clutter_actor_add_child() instead; remember to take a reference on
11518  *   the actor being removed before calling clutter_actor_remove_child()
11519  *   to avoid the reference count dropping to zero and the actor being
11520  *   destroyed.
11521  */
11522 void
11523 clutter_actor_reparent (ClutterActor *self,
11524                         ClutterActor *new_parent)
11525 {
11526   ClutterActorPrivate *priv;
11527
11528   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11529   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11530   g_return_if_fail (self != new_parent);
11531
11532   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11533     {
11534       g_warning ("Cannot set a parent on a toplevel actor");
11535       return;
11536     }
11537
11538   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11539     {
11540       g_warning ("Cannot set a parent currently being destroyed");
11541       return;
11542     }
11543
11544   priv = self->priv;
11545
11546   if (priv->parent != new_parent)
11547     {
11548       ClutterActor *old_parent;
11549
11550       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11551
11552       old_parent = priv->parent;
11553
11554       g_object_ref (self);
11555
11556       if (old_parent != NULL)
11557         {
11558          /* go through the Container implementation if this is a regular
11559           * child and not an internal one
11560           */
11561          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11562            {
11563              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11564
11565              /* this will have to call unparent() */
11566              clutter_container_remove_actor (parent, self);
11567            }
11568          else
11569            clutter_actor_remove_child_internal (old_parent, self,
11570                                                 REMOVE_CHILD_LEGACY_FLAGS);
11571         }
11572
11573       /* Note, will call set_parent() */
11574       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11575         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11576       else
11577         clutter_actor_add_child_internal (new_parent, self,
11578                                           ADD_CHILD_LEGACY_FLAGS,
11579                                           insert_child_at_depth,
11580                                           NULL);
11581
11582       /* we emit the ::parent-set signal once */
11583       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11584
11585       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11586
11587       /* the IN_REPARENT flag suspends state updates */
11588       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11589
11590       g_object_unref (self);
11591    }
11592 }
11593
11594 /**
11595  * clutter_actor_contains:
11596  * @self: A #ClutterActor
11597  * @descendant: A #ClutterActor, possibly contained in @self
11598  *
11599  * Determines if @descendant is contained inside @self (either as an
11600  * immediate child, or as a deeper descendant). If @self and
11601  * @descendant point to the same actor then it will also return %TRUE.
11602  *
11603  * Return value: whether @descendent is contained within @self
11604  *
11605  * Since: 1.4
11606  */
11607 gboolean
11608 clutter_actor_contains (ClutterActor *self,
11609                         ClutterActor *descendant)
11610 {
11611   ClutterActor *actor;
11612
11613   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11614   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11615
11616   for (actor = descendant; actor; actor = actor->priv->parent)
11617     if (actor == self)
11618       return TRUE;
11619
11620   return FALSE;
11621 }
11622
11623 /**
11624  * clutter_actor_set_child_above_sibling:
11625  * @self: a #ClutterActor
11626  * @child: a #ClutterActor child of @self
11627  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11628  *
11629  * Sets @child to be above @sibling in the list of children of @self.
11630  *
11631  * If @sibling is %NULL, @child will be the new last child of @self.
11632  *
11633  * This function is logically equivalent to removing @child and using
11634  * clutter_actor_insert_child_above(), but it will not emit signals
11635  * or change state on @child.
11636  *
11637  * Since: 1.10
11638  */
11639 void
11640 clutter_actor_set_child_above_sibling (ClutterActor *self,
11641                                        ClutterActor *child,
11642                                        ClutterActor *sibling)
11643 {
11644   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11645   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11646   g_return_if_fail (child->priv->parent == self);
11647   g_return_if_fail (child != sibling);
11648   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11649
11650   if (sibling != NULL)
11651     g_return_if_fail (sibling->priv->parent == self);
11652
11653   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11654       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11655       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11656     return;
11657
11658   /* we don't want to change the state of child, or emit signals, or
11659    * regenerate ChildMeta instances here, but we still want to follow
11660    * the correct sequence of steps encoded in remove_child() and
11661    * add_child(), so that correctness is ensured, and we only go
11662    * through one known code path.
11663    */
11664   g_object_ref (child);
11665   clutter_actor_remove_child_internal (self, child, 0);
11666   clutter_actor_add_child_internal (self, child,
11667                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11668                                     insert_child_above,
11669                                     sibling);
11670
11671   clutter_actor_queue_relayout (self);
11672 }
11673
11674 /**
11675  * clutter_actor_set_child_below_sibling:
11676  * @self: a #ClutterActor
11677  * @child: a #ClutterActor child of @self
11678  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11679  *
11680  * Sets @child to be below @sibling in the list of children of @self.
11681  *
11682  * If @sibling is %NULL, @child will be the new first child of @self.
11683  *
11684  * This function is logically equivalent to removing @self and using
11685  * clutter_actor_insert_child_below(), but it will not emit signals
11686  * or change state on @child.
11687  *
11688  * Since: 1.10
11689  */
11690 void
11691 clutter_actor_set_child_below_sibling (ClutterActor *self,
11692                                        ClutterActor *child,
11693                                        ClutterActor *sibling)
11694 {
11695   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11696   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11697   g_return_if_fail (child->priv->parent == self);
11698   g_return_if_fail (child != sibling);
11699   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11700
11701   if (sibling != NULL)
11702     g_return_if_fail (sibling->priv->parent == self);
11703
11704   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11705       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11706       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11707     return;
11708
11709   /* see the comment in set_child_above_sibling() */
11710   g_object_ref (child);
11711   clutter_actor_remove_child_internal (self, child, 0);
11712   clutter_actor_add_child_internal (self, child,
11713                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11714                                     insert_child_below,
11715                                     sibling);
11716
11717   clutter_actor_queue_relayout (self);
11718 }
11719
11720 /**
11721  * clutter_actor_set_child_at_index:
11722  * @self: a #ClutterActor
11723  * @child: a #ClutterActor child of @self
11724  * @index_: the new index for @child
11725  *
11726  * Changes the index of @child in the list of children of @self.
11727  *
11728  * This function is logically equivalent to removing @child and
11729  * calling clutter_actor_insert_child_at_index(), but it will not
11730  * emit signals or change state on @child.
11731  *
11732  * Since: 1.10
11733  */
11734 void
11735 clutter_actor_set_child_at_index (ClutterActor *self,
11736                                   ClutterActor *child,
11737                                   gint          index_)
11738 {
11739   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11740   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11741   g_return_if_fail (child->priv->parent == self);
11742   g_return_if_fail (index_ <= self->priv->n_children);
11743
11744   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11745       CLUTTER_ACTOR_IN_DESTRUCTION (child))
11746     return;
11747
11748   g_object_ref (child);
11749   clutter_actor_remove_child_internal (self, child, 0);
11750   clutter_actor_add_child_internal (self, child,
11751                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11752                                     insert_child_at_index,
11753                                     GINT_TO_POINTER (index_));
11754
11755   clutter_actor_queue_relayout (self);
11756 }
11757
11758 /**
11759  * clutter_actor_raise:
11760  * @self: A #ClutterActor
11761  * @below: (allow-none): A #ClutterActor to raise above.
11762  *
11763  * Puts @self above @below.
11764  *
11765  * Both actors must have the same parent, and the parent must implement
11766  * the #ClutterContainer interface
11767  *
11768  * This function calls clutter_container_raise_child() internally.
11769  *
11770  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11771  */
11772 void
11773 clutter_actor_raise (ClutterActor *self,
11774                      ClutterActor *below)
11775 {
11776   ClutterActor *parent;
11777
11778   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11779
11780   parent = clutter_actor_get_parent (self);
11781   if (parent == NULL)
11782     {
11783       g_warning ("%s: Actor '%s' is not inside a container",
11784                  G_STRFUNC,
11785                  _clutter_actor_get_debug_name (self));
11786       return;
11787     }
11788
11789   if (below != NULL)
11790     {
11791       if (parent != clutter_actor_get_parent (below))
11792         {
11793           g_warning ("%s Actor '%s' is not in the same container as "
11794                      "actor '%s'",
11795                      G_STRFUNC,
11796                      _clutter_actor_get_debug_name (self),
11797                      _clutter_actor_get_debug_name (below));
11798           return;
11799         }
11800     }
11801
11802   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11803 }
11804
11805 /**
11806  * clutter_actor_lower:
11807  * @self: A #ClutterActor
11808  * @above: (allow-none): A #ClutterActor to lower below
11809  *
11810  * Puts @self below @above.
11811  *
11812  * Both actors must have the same parent, and the parent must implement
11813  * the #ClutterContainer interface.
11814  *
11815  * This function calls clutter_container_lower_child() internally.
11816  *
11817  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11818  */
11819 void
11820 clutter_actor_lower (ClutterActor *self,
11821                      ClutterActor *above)
11822 {
11823   ClutterActor *parent;
11824
11825   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11826
11827   parent = clutter_actor_get_parent (self);
11828   if (parent == NULL)
11829     {
11830       g_warning ("%s: Actor of type %s is not inside a container",
11831                  G_STRFUNC,
11832                  _clutter_actor_get_debug_name (self));
11833       return;
11834     }
11835
11836   if (above)
11837     {
11838       if (parent != clutter_actor_get_parent (above))
11839         {
11840           g_warning ("%s: Actor '%s' is not in the same container as "
11841                      "actor '%s'",
11842                      G_STRFUNC,
11843                      _clutter_actor_get_debug_name (self),
11844                      _clutter_actor_get_debug_name (above));
11845           return;
11846         }
11847     }
11848
11849   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11850 }
11851
11852 /**
11853  * clutter_actor_raise_top:
11854  * @self: A #ClutterActor
11855  *
11856  * Raises @self to the top.
11857  *
11858  * This function calls clutter_actor_raise() internally.
11859  *
11860  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11861  *   a %NULL sibling, instead.
11862  */
11863 void
11864 clutter_actor_raise_top (ClutterActor *self)
11865 {
11866   clutter_actor_raise (self, NULL);
11867 }
11868
11869 /**
11870  * clutter_actor_lower_bottom:
11871  * @self: A #ClutterActor
11872  *
11873  * Lowers @self to the bottom.
11874  *
11875  * This function calls clutter_actor_lower() internally.
11876  *
11877  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11878  *   a %NULL sibling, instead.
11879  */
11880 void
11881 clutter_actor_lower_bottom (ClutterActor *self)
11882 {
11883   clutter_actor_lower (self, NULL);
11884 }
11885
11886 /*
11887  * Event handling
11888  */
11889
11890 /**
11891  * clutter_actor_event:
11892  * @actor: a #ClutterActor
11893  * @event: a #ClutterEvent
11894  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11895  *
11896  * This function is used to emit an event on the main stage.
11897  * You should rarely need to use this function, except for
11898  * synthetising events.
11899  *
11900  * Return value: the return value from the signal emission: %TRUE
11901  *   if the actor handled the event, or %FALSE if the event was
11902  *   not handled
11903  *
11904  * Since: 0.6
11905  */
11906 gboolean
11907 clutter_actor_event (ClutterActor *actor,
11908                      ClutterEvent *event,
11909                      gboolean      capture)
11910 {
11911   gboolean retval = FALSE;
11912   gint signal_num = -1;
11913
11914   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11915   g_return_val_if_fail (event != NULL, FALSE);
11916
11917   g_object_ref (actor);
11918
11919   if (capture)
11920     {
11921       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11922                      event,
11923                      &retval);
11924       goto out;
11925     }
11926
11927   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11928
11929   if (!retval)
11930     {
11931       switch (event->type)
11932         {
11933         case CLUTTER_NOTHING:
11934           break;
11935         case CLUTTER_BUTTON_PRESS:
11936           signal_num = BUTTON_PRESS_EVENT;
11937           break;
11938         case CLUTTER_BUTTON_RELEASE:
11939           signal_num = BUTTON_RELEASE_EVENT;
11940           break;
11941         case CLUTTER_SCROLL:
11942           signal_num = SCROLL_EVENT;
11943           break;
11944         case CLUTTER_KEY_PRESS:
11945           signal_num = KEY_PRESS_EVENT;
11946           break;
11947         case CLUTTER_KEY_RELEASE:
11948           signal_num = KEY_RELEASE_EVENT;
11949           break;
11950         case CLUTTER_MOTION:
11951           signal_num = MOTION_EVENT;
11952           break;
11953         case CLUTTER_ENTER:
11954           signal_num = ENTER_EVENT;
11955           break;
11956         case CLUTTER_LEAVE:
11957           signal_num = LEAVE_EVENT;
11958           break;
11959         case CLUTTER_DELETE:
11960         case CLUTTER_DESTROY_NOTIFY:
11961         case CLUTTER_CLIENT_MESSAGE:
11962         default:
11963           signal_num = -1;
11964           break;
11965         }
11966
11967       if (signal_num != -1)
11968         g_signal_emit (actor, actor_signals[signal_num], 0,
11969                        event, &retval);
11970     }
11971
11972 out:
11973   g_object_unref (actor);
11974
11975   return retval;
11976 }
11977
11978 /**
11979  * clutter_actor_set_reactive:
11980  * @actor: a #ClutterActor
11981  * @reactive: whether the actor should be reactive to events
11982  *
11983  * Sets @actor as reactive. Reactive actors will receive events.
11984  *
11985  * Since: 0.6
11986  */
11987 void
11988 clutter_actor_set_reactive (ClutterActor *actor,
11989                             gboolean      reactive)
11990 {
11991   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11992
11993   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11994     return;
11995
11996   if (reactive)
11997     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11998   else
11999     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12000
12001   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12002 }
12003
12004 /**
12005  * clutter_actor_get_reactive:
12006  * @actor: a #ClutterActor
12007  *
12008  * Checks whether @actor is marked as reactive.
12009  *
12010  * Return value: %TRUE if the actor is reactive
12011  *
12012  * Since: 0.6
12013  */
12014 gboolean
12015 clutter_actor_get_reactive (ClutterActor *actor)
12016 {
12017   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12018
12019   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12020 }
12021
12022 /**
12023  * clutter_actor_get_anchor_point:
12024  * @self: a #ClutterActor
12025  * @anchor_x: (out): return location for the X coordinate of the anchor point
12026  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12027  *
12028  * Gets the current anchor point of the @actor in pixels.
12029  *
12030  * Since: 0.6
12031  */
12032 void
12033 clutter_actor_get_anchor_point (ClutterActor *self,
12034                                 gfloat       *anchor_x,
12035                                 gfloat       *anchor_y)
12036 {
12037   const ClutterTransformInfo *info;
12038
12039   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12040
12041   info = _clutter_actor_get_transform_info_or_defaults (self);
12042   clutter_anchor_coord_get_units (self, &info->anchor,
12043                                   anchor_x,
12044                                   anchor_y,
12045                                   NULL);
12046 }
12047
12048 /**
12049  * clutter_actor_set_anchor_point:
12050  * @self: a #ClutterActor
12051  * @anchor_x: X coordinate of the anchor point
12052  * @anchor_y: Y coordinate of the anchor point
12053  *
12054  * Sets an anchor point for @self. The anchor point is a point in the
12055  * coordinate space of an actor to which the actor position within its
12056  * parent is relative; the default is (0, 0), i.e. the top-left corner
12057  * of the actor.
12058  *
12059  * Since: 0.6
12060  */
12061 void
12062 clutter_actor_set_anchor_point (ClutterActor *self,
12063                                 gfloat        anchor_x,
12064                                 gfloat        anchor_y)
12065 {
12066   ClutterTransformInfo *info;
12067   ClutterActorPrivate *priv;
12068   gboolean changed = FALSE;
12069   gfloat old_anchor_x, old_anchor_y;
12070   GObject *obj;
12071
12072   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12073
12074   obj = G_OBJECT (self);
12075   priv = self->priv;
12076   info = _clutter_actor_get_transform_info (self);
12077
12078   g_object_freeze_notify (obj);
12079
12080   clutter_anchor_coord_get_units (self, &info->anchor,
12081                                   &old_anchor_x,
12082                                   &old_anchor_y,
12083                                   NULL);
12084
12085   if (info->anchor.is_fractional)
12086     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12087
12088   if (old_anchor_x != anchor_x)
12089     {
12090       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12091       changed = TRUE;
12092     }
12093
12094   if (old_anchor_y != anchor_y)
12095     {
12096       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12097       changed = TRUE;
12098     }
12099
12100   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12101
12102   if (changed)
12103     {
12104       priv->transform_valid = FALSE;
12105       clutter_actor_queue_redraw (self);
12106     }
12107
12108   g_object_thaw_notify (obj);
12109 }
12110
12111 /**
12112  * clutter_actor_get_anchor_point_gravity:
12113  * @self: a #ClutterActor
12114  *
12115  * Retrieves the anchor position expressed as a #ClutterGravity. If
12116  * the anchor point was specified using pixels or units this will
12117  * return %CLUTTER_GRAVITY_NONE.
12118  *
12119  * Return value: the #ClutterGravity used by the anchor point
12120  *
12121  * Since: 1.0
12122  */
12123 ClutterGravity
12124 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12125 {
12126   const ClutterTransformInfo *info;
12127
12128   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12129
12130   info = _clutter_actor_get_transform_info_or_defaults (self);
12131
12132   return clutter_anchor_coord_get_gravity (&info->anchor);
12133 }
12134
12135 /**
12136  * clutter_actor_move_anchor_point:
12137  * @self: a #ClutterActor
12138  * @anchor_x: X coordinate of the anchor point
12139  * @anchor_y: Y coordinate of the anchor point
12140  *
12141  * Sets an anchor point for the actor, and adjusts the actor postion so that
12142  * the relative position of the actor toward its parent remains the same.
12143  *
12144  * Since: 0.6
12145  */
12146 void
12147 clutter_actor_move_anchor_point (ClutterActor *self,
12148                                  gfloat        anchor_x,
12149                                  gfloat        anchor_y)
12150 {
12151   gfloat old_anchor_x, old_anchor_y;
12152   const ClutterTransformInfo *info;
12153
12154   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12155
12156   info = _clutter_actor_get_transform_info (self);
12157   clutter_anchor_coord_get_units (self, &info->anchor,
12158                                   &old_anchor_x,
12159                                   &old_anchor_y,
12160                                   NULL);
12161
12162   g_object_freeze_notify (G_OBJECT (self));
12163
12164   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12165
12166   if (self->priv->position_set)
12167     clutter_actor_move_by (self,
12168                            anchor_x - old_anchor_x,
12169                            anchor_y - old_anchor_y);
12170
12171   g_object_thaw_notify (G_OBJECT (self));
12172 }
12173
12174 /**
12175  * clutter_actor_move_anchor_point_from_gravity:
12176  * @self: a #ClutterActor
12177  * @gravity: #ClutterGravity.
12178  *
12179  * Sets an anchor point on the actor based on the given gravity, adjusting the
12180  * actor postion so that its relative position within its parent remains
12181  * unchanged.
12182  *
12183  * Since version 1.0 the anchor point will be stored as a gravity so
12184  * that if the actor changes size then the anchor point will move. For
12185  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12186  * and later double the size of the actor, the anchor point will move
12187  * to the bottom right.
12188  *
12189  * Since: 0.6
12190  */
12191 void
12192 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12193                                               ClutterGravity  gravity)
12194 {
12195   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12196   const ClutterTransformInfo *info;
12197   ClutterActorPrivate *priv;
12198
12199   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12200
12201   priv = self->priv;
12202   info = _clutter_actor_get_transform_info (self);
12203
12204   g_object_freeze_notify (G_OBJECT (self));
12205
12206   clutter_anchor_coord_get_units (self, &info->anchor,
12207                                   &old_anchor_x,
12208                                   &old_anchor_y,
12209                                   NULL);
12210   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12211   clutter_anchor_coord_get_units (self, &info->anchor,
12212                                   &new_anchor_x,
12213                                   &new_anchor_y,
12214                                   NULL);
12215
12216   if (priv->position_set)
12217     clutter_actor_move_by (self,
12218                            new_anchor_x - old_anchor_x,
12219                            new_anchor_y - old_anchor_y);
12220
12221   g_object_thaw_notify (G_OBJECT (self));
12222 }
12223
12224 /**
12225  * clutter_actor_set_anchor_point_from_gravity:
12226  * @self: a #ClutterActor
12227  * @gravity: #ClutterGravity.
12228  *
12229  * Sets an anchor point on the actor, based on the given gravity (this is a
12230  * convenience function wrapping clutter_actor_set_anchor_point()).
12231  *
12232  * Since version 1.0 the anchor point will be stored as a gravity so
12233  * that if the actor changes size then the anchor point will move. For
12234  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12235  * and later double the size of the actor, the anchor point will move
12236  * to the bottom right.
12237  *
12238  * Since: 0.6
12239  */
12240 void
12241 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12242                                              ClutterGravity  gravity)
12243 {
12244   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12245
12246   if (gravity == CLUTTER_GRAVITY_NONE)
12247     clutter_actor_set_anchor_point (self, 0, 0);
12248   else
12249     {
12250       GObject *obj = G_OBJECT (self);
12251       ClutterTransformInfo *info;
12252
12253       g_object_freeze_notify (obj);
12254
12255       info = _clutter_actor_get_transform_info (self);
12256       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12257
12258       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12259       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12260       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12261
12262       self->priv->transform_valid = FALSE;
12263
12264       clutter_actor_queue_redraw (self);
12265
12266       g_object_thaw_notify (obj);
12267     }
12268 }
12269
12270 static void
12271 clutter_container_iface_init (ClutterContainerIface *iface)
12272 {
12273   /* we don't override anything, as ClutterContainer already has a default
12274    * implementation that we can use, and which calls into our own API.
12275    */
12276 }
12277
12278 typedef enum
12279 {
12280   PARSE_X,
12281   PARSE_Y,
12282   PARSE_WIDTH,
12283   PARSE_HEIGHT,
12284   PARSE_ANCHOR_X,
12285   PARSE_ANCHOR_Y
12286 } ParseDimension;
12287
12288 static gfloat
12289 parse_units (ClutterActor   *self,
12290              ParseDimension  dimension,
12291              JsonNode       *node)
12292 {
12293   GValue value = G_VALUE_INIT;
12294   gfloat retval = 0;
12295
12296   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12297     return 0;
12298
12299   json_node_get_value (node, &value);
12300
12301   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12302     {
12303       retval = (gfloat) g_value_get_int64 (&value);
12304     }
12305   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12306     {
12307       retval = g_value_get_double (&value);
12308     }
12309   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12310     {
12311       ClutterUnits units;
12312       gboolean res;
12313
12314       res = clutter_units_from_string (&units, g_value_get_string (&value));
12315       if (res)
12316         retval = clutter_units_to_pixels (&units);
12317       else
12318         {
12319           g_warning ("Invalid value '%s': integers, strings or floating point "
12320                      "values can be used for the x, y, width and height "
12321                      "properties. Valid modifiers for strings are 'px', 'mm', "
12322                      "'pt' and 'em'.",
12323                      g_value_get_string (&value));
12324           retval = 0;
12325         }
12326     }
12327   else
12328     {
12329       g_warning ("Invalid value of type '%s': integers, strings of floating "
12330                  "point values can be used for the x, y, width, height "
12331                  "anchor-x and anchor-y properties.",
12332                  g_type_name (G_VALUE_TYPE (&value)));
12333     }
12334
12335   g_value_unset (&value);
12336
12337   return retval;
12338 }
12339
12340 typedef struct {
12341   ClutterRotateAxis axis;
12342
12343   gdouble angle;
12344
12345   gfloat center_x;
12346   gfloat center_y;
12347   gfloat center_z;
12348 } RotationInfo;
12349
12350 static inline gboolean
12351 parse_rotation_array (ClutterActor *actor,
12352                       JsonArray    *array,
12353                       RotationInfo *info)
12354 {
12355   JsonNode *element;
12356
12357   if (json_array_get_length (array) != 2)
12358     return FALSE;
12359
12360   /* angle */
12361   element = json_array_get_element (array, 0);
12362   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12363     info->angle = json_node_get_double (element);
12364   else
12365     return FALSE;
12366
12367   /* center */
12368   element = json_array_get_element (array, 1);
12369   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12370     {
12371       JsonArray *center = json_node_get_array (element);
12372
12373       if (json_array_get_length (center) != 2)
12374         return FALSE;
12375
12376       switch (info->axis)
12377         {
12378         case CLUTTER_X_AXIS:
12379           info->center_y = parse_units (actor, PARSE_Y,
12380                                         json_array_get_element (center, 0));
12381           info->center_z = parse_units (actor, PARSE_Y,
12382                                         json_array_get_element (center, 1));
12383           return TRUE;
12384
12385         case CLUTTER_Y_AXIS:
12386           info->center_x = parse_units (actor, PARSE_X,
12387                                         json_array_get_element (center, 0));
12388           info->center_z = parse_units (actor, PARSE_X,
12389                                         json_array_get_element (center, 1));
12390           return TRUE;
12391
12392         case CLUTTER_Z_AXIS:
12393           info->center_x = parse_units (actor, PARSE_X,
12394                                         json_array_get_element (center, 0));
12395           info->center_y = parse_units (actor, PARSE_Y,
12396                                         json_array_get_element (center, 1));
12397           return TRUE;
12398         }
12399     }
12400
12401   return FALSE;
12402 }
12403
12404 static gboolean
12405 parse_rotation (ClutterActor *actor,
12406                 JsonNode     *node,
12407                 RotationInfo *info)
12408 {
12409   JsonArray *array;
12410   guint len, i;
12411   gboolean retval = FALSE;
12412
12413   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12414     {
12415       g_warning ("Invalid node of type '%s' found, expecting an array",
12416                  json_node_type_name (node));
12417       return FALSE;
12418     }
12419
12420   array = json_node_get_array (node);
12421   len = json_array_get_length (array);
12422
12423   for (i = 0; i < len; i++)
12424     {
12425       JsonNode *element = json_array_get_element (array, i);
12426       JsonObject *object;
12427       JsonNode *member;
12428
12429       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12430         {
12431           g_warning ("Invalid node of type '%s' found, expecting an object",
12432                      json_node_type_name (element));
12433           return FALSE;
12434         }
12435
12436       object = json_node_get_object (element);
12437
12438       if (json_object_has_member (object, "x-axis"))
12439         {
12440           member = json_object_get_member (object, "x-axis");
12441
12442           info->axis = CLUTTER_X_AXIS;
12443
12444           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12445             {
12446               info->angle = json_node_get_double (member);
12447               retval = TRUE;
12448             }
12449           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12450             retval = parse_rotation_array (actor,
12451                                            json_node_get_array (member),
12452                                            info);
12453           else
12454             retval = FALSE;
12455         }
12456       else if (json_object_has_member (object, "y-axis"))
12457         {
12458           member = json_object_get_member (object, "y-axis");
12459
12460           info->axis = CLUTTER_Y_AXIS;
12461
12462           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12463             {
12464               info->angle = json_node_get_double (member);
12465               retval = TRUE;
12466             }
12467           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12468             retval = parse_rotation_array (actor,
12469                                            json_node_get_array (member),
12470                                            info);
12471           else
12472             retval = FALSE;
12473         }
12474       else if (json_object_has_member (object, "z-axis"))
12475         {
12476           member = json_object_get_member (object, "z-axis");
12477
12478           info->axis = CLUTTER_Z_AXIS;
12479
12480           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12481             {
12482               info->angle = json_node_get_double (member);
12483               retval = TRUE;
12484             }
12485           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12486             retval = parse_rotation_array (actor,
12487                                            json_node_get_array (member),
12488                                            info);
12489           else
12490             retval = FALSE;
12491         }
12492     }
12493
12494   return retval;
12495 }
12496
12497 static GSList *
12498 parse_actor_metas (ClutterScript *script,
12499                    ClutterActor  *actor,
12500                    JsonNode      *node)
12501 {
12502   GList *elements, *l;
12503   GSList *retval = NULL;
12504
12505   if (!JSON_NODE_HOLDS_ARRAY (node))
12506     return NULL;
12507
12508   elements = json_array_get_elements (json_node_get_array (node));
12509
12510   for (l = elements; l != NULL; l = l->next)
12511     {
12512       JsonNode *element = l->data;
12513       const gchar *id_ = _clutter_script_get_id_from_node (element);
12514       GObject *meta;
12515
12516       if (id_ == NULL || *id_ == '\0')
12517         continue;
12518
12519       meta = clutter_script_get_object (script, id_);
12520       if (meta == NULL)
12521         continue;
12522
12523       retval = g_slist_prepend (retval, meta);
12524     }
12525
12526   g_list_free (elements);
12527
12528   return g_slist_reverse (retval);
12529 }
12530
12531 static GSList *
12532 parse_behaviours (ClutterScript *script,
12533                   ClutterActor  *actor,
12534                   JsonNode      *node)
12535 {
12536   GList *elements, *l;
12537   GSList *retval = NULL;
12538
12539   if (!JSON_NODE_HOLDS_ARRAY (node))
12540     return NULL;
12541
12542   elements = json_array_get_elements (json_node_get_array (node));
12543
12544   for (l = elements; l != NULL; l = l->next)
12545     {
12546       JsonNode *element = l->data;
12547       const gchar *id_ = _clutter_script_get_id_from_node (element);
12548       GObject *behaviour;
12549
12550       if (id_ == NULL || *id_ == '\0')
12551         continue;
12552
12553       behaviour = clutter_script_get_object (script, id_);
12554       if (behaviour == NULL)
12555         continue;
12556
12557       retval = g_slist_prepend (retval, behaviour);
12558     }
12559
12560   g_list_free (elements);
12561
12562   return g_slist_reverse (retval);
12563 }
12564
12565 static gboolean
12566 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12567                                  ClutterScript     *script,
12568                                  GValue            *value,
12569                                  const gchar       *name,
12570                                  JsonNode          *node)
12571 {
12572   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12573   gboolean retval = FALSE;
12574
12575   if ((name[0] == 'x' && name[1] == '\0') ||
12576       (name[0] == 'y' && name[1] == '\0') ||
12577       (strcmp (name, "width") == 0) ||
12578       (strcmp (name, "height") == 0) ||
12579       (strcmp (name, "anchor_x") == 0) ||
12580       (strcmp (name, "anchor_y") == 0))
12581     {
12582       ParseDimension dimension;
12583       gfloat units;
12584
12585       if (name[0] == 'x')
12586         dimension = PARSE_X;
12587       else if (name[0] == 'y')
12588         dimension = PARSE_Y;
12589       else if (name[0] == 'w')
12590         dimension = PARSE_WIDTH;
12591       else if (name[0] == 'h')
12592         dimension = PARSE_HEIGHT;
12593       else if (name[0] == 'a' && name[7] == 'x')
12594         dimension = PARSE_ANCHOR_X;
12595       else if (name[0] == 'a' && name[7] == 'y')
12596         dimension = PARSE_ANCHOR_Y;
12597       else
12598         return FALSE;
12599
12600       units = parse_units (actor, dimension, node);
12601
12602       /* convert back to pixels: all properties are pixel-based */
12603       g_value_init (value, G_TYPE_FLOAT);
12604       g_value_set_float (value, units);
12605
12606       retval = TRUE;
12607     }
12608   else if (strcmp (name, "rotation") == 0)
12609     {
12610       RotationInfo *info;
12611
12612       info = g_slice_new0 (RotationInfo);
12613       retval = parse_rotation (actor, node, info);
12614
12615       if (retval)
12616         {
12617           g_value_init (value, G_TYPE_POINTER);
12618           g_value_set_pointer (value, info);
12619         }
12620       else
12621         g_slice_free (RotationInfo, info);
12622     }
12623   else if (strcmp (name, "behaviours") == 0)
12624     {
12625       GSList *l;
12626
12627 #ifdef CLUTTER_ENABLE_DEBUG
12628       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12629         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12630                                      "and it should not be used in newly "
12631                                      "written ClutterScript definitions.");
12632 #endif
12633
12634       l = parse_behaviours (script, actor, node);
12635
12636       g_value_init (value, G_TYPE_POINTER);
12637       g_value_set_pointer (value, l);
12638
12639       retval = TRUE;
12640     }
12641   else if (strcmp (name, "actions") == 0 ||
12642            strcmp (name, "constraints") == 0 ||
12643            strcmp (name, "effects") == 0)
12644     {
12645       GSList *l;
12646
12647       l = parse_actor_metas (script, actor, node);
12648
12649       g_value_init (value, G_TYPE_POINTER);
12650       g_value_set_pointer (value, l);
12651
12652       retval = TRUE;
12653     }
12654
12655   return retval;
12656 }
12657
12658 static void
12659 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12660                                    ClutterScript     *script,
12661                                    const gchar       *name,
12662                                    const GValue      *value)
12663 {
12664   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12665
12666 #ifdef CLUTTER_ENABLE_DEBUG
12667   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12668     {
12669       gchar *tmp = g_strdup_value_contents (value);
12670
12671       CLUTTER_NOTE (SCRIPT,
12672                     "in ClutterActor::set_custom_property('%s') = %s",
12673                     name,
12674                     tmp);
12675
12676       g_free (tmp);
12677     }
12678 #endif /* CLUTTER_ENABLE_DEBUG */
12679
12680   if (strcmp (name, "rotation") == 0)
12681     {
12682       RotationInfo *info;
12683
12684       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12685         return;
12686
12687       info = g_value_get_pointer (value);
12688
12689       clutter_actor_set_rotation (actor,
12690                                   info->axis, info->angle,
12691                                   info->center_x,
12692                                   info->center_y,
12693                                   info->center_z);
12694
12695       g_slice_free (RotationInfo, info);
12696
12697       return;
12698     }
12699
12700   if (strcmp (name, "behaviours") == 0)
12701     {
12702       GSList *behaviours, *l;
12703
12704       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12705         return;
12706
12707       behaviours = g_value_get_pointer (value);
12708       for (l = behaviours; l != NULL; l = l->next)
12709         {
12710           ClutterBehaviour *behaviour = l->data;
12711
12712           clutter_behaviour_apply (behaviour, actor);
12713         }
12714
12715       g_slist_free (behaviours);
12716
12717       return;
12718     }
12719
12720   if (strcmp (name, "actions") == 0 ||
12721       strcmp (name, "constraints") == 0 ||
12722       strcmp (name, "effects") == 0)
12723     {
12724       GSList *metas, *l;
12725
12726       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12727         return;
12728
12729       metas = g_value_get_pointer (value);
12730       for (l = metas; l != NULL; l = l->next)
12731         {
12732           if (name[0] == 'a')
12733             clutter_actor_add_action (actor, l->data);
12734
12735           if (name[0] == 'c')
12736             clutter_actor_add_constraint (actor, l->data);
12737
12738           if (name[0] == 'e')
12739             clutter_actor_add_effect (actor, l->data);
12740         }
12741
12742       g_slist_free (metas);
12743
12744       return;
12745     }
12746
12747   g_object_set_property (G_OBJECT (scriptable), name, value);
12748 }
12749
12750 static void
12751 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12752 {
12753   iface->parse_custom_node = clutter_actor_parse_custom_node;
12754   iface->set_custom_property = clutter_actor_set_custom_property;
12755 }
12756
12757 static ClutterActorMeta *
12758 get_meta_from_animation_property (ClutterActor  *actor,
12759                                   const gchar   *name,
12760                                   gchar        **name_p)
12761 {
12762   ClutterActorPrivate *priv = actor->priv;
12763   ClutterActorMeta *meta = NULL;
12764   gchar **tokens;
12765
12766   /* if this is not a special property, fall through */
12767   if (name[0] != '@')
12768     return NULL;
12769
12770   /* detect the properties named using the following spec:
12771    *
12772    *   @<section>.<meta-name>.<property-name>
12773    *
12774    * where <section> can be one of the following:
12775    *
12776    *   - actions
12777    *   - constraints
12778    *   - effects
12779    *
12780    * and <meta-name> is the name set on a specific ActorMeta
12781    */
12782
12783   tokens = g_strsplit (name + 1, ".", -1);
12784   if (tokens == NULL || g_strv_length (tokens) != 3)
12785     {
12786       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12787                     name + 1);
12788       g_strfreev (tokens);
12789       return NULL;
12790     }
12791
12792   if (strcmp (tokens[0], "actions") == 0)
12793     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12794
12795   if (strcmp (tokens[0], "constraints") == 0)
12796     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12797
12798   if (strcmp (tokens[0], "effects") == 0)
12799     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12800
12801   if (name_p != NULL)
12802     *name_p = g_strdup (tokens[2]);
12803
12804   CLUTTER_NOTE (ANIMATION,
12805                 "Looking for property '%s' of object '%s' in section '%s'",
12806                 tokens[2],
12807                 tokens[1],
12808                 tokens[0]);
12809
12810   g_strfreev (tokens);
12811
12812   return meta;
12813 }
12814
12815 static GParamSpec *
12816 clutter_actor_find_property (ClutterAnimatable *animatable,
12817                              const gchar       *property_name)
12818 {
12819   ClutterActorMeta *meta = NULL;
12820   GObjectClass *klass = NULL;
12821   GParamSpec *pspec = NULL;
12822   gchar *p_name = NULL;
12823
12824   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12825                                            property_name,
12826                                            &p_name);
12827
12828   if (meta != NULL)
12829     {
12830       klass = G_OBJECT_GET_CLASS (meta);
12831
12832       pspec = g_object_class_find_property (klass, p_name);
12833     }
12834   else
12835     {
12836       klass = G_OBJECT_GET_CLASS (animatable);
12837
12838       pspec = g_object_class_find_property (klass, property_name);
12839     }
12840
12841   g_free (p_name);
12842
12843   return pspec;
12844 }
12845
12846 static void
12847 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12848                                  const gchar       *property_name,
12849                                  GValue            *initial)
12850 {
12851   ClutterActorMeta *meta = NULL;
12852   gchar *p_name = NULL;
12853
12854   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12855                                            property_name,
12856                                            &p_name);
12857
12858   if (meta != NULL)
12859     g_object_get_property (G_OBJECT (meta), p_name, initial);
12860   else
12861     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12862
12863   g_free (p_name);
12864 }
12865
12866 /*
12867  * clutter_actor_set_animatable_property:
12868  * @actor: a #ClutterActor
12869  * @prop_id: the paramspec id
12870  * @value: the value to set
12871  * @pspec: the paramspec
12872  *
12873  * Sets values of animatable properties.
12874  *
12875  * This is a variant of clutter_actor_set_property() that gets called
12876  * by the #ClutterAnimatable implementation of #ClutterActor for the
12877  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12878  * #GParamSpec.
12879  *
12880  * Unlike the implementation of #GObjectClass.set_property(), this
12881  * function will not update the interval if a transition involving an
12882  * animatable property is in progress - this avoids cycles with the
12883  * transition API calling the public API.
12884  */
12885 static void
12886 clutter_actor_set_animatable_property (ClutterActor *actor,
12887                                        guint         prop_id,
12888                                        const GValue *value,
12889                                        GParamSpec   *pspec)
12890 {
12891   GObject *obj = G_OBJECT (actor);
12892
12893   g_object_freeze_notify (obj);
12894
12895   switch (prop_id)
12896     {
12897     case PROP_X:
12898       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12899       break;
12900
12901     case PROP_Y:
12902       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12903       break;
12904
12905     case PROP_WIDTH:
12906       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12907       break;
12908
12909     case PROP_HEIGHT:
12910       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12911       break;
12912
12913     case PROP_DEPTH:
12914       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12915       break;
12916
12917     case PROP_OPACITY:
12918       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12919       break;
12920
12921     case PROP_BACKGROUND_COLOR:
12922       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12923       break;
12924
12925     case PROP_SCALE_X:
12926       clutter_actor_set_scale_factor_internal (actor,
12927                                                g_value_get_double (value),
12928                                                pspec);
12929       break;
12930
12931     case PROP_SCALE_Y:
12932       clutter_actor_set_scale_factor_internal (actor,
12933                                                g_value_get_double (value),
12934                                                pspec);
12935       break;
12936
12937     case PROP_ROTATION_ANGLE_X:
12938       clutter_actor_set_rotation_angle_internal (actor,
12939                                                  CLUTTER_X_AXIS,
12940                                                  g_value_get_double (value));
12941       break;
12942
12943     case PROP_ROTATION_ANGLE_Y:
12944       clutter_actor_set_rotation_angle_internal (actor,
12945                                                  CLUTTER_Y_AXIS,
12946                                                  g_value_get_double (value));
12947       break;
12948
12949     case PROP_ROTATION_ANGLE_Z:
12950       clutter_actor_set_rotation_angle_internal (actor,
12951                                                  CLUTTER_Z_AXIS,
12952                                                  g_value_get_double (value));
12953       break;
12954
12955     default:
12956       g_object_set_property (obj, pspec->name, value);
12957       break;
12958     }
12959
12960   g_object_thaw_notify (obj);
12961 }
12962
12963 static void
12964 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12965                                const gchar       *property_name,
12966                                const GValue      *final)
12967 {
12968   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12969   ClutterActorMeta *meta = NULL;
12970   gchar *p_name = NULL;
12971
12972   meta = get_meta_from_animation_property (actor,
12973                                            property_name,
12974                                            &p_name);
12975   if (meta != NULL)
12976     g_object_set_property (G_OBJECT (meta), p_name, final);
12977   else
12978     {
12979       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12980       GParamSpec *pspec;
12981
12982       pspec = g_object_class_find_property (obj_class, property_name);
12983
12984       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12985         {
12986           /* XXX - I'm going to the special hell for this */
12987           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12988         }
12989       else
12990         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
12991     }
12992
12993   g_free (p_name);
12994 }
12995
12996 static void
12997 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12998 {
12999   iface->find_property = clutter_actor_find_property;
13000   iface->get_initial_state = clutter_actor_get_initial_state;
13001   iface->set_final_state = clutter_actor_set_final_state;
13002 }
13003
13004 /**
13005  * clutter_actor_transform_stage_point:
13006  * @self: A #ClutterActor
13007  * @x: (in): x screen coordinate of the point to unproject
13008  * @y: (in): y screen coordinate of the point to unproject
13009  * @x_out: (out): return location for the unprojected x coordinance
13010  * @y_out: (out): return location for the unprojected y coordinance
13011  *
13012  * This function translates screen coordinates (@x, @y) to
13013  * coordinates relative to the actor. For example, it can be used to translate
13014  * screen events from global screen coordinates into actor-local coordinates.
13015  *
13016  * The conversion can fail, notably if the transform stack results in the
13017  * actor being projected on the screen as a mere line.
13018  *
13019  * The conversion should not be expected to be pixel-perfect due to the
13020  * nature of the operation. In general the error grows when the skewing
13021  * of the actor rectangle on screen increases.
13022  *
13023  * <note><para>This function can be computationally intensive.</para></note>
13024  *
13025  * <note><para>This function only works when the allocation is up-to-date,
13026  * i.e. inside of paint().</para></note>
13027  *
13028  * Return value: %TRUE if conversion was successful.
13029  *
13030  * Since: 0.6
13031  */
13032 gboolean
13033 clutter_actor_transform_stage_point (ClutterActor *self,
13034                                      gfloat        x,
13035                                      gfloat        y,
13036                                      gfloat       *x_out,
13037                                      gfloat       *y_out)
13038 {
13039   ClutterVertex v[4];
13040   float ST[3][3];
13041   float RQ[3][3];
13042   int du, dv, xi, yi;
13043   float px, py;
13044   float xf, yf, wf, det;
13045   ClutterActorPrivate *priv;
13046
13047   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13048
13049   priv = self->priv;
13050
13051   /* This implementation is based on the quad -> quad projection algorithm
13052    * described by Paul Heckbert in:
13053    *
13054    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13055    *
13056    * and the sample implementation at:
13057    *
13058    *   http://www.cs.cmu.edu/~ph/src/texfund/
13059    *
13060    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13061    * quad to rectangle only, which significantly simplifies things; the
13062    * function calls have been unrolled, and most of the math is done in fixed
13063    * point.
13064    */
13065
13066   clutter_actor_get_abs_allocation_vertices (self, v);
13067
13068   /* Keeping these as ints simplifies the multiplication (no significant
13069    * loss of precision here).
13070    */
13071   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13072   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13073
13074   if (!du || !dv)
13075     return FALSE;
13076
13077 #define UX2FP(x)        (x)
13078 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13079
13080   /* First, find mapping from unit uv square to xy quadrilateral; this
13081    * equivalent to the pmap_square_quad() functions in the sample
13082    * implementation, which we can simplify, since our target is always
13083    * a rectangle.
13084    */
13085   px = v[0].x - v[1].x + v[3].x - v[2].x;
13086   py = v[0].y - v[1].y + v[3].y - v[2].y;
13087
13088   if (!px && !py)
13089     {
13090       /* affine transform */
13091       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13092       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13093       RQ[2][0] = UX2FP (v[0].x);
13094       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13095       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13096       RQ[2][1] = UX2FP (v[0].y);
13097       RQ[0][2] = 0;
13098       RQ[1][2] = 0;
13099       RQ[2][2] = 1.0;
13100     }
13101   else
13102     {
13103       /* projective transform */
13104       double dx1, dx2, dy1, dy2, del;
13105
13106       dx1 = UX2FP (v[1].x - v[3].x);
13107       dx2 = UX2FP (v[2].x - v[3].x);
13108       dy1 = UX2FP (v[1].y - v[3].y);
13109       dy2 = UX2FP (v[2].y - v[3].y);
13110
13111       del = DET2FP (dx1, dx2, dy1, dy2);
13112       if (!del)
13113         return FALSE;
13114
13115       /*
13116        * The division here needs to be done in floating point for
13117        * precisions reasons.
13118        */
13119       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13120       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13121       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13122       RQ[2][2] = 1.0;
13123       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13124       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13125       RQ[2][0] = UX2FP (v[0].x);
13126       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13127       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13128       RQ[2][1] = UX2FP (v[0].y);
13129     }
13130
13131   /*
13132    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13133    * square. Since our rectangle is based at 0,0 we only need to scale.
13134    */
13135   RQ[0][0] /= du;
13136   RQ[1][0] /= dv;
13137   RQ[0][1] /= du;
13138   RQ[1][1] /= dv;
13139   RQ[0][2] /= du;
13140   RQ[1][2] /= dv;
13141
13142   /*
13143    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13144    * inverse of that.
13145    */
13146   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13147   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13148   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13149   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13150   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13151   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13152   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13153   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13154   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13155
13156   /*
13157    * Check the resulting matrix is OK.
13158    */
13159   det = (RQ[0][0] * ST[0][0])
13160       + (RQ[0][1] * ST[0][1])
13161       + (RQ[0][2] * ST[0][2]);
13162   if (!det)
13163     return FALSE;
13164
13165   /*
13166    * Now transform our point with the ST matrix; the notional w
13167    * coordinate is 1, hence the last part is simply added.
13168    */
13169   xi = (int) x;
13170   yi = (int) y;
13171
13172   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13173   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13174   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13175
13176   if (x_out)
13177     *x_out = xf / wf;
13178
13179   if (y_out)
13180     *y_out = yf / wf;
13181
13182 #undef UX2FP
13183 #undef DET2FP
13184
13185   return TRUE;
13186 }
13187
13188 /*
13189  * ClutterGeometry
13190  */
13191
13192 static ClutterGeometry*
13193 clutter_geometry_copy (const ClutterGeometry *geometry)
13194 {
13195   return g_slice_dup (ClutterGeometry, geometry);
13196 }
13197
13198 static void
13199 clutter_geometry_free (ClutterGeometry *geometry)
13200 {
13201   if (G_LIKELY (geometry != NULL))
13202     g_slice_free (ClutterGeometry, geometry);
13203 }
13204
13205 /**
13206  * clutter_geometry_union:
13207  * @geometry_a: a #ClutterGeometry
13208  * @geometry_b: another #ClutterGeometry
13209  * @result: (out): location to store the result
13210  *
13211  * Find the union of two rectangles represented as #ClutterGeometry.
13212  *
13213  * Since: 1.4
13214  */
13215 void
13216 clutter_geometry_union (const ClutterGeometry *geometry_a,
13217                         const ClutterGeometry *geometry_b,
13218                         ClutterGeometry       *result)
13219 {
13220   /* We don't try to handle rectangles that can't be represented
13221    * as a signed integer box */
13222   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13223   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13224   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13225                   geometry_b->x + (gint)geometry_b->width);
13226   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13227                   geometry_b->y + (gint)geometry_b->height);
13228   result->x = x_1;
13229   result->y = y_1;
13230   result->width = x_2 - x_1;
13231   result->height = y_2 - y_1;
13232 }
13233
13234 /**
13235  * clutter_geometry_intersects:
13236  * @geometry0: The first geometry to test
13237  * @geometry1: The second geometry to test
13238  *
13239  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13240  * they do else %FALSE.
13241  *
13242  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13243  * %FALSE.
13244  *
13245  * Since: 1.4
13246  */
13247 gboolean
13248 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13249                              const ClutterGeometry *geometry1)
13250 {
13251   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13252       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13253       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13254       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13255     return FALSE;
13256   else
13257     return TRUE;
13258 }
13259
13260 static gboolean
13261 clutter_geometry_progress (const GValue *a,
13262                            const GValue *b,
13263                            gdouble       progress,
13264                            GValue       *retval)
13265 {
13266   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13267   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13268   ClutterGeometry res = { 0, };
13269   gint a_width = a_geom->width;
13270   gint b_width = b_geom->width;
13271   gint a_height = a_geom->height;
13272   gint b_height = b_geom->height;
13273
13274   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13275   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13276
13277   res.width = a_width + (b_width - a_width) * progress;
13278   res.height = a_height + (b_height - a_height) * progress;
13279
13280   g_value_set_boxed (retval, &res);
13281
13282   return TRUE;
13283 }
13284
13285 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13286                                clutter_geometry_copy,
13287                                clutter_geometry_free,
13288                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13289
13290 /*
13291  * ClutterVertices
13292  */
13293
13294 /**
13295  * clutter_vertex_new:
13296  * @x: X coordinate
13297  * @y: Y coordinate
13298  * @z: Z coordinate
13299  *
13300  * Creates a new #ClutterVertex for the point in 3D space
13301  * identified by the 3 coordinates @x, @y, @z
13302  *
13303  * Return value: the newly allocate #ClutterVertex. Use
13304  *   clutter_vertex_free() to free the resources
13305  *
13306  * Since: 1.0
13307  */
13308 ClutterVertex *
13309 clutter_vertex_new (gfloat x,
13310                     gfloat y,
13311                     gfloat z)
13312 {
13313   ClutterVertex *vertex;
13314
13315   vertex = g_slice_new (ClutterVertex);
13316   clutter_vertex_init (vertex, x, y, z);
13317
13318   return vertex;
13319 }
13320
13321 /**
13322  * clutter_vertex_init:
13323  * @vertex: a #ClutterVertex
13324  * @x: X coordinate
13325  * @y: Y coordinate
13326  * @z: Z coordinate
13327  *
13328  * Initializes @vertex with the given coordinates.
13329  *
13330  * Since: 1.10
13331  */
13332 void
13333 clutter_vertex_init (ClutterVertex *vertex,
13334                      gfloat         x,
13335                      gfloat         y,
13336                      gfloat         z)
13337 {
13338   g_return_if_fail (vertex != NULL);
13339
13340   vertex->x = x;
13341   vertex->y = y;
13342   vertex->z = z;
13343 }
13344
13345 /**
13346  * clutter_vertex_copy:
13347  * @vertex: a #ClutterVertex
13348  *
13349  * Copies @vertex
13350  *
13351  * Return value: a newly allocated copy of #ClutterVertex. Use
13352  *   clutter_vertex_free() to free the allocated resources
13353  *
13354  * Since: 1.0
13355  */
13356 ClutterVertex *
13357 clutter_vertex_copy (const ClutterVertex *vertex)
13358 {
13359   if (G_LIKELY (vertex != NULL))
13360     return g_slice_dup (ClutterVertex, vertex);
13361
13362   return NULL;
13363 }
13364
13365 /**
13366  * clutter_vertex_free:
13367  * @vertex: a #ClutterVertex
13368  *
13369  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13370  *
13371  * Since: 1.0
13372  */
13373 void
13374 clutter_vertex_free (ClutterVertex *vertex)
13375 {
13376   if (G_UNLIKELY (vertex != NULL))
13377     g_slice_free (ClutterVertex, vertex);
13378 }
13379
13380 /**
13381  * clutter_vertex_equal:
13382  * @vertex_a: a #ClutterVertex
13383  * @vertex_b: a #ClutterVertex
13384  *
13385  * Compares @vertex_a and @vertex_b for equality
13386  *
13387  * Return value: %TRUE if the passed #ClutterVertex are equal
13388  *
13389  * Since: 1.0
13390  */
13391 gboolean
13392 clutter_vertex_equal (const ClutterVertex *vertex_a,
13393                       const ClutterVertex *vertex_b)
13394 {
13395   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13396
13397   if (vertex_a == vertex_b)
13398     return TRUE;
13399
13400   return vertex_a->x == vertex_b->x &&
13401          vertex_a->y == vertex_b->y &&
13402          vertex_a->z == vertex_b->z;
13403 }
13404
13405 static gboolean
13406 clutter_vertex_progress (const GValue *a,
13407                          const GValue *b,
13408                          gdouble       progress,
13409                          GValue       *retval)
13410 {
13411   const ClutterVertex *av = g_value_get_boxed (a);
13412   const ClutterVertex *bv = g_value_get_boxed (b);
13413   ClutterVertex res = { 0, };
13414
13415   res.x = av->x + (bv->x - av->x) * progress;
13416   res.y = av->y + (bv->y - av->y) * progress;
13417   res.z = av->z + (bv->z - av->z) * progress;
13418
13419   g_value_set_boxed (retval, &res);
13420
13421   return TRUE;
13422 }
13423
13424 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13425                                clutter_vertex_copy,
13426                                clutter_vertex_free,
13427                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13428
13429 /**
13430  * clutter_actor_is_rotated:
13431  * @self: a #ClutterActor
13432  *
13433  * Checks whether any rotation is applied to the actor.
13434  *
13435  * Return value: %TRUE if the actor is rotated.
13436  *
13437  * Since: 0.6
13438  */
13439 gboolean
13440 clutter_actor_is_rotated (ClutterActor *self)
13441 {
13442   const ClutterTransformInfo *info;
13443
13444   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13445
13446   info = _clutter_actor_get_transform_info_or_defaults (self);
13447
13448   if (info->rx_angle || info->ry_angle || info->rz_angle)
13449     return TRUE;
13450
13451   return FALSE;
13452 }
13453
13454 /**
13455  * clutter_actor_is_scaled:
13456  * @self: a #ClutterActor
13457  *
13458  * Checks whether the actor is scaled in either dimension.
13459  *
13460  * Return value: %TRUE if the actor is scaled.
13461  *
13462  * Since: 0.6
13463  */
13464 gboolean
13465 clutter_actor_is_scaled (ClutterActor *self)
13466 {
13467   const ClutterTransformInfo *info;
13468
13469   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13470
13471   info = _clutter_actor_get_transform_info_or_defaults (self);
13472
13473   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13474     return TRUE;
13475
13476   return FALSE;
13477 }
13478
13479 ClutterActor *
13480 _clutter_actor_get_stage_internal (ClutterActor *actor)
13481 {
13482   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13483     actor = actor->priv->parent;
13484
13485   return actor;
13486 }
13487
13488 /**
13489  * clutter_actor_get_stage:
13490  * @actor: a #ClutterActor
13491  *
13492  * Retrieves the #ClutterStage where @actor is contained.
13493  *
13494  * Return value: (transfer none) (type Clutter.Stage): the stage
13495  *   containing the actor, or %NULL
13496  *
13497  * Since: 0.8
13498  */
13499 ClutterActor *
13500 clutter_actor_get_stage (ClutterActor *actor)
13501 {
13502   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13503
13504   return _clutter_actor_get_stage_internal (actor);
13505 }
13506
13507 /**
13508  * clutter_actor_allocate_available_size:
13509  * @self: a #ClutterActor
13510  * @x: the actor's X coordinate
13511  * @y: the actor's Y coordinate
13512  * @available_width: the maximum available width, or -1 to use the
13513  *   actor's natural width
13514  * @available_height: the maximum available height, or -1 to use the
13515  *   actor's natural height
13516  * @flags: flags controlling the allocation
13517  *
13518  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13519  * preferred size, but limiting it to the maximum available width
13520  * and height provided.
13521  *
13522  * This function will do the right thing when dealing with the
13523  * actor's request mode.
13524  *
13525  * The implementation of this function is equivalent to:
13526  *
13527  * |[
13528  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13529  *     {
13530  *       clutter_actor_get_preferred_width (self, available_height,
13531  *                                          &amp;min_width,
13532  *                                          &amp;natural_width);
13533  *       width = CLAMP (natural_width, min_width, available_width);
13534  *
13535  *       clutter_actor_get_preferred_height (self, width,
13536  *                                           &amp;min_height,
13537  *                                           &amp;natural_height);
13538  *       height = CLAMP (natural_height, min_height, available_height);
13539  *     }
13540  *   else
13541  *     {
13542  *       clutter_actor_get_preferred_height (self, available_width,
13543  *                                           &amp;min_height,
13544  *                                           &amp;natural_height);
13545  *       height = CLAMP (natural_height, min_height, available_height);
13546  *
13547  *       clutter_actor_get_preferred_width (self, height,
13548  *                                          &amp;min_width,
13549  *                                          &amp;natural_width);
13550  *       width = CLAMP (natural_width, min_width, available_width);
13551  *     }
13552  *
13553  *   box.x1 = x; box.y1 = y;
13554  *   box.x2 = box.x1 + available_width;
13555  *   box.y2 = box.y1 + available_height;
13556  *   clutter_actor_allocate (self, &amp;box, flags);
13557  * ]|
13558  *
13559  * This function can be used by fluid layout managers to allocate
13560  * an actor's preferred size without making it bigger than the area
13561  * available for the container.
13562  *
13563  * Since: 1.0
13564  */
13565 void
13566 clutter_actor_allocate_available_size (ClutterActor           *self,
13567                                        gfloat                  x,
13568                                        gfloat                  y,
13569                                        gfloat                  available_width,
13570                                        gfloat                  available_height,
13571                                        ClutterAllocationFlags  flags)
13572 {
13573   ClutterActorPrivate *priv;
13574   gfloat width, height;
13575   gfloat min_width, min_height;
13576   gfloat natural_width, natural_height;
13577   ClutterActorBox box;
13578
13579   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13580
13581   priv = self->priv;
13582
13583   width = height = 0.0;
13584
13585   switch (priv->request_mode)
13586     {
13587     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13588       clutter_actor_get_preferred_width (self, available_height,
13589                                          &min_width,
13590                                          &natural_width);
13591       width  = CLAMP (natural_width, min_width, available_width);
13592
13593       clutter_actor_get_preferred_height (self, width,
13594                                           &min_height,
13595                                           &natural_height);
13596       height = CLAMP (natural_height, min_height, available_height);
13597       break;
13598
13599     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13600       clutter_actor_get_preferred_height (self, available_width,
13601                                           &min_height,
13602                                           &natural_height);
13603       height = CLAMP (natural_height, min_height, available_height);
13604
13605       clutter_actor_get_preferred_width (self, height,
13606                                          &min_width,
13607                                          &natural_width);
13608       width  = CLAMP (natural_width, min_width, available_width);
13609       break;
13610     }
13611
13612
13613   box.x1 = x;
13614   box.y1 = y;
13615   box.x2 = box.x1 + width;
13616   box.y2 = box.y1 + height;
13617   clutter_actor_allocate (self, &box, flags);
13618 }
13619
13620 /**
13621  * clutter_actor_allocate_preferred_size:
13622  * @self: a #ClutterActor
13623  * @flags: flags controlling the allocation
13624  *
13625  * Allocates the natural size of @self.
13626  *
13627  * This function is a utility call for #ClutterActor implementations
13628  * that allocates the actor's preferred natural size. It can be used
13629  * by fixed layout managers (like #ClutterGroup or so called
13630  * 'composite actors') inside the ClutterActor::allocate
13631  * implementation to give each child exactly how much space it
13632  * requires.
13633  *
13634  * This function is not meant to be used by applications. It is also
13635  * not meant to be used outside the implementation of the
13636  * ClutterActor::allocate virtual function.
13637  *
13638  * Since: 0.8
13639  */
13640 void
13641 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13642                                        ClutterAllocationFlags  flags)
13643 {
13644   gfloat actor_x, actor_y;
13645   gfloat natural_width, natural_height;
13646   ClutterActorBox actor_box;
13647
13648   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13649
13650   actor_x = clutter_actor_get_x (self);
13651   actor_y = clutter_actor_get_y (self);
13652
13653   clutter_actor_get_preferred_size (self,
13654                                     NULL, NULL,
13655                                     &natural_width,
13656                                     &natural_height);
13657
13658   actor_box.x1 = actor_x;
13659   actor_box.y1 = actor_y;
13660   actor_box.x2 = actor_box.x1 + natural_width;
13661   actor_box.y2 = actor_box.y1 + natural_height;
13662
13663   clutter_actor_allocate (self, &actor_box, flags);
13664 }
13665
13666 /**
13667  * clutter_actor_allocate_align_fill:
13668  * @self: a #ClutterActor
13669  * @box: a #ClutterActorBox, containing the available width and height
13670  * @x_align: the horizontal alignment, between 0 and 1
13671  * @y_align: the vertical alignment, between 0 and 1
13672  * @x_fill: whether the actor should fill horizontally
13673  * @y_fill: whether the actor should fill vertically
13674  * @flags: allocation flags to be passed to clutter_actor_allocate()
13675  *
13676  * Allocates @self by taking into consideration the available allocation
13677  * area; an alignment factor on either axis; and whether the actor should
13678  * fill the allocation on either axis.
13679  *
13680  * The @box should contain the available allocation width and height;
13681  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13682  * allocation will be offset by their value.
13683  *
13684  * This function takes into consideration the geometry request specified by
13685  * the #ClutterActor:request-mode property, and the text direction.
13686  *
13687  * This function is useful for fluid layout managers, like #ClutterBinLayout
13688  * or #ClutterTableLayout
13689  *
13690  * Since: 1.4
13691  */
13692 void
13693 clutter_actor_allocate_align_fill (ClutterActor           *self,
13694                                    const ClutterActorBox  *box,
13695                                    gdouble                 x_align,
13696                                    gdouble                 y_align,
13697                                    gboolean                x_fill,
13698                                    gboolean                y_fill,
13699                                    ClutterAllocationFlags  flags)
13700 {
13701   ClutterActorPrivate *priv;
13702   ClutterActorBox allocation = { 0, };
13703   gfloat x_offset, y_offset;
13704   gfloat available_width, available_height;
13705   gfloat child_width, child_height;
13706
13707   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13708   g_return_if_fail (box != NULL);
13709   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13710   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13711
13712   priv = self->priv;
13713
13714   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13715   clutter_actor_box_get_size (box, &available_width, &available_height);
13716
13717   if (available_width < 0)
13718     available_width = 0;
13719
13720   if (available_height < 0)
13721     available_height = 0;
13722
13723   if (x_fill)
13724     {
13725       allocation.x1 = x_offset;
13726       allocation.x2 = allocation.x1 + available_width;
13727     }
13728
13729   if (y_fill)
13730     {
13731       allocation.y1 = y_offset;
13732       allocation.y2 = allocation.y1 + available_height;
13733     }
13734
13735   /* if we are filling horizontally and vertically then we're done */
13736   if (x_fill && y_fill)
13737     goto out;
13738
13739   child_width = child_height = 0.0f;
13740
13741   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13742     {
13743       gfloat min_width, natural_width;
13744       gfloat min_height, natural_height;
13745
13746       clutter_actor_get_preferred_width (self, available_height,
13747                                          &min_width,
13748                                          &natural_width);
13749
13750       child_width = CLAMP (natural_width, min_width, available_width);
13751
13752       if (!y_fill)
13753         {
13754           clutter_actor_get_preferred_height (self, child_width,
13755                                               &min_height,
13756                                               &natural_height);
13757
13758           child_height = CLAMP (natural_height, min_height, available_height);
13759         }
13760     }
13761   else
13762     {
13763       gfloat min_width, natural_width;
13764       gfloat min_height, natural_height;
13765
13766       clutter_actor_get_preferred_height (self, available_width,
13767                                           &min_height,
13768                                           &natural_height);
13769
13770       child_height = CLAMP (natural_height, min_height, available_height);
13771
13772       if (!x_fill)
13773         {
13774           clutter_actor_get_preferred_width (self, child_height,
13775                                              &min_width,
13776                                              &natural_width);
13777
13778           child_width = CLAMP (natural_width, min_width, available_width);
13779         }
13780     }
13781
13782   /* invert the horizontal alignment for RTL languages */
13783   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13784     x_align = 1.0 - x_align;
13785
13786   if (!x_fill)
13787     {
13788       allocation.x1 = x_offset
13789                     + ((available_width - child_width) * x_align);
13790       allocation.x2 = allocation.x1 + child_width;
13791     }
13792
13793   if (!y_fill)
13794     {
13795       allocation.y1 = y_offset
13796                     + ((available_height - child_height) * y_align);
13797       allocation.y2 = allocation.y1 + child_height;
13798     }
13799
13800 out:
13801   clutter_actor_box_clamp_to_pixel (&allocation);
13802   clutter_actor_allocate (self, &allocation, flags);
13803 }
13804
13805 /**
13806  * clutter_actor_grab_key_focus:
13807  * @self: a #ClutterActor
13808  *
13809  * Sets the key focus of the #ClutterStage including @self
13810  * to this #ClutterActor.
13811  *
13812  * Since: 1.0
13813  */
13814 void
13815 clutter_actor_grab_key_focus (ClutterActor *self)
13816 {
13817   ClutterActor *stage;
13818
13819   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13820
13821   stage = _clutter_actor_get_stage_internal (self);
13822   if (stage != NULL)
13823     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13824 }
13825
13826 /**
13827  * clutter_actor_get_pango_context:
13828  * @self: a #ClutterActor
13829  *
13830  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13831  * is already configured using the appropriate font map, resolution
13832  * and font options.
13833  *
13834  * Unlike clutter_actor_create_pango_context(), this context is owend
13835  * by the #ClutterActor and it will be updated each time the options
13836  * stored by the #ClutterBackend change.
13837  *
13838  * You can use the returned #PangoContext to create a #PangoLayout
13839  * and render text using cogl_pango_render_layout() to reuse the
13840  * glyphs cache also used by Clutter.
13841  *
13842  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13843  *   The returned #PangoContext is owned by the actor and should not be
13844  *   unreferenced by the application code
13845  *
13846  * Since: 1.0
13847  */
13848 PangoContext *
13849 clutter_actor_get_pango_context (ClutterActor *self)
13850 {
13851   ClutterActorPrivate *priv;
13852
13853   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13854
13855   priv = self->priv;
13856
13857   if (priv->pango_context != NULL)
13858     return priv->pango_context;
13859
13860   priv->pango_context = _clutter_context_get_pango_context ();
13861   g_object_ref (priv->pango_context);
13862
13863   return priv->pango_context;
13864 }
13865
13866 /**
13867  * clutter_actor_create_pango_context:
13868  * @self: a #ClutterActor
13869  *
13870  * Creates a #PangoContext for the given actor. The #PangoContext
13871  * is already configured using the appropriate font map, resolution
13872  * and font options.
13873  *
13874  * See also clutter_actor_get_pango_context().
13875  *
13876  * Return value: (transfer full): the newly created #PangoContext.
13877  *   Use g_object_unref() on the returned value to deallocate its
13878  *   resources
13879  *
13880  * Since: 1.0
13881  */
13882 PangoContext *
13883 clutter_actor_create_pango_context (ClutterActor *self)
13884 {
13885   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13886
13887   return _clutter_context_create_pango_context ();
13888 }
13889
13890 /**
13891  * clutter_actor_create_pango_layout:
13892  * @self: a #ClutterActor
13893  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13894  *
13895  * Creates a new #PangoLayout from the same #PangoContext used
13896  * by the #ClutterActor. The #PangoLayout is already configured
13897  * with the font map, resolution and font options, and the
13898  * given @text.
13899  *
13900  * If you want to keep around a #PangoLayout created by this
13901  * function you will have to connect to the #ClutterBackend::font-changed
13902  * and #ClutterBackend::resolution-changed signals, and call
13903  * pango_layout_context_changed() in response to them.
13904  *
13905  * Return value: (transfer full): the newly created #PangoLayout.
13906  *   Use g_object_unref() when done
13907  *
13908  * Since: 1.0
13909  */
13910 PangoLayout *
13911 clutter_actor_create_pango_layout (ClutterActor *self,
13912                                    const gchar  *text)
13913 {
13914   PangoContext *context;
13915   PangoLayout *layout;
13916
13917   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13918
13919   context = clutter_actor_get_pango_context (self);
13920   layout = pango_layout_new (context);
13921
13922   if (text)
13923     pango_layout_set_text (layout, text, -1);
13924
13925   return layout;
13926 }
13927
13928 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13929  * ClutterOffscreenEffect.
13930  */
13931 void
13932 _clutter_actor_set_opacity_override (ClutterActor *self,
13933                                      gint          opacity)
13934 {
13935   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13936
13937   self->priv->opacity_override = opacity;
13938 }
13939
13940 gint
13941 _clutter_actor_get_opacity_override (ClutterActor *self)
13942 {
13943   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13944
13945   return self->priv->opacity_override;
13946 }
13947
13948 /* Allows you to disable applying the actors model view transform during
13949  * a paint. Used by ClutterClone. */
13950 void
13951 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13952                                                 gboolean      enable)
13953 {
13954   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13955
13956   self->priv->enable_model_view_transform = enable;
13957 }
13958
13959 void
13960 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13961                                           gboolean      enable)
13962 {
13963   ClutterActorPrivate *priv;
13964
13965   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13966
13967   priv = self->priv;
13968
13969   priv->enable_paint_unmapped = enable;
13970
13971   if (priv->enable_paint_unmapped)
13972     {
13973       /* Make sure that the parents of the widget are realized first;
13974        * otherwise checks in clutter_actor_update_map_state() will
13975        * fail.
13976        */
13977       clutter_actor_realize (self);
13978
13979       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13980     }
13981   else
13982     {
13983       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13984     }
13985 }
13986
13987 static void
13988 clutter_anchor_coord_get_units (ClutterActor      *self,
13989                                 const AnchorCoord *coord,
13990                                 gfloat            *x,
13991                                 gfloat            *y,
13992                                 gfloat            *z)
13993 {
13994   if (coord->is_fractional)
13995     {
13996       gfloat actor_width, actor_height;
13997
13998       clutter_actor_get_size (self, &actor_width, &actor_height);
13999
14000       if (x)
14001         *x = actor_width * coord->v.fraction.x;
14002
14003       if (y)
14004         *y = actor_height * coord->v.fraction.y;
14005
14006       if (z)
14007         *z = 0;
14008     }
14009   else
14010     {
14011       if (x)
14012         *x = coord->v.units.x;
14013
14014       if (y)
14015         *y = coord->v.units.y;
14016
14017       if (z)
14018         *z = coord->v.units.z;
14019     }
14020 }
14021
14022 static void
14023 clutter_anchor_coord_set_units (AnchorCoord *coord,
14024                                 gfloat       x,
14025                                 gfloat       y,
14026                                 gfloat       z)
14027 {
14028   coord->is_fractional = FALSE;
14029   coord->v.units.x = x;
14030   coord->v.units.y = y;
14031   coord->v.units.z = z;
14032 }
14033
14034 static ClutterGravity
14035 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14036 {
14037   if (coord->is_fractional)
14038     {
14039       if (coord->v.fraction.x == 0.0)
14040         {
14041           if (coord->v.fraction.y == 0.0)
14042             return CLUTTER_GRAVITY_NORTH_WEST;
14043           else if (coord->v.fraction.y == 0.5)
14044             return CLUTTER_GRAVITY_WEST;
14045           else if (coord->v.fraction.y == 1.0)
14046             return CLUTTER_GRAVITY_SOUTH_WEST;
14047           else
14048             return CLUTTER_GRAVITY_NONE;
14049         }
14050       else if (coord->v.fraction.x == 0.5)
14051         {
14052           if (coord->v.fraction.y == 0.0)
14053             return CLUTTER_GRAVITY_NORTH;
14054           else if (coord->v.fraction.y == 0.5)
14055             return CLUTTER_GRAVITY_CENTER;
14056           else if (coord->v.fraction.y == 1.0)
14057             return CLUTTER_GRAVITY_SOUTH;
14058           else
14059             return CLUTTER_GRAVITY_NONE;
14060         }
14061       else if (coord->v.fraction.x == 1.0)
14062         {
14063           if (coord->v.fraction.y == 0.0)
14064             return CLUTTER_GRAVITY_NORTH_EAST;
14065           else if (coord->v.fraction.y == 0.5)
14066             return CLUTTER_GRAVITY_EAST;
14067           else if (coord->v.fraction.y == 1.0)
14068             return CLUTTER_GRAVITY_SOUTH_EAST;
14069           else
14070             return CLUTTER_GRAVITY_NONE;
14071         }
14072       else
14073         return CLUTTER_GRAVITY_NONE;
14074     }
14075   else
14076     return CLUTTER_GRAVITY_NONE;
14077 }
14078
14079 static void
14080 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14081                                   ClutterGravity  gravity)
14082 {
14083   switch (gravity)
14084     {
14085     case CLUTTER_GRAVITY_NORTH:
14086       coord->v.fraction.x = 0.5;
14087       coord->v.fraction.y = 0.0;
14088       break;
14089
14090     case CLUTTER_GRAVITY_NORTH_EAST:
14091       coord->v.fraction.x = 1.0;
14092       coord->v.fraction.y = 0.0;
14093       break;
14094
14095     case CLUTTER_GRAVITY_EAST:
14096       coord->v.fraction.x = 1.0;
14097       coord->v.fraction.y = 0.5;
14098       break;
14099
14100     case CLUTTER_GRAVITY_SOUTH_EAST:
14101       coord->v.fraction.x = 1.0;
14102       coord->v.fraction.y = 1.0;
14103       break;
14104
14105     case CLUTTER_GRAVITY_SOUTH:
14106       coord->v.fraction.x = 0.5;
14107       coord->v.fraction.y = 1.0;
14108       break;
14109
14110     case CLUTTER_GRAVITY_SOUTH_WEST:
14111       coord->v.fraction.x = 0.0;
14112       coord->v.fraction.y = 1.0;
14113       break;
14114
14115     case CLUTTER_GRAVITY_WEST:
14116       coord->v.fraction.x = 0.0;
14117       coord->v.fraction.y = 0.5;
14118       break;
14119
14120     case CLUTTER_GRAVITY_NORTH_WEST:
14121       coord->v.fraction.x = 0.0;
14122       coord->v.fraction.y = 0.0;
14123       break;
14124
14125     case CLUTTER_GRAVITY_CENTER:
14126       coord->v.fraction.x = 0.5;
14127       coord->v.fraction.y = 0.5;
14128       break;
14129
14130     default:
14131       coord->v.fraction.x = 0.0;
14132       coord->v.fraction.y = 0.0;
14133       break;
14134     }
14135
14136   coord->is_fractional = TRUE;
14137 }
14138
14139 static gboolean
14140 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14141 {
14142   if (coord->is_fractional)
14143     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14144   else
14145     return (coord->v.units.x == 0.0
14146             && coord->v.units.y == 0.0
14147             && coord->v.units.z == 0.0);
14148 }
14149
14150 /**
14151  * clutter_actor_get_flags:
14152  * @self: a #ClutterActor
14153  *
14154  * Retrieves the flags set on @self
14155  *
14156  * Return value: a bitwise or of #ClutterActorFlags or 0
14157  *
14158  * Since: 1.0
14159  */
14160 ClutterActorFlags
14161 clutter_actor_get_flags (ClutterActor *self)
14162 {
14163   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14164
14165   return self->flags;
14166 }
14167
14168 /**
14169  * clutter_actor_set_flags:
14170  * @self: a #ClutterActor
14171  * @flags: the flags to set
14172  *
14173  * Sets @flags on @self
14174  *
14175  * This function will emit notifications for the changed properties
14176  *
14177  * Since: 1.0
14178  */
14179 void
14180 clutter_actor_set_flags (ClutterActor      *self,
14181                          ClutterActorFlags  flags)
14182 {
14183   ClutterActorFlags old_flags;
14184   GObject *obj;
14185   gboolean was_reactive_set, reactive_set;
14186   gboolean was_realized_set, realized_set;
14187   gboolean was_mapped_set, mapped_set;
14188   gboolean was_visible_set, visible_set;
14189
14190   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14191
14192   if (self->flags == flags)
14193     return;
14194
14195   obj = G_OBJECT (self);
14196   g_object_ref (obj);
14197   g_object_freeze_notify (obj);
14198
14199   old_flags = self->flags;
14200
14201   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14202   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14203   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14204   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14205
14206   self->flags |= flags;
14207
14208   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14209   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14210   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14211   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14212
14213   if (reactive_set != was_reactive_set)
14214     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14215
14216   if (realized_set != was_realized_set)
14217     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14218
14219   if (mapped_set != was_mapped_set)
14220     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14221
14222   if (visible_set != was_visible_set)
14223     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14224
14225   g_object_thaw_notify (obj);
14226   g_object_unref (obj);
14227 }
14228
14229 /**
14230  * clutter_actor_unset_flags:
14231  * @self: a #ClutterActor
14232  * @flags: the flags to unset
14233  *
14234  * Unsets @flags on @self
14235  *
14236  * This function will emit notifications for the changed properties
14237  *
14238  * Since: 1.0
14239  */
14240 void
14241 clutter_actor_unset_flags (ClutterActor      *self,
14242                            ClutterActorFlags  flags)
14243 {
14244   ClutterActorFlags old_flags;
14245   GObject *obj;
14246   gboolean was_reactive_set, reactive_set;
14247   gboolean was_realized_set, realized_set;
14248   gboolean was_mapped_set, mapped_set;
14249   gboolean was_visible_set, visible_set;
14250
14251   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14252
14253   obj = G_OBJECT (self);
14254   g_object_freeze_notify (obj);
14255
14256   old_flags = self->flags;
14257
14258   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14259   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14260   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14261   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14262
14263   self->flags &= ~flags;
14264
14265   if (self->flags == old_flags)
14266     return;
14267
14268   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14269   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14270   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14271   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14272
14273   if (reactive_set != was_reactive_set)
14274     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14275
14276   if (realized_set != was_realized_set)
14277     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14278
14279   if (mapped_set != was_mapped_set)
14280     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14281
14282   if (visible_set != was_visible_set)
14283     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14284
14285   g_object_thaw_notify (obj);
14286 }
14287
14288 /**
14289  * clutter_actor_get_transformation_matrix:
14290  * @self: a #ClutterActor
14291  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14292  *
14293  * Retrieves the transformations applied to @self relative to its
14294  * parent.
14295  *
14296  * Since: 1.0
14297  */
14298 void
14299 clutter_actor_get_transformation_matrix (ClutterActor *self,
14300                                          CoglMatrix   *matrix)
14301 {
14302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14303
14304   cogl_matrix_init_identity (matrix);
14305
14306   _clutter_actor_apply_modelview_transform (self, matrix);
14307 }
14308
14309 void
14310 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14311                                    gboolean      is_in_clone_paint)
14312 {
14313   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14314   self->priv->in_clone_paint = is_in_clone_paint;
14315 }
14316
14317 /**
14318  * clutter_actor_is_in_clone_paint:
14319  * @self: a #ClutterActor
14320  *
14321  * Checks whether @self is being currently painted by a #ClutterClone
14322  *
14323  * This function is useful only inside the ::paint virtual function
14324  * implementations or within handlers for the #ClutterActor::paint
14325  * signal
14326  *
14327  * This function should not be used by applications
14328  *
14329  * Return value: %TRUE if the #ClutterActor is currently being painted
14330  *   by a #ClutterClone, and %FALSE otherwise
14331  *
14332  * Since: 1.0
14333  */
14334 gboolean
14335 clutter_actor_is_in_clone_paint (ClutterActor *self)
14336 {
14337   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14338
14339   return self->priv->in_clone_paint;
14340 }
14341
14342 static gboolean
14343 set_direction_recursive (ClutterActor *actor,
14344                          gpointer      user_data)
14345 {
14346   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14347
14348   clutter_actor_set_text_direction (actor, text_dir);
14349
14350   return TRUE;
14351 }
14352
14353 /**
14354  * clutter_actor_set_text_direction:
14355  * @self: a #ClutterActor
14356  * @text_dir: the text direction for @self
14357  *
14358  * Sets the #ClutterTextDirection for an actor
14359  *
14360  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14361  *
14362  * If @self implements #ClutterContainer then this function will recurse
14363  * inside all the children of @self (including the internal ones).
14364  *
14365  * Composite actors not implementing #ClutterContainer, or actors requiring
14366  * special handling when the text direction changes, should connect to
14367  * the #GObject::notify signal for the #ClutterActor:text-direction property
14368  *
14369  * Since: 1.2
14370  */
14371 void
14372 clutter_actor_set_text_direction (ClutterActor         *self,
14373                                   ClutterTextDirection  text_dir)
14374 {
14375   ClutterActorPrivate *priv;
14376
14377   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14378   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14379
14380   priv = self->priv;
14381
14382   if (priv->text_direction != text_dir)
14383     {
14384       priv->text_direction = text_dir;
14385
14386       /* we need to emit the notify::text-direction first, so that
14387        * the sub-classes can catch that and do specific handling of
14388        * the text direction; see clutter_text_direction_changed_cb()
14389        * inside clutter-text.c
14390        */
14391       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14392
14393       _clutter_actor_foreach_child (self, set_direction_recursive,
14394                                     GINT_TO_POINTER (text_dir));
14395
14396       clutter_actor_queue_relayout (self);
14397     }
14398 }
14399
14400 void
14401 _clutter_actor_set_has_pointer (ClutterActor *self,
14402                                 gboolean      has_pointer)
14403 {
14404   ClutterActorPrivate *priv = self->priv;
14405
14406   if (priv->has_pointer != has_pointer)
14407     {
14408       priv->has_pointer = has_pointer;
14409
14410       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14411     }
14412 }
14413
14414 /**
14415  * clutter_actor_get_text_direction:
14416  * @self: a #ClutterActor
14417  *
14418  * Retrieves the value set using clutter_actor_set_text_direction()
14419  *
14420  * If no text direction has been previously set, the default text
14421  * direction, as returned by clutter_get_default_text_direction(), will
14422  * be returned instead
14423  *
14424  * Return value: the #ClutterTextDirection for the actor
14425  *
14426  * Since: 1.2
14427  */
14428 ClutterTextDirection
14429 clutter_actor_get_text_direction (ClutterActor *self)
14430 {
14431   ClutterActorPrivate *priv;
14432
14433   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14434                         CLUTTER_TEXT_DIRECTION_LTR);
14435
14436   priv = self->priv;
14437
14438   /* if no direction has been set yet use the default */
14439   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14440     priv->text_direction = clutter_get_default_text_direction ();
14441
14442   return priv->text_direction;
14443 }
14444
14445 /**
14446  * clutter_actor_push_internal:
14447  * @self: a #ClutterActor
14448  *
14449  * Should be used by actors implementing the #ClutterContainer and with
14450  * internal children added through clutter_actor_set_parent(), for instance:
14451  *
14452  * |[
14453  *   static void
14454  *   my_actor_init (MyActor *self)
14455  *   {
14456  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14457  *
14458  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14459  *
14460  *     /&ast; calling clutter_actor_set_parent() now will result in
14461  *      &ast; the internal flag being set on a child of MyActor
14462  *      &ast;/
14463  *
14464  *     /&ast; internal child - a background texture &ast;/
14465  *     self->priv->background_tex = clutter_texture_new ();
14466  *     clutter_actor_set_parent (self->priv->background_tex,
14467  *                               CLUTTER_ACTOR (self));
14468  *
14469  *     /&ast; internal child - a label &ast;/
14470  *     self->priv->label = clutter_text_new ();
14471  *     clutter_actor_set_parent (self->priv->label,
14472  *                               CLUTTER_ACTOR (self));
14473  *
14474  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14475  *
14476  *     /&ast; calling clutter_actor_set_parent() now will not result in
14477  *      &ast; the internal flag being set on a child of MyActor
14478  *      &ast;/
14479  *   }
14480  * ]|
14481  *
14482  * This function will be used by Clutter to toggle an "internal child"
14483  * flag whenever clutter_actor_set_parent() is called; internal children
14484  * are handled differently by Clutter, specifically when destroying their
14485  * parent.
14486  *
14487  * Call clutter_actor_pop_internal() when you finished adding internal
14488  * children.
14489  *
14490  * Nested calls to clutter_actor_push_internal() are allowed, but each
14491  * one must by followed by a clutter_actor_pop_internal() call.
14492  *
14493  * Since: 1.2
14494  *
14495  * Deprecated: 1.10: All children of an actor are accessible through
14496  *   the #ClutterActor API, and #ClutterActor implements the
14497  *   #ClutterContainer interface, so this function is only useful
14498  *   for legacy containers overriding the default implementation.
14499  */
14500 void
14501 clutter_actor_push_internal (ClutterActor *self)
14502 {
14503   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14504
14505   self->priv->internal_child += 1;
14506 }
14507
14508 /**
14509  * clutter_actor_pop_internal:
14510  * @self: a #ClutterActor
14511  *
14512  * Disables the effects of clutter_actor_push_internal().
14513  *
14514  * Since: 1.2
14515  *
14516  * Deprecated: 1.10: All children of an actor are accessible through
14517  *   the #ClutterActor API. This function is only useful for legacy
14518  *   containers overriding the default implementation of the
14519  *   #ClutterContainer interface.
14520  */
14521 void
14522 clutter_actor_pop_internal (ClutterActor *self)
14523 {
14524   ClutterActorPrivate *priv;
14525
14526   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14527
14528   priv = self->priv;
14529
14530   if (priv->internal_child == 0)
14531     {
14532       g_warning ("Mismatched %s: you need to call "
14533                  "clutter_actor_push_composite() at least once before "
14534                  "calling this function", G_STRFUNC);
14535       return;
14536     }
14537
14538   priv->internal_child -= 1;
14539 }
14540
14541 /**
14542  * clutter_actor_has_pointer:
14543  * @self: a #ClutterActor
14544  *
14545  * Checks whether an actor contains the pointer of a
14546  * #ClutterInputDevice
14547  *
14548  * Return value: %TRUE if the actor contains the pointer, and
14549  *   %FALSE otherwise
14550  *
14551  * Since: 1.2
14552  */
14553 gboolean
14554 clutter_actor_has_pointer (ClutterActor *self)
14555 {
14556   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14557
14558   return self->priv->has_pointer;
14559 }
14560
14561 /* XXX: This is a workaround for not being able to break the ABI of
14562  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14563  * clutter_actor_queue_clipped_redraw() for details.
14564  */
14565 ClutterPaintVolume *
14566 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14567 {
14568   return g_object_get_data (G_OBJECT (self),
14569                             "-clutter-actor-queue-redraw-clip");
14570 }
14571
14572 void
14573 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14574                                       ClutterPaintVolume *clip)
14575 {
14576   g_object_set_data (G_OBJECT (self),
14577                      "-clutter-actor-queue-redraw-clip",
14578                      clip);
14579 }
14580
14581 /**
14582  * clutter_actor_has_allocation:
14583  * @self: a #ClutterActor
14584  *
14585  * Checks if the actor has an up-to-date allocation assigned to
14586  * it. This means that the actor should have an allocation: it's
14587  * visible and has a parent. It also means that there is no
14588  * outstanding relayout request in progress for the actor or its
14589  * children (There might be other outstanding layout requests in
14590  * progress that will cause the actor to get a new allocation
14591  * when the stage is laid out, however).
14592  *
14593  * If this function returns %FALSE, then the actor will normally
14594  * be allocated before it is next drawn on the screen.
14595  *
14596  * Return value: %TRUE if the actor has an up-to-date allocation
14597  *
14598  * Since: 1.4
14599  */
14600 gboolean
14601 clutter_actor_has_allocation (ClutterActor *self)
14602 {
14603   ClutterActorPrivate *priv;
14604
14605   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14606
14607   priv = self->priv;
14608
14609   return priv->parent != NULL &&
14610          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14611          !priv->needs_allocation;
14612 }
14613
14614 /**
14615  * clutter_actor_add_action:
14616  * @self: a #ClutterActor
14617  * @action: a #ClutterAction
14618  *
14619  * Adds @action to the list of actions applied to @self
14620  *
14621  * A #ClutterAction can only belong to one actor at a time
14622  *
14623  * The #ClutterActor will hold a reference on @action until either
14624  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14625  * is called
14626  *
14627  * Since: 1.4
14628  */
14629 void
14630 clutter_actor_add_action (ClutterActor  *self,
14631                           ClutterAction *action)
14632 {
14633   ClutterActorPrivate *priv;
14634
14635   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14636   g_return_if_fail (CLUTTER_IS_ACTION (action));
14637
14638   priv = self->priv;
14639
14640   if (priv->actions == NULL)
14641     {
14642       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14643       priv->actions->actor = self;
14644     }
14645
14646   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14647
14648   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14649 }
14650
14651 /**
14652  * clutter_actor_add_action_with_name:
14653  * @self: a #ClutterActor
14654  * @name: the name to set on the action
14655  * @action: a #ClutterAction
14656  *
14657  * A convenience function for setting the name of a #ClutterAction
14658  * while adding it to the list of actions applied to @self
14659  *
14660  * This function is the logical equivalent of:
14661  *
14662  * |[
14663  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14664  *   clutter_actor_add_action (self, action);
14665  * ]|
14666  *
14667  * Since: 1.4
14668  */
14669 void
14670 clutter_actor_add_action_with_name (ClutterActor  *self,
14671                                     const gchar   *name,
14672                                     ClutterAction *action)
14673 {
14674   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14675   g_return_if_fail (name != NULL);
14676   g_return_if_fail (CLUTTER_IS_ACTION (action));
14677
14678   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14679   clutter_actor_add_action (self, action);
14680 }
14681
14682 /**
14683  * clutter_actor_remove_action:
14684  * @self: a #ClutterActor
14685  * @action: a #ClutterAction
14686  *
14687  * Removes @action from the list of actions applied to @self
14688  *
14689  * The reference held by @self on the #ClutterAction will be released
14690  *
14691  * Since: 1.4
14692  */
14693 void
14694 clutter_actor_remove_action (ClutterActor  *self,
14695                              ClutterAction *action)
14696 {
14697   ClutterActorPrivate *priv;
14698
14699   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14700   g_return_if_fail (CLUTTER_IS_ACTION (action));
14701
14702   priv = self->priv;
14703
14704   if (priv->actions == NULL)
14705     return;
14706
14707   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14708
14709   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14710 }
14711
14712 /**
14713  * clutter_actor_remove_action_by_name:
14714  * @self: a #ClutterActor
14715  * @name: the name of the action to remove
14716  *
14717  * Removes the #ClutterAction with the given name from the list
14718  * of actions applied to @self
14719  *
14720  * Since: 1.4
14721  */
14722 void
14723 clutter_actor_remove_action_by_name (ClutterActor *self,
14724                                      const gchar  *name)
14725 {
14726   ClutterActorPrivate *priv;
14727   ClutterActorMeta *meta;
14728
14729   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14730   g_return_if_fail (name != NULL);
14731
14732   priv = self->priv;
14733
14734   if (priv->actions == NULL)
14735     return;
14736
14737   meta = _clutter_meta_group_get_meta (priv->actions, name);
14738   if (meta == NULL)
14739     return;
14740
14741   _clutter_meta_group_remove_meta (priv->actions, meta);
14742
14743   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14744 }
14745
14746 /**
14747  * clutter_actor_get_actions:
14748  * @self: a #ClutterActor
14749  *
14750  * Retrieves the list of actions applied to @self
14751  *
14752  * Return value: (transfer container) (element-type Clutter.Action): a copy
14753  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14754  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14755  *   allocated by the returned #GList
14756  *
14757  * Since: 1.4
14758  */
14759 GList *
14760 clutter_actor_get_actions (ClutterActor *self)
14761 {
14762   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14763
14764   if (self->priv->actions == NULL)
14765     return NULL;
14766
14767   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14768 }
14769
14770 /**
14771  * clutter_actor_get_action:
14772  * @self: a #ClutterActor
14773  * @name: the name of the action to retrieve
14774  *
14775  * Retrieves the #ClutterAction with the given name in the list
14776  * of actions applied to @self
14777  *
14778  * Return value: (transfer none): a #ClutterAction for the given
14779  *   name, or %NULL. The returned #ClutterAction is owned by the
14780  *   actor and it should not be unreferenced directly
14781  *
14782  * Since: 1.4
14783  */
14784 ClutterAction *
14785 clutter_actor_get_action (ClutterActor *self,
14786                           const gchar  *name)
14787 {
14788   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14789   g_return_val_if_fail (name != NULL, NULL);
14790
14791   if (self->priv->actions == NULL)
14792     return NULL;
14793
14794   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14795 }
14796
14797 /**
14798  * clutter_actor_clear_actions:
14799  * @self: a #ClutterActor
14800  *
14801  * Clears the list of actions applied to @self
14802  *
14803  * Since: 1.4
14804  */
14805 void
14806 clutter_actor_clear_actions (ClutterActor *self)
14807 {
14808   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14809
14810   if (self->priv->actions == NULL)
14811     return;
14812
14813   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14814 }
14815
14816 /**
14817  * clutter_actor_add_constraint:
14818  * @self: a #ClutterActor
14819  * @constraint: a #ClutterConstraint
14820  *
14821  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14822  * to @self
14823  *
14824  * The #ClutterActor will hold a reference on the @constraint until
14825  * either clutter_actor_remove_constraint() or
14826  * clutter_actor_clear_constraints() is called.
14827  *
14828  * Since: 1.4
14829  */
14830 void
14831 clutter_actor_add_constraint (ClutterActor      *self,
14832                               ClutterConstraint *constraint)
14833 {
14834   ClutterActorPrivate *priv;
14835
14836   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14837   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14838
14839   priv = self->priv;
14840
14841   if (priv->constraints == NULL)
14842     {
14843       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14844       priv->constraints->actor = self;
14845     }
14846
14847   _clutter_meta_group_add_meta (priv->constraints,
14848                                 CLUTTER_ACTOR_META (constraint));
14849   clutter_actor_queue_relayout (self);
14850
14851   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14852 }
14853
14854 /**
14855  * clutter_actor_add_constraint_with_name:
14856  * @self: a #ClutterActor
14857  * @name: the name to set on the constraint
14858  * @constraint: a #ClutterConstraint
14859  *
14860  * A convenience function for setting the name of a #ClutterConstraint
14861  * while adding it to the list of constraints applied to @self
14862  *
14863  * This function is the logical equivalent of:
14864  *
14865  * |[
14866  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14867  *   clutter_actor_add_constraint (self, constraint);
14868  * ]|
14869  *
14870  * Since: 1.4
14871  */
14872 void
14873 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14874                                         const gchar       *name,
14875                                         ClutterConstraint *constraint)
14876 {
14877   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14878   g_return_if_fail (name != NULL);
14879   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14880
14881   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14882   clutter_actor_add_constraint (self, constraint);
14883 }
14884
14885 /**
14886  * clutter_actor_remove_constraint:
14887  * @self: a #ClutterActor
14888  * @constraint: a #ClutterConstraint
14889  *
14890  * Removes @constraint from the list of constraints applied to @self
14891  *
14892  * The reference held by @self on the #ClutterConstraint will be released
14893  *
14894  * Since: 1.4
14895  */
14896 void
14897 clutter_actor_remove_constraint (ClutterActor      *self,
14898                                  ClutterConstraint *constraint)
14899 {
14900   ClutterActorPrivate *priv;
14901
14902   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14903   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14904
14905   priv = self->priv;
14906
14907   if (priv->constraints == NULL)
14908     return;
14909
14910   _clutter_meta_group_remove_meta (priv->constraints,
14911                                    CLUTTER_ACTOR_META (constraint));
14912   clutter_actor_queue_relayout (self);
14913
14914   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14915 }
14916
14917 /**
14918  * clutter_actor_remove_constraint_by_name:
14919  * @self: a #ClutterActor
14920  * @name: the name of the constraint to remove
14921  *
14922  * Removes the #ClutterConstraint with the given name from the list
14923  * of constraints applied to @self
14924  *
14925  * Since: 1.4
14926  */
14927 void
14928 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14929                                          const gchar  *name)
14930 {
14931   ClutterActorPrivate *priv;
14932   ClutterActorMeta *meta;
14933
14934   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14935   g_return_if_fail (name != NULL);
14936
14937   priv = self->priv;
14938
14939   if (priv->constraints == NULL)
14940     return;
14941
14942   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14943   if (meta == NULL)
14944     return;
14945
14946   _clutter_meta_group_remove_meta (priv->constraints, meta);
14947   clutter_actor_queue_relayout (self);
14948 }
14949
14950 /**
14951  * clutter_actor_get_constraints:
14952  * @self: a #ClutterActor
14953  *
14954  * Retrieves the list of constraints applied to @self
14955  *
14956  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14957  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14958  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14959  *   allocated by the returned #GList
14960  *
14961  * Since: 1.4
14962  */
14963 GList *
14964 clutter_actor_get_constraints (ClutterActor *self)
14965 {
14966   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14967
14968   if (self->priv->constraints == NULL)
14969     return NULL;
14970
14971   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14972 }
14973
14974 /**
14975  * clutter_actor_get_constraint:
14976  * @self: a #ClutterActor
14977  * @name: the name of the constraint to retrieve
14978  *
14979  * Retrieves the #ClutterConstraint with the given name in the list
14980  * of constraints applied to @self
14981  *
14982  * Return value: (transfer none): a #ClutterConstraint for the given
14983  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14984  *   actor and it should not be unreferenced directly
14985  *
14986  * Since: 1.4
14987  */
14988 ClutterConstraint *
14989 clutter_actor_get_constraint (ClutterActor *self,
14990                               const gchar  *name)
14991 {
14992   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14993   g_return_val_if_fail (name != NULL, NULL);
14994
14995   if (self->priv->constraints == NULL)
14996     return NULL;
14997
14998   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14999 }
15000
15001 /**
15002  * clutter_actor_clear_constraints:
15003  * @self: a #ClutterActor
15004  *
15005  * Clears the list of constraints applied to @self
15006  *
15007  * Since: 1.4
15008  */
15009 void
15010 clutter_actor_clear_constraints (ClutterActor *self)
15011 {
15012   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15013
15014   if (self->priv->constraints == NULL)
15015     return;
15016
15017   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15018
15019   clutter_actor_queue_relayout (self);
15020 }
15021
15022 /**
15023  * clutter_actor_set_clip_to_allocation:
15024  * @self: a #ClutterActor
15025  * @clip_set: %TRUE to apply a clip tracking the allocation
15026  *
15027  * Sets whether @self should be clipped to the same size as its
15028  * allocation
15029  *
15030  * Since: 1.4
15031  */
15032 void
15033 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15034                                       gboolean      clip_set)
15035 {
15036   ClutterActorPrivate *priv;
15037
15038   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15039
15040   clip_set = !!clip_set;
15041
15042   priv = self->priv;
15043
15044   if (priv->clip_to_allocation != clip_set)
15045     {
15046       priv->clip_to_allocation = clip_set;
15047
15048       clutter_actor_queue_redraw (self);
15049
15050       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15051     }
15052 }
15053
15054 /**
15055  * clutter_actor_get_clip_to_allocation:
15056  * @self: a #ClutterActor
15057  *
15058  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15059  *
15060  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15061  *
15062  * Since: 1.4
15063  */
15064 gboolean
15065 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15066 {
15067   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15068
15069   return self->priv->clip_to_allocation;
15070 }
15071
15072 /**
15073  * clutter_actor_add_effect:
15074  * @self: a #ClutterActor
15075  * @effect: a #ClutterEffect
15076  *
15077  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15078  *
15079  * The #ClutterActor will hold a reference on the @effect until either
15080  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15081  * called.
15082  *
15083  * Since: 1.4
15084  */
15085 void
15086 clutter_actor_add_effect (ClutterActor  *self,
15087                           ClutterEffect *effect)
15088 {
15089   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15090   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15091
15092   _clutter_actor_add_effect_internal (self, effect);
15093
15094   clutter_actor_queue_redraw (self);
15095
15096   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15097 }
15098
15099 /**
15100  * clutter_actor_add_effect_with_name:
15101  * @self: a #ClutterActor
15102  * @name: the name to set on the effect
15103  * @effect: a #ClutterEffect
15104  *
15105  * A convenience function for setting the name of a #ClutterEffect
15106  * while adding it to the list of effectss applied to @self
15107  *
15108  * This function is the logical equivalent of:
15109  *
15110  * |[
15111  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15112  *   clutter_actor_add_effect (self, effect);
15113  * ]|
15114  *
15115  * Since: 1.4
15116  */
15117 void
15118 clutter_actor_add_effect_with_name (ClutterActor  *self,
15119                                     const gchar   *name,
15120                                     ClutterEffect *effect)
15121 {
15122   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15123   g_return_if_fail (name != NULL);
15124   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15125
15126   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15127   clutter_actor_add_effect (self, effect);
15128 }
15129
15130 /**
15131  * clutter_actor_remove_effect:
15132  * @self: a #ClutterActor
15133  * @effect: a #ClutterEffect
15134  *
15135  * Removes @effect from the list of effects applied to @self
15136  *
15137  * The reference held by @self on the #ClutterEffect will be released
15138  *
15139  * Since: 1.4
15140  */
15141 void
15142 clutter_actor_remove_effect (ClutterActor  *self,
15143                              ClutterEffect *effect)
15144 {
15145   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15146   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15147
15148   _clutter_actor_remove_effect_internal (self, effect);
15149
15150   clutter_actor_queue_redraw (self);
15151
15152   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15153 }
15154
15155 /**
15156  * clutter_actor_remove_effect_by_name:
15157  * @self: a #ClutterActor
15158  * @name: the name of the effect to remove
15159  *
15160  * Removes the #ClutterEffect with the given name from the list
15161  * of effects applied to @self
15162  *
15163  * Since: 1.4
15164  */
15165 void
15166 clutter_actor_remove_effect_by_name (ClutterActor *self,
15167                                      const gchar  *name)
15168 {
15169   ClutterActorPrivate *priv;
15170   ClutterActorMeta *meta;
15171
15172   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15173   g_return_if_fail (name != NULL);
15174
15175   priv = self->priv;
15176
15177   if (priv->effects == NULL)
15178     return;
15179
15180   meta = _clutter_meta_group_get_meta (priv->effects, name);
15181   if (meta == NULL)
15182     return;
15183
15184   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15185 }
15186
15187 /**
15188  * clutter_actor_get_effects:
15189  * @self: a #ClutterActor
15190  *
15191  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15192  *
15193  * Return value: (transfer container) (element-type Clutter.Effect): a list
15194  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15195  *   list are owned by Clutter and they should not be freed. You should
15196  *   free the returned list using g_list_free() when done
15197  *
15198  * Since: 1.4
15199  */
15200 GList *
15201 clutter_actor_get_effects (ClutterActor *self)
15202 {
15203   ClutterActorPrivate *priv;
15204
15205   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15206
15207   priv = self->priv;
15208
15209   if (priv->effects == NULL)
15210     return NULL;
15211
15212   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15213 }
15214
15215 /**
15216  * clutter_actor_get_effect:
15217  * @self: a #ClutterActor
15218  * @name: the name of the effect to retrieve
15219  *
15220  * Retrieves the #ClutterEffect with the given name in the list
15221  * of effects applied to @self
15222  *
15223  * Return value: (transfer none): a #ClutterEffect for the given
15224  *   name, or %NULL. The returned #ClutterEffect is owned by the
15225  *   actor and it should not be unreferenced directly
15226  *
15227  * Since: 1.4
15228  */
15229 ClutterEffect *
15230 clutter_actor_get_effect (ClutterActor *self,
15231                           const gchar  *name)
15232 {
15233   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15234   g_return_val_if_fail (name != NULL, NULL);
15235
15236   if (self->priv->effects == NULL)
15237     return NULL;
15238
15239   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15240 }
15241
15242 /**
15243  * clutter_actor_clear_effects:
15244  * @self: a #ClutterActor
15245  *
15246  * Clears the list of effects applied to @self
15247  *
15248  * Since: 1.4
15249  */
15250 void
15251 clutter_actor_clear_effects (ClutterActor *self)
15252 {
15253   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15254
15255   if (self->priv->effects == NULL)
15256     return;
15257
15258   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15259
15260   clutter_actor_queue_redraw (self);
15261 }
15262
15263 /**
15264  * clutter_actor_has_key_focus:
15265  * @self: a #ClutterActor
15266  *
15267  * Checks whether @self is the #ClutterActor that has key focus
15268  *
15269  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15270  *
15271  * Since: 1.4
15272  */
15273 gboolean
15274 clutter_actor_has_key_focus (ClutterActor *self)
15275 {
15276   ClutterActor *stage;
15277
15278   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15279
15280   stage = _clutter_actor_get_stage_internal (self);
15281   if (stage == NULL)
15282     return FALSE;
15283
15284   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15285 }
15286
15287 static gboolean
15288 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15289                                       ClutterPaintVolume *pv)
15290 {
15291   ClutterActorPrivate *priv = self->priv;
15292
15293   /* Actors are only expected to report a valid paint volume
15294    * while they have a valid allocation. */
15295   if (G_UNLIKELY (priv->needs_allocation))
15296     {
15297       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15298                     "Actor needs allocation",
15299                     _clutter_actor_get_debug_name (self));
15300       return FALSE;
15301     }
15302
15303   /* Check if there are any handlers connected to the paint
15304    * signal. If there are then all bets are off for what the paint
15305    * volume for this actor might possibly be!
15306    *
15307    * XXX: It's expected that this is going to end up being quite a
15308    * costly check to have to do here, but we haven't come up with
15309    * another solution that can reliably catch paint signal handlers at
15310    * the right time to either avoid artefacts due to invalid stage
15311    * clipping or due to incorrect culling.
15312    *
15313    * Previously we checked in clutter_actor_paint(), but at that time
15314    * we may already be using a stage clip that could be derived from
15315    * an invalid paint-volume. We used to try and handle that by
15316    * queuing a follow up, unclipped, redraw but still the previous
15317    * checking wasn't enough to catch invalid volumes involved in
15318    * culling (considering that containers may derive their volume from
15319    * children that haven't yet been painted)
15320    *
15321    * Longer term, improved solutions could be:
15322    * - Disallow painting in the paint signal, only allow using it
15323    *   for tracking when paints happen. We can add another API that
15324    *   allows monkey patching the paint of arbitrary actors but in a
15325    *   more controlled way and that also supports modifying the
15326    *   paint-volume.
15327    * - If we could be notified somehow when signal handlers are
15328    *   connected we wouldn't have to poll for handlers like this.
15329    */
15330   if (g_signal_has_handler_pending (self,
15331                                     actor_signals[PAINT],
15332                                     0,
15333                                     TRUE))
15334     {
15335       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15336                     "Actor has \"paint\" signal handlers",
15337                     _clutter_actor_get_debug_name (self));
15338       return FALSE;
15339     }
15340
15341   _clutter_paint_volume_init_static (pv, self);
15342
15343   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15344     {
15345       clutter_paint_volume_free (pv);
15346       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15347                     "Actor failed to report a volume",
15348                     _clutter_actor_get_debug_name (self));
15349       return FALSE;
15350     }
15351
15352   /* since effects can modify the paint volume, we allow them to actually
15353    * do this by making get_paint_volume() "context sensitive"
15354    */
15355   if (priv->effects != NULL)
15356     {
15357       if (priv->current_effect != NULL)
15358         {
15359           const GList *effects, *l;
15360
15361           /* if we are being called from within the paint sequence of
15362            * an actor, get the paint volume up to the current effect
15363            */
15364           effects = _clutter_meta_group_peek_metas (priv->effects);
15365           for (l = effects;
15366                l != NULL || (l != NULL && l->data != priv->current_effect);
15367                l = l->next)
15368             {
15369               if (!_clutter_effect_get_paint_volume (l->data, pv))
15370                 {
15371                   clutter_paint_volume_free (pv);
15372                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15373                                 "Effect (%s) failed to report a volume",
15374                                 _clutter_actor_get_debug_name (self),
15375                                 _clutter_actor_meta_get_debug_name (l->data));
15376                   return FALSE;
15377                 }
15378             }
15379         }
15380       else
15381         {
15382           const GList *effects, *l;
15383
15384           /* otherwise, get the cumulative volume */
15385           effects = _clutter_meta_group_peek_metas (priv->effects);
15386           for (l = effects; l != NULL; l = l->next)
15387             if (!_clutter_effect_get_paint_volume (l->data, pv))
15388               {
15389                 clutter_paint_volume_free (pv);
15390                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15391                               "Effect (%s) failed to report a volume",
15392                               _clutter_actor_get_debug_name (self),
15393                               _clutter_actor_meta_get_debug_name (l->data));
15394                 return FALSE;
15395               }
15396         }
15397     }
15398
15399   return TRUE;
15400 }
15401
15402 /* The public clutter_actor_get_paint_volume API returns a const
15403  * pointer since we return a pointer directly to the cached
15404  * PaintVolume associated with the actor and don't want the user to
15405  * inadvertently modify it, but for internal uses we sometimes need
15406  * access to the same PaintVolume but need to apply some book-keeping
15407  * modifications to it so we don't want a const pointer.
15408  */
15409 static ClutterPaintVolume *
15410 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15411 {
15412   ClutterActorPrivate *priv;
15413
15414   priv = self->priv;
15415
15416   if (priv->paint_volume_valid)
15417     clutter_paint_volume_free (&priv->paint_volume);
15418
15419   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15420     {
15421       priv->paint_volume_valid = TRUE;
15422       return &priv->paint_volume;
15423     }
15424   else
15425     {
15426       priv->paint_volume_valid = FALSE;
15427       return NULL;
15428     }
15429 }
15430
15431 /**
15432  * clutter_actor_get_paint_volume:
15433  * @self: a #ClutterActor
15434  *
15435  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15436  * when a paint volume can't be determined.
15437  *
15438  * The paint volume is defined as the 3D space occupied by an actor
15439  * when being painted.
15440  *
15441  * This function will call the <function>get_paint_volume()</function>
15442  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15443  * should not usually care about overriding the default implementation,
15444  * unless they are, for instance: painting outside their allocation, or
15445  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15446  * 3D depth).
15447  *
15448  * <note>2D actors overriding <function>get_paint_volume()</function>
15449  * ensure their volume has a depth of 0. (This will be true so long as
15450  * you don't call clutter_paint_volume_set_depth().)</note>
15451  *
15452  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15453  *   or %NULL if no volume could be determined. The returned pointer
15454  *   is not guaranteed to be valid across multiple frames; if you want
15455  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15456  *
15457  * Since: 1.6
15458  */
15459 const ClutterPaintVolume *
15460 clutter_actor_get_paint_volume (ClutterActor *self)
15461 {
15462   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15463
15464   return _clutter_actor_get_paint_volume_mutable (self);
15465 }
15466
15467 /**
15468  * clutter_actor_get_transformed_paint_volume:
15469  * @self: a #ClutterActor
15470  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15471  *    (or %NULL for the stage)
15472  *
15473  * Retrieves the 3D paint volume of an actor like
15474  * clutter_actor_get_paint_volume() does (Please refer to the
15475  * documentation of clutter_actor_get_paint_volume() for more
15476  * details.) and it additionally transforms the paint volume into the
15477  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15478  * is passed for @relative_to_ancestor)
15479  *
15480  * This can be used by containers that base their paint volume on
15481  * the volume of their children. Such containers can query the
15482  * transformed paint volume of all of its children and union them
15483  * together using clutter_paint_volume_union().
15484  *
15485  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15486  *   or %NULL if no volume could be determined. The returned pointer is
15487  *   not guaranteed to be valid across multiple frames; if you wish to
15488  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15489  *
15490  * Since: 1.6
15491  */
15492 const ClutterPaintVolume *
15493 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15494                                             ClutterActor *relative_to_ancestor)
15495 {
15496   const ClutterPaintVolume *volume;
15497   ClutterActor *stage;
15498   ClutterPaintVolume *transformed_volume;
15499
15500   stage = _clutter_actor_get_stage_internal (self);
15501   if (G_UNLIKELY (stage == NULL))
15502     return NULL;
15503
15504   if (relative_to_ancestor == NULL)
15505     relative_to_ancestor = stage;
15506
15507   volume = clutter_actor_get_paint_volume (self);
15508   if (volume == NULL)
15509     return NULL;
15510
15511   transformed_volume =
15512     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15513
15514   _clutter_paint_volume_copy_static (volume, transformed_volume);
15515
15516   _clutter_paint_volume_transform_relative (transformed_volume,
15517                                             relative_to_ancestor);
15518
15519   return transformed_volume;
15520 }
15521
15522 /**
15523  * clutter_actor_get_paint_box:
15524  * @self: a #ClutterActor
15525  * @box: (out): return location for a #ClutterActorBox
15526  *
15527  * Retrieves the paint volume of the passed #ClutterActor, and
15528  * transforms it into a 2D bounding box in stage coordinates.
15529  *
15530  * This function is useful to determine the on screen area occupied by
15531  * the actor. The box is only an approximation and may often be
15532  * considerably larger due to the optimizations used to calculate the
15533  * box. The box is never smaller though, so it can reliably be used
15534  * for culling.
15535  *
15536  * There are times when a 2D paint box can't be determined, e.g.
15537  * because the actor isn't yet parented under a stage or because
15538  * the actor is unable to determine a paint volume.
15539  *
15540  * Return value: %TRUE if a 2D paint box could be determined, else
15541  * %FALSE.
15542  *
15543  * Since: 1.6
15544  */
15545 gboolean
15546 clutter_actor_get_paint_box (ClutterActor    *self,
15547                              ClutterActorBox *box)
15548 {
15549   ClutterActor *stage;
15550   ClutterPaintVolume *pv;
15551
15552   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15553   g_return_val_if_fail (box != NULL, FALSE);
15554
15555   stage = _clutter_actor_get_stage_internal (self);
15556   if (G_UNLIKELY (!stage))
15557     return FALSE;
15558
15559   pv = _clutter_actor_get_paint_volume_mutable (self);
15560   if (G_UNLIKELY (!pv))
15561     return FALSE;
15562
15563   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15564
15565   return TRUE;
15566 }
15567
15568 /**
15569  * clutter_actor_has_overlaps:
15570  * @self: A #ClutterActor
15571  *
15572  * Asks the actor's implementation whether it may contain overlapping
15573  * primitives.
15574  *
15575  * For example; Clutter may use this to determine whether the painting
15576  * should be redirected to an offscreen buffer to correctly implement
15577  * the opacity property.
15578  *
15579  * Custom actors can override the default response by implementing the
15580  * #ClutterActor <function>has_overlaps</function> virtual function. See
15581  * clutter_actor_set_offscreen_redirect() for more information.
15582  *
15583  * Return value: %TRUE if the actor may have overlapping primitives, and
15584  *   %FALSE otherwise
15585  *
15586  * Since: 1.8
15587  */
15588 gboolean
15589 clutter_actor_has_overlaps (ClutterActor *self)
15590 {
15591   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15592
15593   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15594 }
15595
15596 /**
15597  * clutter_actor_has_effects:
15598  * @self: A #ClutterActor
15599  *
15600  * Returns whether the actor has any effects applied.
15601  *
15602  * Return value: %TRUE if the actor has any effects,
15603  *   %FALSE otherwise
15604  *
15605  * Since: 1.10
15606  */
15607 gboolean
15608 clutter_actor_has_effects (ClutterActor *self)
15609 {
15610   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15611
15612   if (self->priv->effects == NULL)
15613     return FALSE;
15614
15615   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15616 }
15617
15618 /**
15619  * clutter_actor_has_constraints:
15620  * @self: A #ClutterActor
15621  *
15622  * Returns whether the actor has any constraints applied.
15623  *
15624  * Return value: %TRUE if the actor has any constraints,
15625  *   %FALSE otherwise
15626  *
15627  * Since: 1.10
15628  */
15629 gboolean
15630 clutter_actor_has_constraints (ClutterActor *self)
15631 {
15632   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15633
15634   return self->priv->constraints != NULL;
15635 }
15636
15637 /**
15638  * clutter_actor_has_actions:
15639  * @self: A #ClutterActor
15640  *
15641  * Returns whether the actor has any actions applied.
15642  *
15643  * Return value: %TRUE if the actor has any actions,
15644  *   %FALSE otherwise
15645  *
15646  * Since: 1.10
15647  */
15648 gboolean
15649 clutter_actor_has_actions (ClutterActor *self)
15650 {
15651   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15652
15653   return self->priv->actions != NULL;
15654 }
15655
15656 /**
15657  * clutter_actor_get_n_children:
15658  * @self: a #ClutterActor
15659  *
15660  * Retrieves the number of children of @self.
15661  *
15662  * Return value: the number of children of an actor
15663  *
15664  * Since: 1.10
15665  */
15666 gint
15667 clutter_actor_get_n_children (ClutterActor *self)
15668 {
15669   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15670
15671   return self->priv->n_children;
15672 }
15673
15674 /**
15675  * clutter_actor_get_child_at_index:
15676  * @self: a #ClutterActor
15677  * @index_: the position in the list of children
15678  *
15679  * Retrieves the actor at the given @index_ inside the list of
15680  * children of @self.
15681  *
15682  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15683  *
15684  * Since: 1.10
15685  */
15686 ClutterActor *
15687 clutter_actor_get_child_at_index (ClutterActor *self,
15688                                   gint          index_)
15689 {
15690   ClutterActor *iter;
15691   int i;
15692
15693   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15694   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15695
15696   for (iter = self->priv->first_child, i = 0;
15697        iter != NULL && i < index_;
15698        iter = iter->priv->next_sibling, i += 1)
15699     ;
15700
15701   return iter;
15702 }
15703
15704 /*< private >
15705  * _clutter_actor_foreach_child:
15706  * @actor: The actor whos children you want to iterate
15707  * @callback: The function to call for each child
15708  * @user_data: Private data to pass to @callback
15709  *
15710  * Calls a given @callback once for each child of the specified @actor and
15711  * passing the @user_data pointer each time.
15712  *
15713  * Return value: returns %TRUE if all children were iterated, else
15714  *    %FALSE if a callback broke out of iteration early.
15715  */
15716 gboolean
15717 _clutter_actor_foreach_child (ClutterActor           *self,
15718                               ClutterForeachCallback  callback,
15719                               gpointer                user_data)
15720 {
15721   ClutterActorPrivate *priv = self->priv;
15722   ClutterActor *iter;
15723   gboolean cont;
15724
15725   for (cont = TRUE, iter = priv->first_child;
15726        cont && iter != NULL;
15727        iter = iter->priv->next_sibling)
15728     {
15729       cont = callback (iter, user_data);
15730     }
15731
15732   return cont;
15733 }
15734
15735 #if 0
15736 /* For debugging purposes this gives us a simple way to print out
15737  * the scenegraph e.g in gdb using:
15738  * [|
15739  *   _clutter_actor_traverse (stage,
15740  *                            0,
15741  *                            clutter_debug_print_actor_cb,
15742  *                            NULL,
15743  *                            NULL);
15744  * |]
15745  */
15746 static ClutterActorTraverseVisitFlags
15747 clutter_debug_print_actor_cb (ClutterActor *actor,
15748                               int depth,
15749                               void *user_data)
15750 {
15751   g_print ("%*s%s:%p\n",
15752            depth * 2, "",
15753            _clutter_actor_get_debug_name (actor),
15754            actor);
15755
15756   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15757 }
15758 #endif
15759
15760 static void
15761 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15762                                  ClutterTraverseCallback callback,
15763                                  gpointer                user_data)
15764 {
15765   GQueue *queue = g_queue_new ();
15766   ClutterActor dummy;
15767   int current_depth = 0;
15768
15769   g_queue_push_tail (queue, actor);
15770   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15771
15772   while ((actor = g_queue_pop_head (queue)))
15773     {
15774       ClutterActorTraverseVisitFlags flags;
15775
15776       if (actor == &dummy)
15777         {
15778           current_depth++;
15779           g_queue_push_tail (queue, &dummy);
15780           continue;
15781         }
15782
15783       flags = callback (actor, current_depth, user_data);
15784       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15785         break;
15786       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15787         {
15788           ClutterActor *iter;
15789
15790           for (iter = actor->priv->first_child;
15791                iter != NULL;
15792                iter = iter->priv->next_sibling)
15793             {
15794               g_queue_push_tail (queue, iter);
15795             }
15796         }
15797     }
15798
15799   g_queue_free (queue);
15800 }
15801
15802 static ClutterActorTraverseVisitFlags
15803 _clutter_actor_traverse_depth (ClutterActor           *actor,
15804                                ClutterTraverseCallback before_children_callback,
15805                                ClutterTraverseCallback after_children_callback,
15806                                int                     current_depth,
15807                                gpointer                user_data)
15808 {
15809   ClutterActorTraverseVisitFlags flags;
15810
15811   flags = before_children_callback (actor, current_depth, user_data);
15812   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15813     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15814
15815   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15816     {
15817       ClutterActor *iter;
15818
15819       for (iter = actor->priv->first_child;
15820            iter != NULL;
15821            iter = iter->priv->next_sibling)
15822         {
15823           flags = _clutter_actor_traverse_depth (iter,
15824                                                  before_children_callback,
15825                                                  after_children_callback,
15826                                                  current_depth + 1,
15827                                                  user_data);
15828
15829           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15830             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15831         }
15832     }
15833
15834   if (after_children_callback)
15835     return after_children_callback (actor, current_depth, user_data);
15836   else
15837     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15838 }
15839
15840 /* _clutter_actor_traverse:
15841  * @actor: The actor to start traversing the graph from
15842  * @flags: These flags may affect how the traversal is done
15843  * @before_children_callback: A function to call before visiting the
15844  *   children of the current actor.
15845  * @after_children_callback: A function to call after visiting the
15846  *   children of the current actor. (Ignored if
15847  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15848  * @user_data: The private data to pass to the callbacks
15849  *
15850  * Traverses the scenegraph starting at the specified @actor and
15851  * descending through all its children and its children's children.
15852  * For each actor traversed @before_children_callback and
15853  * @after_children_callback are called with the specified
15854  * @user_data, before and after visiting that actor's children.
15855  *
15856  * The callbacks can return flags that affect the ongoing traversal
15857  * such as by skipping over an actors children or bailing out of
15858  * any further traversing.
15859  */
15860 void
15861 _clutter_actor_traverse (ClutterActor              *actor,
15862                          ClutterActorTraverseFlags  flags,
15863                          ClutterTraverseCallback    before_children_callback,
15864                          ClutterTraverseCallback    after_children_callback,
15865                          gpointer                   user_data)
15866 {
15867   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15868     _clutter_actor_traverse_breadth (actor,
15869                                      before_children_callback,
15870                                      user_data);
15871   else /* DEPTH_FIRST */
15872     _clutter_actor_traverse_depth (actor,
15873                                    before_children_callback,
15874                                    after_children_callback,
15875                                    0, /* start depth */
15876                                    user_data);
15877 }
15878
15879 static void
15880 on_layout_manager_changed (ClutterLayoutManager *manager,
15881                            ClutterActor         *self)
15882 {
15883   clutter_actor_queue_relayout (self);
15884 }
15885
15886 /**
15887  * clutter_actor_set_layout_manager:
15888  * @self: a #ClutterActor
15889  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15890  *
15891  * Sets the #ClutterLayoutManager delegate object that will be used to
15892  * lay out the children of @self.
15893  *
15894  * The #ClutterActor will take a reference on the passed @manager which
15895  * will be released either when the layout manager is removed, or when
15896  * the actor is destroyed.
15897  *
15898  * Since: 1.10
15899  */
15900 void
15901 clutter_actor_set_layout_manager (ClutterActor         *self,
15902                                   ClutterLayoutManager *manager)
15903 {
15904   ClutterActorPrivate *priv;
15905
15906   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15907   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15908
15909   priv = self->priv;
15910
15911   if (priv->layout_manager != NULL)
15912     {
15913       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15914                                             G_CALLBACK (on_layout_manager_changed),
15915                                             self);
15916       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15917       g_clear_object (&priv->layout_manager);
15918     }
15919
15920   priv->layout_manager = manager;
15921
15922   if (priv->layout_manager != NULL)
15923     {
15924       g_object_ref_sink (priv->layout_manager);
15925       clutter_layout_manager_set_container (priv->layout_manager,
15926                                             CLUTTER_CONTAINER (self));
15927       g_signal_connect (priv->layout_manager, "layout-changed",
15928                         G_CALLBACK (on_layout_manager_changed),
15929                         self);
15930     }
15931
15932   clutter_actor_queue_relayout (self);
15933
15934   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15935 }
15936
15937 /**
15938  * clutter_actor_get_layout_manager:
15939  * @self: a #ClutterActor
15940  *
15941  * Retrieves the #ClutterLayoutManager used by @self.
15942  *
15943  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15944  *   or %NULL
15945  *
15946  * Since: 1.10
15947  */
15948 ClutterLayoutManager *
15949 clutter_actor_get_layout_manager (ClutterActor *self)
15950 {
15951   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15952
15953   return self->priv->layout_manager;
15954 }
15955
15956 static const ClutterLayoutInfo default_layout_info = {
15957   0.f,                          /* fixed-x */
15958   0.f,                          /* fixed-y */
15959   { 0, 0, 0, 0 },               /* margin */
15960   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15961   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15962   0.f, 0.f,                     /* min_width, natural_width */
15963   0.f, 0.f,                     /* natual_width, natural_height */
15964 };
15965
15966 static void
15967 layout_info_free (gpointer data)
15968 {
15969   if (G_LIKELY (data != NULL))
15970     g_slice_free (ClutterLayoutInfo, data);
15971 }
15972
15973 /*< private >
15974  * _clutter_actor_get_layout_info:
15975  * @self: a #ClutterActor
15976  *
15977  * Retrieves a pointer to the ClutterLayoutInfo structure.
15978  *
15979  * If the actor does not have a ClutterLayoutInfo associated to it, one
15980  * will be created and initialized to the default values.
15981  *
15982  * This function should be used for setters.
15983  *
15984  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15985  * instead.
15986  *
15987  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15988  */
15989 ClutterLayoutInfo *
15990 _clutter_actor_get_layout_info (ClutterActor *self)
15991 {
15992   ClutterLayoutInfo *retval;
15993
15994   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15995   if (retval == NULL)
15996     {
15997       retval = g_slice_new (ClutterLayoutInfo);
15998
15999       *retval = default_layout_info;
16000
16001       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16002                                retval,
16003                                layout_info_free);
16004     }
16005
16006   return retval;
16007 }
16008
16009 /*< private >
16010  * _clutter_actor_get_layout_info_or_defaults:
16011  * @self: a #ClutterActor
16012  *
16013  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16014  *
16015  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16016  * then the default structure will be returned.
16017  *
16018  * This function should only be used for getters.
16019  *
16020  * Return value: a const pointer to the ClutterLayoutInfo structure
16021  */
16022 const ClutterLayoutInfo *
16023 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16024 {
16025   const ClutterLayoutInfo *info;
16026
16027   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16028   if (info == NULL)
16029     return &default_layout_info;
16030
16031   return info;
16032 }
16033
16034 /**
16035  * clutter_actor_set_x_align:
16036  * @self: a #ClutterActor
16037  * @x_align: the horizontal alignment policy
16038  *
16039  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16040  * actor received extra horizontal space.
16041  *
16042  * See also the #ClutterActor:x-align property.
16043  *
16044  * Since: 1.10
16045  */
16046 void
16047 clutter_actor_set_x_align (ClutterActor      *self,
16048                            ClutterActorAlign  x_align)
16049 {
16050   ClutterLayoutInfo *info;
16051
16052   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16053
16054   info = _clutter_actor_get_layout_info (self);
16055
16056   if (info->x_align != x_align)
16057     {
16058       info->x_align = x_align;
16059
16060       clutter_actor_queue_relayout (self);
16061
16062       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16063     }
16064 }
16065
16066 /**
16067  * clutter_actor_get_x_align:
16068  * @self: a #ClutterActor
16069  *
16070  * Retrieves the horizontal alignment policy set using
16071  * clutter_actor_set_x_align().
16072  *
16073  * Return value: the horizontal alignment policy.
16074  *
16075  * Since: 1.10
16076  */
16077 ClutterActorAlign
16078 clutter_actor_get_x_align (ClutterActor *self)
16079 {
16080   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16081
16082   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16083 }
16084
16085 /**
16086  * clutter_actor_set_y_align:
16087  * @self: a #ClutterActor
16088  * @y_align: the vertical alignment policy
16089  *
16090  * Sets the vertical alignment policy of a #ClutterActor, in case the
16091  * actor received extra vertical space.
16092  *
16093  * See also the #ClutterActor:y-align property.
16094  *
16095  * Since: 1.10
16096  */
16097 void
16098 clutter_actor_set_y_align (ClutterActor      *self,
16099                            ClutterActorAlign  y_align)
16100 {
16101   ClutterLayoutInfo *info;
16102
16103   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16104
16105   info = _clutter_actor_get_layout_info (self);
16106
16107   if (info->y_align != y_align)
16108     {
16109       info->y_align = y_align;
16110
16111       clutter_actor_queue_relayout (self);
16112
16113       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16114     }
16115 }
16116
16117 /**
16118  * clutter_actor_get_y_align:
16119  * @self: a #ClutterActor
16120  *
16121  * Retrieves the vertical alignment policy set using
16122  * clutter_actor_set_y_align().
16123  *
16124  * Return value: the vertical alignment policy.
16125  *
16126  * Since: 1.10
16127  */
16128 ClutterActorAlign
16129 clutter_actor_get_y_align (ClutterActor *self)
16130 {
16131   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16132
16133   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16134 }
16135
16136
16137 /**
16138  * clutter_margin_new:
16139  *
16140  * Creates a new #ClutterMargin.
16141  *
16142  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16143  *   clutter_margin_free() to free the resources associated with it when
16144  *   done.
16145  *
16146  * Since: 1.10
16147  */
16148 ClutterMargin *
16149 clutter_margin_new (void)
16150 {
16151   return g_slice_new0 (ClutterMargin);
16152 }
16153
16154 /**
16155  * clutter_margin_copy:
16156  * @margin_: a #ClutterMargin
16157  *
16158  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16159  * the newly created structure.
16160  *
16161  * Return value: (transfer full): a copy of the #ClutterMargin.
16162  *
16163  * Since: 1.10
16164  */
16165 ClutterMargin *
16166 clutter_margin_copy (const ClutterMargin *margin_)
16167 {
16168   if (G_LIKELY (margin_ != NULL))
16169     return g_slice_dup (ClutterMargin, margin_);
16170
16171   return NULL;
16172 }
16173
16174 /**
16175  * clutter_margin_free:
16176  * @margin_: a #ClutterMargin
16177  *
16178  * Frees the resources allocated by clutter_margin_new() and
16179  * clutter_margin_copy().
16180  *
16181  * Since: 1.10
16182  */
16183 void
16184 clutter_margin_free (ClutterMargin *margin_)
16185 {
16186   if (G_LIKELY (margin_ != NULL))
16187     g_slice_free (ClutterMargin, margin_);
16188 }
16189
16190 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16191                      clutter_margin_copy,
16192                      clutter_margin_free)
16193
16194 /**
16195  * clutter_actor_set_margin:
16196  * @self: a #ClutterActor
16197  * @margin: a #ClutterMargin
16198  *
16199  * Sets all the components of the margin of a #ClutterActor.
16200  *
16201  * Since: 1.10
16202  */
16203 void
16204 clutter_actor_set_margin (ClutterActor        *self,
16205                           const ClutterMargin *margin)
16206 {
16207   ClutterLayoutInfo *info;
16208   gboolean changed;
16209   GObject *obj;
16210
16211   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16212   g_return_if_fail (margin != NULL);
16213
16214   obj = G_OBJECT (self);
16215   changed = FALSE;
16216
16217   g_object_freeze_notify (obj);
16218
16219   info = _clutter_actor_get_layout_info (self);
16220
16221   if (info->margin.top != margin->top)
16222     {
16223       info->margin.top = margin->top;
16224       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16225       changed = TRUE;
16226     }
16227
16228   if (info->margin.right != margin->right)
16229     {
16230       info->margin.right = margin->right;
16231       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16232       changed = TRUE;
16233     }
16234
16235   if (info->margin.bottom != margin->bottom)
16236     {
16237       info->margin.bottom = margin->bottom;
16238       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16239       changed = TRUE;
16240     }
16241
16242   if (info->margin.left != margin->left)
16243     {
16244       info->margin.left = margin->left;
16245       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16246       changed = TRUE;
16247     }
16248
16249   if (changed)
16250     clutter_actor_queue_relayout (self);
16251
16252   g_object_thaw_notify (obj);
16253 }
16254
16255 /**
16256  * clutter_actor_get_margin:
16257  * @self: a #ClutterActor
16258  * @margin: (out caller-allocates): return location for a #ClutterMargin
16259  *
16260  * Retrieves all the components of the margin of a #ClutterActor.
16261  *
16262  * Since: 1.10
16263  */
16264 void
16265 clutter_actor_get_margin (ClutterActor  *self,
16266                           ClutterMargin *margin)
16267 {
16268   const ClutterLayoutInfo *info;
16269
16270   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16271   g_return_if_fail (margin != NULL);
16272
16273   info = _clutter_actor_get_layout_info_or_defaults (self);
16274
16275   *margin = info->margin;
16276 }
16277
16278 /**
16279  * clutter_actor_set_margin_top:
16280  * @self: a #ClutterActor
16281  * @margin: the top margin
16282  *
16283  * Sets the margin from the top of a #ClutterActor.
16284  *
16285  * Since: 1.10
16286  */
16287 void
16288 clutter_actor_set_margin_top (ClutterActor *self,
16289                               gfloat        margin)
16290 {
16291   ClutterLayoutInfo *info;
16292
16293   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16294   g_return_if_fail (margin >= 0.f);
16295
16296   info = _clutter_actor_get_layout_info (self);
16297
16298   if (info->margin.top == margin)
16299     return;
16300
16301   info->margin.top = margin;
16302
16303   clutter_actor_queue_relayout (self);
16304
16305   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16306 }
16307
16308 /**
16309  * clutter_actor_get_margin_top:
16310  * @self: a #ClutterActor
16311  *
16312  * Retrieves the top margin of a #ClutterActor.
16313  *
16314  * Return value: the top margin
16315  *
16316  * Since: 1.10
16317  */
16318 gfloat
16319 clutter_actor_get_margin_top (ClutterActor *self)
16320 {
16321   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16322
16323   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16324 }
16325
16326 /**
16327  * clutter_actor_set_margin_bottom:
16328  * @self: a #ClutterActor
16329  * @margin: the bottom margin
16330  *
16331  * Sets the margin from the bottom of a #ClutterActor.
16332  *
16333  * Since: 1.10
16334  */
16335 void
16336 clutter_actor_set_margin_bottom (ClutterActor *self,
16337                                  gfloat        margin)
16338 {
16339   ClutterLayoutInfo *info;
16340
16341   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16342   g_return_if_fail (margin >= 0.f);
16343
16344   info = _clutter_actor_get_layout_info (self);
16345
16346   if (info->margin.bottom == margin)
16347     return;
16348
16349   info->margin.bottom = margin;
16350
16351   clutter_actor_queue_relayout (self);
16352
16353   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16354 }
16355
16356 /**
16357  * clutter_actor_get_margin_bottom:
16358  * @self: a #ClutterActor
16359  *
16360  * Retrieves the bottom margin of a #ClutterActor.
16361  *
16362  * Return value: the bottom margin
16363  *
16364  * Since: 1.10
16365  */
16366 gfloat
16367 clutter_actor_get_margin_bottom (ClutterActor *self)
16368 {
16369   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16370
16371   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16372 }
16373
16374 /**
16375  * clutter_actor_set_margin_left:
16376  * @self: a #ClutterActor
16377  * @margin: the left margin
16378  *
16379  * Sets the margin from the left of a #ClutterActor.
16380  *
16381  * Since: 1.10
16382  */
16383 void
16384 clutter_actor_set_margin_left (ClutterActor *self,
16385                                gfloat        margin)
16386 {
16387   ClutterLayoutInfo *info;
16388
16389   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16390   g_return_if_fail (margin >= 0.f);
16391
16392   info = _clutter_actor_get_layout_info (self);
16393
16394   if (info->margin.left == margin)
16395     return;
16396
16397   info->margin.left = margin;
16398
16399   clutter_actor_queue_relayout (self);
16400
16401   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16402 }
16403
16404 /**
16405  * clutter_actor_get_margin_left:
16406  * @self: a #ClutterActor
16407  *
16408  * Retrieves the left margin of a #ClutterActor.
16409  *
16410  * Return value: the left margin
16411  *
16412  * Since: 1.10
16413  */
16414 gfloat
16415 clutter_actor_get_margin_left (ClutterActor *self)
16416 {
16417   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16418
16419   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16420 }
16421
16422 /**
16423  * clutter_actor_set_margin_right:
16424  * @self: a #ClutterActor
16425  * @margin: the right margin
16426  *
16427  * Sets the margin from the right of a #ClutterActor.
16428  *
16429  * Since: 1.10
16430  */
16431 void
16432 clutter_actor_set_margin_right (ClutterActor *self,
16433                                 gfloat        margin)
16434 {
16435   ClutterLayoutInfo *info;
16436
16437   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16438   g_return_if_fail (margin >= 0.f);
16439
16440   info = _clutter_actor_get_layout_info (self);
16441
16442   if (info->margin.right == margin)
16443     return;
16444
16445   info->margin.right = margin;
16446
16447   clutter_actor_queue_relayout (self);
16448
16449   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16450 }
16451
16452 /**
16453  * clutter_actor_get_margin_right:
16454  * @self: a #ClutterActor
16455  *
16456  * Retrieves the right margin of a #ClutterActor.
16457  *
16458  * Return value: the right margin
16459  *
16460  * Since: 1.10
16461  */
16462 gfloat
16463 clutter_actor_get_margin_right (ClutterActor *self)
16464 {
16465   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16466
16467   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16468 }
16469
16470 static inline void
16471 clutter_actor_set_background_color_internal (ClutterActor *self,
16472                                              const ClutterColor *color)
16473 {
16474   ClutterActorPrivate *priv = self->priv;
16475   GObject *obj;
16476
16477   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16478     return;
16479
16480   obj = G_OBJECT (self);
16481
16482   priv->bg_color = *color;
16483   priv->bg_color_set = TRUE;
16484
16485   clutter_actor_queue_redraw (self);
16486
16487   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16488   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16489 }
16490
16491 /**
16492  * clutter_actor_set_background_color:
16493  * @self: a #ClutterActor
16494  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16495  *  set color
16496  *
16497  * Sets the background color of a #ClutterActor.
16498  *
16499  * The background color will be used to cover the whole allocation of the
16500  * actor. The default background color of an actor is transparent.
16501  *
16502  * To check whether an actor has a background color, you can use the
16503  * #ClutterActor:background-color-set actor property.
16504  *
16505  * The #ClutterActor:background-color property is animatable.
16506  *
16507  * Since: 1.10
16508  */
16509 void
16510 clutter_actor_set_background_color (ClutterActor       *self,
16511                                     const ClutterColor *color)
16512 {
16513   ClutterActorPrivate *priv;
16514   GObject *obj;
16515   GParamSpec *bg_color_pspec;
16516
16517   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16518
16519   obj = G_OBJECT (self);
16520
16521   priv = self->priv;
16522
16523   if (color == NULL)
16524     {
16525       priv->bg_color_set = FALSE;
16526       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16527       clutter_actor_queue_redraw (self);
16528       return;
16529     }
16530
16531   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16532   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16533     {
16534       _clutter_actor_create_transition (self, bg_color_pspec,
16535                                         &priv->bg_color,
16536                                         color);
16537     }
16538   else
16539     _clutter_actor_update_transition (self, bg_color_pspec, color);
16540
16541   clutter_actor_queue_redraw (self);
16542 }
16543
16544 /**
16545  * clutter_actor_get_background_color:
16546  * @self: a #ClutterActor
16547  * @color: (out caller-allocates): return location for a #ClutterColor
16548  *
16549  * Retrieves the color set using clutter_actor_set_background_color().
16550  *
16551  * Since: 1.10
16552  */
16553 void
16554 clutter_actor_get_background_color (ClutterActor *self,
16555                                     ClutterColor *color)
16556 {
16557   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16558   g_return_if_fail (color != NULL);
16559
16560   *color = self->priv->bg_color;
16561 }
16562
16563 /**
16564  * clutter_actor_get_previous_sibling:
16565  * @self: a #ClutterActor
16566  *
16567  * Retrieves the sibling of @self that comes before it in the list
16568  * of children of @self's parent.
16569  *
16570  * The returned pointer is only valid until the scene graph changes; it
16571  * is not safe to modify the list of children of @self while iterating
16572  * it.
16573  *
16574  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16575  *
16576  * Since: 1.10
16577  */
16578 ClutterActor *
16579 clutter_actor_get_previous_sibling (ClutterActor *self)
16580 {
16581   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16582
16583   return self->priv->prev_sibling;
16584 }
16585
16586 /**
16587  * clutter_actor_get_next_sibling:
16588  * @self: a #ClutterActor
16589  *
16590  * Retrieves the sibling of @self that comes after it in the list
16591  * of children of @self's parent.
16592  *
16593  * The returned pointer is only valid until the scene graph changes; it
16594  * is not safe to modify the list of children of @self while iterating
16595  * it.
16596  *
16597  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16598  *
16599  * Since: 1.10
16600  */
16601 ClutterActor *
16602 clutter_actor_get_next_sibling (ClutterActor *self)
16603 {
16604   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16605
16606   return self->priv->next_sibling;
16607 }
16608
16609 /**
16610  * clutter_actor_get_first_child:
16611  * @self: a #ClutterActor
16612  *
16613  * Retrieves the first child of @self.
16614  *
16615  * The returned pointer is only valid until the scene graph changes; it
16616  * is not safe to modify the list of children of @self while iterating
16617  * it.
16618  *
16619  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16620  *
16621  * Since: 1.10
16622  */
16623 ClutterActor *
16624 clutter_actor_get_first_child (ClutterActor *self)
16625 {
16626   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16627
16628   return self->priv->first_child;
16629 }
16630
16631 /**
16632  * clutter_actor_get_last_child:
16633  * @self: a #ClutterActor
16634  *
16635  * Retrieves the last child of @self.
16636  *
16637  * The returned pointer is only valid until the scene graph changes; it
16638  * is not safe to modify the list of children of @self while iterating
16639  * it.
16640  *
16641  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16642  *
16643  * Since: 1.10
16644  */
16645 ClutterActor *
16646 clutter_actor_get_last_child (ClutterActor *self)
16647 {
16648   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16649
16650   return self->priv->last_child;
16651 }
16652
16653 /* easy way to have properly named fields instead of the dummy ones
16654  * we use in the public structure
16655  */
16656 typedef struct _RealActorIter
16657 {
16658   ClutterActor *root;           /* dummy1 */
16659   ClutterActor *current;        /* dummy2 */
16660   gpointer padding_1;           /* dummy3 */
16661   gint age;                     /* dummy4 */
16662   gpointer padding_2;           /* dummy5 */
16663 } RealActorIter;
16664
16665 /**
16666  * clutter_actor_iter_init:
16667  * @iter: a #ClutterActorIter
16668  * @root: a #ClutterActor
16669  *
16670  * Initializes a #ClutterActorIter, which can then be used to iterate
16671  * efficiently over a section of the scene graph, and associates it
16672  * with @root.
16673  *
16674  * Modifying the scene graph section that contains @root will invalidate
16675  * the iterator.
16676  *
16677  * |[
16678  *   ClutterActorIter iter;
16679  *   ClutterActor *child;
16680  *
16681  *   clutter_actor_iter_init (&iter, container);
16682  *   while (clutter_actor_iter_next (&iter, &child))
16683  *     {
16684  *       /&ast; do something with child &ast;/
16685  *     }
16686  * ]|
16687  *
16688  * Since: 1.10
16689  */
16690 void
16691 clutter_actor_iter_init (ClutterActorIter *iter,
16692                          ClutterActor     *root)
16693 {
16694   RealActorIter *ri = (RealActorIter *) iter;
16695
16696   g_return_if_fail (iter != NULL);
16697   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16698
16699   ri->root = root;
16700   ri->current = NULL;
16701   ri->age = root->priv->age;
16702 }
16703
16704 /**
16705  * clutter_actor_iter_next:
16706  * @iter: a #ClutterActorIter
16707  * @child: (out): return location for a #ClutterActor
16708  *
16709  * Advances the @iter and retrieves the next child of the root #ClutterActor
16710  * that was used to initialize the #ClutterActorIterator.
16711  *
16712  * If the iterator can advance, this function returns %TRUE and sets the
16713  * @child argument.
16714  *
16715  * If the iterator cannot advance, this function returns %FALSE, and
16716  * the contents of @child are undefined.
16717  *
16718  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16719  *
16720  * Since: 1.10
16721  */
16722 gboolean
16723 clutter_actor_iter_next (ClutterActorIter  *iter,
16724                          ClutterActor     **child)
16725 {
16726   RealActorIter *ri = (RealActorIter *) iter;
16727
16728   g_return_val_if_fail (iter != NULL, FALSE);
16729   g_return_val_if_fail (ri->root != NULL, FALSE);
16730 #ifndef G_DISABLE_ASSERT
16731   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16732 #endif
16733
16734   if (ri->current == NULL)
16735     ri->current = ri->root->priv->first_child;
16736   else
16737     ri->current = ri->current->priv->next_sibling;
16738
16739   if (child != NULL)
16740     *child = ri->current;
16741
16742   return ri->current != NULL;
16743 }
16744
16745 /**
16746  * clutter_actor_iter_prev:
16747  * @iter: a #ClutterActorIter
16748  * @child: (out): return location for a #ClutterActor
16749  *
16750  * Advances the @iter and retrieves the previous child of the root
16751  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16752  *
16753  * If the iterator can advance, this function returns %TRUE and sets the
16754  * @child argument.
16755  *
16756  * If the iterator cannot advance, this function returns %FALSE, and
16757  * the contents of @child are undefined.
16758  *
16759  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16760  *
16761  * Since: 1.10
16762  */
16763 gboolean
16764 clutter_actor_iter_prev (ClutterActorIter  *iter,
16765                          ClutterActor     **child)
16766 {
16767   RealActorIter *ri = (RealActorIter *) iter;
16768
16769   g_return_val_if_fail (iter != NULL, FALSE);
16770   g_return_val_if_fail (ri->root != NULL, FALSE);
16771 #ifndef G_DISABLE_ASSERT
16772   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16773 #endif
16774
16775   if (ri->current == NULL)
16776     ri->current = ri->root->priv->last_child;
16777   else
16778     ri->current = ri->current->priv->prev_sibling;
16779
16780   if (child != NULL)
16781     *child = ri->current;
16782
16783   return ri->current != NULL;
16784 }
16785
16786 /**
16787  * clutter_actor_iter_remove:
16788  * @iter: a #ClutterActorIter
16789  *
16790  * Safely removes the #ClutterActor currently pointer to by the iterator
16791  * from its parent.
16792  *
16793  * This function can only be called after clutter_actor_iter_next() or
16794  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16795  * than once for the same actor.
16796  *
16797  * This function will call clutter_actor_remove_child() internally.
16798  *
16799  * Since: 1.10
16800  */
16801 void
16802 clutter_actor_iter_remove (ClutterActorIter *iter)
16803 {
16804   RealActorIter *ri = (RealActorIter *) iter;
16805   ClutterActor *cur;
16806
16807   g_return_if_fail (iter != NULL);
16808   g_return_if_fail (ri->root != NULL);
16809 #ifndef G_DISABLE_ASSERT
16810   g_return_if_fail (ri->age == ri->root->priv->age);
16811 #endif
16812   g_return_if_fail (ri->current != NULL);
16813
16814   cur = ri->current;
16815
16816   if (cur != NULL)
16817     {
16818       ri->current = cur->priv->prev_sibling;
16819
16820       clutter_actor_remove_child_internal (ri->root, cur,
16821                                            REMOVE_CHILD_DEFAULT_FLAGS);
16822
16823       ri->age += 1;
16824     }
16825 }
16826
16827 /**
16828  * clutter_actor_iter_destroy:
16829  * @iter: a #ClutterActorIter
16830  *
16831  * Safely destroys the #ClutterActor currently pointer to by the iterator
16832  * from its parent.
16833  *
16834  * This function can only be called after clutter_actor_iter_next() or
16835  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16836  * than once for the same actor.
16837  *
16838  * This function will call clutter_actor_destroy() internally.
16839  *
16840  * Since: 1.10
16841  */
16842 void
16843 clutter_actor_iter_destroy (ClutterActorIter *iter)
16844 {
16845   RealActorIter *ri = (RealActorIter *) iter;
16846   ClutterActor *cur;
16847
16848   g_return_if_fail (iter != NULL);
16849   g_return_if_fail (ri->root != NULL);
16850 #ifndef G_DISABLE_ASSERT
16851   g_return_if_fail (ri->age == ri->root->priv->age);
16852 #endif
16853   g_return_if_fail (ri->current != NULL);
16854
16855   cur = ri->current;
16856
16857   if (cur != NULL)
16858     {
16859       ri->current = cur->priv->prev_sibling;
16860
16861       clutter_actor_destroy (cur);
16862
16863       ri->age += 1;
16864     }
16865 }
16866
16867 static const ClutterAnimationInfo default_animation_info = {
16868   NULL,         /* transitions */
16869   NULL,         /* states */
16870   NULL,         /* cur_state */
16871 };
16872
16873 static void
16874 clutter_animation_info_free (gpointer data)
16875 {
16876   if (data != NULL)
16877     {
16878       ClutterAnimationInfo *info = data;
16879
16880       if (info->transitions != NULL)
16881         g_hash_table_unref (info->transitions);
16882
16883       if (info->states != NULL)
16884         g_array_unref (info->states);
16885
16886       g_slice_free (ClutterAnimationInfo, info);
16887     }
16888 }
16889
16890 const ClutterAnimationInfo *
16891 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16892 {
16893   const ClutterAnimationInfo *res;
16894   GObject *obj = G_OBJECT (self);
16895
16896   res = g_object_get_qdata (obj, quark_actor_animation_info);
16897   if (res != NULL)
16898     return res;
16899
16900   return &default_animation_info;
16901 }
16902
16903 ClutterAnimationInfo *
16904 _clutter_actor_get_animation_info (ClutterActor *self)
16905 {
16906   GObject *obj = G_OBJECT (self);
16907   ClutterAnimationInfo *res;
16908
16909   res = g_object_get_qdata (obj, quark_actor_animation_info);
16910   if (res == NULL)
16911     {
16912       res = g_slice_new (ClutterAnimationInfo);
16913
16914       *res = default_animation_info;
16915
16916       g_object_set_qdata_full (obj, quark_actor_animation_info,
16917                                res,
16918                                clutter_animation_info_free);
16919     }
16920
16921   return res;
16922 }
16923
16924 ClutterTransition *
16925 _clutter_actor_get_transition (ClutterActor *actor,
16926                                GParamSpec   *pspec)
16927 {
16928   const ClutterAnimationInfo *info;
16929
16930   info = _clutter_actor_get_animation_info_or_defaults (actor);
16931
16932   if (info->transitions == NULL)
16933     return NULL;
16934
16935   return g_hash_table_lookup (info->transitions, pspec->name);
16936 }
16937
16938 typedef struct _TransitionClosure
16939 {
16940   ClutterActor *actor;
16941   ClutterTransition *transition;
16942   gchar *name;
16943   gulong completed_id;
16944 } TransitionClosure;
16945
16946 static void
16947 transition_closure_free (gpointer data)
16948 {
16949   if (G_LIKELY (data != NULL))
16950     {
16951       TransitionClosure *clos = data;
16952
16953       if (clutter_timeline_is_playing (CLUTTER_TIMELINE (clos->transition)))
16954         clutter_timeline_stop (CLUTTER_TIMELINE (clos->transition));
16955
16956       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16957
16958       g_object_unref (clos->transition);
16959       g_free (clos->name);
16960
16961       g_slice_free (TransitionClosure, clos);
16962     }
16963 }
16964
16965 static void
16966 on_transition_completed (ClutterTransition *transition,
16967                          TransitionClosure *clos)
16968 {
16969   ClutterActor *actor = clos->actor;
16970   ClutterAnimationInfo *info;
16971
16972   info = _clutter_actor_get_animation_info (actor);
16973
16974   /* this will take care of cleaning clos for us */
16975   if (clutter_transition_get_remove_on_complete (transition))
16976     {
16977       /* we take a reference here because removing the closure
16978        * will release the reference on the transition, and we
16979        * want the transition to survive the signal emission;
16980        * the master clock will release the laste reference at
16981        * the end of the frame processing.
16982        */
16983       g_object_ref (transition);
16984       g_hash_table_remove (info->transitions, clos->name);
16985     }
16986
16987   /* if it's the last transition then we clean up */
16988   if (g_hash_table_size (info->transitions) == 0)
16989     {
16990       g_hash_table_unref (info->transitions);
16991       info->transitions = NULL;
16992
16993       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
16994                     _clutter_actor_get_debug_name (actor));
16995
16996       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
16997     }
16998 }
16999
17000 void
17001 _clutter_actor_update_transition (ClutterActor *actor,
17002                                   GParamSpec   *pspec,
17003                                   ...)
17004 {
17005   TransitionClosure *clos;
17006   ClutterInterval *interval;
17007   const ClutterAnimationInfo *info;
17008   va_list var_args;
17009   GType ptype;
17010   GValue initial = G_VALUE_INIT;
17011   GValue final = G_VALUE_INIT;
17012   char *error = NULL;
17013
17014   info = _clutter_actor_get_animation_info_or_defaults (actor);
17015
17016   if (info->transitions == NULL)
17017     return;
17018
17019   clos = g_hash_table_lookup (info->transitions, pspec->name);
17020   if (clos == NULL)
17021     return;
17022
17023   va_start (var_args, pspec);
17024
17025   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17026
17027   g_value_init (&initial, ptype);
17028   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17029                                         pspec->name,
17030                                         &initial);
17031
17032   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17033   if (error != NULL)
17034     {
17035       g_critical ("%s: %s", G_STRLOC, error);
17036       g_free (error);
17037       goto out;
17038     }
17039
17040   interval = clutter_transition_get_interval (clos->transition);
17041   clutter_interval_set_initial_value (interval, &initial);
17042   clutter_interval_set_final_value (interval, &final);
17043
17044   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
17045
17046 out:
17047   g_value_unset (&initial);
17048   g_value_unset (&final);
17049
17050   va_end (var_args);
17051 }
17052
17053 /*< private >*
17054  * _clutter_actor_create_transition:
17055  * @actor: a #ClutterActor
17056  * @pspec: the property used for the transition
17057  * @...: initial and final state
17058  *
17059  * Creates a #ClutterTransition for the property represented by @pspec.
17060  *
17061  * Return value: a #ClutterTransition
17062  */
17063 ClutterTransition *
17064 _clutter_actor_create_transition (ClutterActor *actor,
17065                                   GParamSpec   *pspec,
17066                                   ...)
17067 {
17068   ClutterAnimationInfo *info;
17069   ClutterTransition *res = NULL;
17070   gboolean call_restore = FALSE;
17071   TransitionClosure *clos;
17072   va_list var_args;
17073
17074   info = _clutter_actor_get_animation_info (actor);
17075
17076   /* XXX - this will go away in 2.0
17077    *
17078    * if no state has been pushed, we assume that the easing state is
17079    * in "compatibility mode": all transitions have a duration of 0
17080    * msecs, which means that they happen immediately. in Clutter 2.0
17081    * this will turn into a g_assert(info->states != NULL), as every
17082    * actor will start with a predefined easing state
17083    */
17084   if (info->states == NULL)
17085     {
17086       clutter_actor_save_easing_state (actor);
17087       clutter_actor_set_easing_duration (actor, 0);
17088       call_restore = TRUE;
17089     }
17090
17091   if (info->transitions == NULL)
17092     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17093                                                NULL,
17094                                                transition_closure_free);
17095
17096   va_start (var_args, pspec);
17097
17098   clos = g_hash_table_lookup (info->transitions, pspec->name);
17099   if (clos == NULL)
17100     {
17101       ClutterInterval *interval;
17102       GValue initial = G_VALUE_INIT;
17103       GValue final = G_VALUE_INIT;
17104       GType ptype;
17105       char *error;
17106
17107       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17108
17109       G_VALUE_COLLECT_INIT (&initial, ptype,
17110                             var_args, 0,
17111                             &error);
17112       if (error != NULL)
17113         {
17114           g_critical ("%s: %s", G_STRLOC, error);
17115           g_free (error);
17116           goto out;
17117         }
17118
17119       G_VALUE_COLLECT_INIT (&final, ptype,
17120                             var_args, 0,
17121                             &error);
17122
17123       if (error != NULL)
17124         {
17125           g_critical ("%s: %s", G_STRLOC, error);
17126           g_value_unset (&initial);
17127           g_free (error);
17128           goto out;
17129         }
17130
17131       /* if the current easing state has a duration of 0, then we don't
17132        * bother to create the transition, and we just set the final value
17133        * directly on the actor; we don't go through the Animatable
17134        * interface because we know we got here through an animatable
17135        * property.
17136        */
17137       if (info->cur_state->easing_duration == 0)
17138         {
17139           clutter_actor_set_animatable_property (actor,
17140                                                  pspec->param_id,
17141                                                  &final,
17142                                                  pspec);
17143           g_value_unset (&initial);
17144           g_value_unset (&final);
17145
17146           goto out;
17147         }
17148
17149       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17150
17151       g_value_unset (&initial);
17152       g_value_unset (&final);
17153
17154       res = clutter_property_transition_new (pspec->name);
17155
17156       clutter_transition_set_interval (res, interval);
17157       clutter_transition_set_remove_on_complete (res, TRUE);
17158
17159       /* this will start the transition as well */
17160       clutter_actor_add_transition (actor, pspec->name, res);
17161
17162       /* the actor now owns the transition */
17163       g_object_unref (res);
17164     }
17165   else
17166     res = clos->transition;
17167
17168 out:
17169   if (call_restore)
17170     clutter_actor_restore_easing_state (actor);
17171
17172   va_end (var_args);
17173
17174   return res;
17175 }
17176
17177 /**
17178  * clutter_actor_add_transition:
17179  * @self: a #ClutterActor
17180  * @name: the name of the transition to add
17181  * @transition: the #ClutterTransition to add
17182  *
17183  * Adds a @transition to the #ClutterActor's list of animations.
17184  *
17185  * The @name string is a per-actor unique identifier of the @transition: only
17186  * one #ClutterTransition can be associated to the specified @name.
17187  *
17188  * The @transition will be given the easing duration, mode, and delay
17189  * associated to the actor's current easing state; it is possible to modify
17190  * these values after calling clutter_actor_add_transition().
17191  *
17192  * The @transition will be started once added.
17193  *
17194  * This function will take a reference on the @transition.
17195  *
17196  * This function is usually called implicitly when modifying an animatable
17197  * property.
17198  *
17199  * Since: 1.10
17200  */
17201 void
17202 clutter_actor_add_transition (ClutterActor      *self,
17203                               const char        *name,
17204                               ClutterTransition *transition)
17205 {
17206   ClutterTimeline *timeline;
17207   TransitionClosure *clos;
17208   ClutterAnimationInfo *info;
17209
17210   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17211   g_return_if_fail (name != NULL);
17212   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17213
17214   info = _clutter_actor_get_animation_info (self);
17215
17216   if (info->cur_state == NULL)
17217     {
17218       g_warning ("No easing state is defined for the actor '%s'; you "
17219                  "must call clutter_actor_save_easing_state() before "
17220                  "calling clutter_actor_add_transition().",
17221                  _clutter_actor_get_debug_name (self));
17222       return;
17223     }
17224
17225   if (info->transitions == NULL)
17226     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17227                                                NULL,
17228                                                transition_closure_free);
17229
17230   if (g_hash_table_lookup (info->transitions, name) != NULL)
17231     {
17232       g_warning ("A transition with name '%s' already exists for "
17233                  "the actor '%s'",
17234                  name,
17235                  _clutter_actor_get_debug_name (self));
17236       return;
17237     }
17238
17239   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17240
17241   timeline = CLUTTER_TIMELINE (transition);
17242
17243   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17244   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17245   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17246
17247   clos = g_slice_new (TransitionClosure);
17248   clos->actor = self;
17249   clos->transition = g_object_ref (transition);
17250   clos->name = g_strdup (name);
17251   clos->completed_id = g_signal_connect (timeline, "completed",
17252                                          G_CALLBACK (on_transition_completed),
17253                                          clos);
17254
17255   CLUTTER_NOTE (ANIMATION,
17256                 "Adding transition '%s' [%p] to actor '%s'",
17257                 clos->name,
17258                 clos->transition,
17259                 _clutter_actor_get_debug_name (self));
17260
17261   g_hash_table_insert (info->transitions, clos->name, clos);
17262   clutter_timeline_start (timeline);
17263 }
17264
17265 /**
17266  * clutter_actor_remove_transition:
17267  * @self: a #ClutterActor
17268  * @name: the name of the transition to remove
17269  *
17270  * Removes the transition stored inside a #ClutterActor using @name
17271  * identifier.
17272  *
17273  * If the transition is currently in progress, it will be stopped.
17274  *
17275  * This function releases the reference acquired when the transition
17276  * was added to the #ClutterActor.
17277  *
17278  * Since: 1.10
17279  */
17280 void
17281 clutter_actor_remove_transition (ClutterActor *self,
17282                                  const char   *name)
17283 {
17284   const ClutterAnimationInfo *info;
17285
17286   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17287   g_return_if_fail (name != NULL);
17288
17289   info = _clutter_actor_get_animation_info_or_defaults (self);
17290
17291   if (info->transitions == NULL)
17292     return;
17293
17294   g_hash_table_remove (info->transitions, name);
17295 }
17296
17297 /**
17298  * clutter_actor_remove_all_transitions:
17299  * @self: a #ClutterActor
17300  *
17301  * Removes all transitions associated to @self.
17302  *
17303  * Since: 1.10
17304  */
17305 void
17306 clutter_actor_remove_all_transitions (ClutterActor *self)
17307 {
17308   const ClutterAnimationInfo *info;
17309
17310   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17311
17312   info = _clutter_actor_get_animation_info_or_defaults (self);
17313   if (info->transitions == NULL)
17314     return;
17315
17316   g_hash_table_remove_all (info->transitions);
17317 }
17318
17319 /**
17320  * clutter_actor_set_easing_duration:
17321  * @self: a #ClutterActor
17322  * @msecs: the duration of the easing, or %NULL
17323  *
17324  * Sets the duration of the tweening for animatable properties
17325  * of @self for the current easing state.
17326  *
17327  * Since: 1.10
17328  */
17329 void
17330 clutter_actor_set_easing_duration (ClutterActor *self,
17331                                    guint         msecs)
17332 {
17333   ClutterAnimationInfo *info;
17334
17335   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17336
17337   info = _clutter_actor_get_animation_info (self);
17338
17339   if (info->cur_state == NULL)
17340     {
17341       g_warning ("You must call clutter_actor_save_easing_state() prior "
17342                  "to calling clutter_actor_set_easing_duration().");
17343       return;
17344     }
17345
17346   if (info->cur_state->easing_duration != msecs)
17347     info->cur_state->easing_duration = msecs;
17348 }
17349
17350 /**
17351  * clutter_actor_get_easing_duration:
17352  * @self: a #ClutterActor
17353  *
17354  * Retrieves the duration of the tweening for animatable
17355  * properties of @self for the current easing state.
17356  *
17357  * Return value: the duration of the tweening, in milliseconds
17358  *
17359  * Since: 1.10
17360  */
17361 guint
17362 clutter_actor_get_easing_duration (ClutterActor *self)
17363 {
17364   const ClutterAnimationInfo *info;
17365
17366   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17367
17368   info = _clutter_actor_get_animation_info_or_defaults (self);
17369
17370   if (info->cur_state != NULL)
17371     return info->cur_state->easing_duration;
17372
17373   return 0;
17374 }
17375
17376 /**
17377  * clutter_actor_set_easing_mode:
17378  * @self: a #ClutterActor
17379  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17380  *
17381  * Sets the easing mode for the tweening of animatable properties
17382  * of @self.
17383  *
17384  * Since: 1.10
17385  */
17386 void
17387 clutter_actor_set_easing_mode (ClutterActor         *self,
17388                                ClutterAnimationMode  mode)
17389 {
17390   ClutterAnimationInfo *info;
17391
17392   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17393   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17394   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17395
17396   info = _clutter_actor_get_animation_info (self);
17397
17398   if (info->cur_state == NULL)
17399     {
17400       g_warning ("You must call clutter_actor_save_easing_state() prior "
17401                  "to calling clutter_actor_set_easing_mode().");
17402       return;
17403     }
17404
17405   if (info->cur_state->easing_mode != mode)
17406     info->cur_state->easing_mode = mode;
17407 }
17408
17409 /**
17410  * clutter_actor_get_easing_mode:
17411  * @self: a #ClutterActor
17412  *
17413  * Retrieves the easing mode for the tweening of animatable properties
17414  * of @self for the current easing state.
17415  *
17416  * Return value: an easing mode
17417  *
17418  * Since: 1.10
17419  */
17420 ClutterAnimationMode
17421 clutter_actor_get_easing_mode (ClutterActor *self)
17422 {
17423   const ClutterAnimationInfo *info;
17424
17425   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17426
17427   info = _clutter_actor_get_animation_info_or_defaults (self);
17428
17429   if (info->cur_state != NULL)
17430     return info->cur_state->easing_mode;
17431
17432   return CLUTTER_EASE_OUT_CUBIC;
17433 }
17434
17435 /**
17436  * clutter_actor_set_easing_delay:
17437  * @self: a #ClutterActor
17438  * @msecs: the delay before the start of the tweening, in milliseconds
17439  *
17440  * Sets the delay that should be applied before tweening animatable
17441  * properties.
17442  *
17443  * Since: 1.10
17444  */
17445 void
17446 clutter_actor_set_easing_delay (ClutterActor *self,
17447                                 guint         msecs)
17448 {
17449   ClutterAnimationInfo *info;
17450
17451   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17452
17453   info = _clutter_actor_get_animation_info (self);
17454
17455   if (info->cur_state == NULL)
17456     {
17457       g_warning ("You must call clutter_actor_save_easing_state() prior "
17458                  "to calling clutter_actor_set_easing_delay().");
17459       return;
17460     }
17461
17462   if (info->cur_state->easing_delay != msecs)
17463     info->cur_state->easing_delay = msecs;
17464 }
17465
17466 /**
17467  * clutter_actor_get_easing_delay:
17468  * @self: a #ClutterActor
17469  *
17470  * Retrieves the delay that should be applied when tweening animatable
17471  * properties.
17472  *
17473  * Return value: a delay, in milliseconds
17474  *
17475  * Since: 1.10
17476  */
17477 guint
17478 clutter_actor_get_easing_delay (ClutterActor *self)
17479 {
17480   const ClutterAnimationInfo *info;
17481
17482   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17483
17484   info = _clutter_actor_get_animation_info_or_defaults (self);
17485
17486   if (info->cur_state != NULL)
17487     return info->cur_state->easing_delay;
17488
17489   return 0;
17490 }
17491
17492 /**
17493  * clutter_actor_get_transition:
17494  * @self: a #ClutterActor
17495  * @name: the name of the transition
17496  *
17497  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17498  * transition @name.
17499  *
17500  * Transitions created for animatable properties use the name of the
17501  * property itself, for instance the code below:
17502  *
17503  * |[
17504  *   clutter_actor_set_easing_duration (actor, 1000);
17505  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17506  *
17507  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17508  *   g_signal_connect (transition, "completed",
17509  *                     G_CALLBACK (on_transition_complete),
17510  *                     actor);
17511  * ]|
17512  *
17513  * will call the <function>on_transition_complete</function> callback when
17514  * the transition is complete.
17515  *
17516  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17517  *   was found to match the passed name; the returned instance is owned
17518  *   by Clutter and it should not be freed
17519  *
17520  * Since: 1.10
17521  */
17522 ClutterTransition *
17523 clutter_actor_get_transition (ClutterActor *self,
17524                               const char   *name)
17525 {
17526   TransitionClosure *clos;
17527   const ClutterAnimationInfo *info;
17528
17529   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17530   g_return_val_if_fail (name != NULL, NULL);
17531
17532   info = _clutter_actor_get_animation_info_or_defaults (self);
17533   if (info->transitions == NULL)
17534     return NULL;
17535
17536   clos = g_hash_table_lookup (info->transitions, name);
17537   if (clos == NULL)
17538     return NULL;
17539
17540   return clos->transition;
17541 }
17542
17543 /**
17544  * clutter_actor_save_easing_state:
17545  * @self: a #ClutterActor
17546  *
17547  * Saves the current easing state for animatable properties, and creates
17548  * a new state with the default values for easing mode and duration.
17549  *
17550  * Since: 1.10
17551  */
17552 void
17553 clutter_actor_save_easing_state (ClutterActor *self)
17554 {
17555   ClutterAnimationInfo *info;
17556   AState new_state;
17557
17558   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17559
17560   info = _clutter_actor_get_animation_info (self);
17561
17562   if (info->states == NULL)
17563     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17564
17565   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17566   new_state.easing_duration = 250;
17567   new_state.easing_delay = 0;
17568
17569   g_array_append_val (info->states, new_state);
17570
17571   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17572 }
17573
17574 /**
17575  * clutter_actor_restore_easing_state:
17576  * @self: a #ClutterActor
17577  *
17578  * Restores the easing state as it was prior to a call to
17579  * clutter_actor_save_easing_state().
17580  *
17581  * Since: 1.10
17582  */
17583 void
17584 clutter_actor_restore_easing_state (ClutterActor *self)
17585 {
17586   ClutterAnimationInfo *info;
17587
17588   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17589
17590   info = _clutter_actor_get_animation_info (self);
17591
17592   if (info->states == NULL)
17593     {
17594       g_critical ("The function clutter_actor_restore_easing_state() has "
17595                   "called without a previous call to "
17596                   "clutter_actor_save_easing_state().");
17597       return;
17598     }
17599
17600   g_array_remove_index (info->states, info->states->len - 1);
17601
17602   if (info->states->len > 0)
17603     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17604   else
17605     {
17606       g_array_unref (info->states);
17607       info->states = NULL;
17608       info->cur_state = NULL;
17609     }
17610 }
17611
17612 /**
17613  * clutter_actor_set_content:
17614  * @self: a #ClutterActor
17615  * @content: (allow-none): a #ClutterContent, or %NULL
17616  *
17617  * Sets the contents of a #ClutterActor.
17618  *
17619  * Since: 1.10
17620  */
17621 void
17622 clutter_actor_set_content (ClutterActor   *self,
17623                            ClutterContent *content)
17624 {
17625   ClutterActorPrivate *priv;
17626
17627   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17628   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17629
17630   priv = self->priv;
17631
17632   if (priv->content != NULL)
17633     {
17634       _clutter_content_detached (priv->content, self);
17635       g_clear_object (&priv->content);
17636     }
17637
17638   priv->content = content;
17639
17640   if (priv->content != NULL)
17641     {
17642       g_object_ref (priv->content);
17643       _clutter_content_attached (priv->content, self);
17644     }
17645
17646   /* given that the content is always painted within the allocation,
17647    * we only need to queue a redraw here
17648    */
17649   clutter_actor_queue_redraw (self);
17650
17651   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17652
17653   /* if the content gravity is not resize-fill, and the new content has a
17654    * different preferred size than the previous one, then the content box
17655    * may have been changed. since we compute that lazily, we just notify
17656    * here, and let whomever watches :content-box do whatever they need to
17657    * do.
17658    */
17659   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17660     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17661 }
17662
17663 /**
17664  * clutter_actor_get_content:
17665  * @self: a #ClutterActor
17666  *
17667  * Retrieves the contents of @self.
17668  *
17669  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17670  *   or %NULL if none was set
17671  *
17672  * Since: 1.10
17673  */
17674 ClutterContent *
17675 clutter_actor_get_content (ClutterActor *self)
17676 {
17677   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17678
17679   return self->priv->content;
17680 }
17681
17682 /**
17683  * clutter_actor_set_content_gravity:
17684  * @self: a #ClutterActor
17685  * @gravity: the #ClutterContentGravity
17686  *
17687  * Sets the gravity of the #ClutterContent used by @self.
17688  *
17689  * See the description of the #ClutterActor:content-gravity property for
17690  * more information.
17691  *
17692  * Since: 1.10
17693  */
17694 void
17695 clutter_actor_set_content_gravity (ClutterActor *self,
17696                                    ClutterContentGravity  gravity)
17697 {
17698   ClutterActorPrivate *priv;
17699
17700   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17701
17702   priv = self->priv;
17703
17704   if (priv->content_gravity == gravity)
17705     return;
17706
17707   priv->content_gravity = gravity;
17708
17709   clutter_actor_queue_redraw (self);
17710
17711   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17712   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17713 }
17714
17715 /**
17716  * clutter_actor_get_content_gravity:
17717  * @self: a #ClutterActor
17718  *
17719  * Retrieves the content gravity as set using
17720  * clutter_actor_get_content_gravity().
17721  *
17722  * Return value: the content gravity
17723  *
17724  * Since: 1.10
17725  */
17726 ClutterContentGravity
17727 clutter_actor_get_content_gravity (ClutterActor *self)
17728 {
17729   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17730                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17731
17732   return self->priv->content_gravity;
17733 }
17734
17735 /**
17736  * clutter_actor_get_content_box:
17737  * @self: a #ClutterActor
17738  * @box: (out caller-allocates): the return location for the bounding
17739  *   box for the #ClutterContent
17740  *
17741  * Retrieves the bounding box for the #ClutterContent of @self.
17742  *
17743  * The bounding box is relative to the actor's allocation.
17744  *
17745  * If no #ClutterContent is set for @self, or if @self has not been
17746  * allocated yet, then the result is undefined.
17747  *
17748  * The content box is guaranteed to be, at most, as big as the allocation
17749  * of the #ClutterActor.
17750  *
17751  * If the #ClutterContent used by the actor has a preferred size, then
17752  * it is possible to modify the content box by using the
17753  * #ClutterActor:content-gravity property.
17754  *
17755  * Since: 1.10
17756  */
17757 void
17758 clutter_actor_get_content_box (ClutterActor    *self,
17759                                ClutterActorBox *box)
17760 {
17761   ClutterActorPrivate *priv;
17762   gfloat content_w, content_h;
17763   gfloat alloc_w, alloc_h;
17764
17765   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17766   g_return_if_fail (box != NULL);
17767
17768   priv = self->priv;
17769
17770   box->x1 = 0.f;
17771   box->y1 = 0.f;
17772   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17773   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17774
17775   if (priv->content == NULL)
17776     return;
17777
17778   /* no need to do any more work */
17779   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17780     return;
17781
17782   /* if the content does not have a preferred size then there is
17783    * no point in computing the content box
17784    */
17785   if (!clutter_content_get_preferred_size (priv->content,
17786                                            &content_w,
17787                                            &content_h))
17788     return;
17789
17790   alloc_w = box->x2;
17791   alloc_h = box->y2;
17792
17793   switch (priv->content_gravity)
17794     {
17795     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17796       box->x2 = box->x1 + MIN (content_w, alloc_w);
17797       box->y2 = box->y1 + MIN (content_h, alloc_h);
17798       break;
17799
17800     case CLUTTER_CONTENT_GRAVITY_TOP:
17801       if (alloc_w > content_w)
17802         {
17803           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17804           box->x2 = box->x1 + content_w;
17805         }
17806       box->y2 = box->y1 + MIN (content_h, alloc_h);
17807       break;
17808
17809     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17810       if (alloc_w > content_w)
17811         {
17812           box->x1 += (alloc_w - content_w);
17813           box->x2 = box->x1 + content_w;
17814         }
17815       box->y2 = box->y1 + MIN (content_h, alloc_h);
17816       break;
17817
17818     case CLUTTER_CONTENT_GRAVITY_LEFT:
17819       box->x2 = box->x1 + MIN (content_w, alloc_w);
17820       if (alloc_h > content_h)
17821         {
17822           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17823           box->y2 = box->y1 + content_h;
17824         }
17825       break;
17826
17827     case CLUTTER_CONTENT_GRAVITY_CENTER:
17828       if (alloc_w > content_w)
17829         {
17830           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17831           box->x2 = box->x1 + content_w;
17832         }
17833       if (alloc_h > content_h)
17834         {
17835           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17836           box->y2 = box->y1 + content_h;
17837         }
17838       break;
17839
17840     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17841       if (alloc_w > content_w)
17842         {
17843           box->x1 += (alloc_w - content_w);
17844           box->x2 = box->x1 + content_w;
17845         }
17846       if (alloc_h > content_h)
17847         {
17848           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17849           box->y2 = box->y1 + content_h;
17850         }
17851       break;
17852
17853     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17854       box->x2 = box->x1 + MIN (content_w, alloc_w);
17855       if (alloc_h > content_h)
17856         {
17857           box->y1 += (alloc_h - content_h);
17858           box->y2 = box->y1 + content_h;
17859         }
17860       break;
17861
17862     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17863       if (alloc_w > content_w)
17864         {
17865           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17866           box->x2 = box->x1 + content_w;
17867         }
17868       if (alloc_h > content_h)
17869         {
17870           box->y1 += (alloc_h - content_h);
17871           box->y2 = box->y1 + content_h;
17872         }
17873       break;
17874
17875     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17876       if (alloc_w > content_w)
17877         {
17878           box->x1 += (alloc_w - content_w);
17879           box->x2 = box->x1 + content_w;
17880         }
17881       if (alloc_h > content_h)
17882         {
17883           box->y1 += (alloc_h - content_h);
17884           box->y2 = box->y1 + content_h;
17885         }
17886       break;
17887
17888     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17889       g_assert_not_reached ();
17890       break;
17891
17892     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17893       {
17894         double r_c = content_w / content_h;
17895         double r_a = alloc_w / alloc_h;
17896
17897         if (r_c >= 1.0)
17898           {
17899             if (r_a >= 1.0)
17900               {
17901                 box->x1 = 0.f;
17902                 box->x2 = alloc_w;
17903
17904                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17905                 box->y2 = box->y1 + (alloc_w * r_c);
17906               }
17907             else
17908               {
17909                 box->y1 = 0.f;
17910                 box->y2 = alloc_h;
17911
17912                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17913                 box->x2 = box->x1 + (alloc_h * r_c);
17914               }
17915           }
17916         else
17917           {
17918             if (r_a >= 1.0)
17919               {
17920                 box->y1 = 0.f;
17921                 box->y2 = alloc_h;
17922
17923                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17924                 box->x2 = box->x1 + (alloc_h * r_c);
17925               }
17926             else
17927               {
17928                 box->x1 = 0.f;
17929                 box->x2 = alloc_w;
17930
17931                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17932                 box->y2 = box->y1 + (alloc_w * r_c);
17933               }
17934           }
17935       }
17936       break;
17937     }
17938 }
17939
17940 /**
17941  * clutter_actor_set_content_scaling_filters:
17942  * @self: a #ClutterActor
17943  * @min_filter: the minification filter for the content
17944  * @mag_filter: the magnification filter for the content
17945  *
17946  * Sets the minification and magnification filter to be applied when
17947  * scaling the #ClutterActor:content of a #ClutterActor.
17948  *
17949  * The #ClutterActor:minification-filter will be used when reducing
17950  * the size of the content; the #ClutterActor:magnification-filter
17951  * will be used when increasing the size of the content.
17952  *
17953  * Since: 1.10
17954  */
17955 void
17956 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
17957                                            ClutterScalingFilter  min_filter,
17958                                            ClutterScalingFilter  mag_filter)
17959 {
17960   ClutterActorPrivate *priv;
17961   gboolean changed;
17962   GObject *obj;
17963
17964   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17965
17966   priv = self->priv;
17967   obj = G_OBJECT (self);
17968
17969   g_object_freeze_notify (obj);
17970
17971   changed = FALSE;
17972
17973   if (priv->min_filter != min_filter)
17974     {
17975       priv->min_filter = min_filter;
17976       changed = TRUE;
17977
17978       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17979     }
17980
17981   if (priv->mag_filter != mag_filter)
17982     {
17983       priv->mag_filter = mag_filter;
17984       changed = TRUE;
17985
17986       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17987     }
17988
17989   if (changed)
17990     clutter_actor_queue_redraw (self);
17991
17992   g_object_thaw_notify (obj);
17993 }
17994
17995 /**
17996  * clutter_actor_get_content_scaling_filters:
17997  * @self: a #ClutterActor
17998  * @min_filter: (out) (allow-none): return location for the minification
17999  *   filter, or %NULL
18000  * @mag_filter: (out) (allow-none): return location for the magnification
18001  *   filter, or %NULL
18002  *
18003  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18004  *
18005  * Since: 1.10
18006  */
18007 void
18008 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18009                                            ClutterScalingFilter *min_filter,
18010                                            ClutterScalingFilter *mag_filter)
18011 {
18012   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18013
18014   if (min_filter != NULL)
18015     *min_filter = self->priv->min_filter;
18016
18017   if (mag_filter != NULL)
18018     *mag_filter = self->priv->mag_filter;
18019 }