actor: Add IN_DESTRUCTION checks
[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   ClutterTransformInfo *info;
4018
4019   info = _clutter_actor_get_transform_info (self);
4020
4021   if (clutter_actor_get_easing_duration (self) != 0)
4022     {
4023       ClutterTransition *transition;
4024       GParamSpec *pspec = NULL;
4025       double *cur_angle_p = NULL;
4026
4027       switch (axis)
4028         {
4029         case CLUTTER_X_AXIS:
4030           cur_angle_p = &info->rx_angle;
4031           pspec = obj_props[PROP_ROTATION_ANGLE_X];
4032           break;
4033
4034         case CLUTTER_Y_AXIS:
4035           cur_angle_p = &info->ry_angle;
4036           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4037           break;
4038
4039         case CLUTTER_Z_AXIS:
4040           cur_angle_p = &info->rz_angle;
4041           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4042           break;
4043         }
4044
4045       g_assert (pspec != NULL);
4046       g_assert (cur_angle_p != NULL);
4047
4048       transition = _clutter_actor_get_transition (self, pspec);
4049       if (transition == NULL)
4050         {
4051           transition = _clutter_actor_create_transition (self, pspec,
4052                                                          *cur_angle_p,
4053                                                          angle);
4054         }
4055       else
4056         _clutter_actor_update_transition (self, pspec, angle);
4057
4058       self->priv->transform_valid = FALSE;
4059       clutter_actor_queue_redraw (self);
4060     }
4061   else
4062     clutter_actor_set_rotation_angle_internal (self, axis, angle);
4063 }
4064
4065 /*< private >
4066  * clutter_actor_set_rotation_center_internal:
4067  * @self: a #ClutterActor
4068  * @axis: the axis of the center to change
4069  * @center: the coordinates of the rotation center
4070  *
4071  * Sets the rotation center on the given axis without affecting the
4072  * rotation angle.
4073  */
4074 static inline void
4075 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4076                                             ClutterRotateAxis    axis,
4077                                             const ClutterVertex *center)
4078 {
4079   GObject *obj = G_OBJECT (self);
4080   ClutterTransformInfo *info;
4081   ClutterVertex v = { 0, 0, 0 };
4082
4083   info = _clutter_actor_get_transform_info (self);
4084
4085   if (center != NULL)
4086     v = *center;
4087
4088   g_object_freeze_notify (obj);
4089
4090   switch (axis)
4091     {
4092     case CLUTTER_X_AXIS:
4093       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4094       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4095       break;
4096
4097     case CLUTTER_Y_AXIS:
4098       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4099       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4100       break;
4101
4102     case CLUTTER_Z_AXIS:
4103       /* if the previously set rotation center was fractional, then
4104        * setting explicit coordinates will have to notify the
4105        * :rotation-center-z-gravity property as well
4106        */
4107       if (info->rz_center.is_fractional)
4108         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4109
4110       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4111       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4112       break;
4113     }
4114
4115   self->priv->transform_valid = FALSE;
4116
4117   g_object_thaw_notify (obj);
4118
4119   clutter_actor_queue_redraw (self);
4120 }
4121
4122 static void
4123 clutter_actor_animate_scale_factor (ClutterActor *self,
4124                                     double        old_factor,
4125                                     double        new_factor,
4126                                     GParamSpec   *pspec)
4127 {
4128   ClutterTransition *transition;
4129
4130   transition = _clutter_actor_get_transition (self, pspec);
4131   if (transition == NULL)
4132     {
4133       transition = _clutter_actor_create_transition (self, pspec,
4134                                                      old_factor,
4135                                                      new_factor);
4136     }
4137   else
4138     _clutter_actor_update_transition (self, pspec, new_factor);
4139
4140
4141   self->priv->transform_valid = FALSE;
4142   clutter_actor_queue_redraw (self);
4143 }
4144
4145 static void
4146 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4147                                          double factor,
4148                                          GParamSpec *pspec)
4149 {
4150   GObject *obj = G_OBJECT (self);
4151   ClutterTransformInfo *info;
4152
4153   info = _clutter_actor_get_transform_info (self);
4154
4155   if (pspec == obj_props[PROP_SCALE_X])
4156     info->scale_x = factor;
4157   else
4158     info->scale_y = factor;
4159
4160   self->priv->transform_valid = FALSE;
4161   clutter_actor_queue_redraw (self);
4162   g_object_notify_by_pspec (obj, pspec);
4163 }
4164
4165 static inline void
4166 clutter_actor_set_scale_factor (ClutterActor      *self,
4167                                 ClutterRotateAxis  axis,
4168                                 gdouble            factor)
4169 {
4170   GObject *obj = G_OBJECT (self);
4171   ClutterTransformInfo *info;
4172   GParamSpec *pspec;
4173
4174   info = _clutter_actor_get_transform_info (self);
4175
4176   g_object_freeze_notify (obj);
4177
4178   switch (axis)
4179     {
4180     case CLUTTER_X_AXIS:
4181       pspec = obj_props[PROP_SCALE_X];
4182
4183       if (clutter_actor_get_easing_duration (self) != 0)
4184         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4185       else
4186         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4187       break;
4188
4189     case CLUTTER_Y_AXIS:
4190       pspec = obj_props[PROP_SCALE_Y];
4191
4192       if (clutter_actor_get_easing_duration (self) != 0)
4193         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4194       else
4195         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4196       break;
4197
4198     default:
4199       g_assert_not_reached ();
4200     }
4201
4202   g_object_thaw_notify (obj);
4203 }
4204
4205 static inline void
4206 clutter_actor_set_scale_center (ClutterActor      *self,
4207                                 ClutterRotateAxis  axis,
4208                                 gfloat             coord)
4209 {
4210   GObject *obj = G_OBJECT (self);
4211   ClutterTransformInfo *info;
4212   gfloat center_x, center_y;
4213
4214   info = _clutter_actor_get_transform_info (self);
4215
4216   g_object_freeze_notify (obj);
4217
4218   /* get the current scale center coordinates */
4219   clutter_anchor_coord_get_units (self, &info->scale_center,
4220                                   &center_x,
4221                                   &center_y,
4222                                   NULL);
4223
4224   /* we need to notify this too, because setting explicit coordinates will
4225    * change the gravity as a side effect
4226    */
4227   if (info->scale_center.is_fractional)
4228     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4229
4230   switch (axis)
4231     {
4232     case CLUTTER_X_AXIS:
4233       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4234       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4235       break;
4236
4237     case CLUTTER_Y_AXIS:
4238       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4239       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4240       break;
4241
4242     default:
4243       g_assert_not_reached ();
4244     }
4245
4246   self->priv->transform_valid = FALSE;
4247
4248   clutter_actor_queue_redraw (self);
4249
4250   g_object_thaw_notify (obj);
4251 }
4252
4253 static inline void
4254 clutter_actor_set_scale_gravity (ClutterActor   *self,
4255                                  ClutterGravity  gravity)
4256 {
4257   ClutterTransformInfo *info;
4258   GObject *obj;
4259
4260   info = _clutter_actor_get_transform_info (self);
4261   obj = G_OBJECT (self);
4262
4263   if (gravity == CLUTTER_GRAVITY_NONE)
4264     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4265   else
4266     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4267
4268   self->priv->transform_valid = FALSE;
4269
4270   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4271   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4272   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4273
4274   clutter_actor_queue_redraw (self);
4275 }
4276
4277 static inline void
4278 clutter_actor_set_anchor_coord (ClutterActor      *self,
4279                                 ClutterRotateAxis  axis,
4280                                 gfloat             coord)
4281 {
4282   GObject *obj = G_OBJECT (self);
4283   ClutterTransformInfo *info;
4284   gfloat anchor_x, anchor_y;
4285
4286   info = _clutter_actor_get_transform_info (self);
4287
4288   g_object_freeze_notify (obj);
4289
4290   clutter_anchor_coord_get_units (self, &info->anchor,
4291                                   &anchor_x,
4292                                   &anchor_y,
4293                                   NULL);
4294
4295   if (info->anchor.is_fractional)
4296     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4297
4298   switch (axis)
4299     {
4300     case CLUTTER_X_AXIS:
4301       clutter_anchor_coord_set_units (&info->anchor,
4302                                       coord,
4303                                       anchor_y,
4304                                       0.0);
4305       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4306       break;
4307
4308     case CLUTTER_Y_AXIS:
4309       clutter_anchor_coord_set_units (&info->anchor,
4310                                       anchor_x,
4311                                       coord,
4312                                       0.0);
4313       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4314       break;
4315
4316     default:
4317       g_assert_not_reached ();
4318     }
4319
4320   self->priv->transform_valid = FALSE;
4321
4322   clutter_actor_queue_redraw (self);
4323
4324   g_object_thaw_notify (obj);
4325 }
4326
4327 static void
4328 clutter_actor_set_property (GObject      *object,
4329                             guint         prop_id,
4330                             const GValue *value,
4331                             GParamSpec   *pspec)
4332 {
4333   ClutterActor *actor = CLUTTER_ACTOR (object);
4334   ClutterActorPrivate *priv = actor->priv;
4335
4336   switch (prop_id)
4337     {
4338     case PROP_X:
4339       clutter_actor_set_x (actor, g_value_get_float (value));
4340       break;
4341
4342     case PROP_Y:
4343       clutter_actor_set_y (actor, g_value_get_float (value));
4344       break;
4345
4346     case PROP_WIDTH:
4347       clutter_actor_set_width (actor, g_value_get_float (value));
4348       break;
4349
4350     case PROP_HEIGHT:
4351       clutter_actor_set_height (actor, g_value_get_float (value));
4352       break;
4353
4354     case PROP_FIXED_X:
4355       clutter_actor_set_x (actor, g_value_get_float (value));
4356       break;
4357
4358     case PROP_FIXED_Y:
4359       clutter_actor_set_y (actor, g_value_get_float (value));
4360       break;
4361
4362     case PROP_FIXED_POSITION_SET:
4363       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4364       break;
4365
4366     case PROP_MIN_WIDTH:
4367       clutter_actor_set_min_width (actor, g_value_get_float (value));
4368       break;
4369
4370     case PROP_MIN_HEIGHT:
4371       clutter_actor_set_min_height (actor, g_value_get_float (value));
4372       break;
4373
4374     case PROP_NATURAL_WIDTH:
4375       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4376       break;
4377
4378     case PROP_NATURAL_HEIGHT:
4379       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4380       break;
4381
4382     case PROP_MIN_WIDTH_SET:
4383       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4384       break;
4385
4386     case PROP_MIN_HEIGHT_SET:
4387       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4388       break;
4389
4390     case PROP_NATURAL_WIDTH_SET:
4391       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4392       break;
4393
4394     case PROP_NATURAL_HEIGHT_SET:
4395       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4396       break;
4397
4398     case PROP_REQUEST_MODE:
4399       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4400       break;
4401
4402     case PROP_DEPTH:
4403       clutter_actor_set_depth (actor, g_value_get_float (value));
4404       break;
4405
4406     case PROP_OPACITY:
4407       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4408       break;
4409
4410     case PROP_OFFSCREEN_REDIRECT:
4411       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4412       break;
4413
4414     case PROP_NAME:
4415       clutter_actor_set_name (actor, g_value_get_string (value));
4416       break;
4417
4418     case PROP_VISIBLE:
4419       if (g_value_get_boolean (value) == TRUE)
4420         clutter_actor_show (actor);
4421       else
4422         clutter_actor_hide (actor);
4423       break;
4424
4425     case PROP_SCALE_X:
4426       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4427                                       g_value_get_double (value));
4428       break;
4429
4430     case PROP_SCALE_Y:
4431       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4432                                       g_value_get_double (value));
4433       break;
4434
4435     case PROP_SCALE_CENTER_X:
4436       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4437                                       g_value_get_float (value));
4438       break;
4439
4440     case PROP_SCALE_CENTER_Y:
4441       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4442                                       g_value_get_float (value));
4443       break;
4444
4445     case PROP_SCALE_GRAVITY:
4446       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4447       break;
4448
4449     case PROP_CLIP:
4450       {
4451         const ClutterGeometry *geom = g_value_get_boxed (value);
4452
4453         clutter_actor_set_clip (actor,
4454                                 geom->x, geom->y,
4455                                 geom->width, geom->height);
4456       }
4457       break;
4458
4459     case PROP_CLIP_TO_ALLOCATION:
4460       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4461       break;
4462
4463     case PROP_REACTIVE:
4464       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4465       break;
4466
4467     case PROP_ROTATION_ANGLE_X:
4468       clutter_actor_set_rotation_angle (actor,
4469                                         CLUTTER_X_AXIS,
4470                                         g_value_get_double (value));
4471       break;
4472
4473     case PROP_ROTATION_ANGLE_Y:
4474       clutter_actor_set_rotation_angle (actor,
4475                                         CLUTTER_Y_AXIS,
4476                                         g_value_get_double (value));
4477       break;
4478
4479     case PROP_ROTATION_ANGLE_Z:
4480       clutter_actor_set_rotation_angle (actor,
4481                                         CLUTTER_Z_AXIS,
4482                                         g_value_get_double (value));
4483       break;
4484
4485     case PROP_ROTATION_CENTER_X:
4486       clutter_actor_set_rotation_center_internal (actor,
4487                                                   CLUTTER_X_AXIS,
4488                                                   g_value_get_boxed (value));
4489       break;
4490
4491     case PROP_ROTATION_CENTER_Y:
4492       clutter_actor_set_rotation_center_internal (actor,
4493                                                   CLUTTER_Y_AXIS,
4494                                                   g_value_get_boxed (value));
4495       break;
4496
4497     case PROP_ROTATION_CENTER_Z:
4498       clutter_actor_set_rotation_center_internal (actor,
4499                                                   CLUTTER_Z_AXIS,
4500                                                   g_value_get_boxed (value));
4501       break;
4502
4503     case PROP_ROTATION_CENTER_Z_GRAVITY:
4504       {
4505         const ClutterTransformInfo *info;
4506
4507         info = _clutter_actor_get_transform_info_or_defaults (actor);
4508         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4509                                                    g_value_get_enum (value));
4510       }
4511       break;
4512
4513     case PROP_ANCHOR_X:
4514       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4515                                       g_value_get_float (value));
4516       break;
4517
4518     case PROP_ANCHOR_Y:
4519       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4520                                       g_value_get_float (value));
4521       break;
4522
4523     case PROP_ANCHOR_GRAVITY:
4524       clutter_actor_set_anchor_point_from_gravity (actor,
4525                                                    g_value_get_enum (value));
4526       break;
4527
4528     case PROP_SHOW_ON_SET_PARENT:
4529       priv->show_on_set_parent = g_value_get_boolean (value);
4530       break;
4531
4532     case PROP_TEXT_DIRECTION:
4533       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4534       break;
4535
4536     case PROP_ACTIONS:
4537       clutter_actor_add_action (actor, g_value_get_object (value));
4538       break;
4539
4540     case PROP_CONSTRAINTS:
4541       clutter_actor_add_constraint (actor, g_value_get_object (value));
4542       break;
4543
4544     case PROP_EFFECT:
4545       clutter_actor_add_effect (actor, g_value_get_object (value));
4546       break;
4547
4548     case PROP_LAYOUT_MANAGER:
4549       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4550       break;
4551
4552     case PROP_X_ALIGN:
4553       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4554       break;
4555
4556     case PROP_Y_ALIGN:
4557       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4558       break;
4559
4560     case PROP_MARGIN_TOP:
4561       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4562       break;
4563
4564     case PROP_MARGIN_BOTTOM:
4565       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4566       break;
4567
4568     case PROP_MARGIN_LEFT:
4569       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4570       break;
4571
4572     case PROP_MARGIN_RIGHT:
4573       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4574       break;
4575
4576     case PROP_BACKGROUND_COLOR:
4577       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4578       break;
4579
4580     case PROP_CONTENT:
4581       clutter_actor_set_content (actor, g_value_get_object (value));
4582       break;
4583
4584     case PROP_CONTENT_GRAVITY:
4585       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4586       break;
4587
4588     case PROP_MINIFICATION_FILTER:
4589       clutter_actor_set_content_scaling_filters (actor,
4590                                                  g_value_get_enum (value),
4591                                                  actor->priv->mag_filter);
4592       break;
4593
4594     case PROP_MAGNIFICATION_FILTER:
4595       clutter_actor_set_content_scaling_filters (actor,
4596                                                  actor->priv->min_filter,
4597                                                  g_value_get_enum (value));
4598       break;
4599
4600     default:
4601       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4602       break;
4603     }
4604 }
4605
4606 static void
4607 clutter_actor_get_property (GObject    *object,
4608                             guint       prop_id,
4609                             GValue     *value,
4610                             GParamSpec *pspec)
4611 {
4612   ClutterActor *actor = CLUTTER_ACTOR (object);
4613   ClutterActorPrivate *priv = actor->priv;
4614
4615   switch (prop_id)
4616     {
4617     case PROP_X:
4618       g_value_set_float (value, clutter_actor_get_x (actor));
4619       break;
4620
4621     case PROP_Y:
4622       g_value_set_float (value, clutter_actor_get_y (actor));
4623       break;
4624
4625     case PROP_WIDTH:
4626       g_value_set_float (value, clutter_actor_get_width (actor));
4627       break;
4628
4629     case PROP_HEIGHT:
4630       g_value_set_float (value, clutter_actor_get_height (actor));
4631       break;
4632
4633     case PROP_FIXED_X:
4634       {
4635         const ClutterLayoutInfo *info;
4636
4637         info = _clutter_actor_get_layout_info_or_defaults (actor);
4638         g_value_set_float (value, info->fixed_x);
4639       }
4640       break;
4641
4642     case PROP_FIXED_Y:
4643       {
4644         const ClutterLayoutInfo *info;
4645
4646         info = _clutter_actor_get_layout_info_or_defaults (actor);
4647         g_value_set_float (value, info->fixed_y);
4648       }
4649       break;
4650
4651     case PROP_FIXED_POSITION_SET:
4652       g_value_set_boolean (value, priv->position_set);
4653       break;
4654
4655     case PROP_MIN_WIDTH:
4656       {
4657         const ClutterLayoutInfo *info;
4658
4659         info = _clutter_actor_get_layout_info_or_defaults (actor);
4660         g_value_set_float (value, info->min_width);
4661       }
4662       break;
4663
4664     case PROP_MIN_HEIGHT:
4665       {
4666         const ClutterLayoutInfo *info;
4667
4668         info = _clutter_actor_get_layout_info_or_defaults (actor);
4669         g_value_set_float (value, info->min_height);
4670       }
4671       break;
4672
4673     case PROP_NATURAL_WIDTH:
4674       {
4675         const ClutterLayoutInfo *info;
4676
4677         info = _clutter_actor_get_layout_info_or_defaults (actor);
4678         g_value_set_float (value, info->natural_width);
4679       }
4680       break;
4681
4682     case PROP_NATURAL_HEIGHT:
4683       {
4684         const ClutterLayoutInfo *info;
4685
4686         info = _clutter_actor_get_layout_info_or_defaults (actor);
4687         g_value_set_float (value, info->natural_height);
4688       }
4689       break;
4690
4691     case PROP_MIN_WIDTH_SET:
4692       g_value_set_boolean (value, priv->min_width_set);
4693       break;
4694
4695     case PROP_MIN_HEIGHT_SET:
4696       g_value_set_boolean (value, priv->min_height_set);
4697       break;
4698
4699     case PROP_NATURAL_WIDTH_SET:
4700       g_value_set_boolean (value, priv->natural_width_set);
4701       break;
4702
4703     case PROP_NATURAL_HEIGHT_SET:
4704       g_value_set_boolean (value, priv->natural_height_set);
4705       break;
4706
4707     case PROP_REQUEST_MODE:
4708       g_value_set_enum (value, priv->request_mode);
4709       break;
4710
4711     case PROP_ALLOCATION:
4712       g_value_set_boxed (value, &priv->allocation);
4713       break;
4714
4715     case PROP_DEPTH:
4716       g_value_set_float (value, clutter_actor_get_depth (actor));
4717       break;
4718
4719     case PROP_OPACITY:
4720       g_value_set_uint (value, priv->opacity);
4721       break;
4722
4723     case PROP_OFFSCREEN_REDIRECT:
4724       g_value_set_enum (value, priv->offscreen_redirect);
4725       break;
4726
4727     case PROP_NAME:
4728       g_value_set_string (value, priv->name);
4729       break;
4730
4731     case PROP_VISIBLE:
4732       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4733       break;
4734
4735     case PROP_MAPPED:
4736       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4737       break;
4738
4739     case PROP_REALIZED:
4740       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4741       break;
4742
4743     case PROP_HAS_CLIP:
4744       g_value_set_boolean (value, priv->has_clip);
4745       break;
4746
4747     case PROP_CLIP:
4748       {
4749         ClutterGeometry clip;
4750
4751         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4752         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4753         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4754         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4755
4756         g_value_set_boxed (value, &clip);
4757       }
4758       break;
4759
4760     case PROP_CLIP_TO_ALLOCATION:
4761       g_value_set_boolean (value, priv->clip_to_allocation);
4762       break;
4763
4764     case PROP_SCALE_X:
4765       {
4766         const ClutterTransformInfo *info;
4767
4768         info = _clutter_actor_get_transform_info_or_defaults (actor);
4769         g_value_set_double (value, info->scale_x);
4770       }
4771       break;
4772
4773     case PROP_SCALE_Y:
4774       {
4775         const ClutterTransformInfo *info;
4776
4777         info = _clutter_actor_get_transform_info_or_defaults (actor);
4778         g_value_set_double (value, info->scale_y);
4779       }
4780       break;
4781
4782     case PROP_SCALE_CENTER_X:
4783       {
4784         gfloat center;
4785
4786         clutter_actor_get_scale_center (actor, &center, NULL);
4787
4788         g_value_set_float (value, center);
4789       }
4790       break;
4791
4792     case PROP_SCALE_CENTER_Y:
4793       {
4794         gfloat center;
4795
4796         clutter_actor_get_scale_center (actor, NULL, &center);
4797
4798         g_value_set_float (value, center);
4799       }
4800       break;
4801
4802     case PROP_SCALE_GRAVITY:
4803       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4804       break;
4805
4806     case PROP_REACTIVE:
4807       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4808       break;
4809
4810     case PROP_ROTATION_ANGLE_X:
4811       {
4812         const ClutterTransformInfo *info;
4813
4814         info = _clutter_actor_get_transform_info_or_defaults (actor);
4815         g_value_set_double (value, info->rx_angle);
4816       }
4817       break;
4818
4819     case PROP_ROTATION_ANGLE_Y:
4820       {
4821         const ClutterTransformInfo *info;
4822
4823         info = _clutter_actor_get_transform_info_or_defaults (actor);
4824         g_value_set_double (value, info->ry_angle);
4825       }
4826       break;
4827
4828     case PROP_ROTATION_ANGLE_Z:
4829       {
4830         const ClutterTransformInfo *info;
4831
4832         info = _clutter_actor_get_transform_info_or_defaults (actor);
4833         g_value_set_double (value, info->rz_angle);
4834       }
4835       break;
4836
4837     case PROP_ROTATION_CENTER_X:
4838       {
4839         ClutterVertex center;
4840
4841         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4842                                     &center.x,
4843                                     &center.y,
4844                                     &center.z);
4845
4846         g_value_set_boxed (value, &center);
4847       }
4848       break;
4849
4850     case PROP_ROTATION_CENTER_Y:
4851       {
4852         ClutterVertex center;
4853
4854         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4855                                     &center.x,
4856                                     &center.y,
4857                                     &center.z);
4858
4859         g_value_set_boxed (value, &center);
4860       }
4861       break;
4862
4863     case PROP_ROTATION_CENTER_Z:
4864       {
4865         ClutterVertex center;
4866
4867         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4868                                     &center.x,
4869                                     &center.y,
4870                                     &center.z);
4871
4872         g_value_set_boxed (value, &center);
4873       }
4874       break;
4875
4876     case PROP_ROTATION_CENTER_Z_GRAVITY:
4877       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4878       break;
4879
4880     case PROP_ANCHOR_X:
4881       {
4882         const ClutterTransformInfo *info;
4883         gfloat anchor_x;
4884
4885         info = _clutter_actor_get_transform_info_or_defaults (actor);
4886         clutter_anchor_coord_get_units (actor, &info->anchor,
4887                                         &anchor_x,
4888                                         NULL,
4889                                         NULL);
4890         g_value_set_float (value, anchor_x);
4891       }
4892       break;
4893
4894     case PROP_ANCHOR_Y:
4895       {
4896         const ClutterTransformInfo *info;
4897         gfloat anchor_y;
4898
4899         info = _clutter_actor_get_transform_info_or_defaults (actor);
4900         clutter_anchor_coord_get_units (actor, &info->anchor,
4901                                         NULL,
4902                                         &anchor_y,
4903                                         NULL);
4904         g_value_set_float (value, anchor_y);
4905       }
4906       break;
4907
4908     case PROP_ANCHOR_GRAVITY:
4909       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4910       break;
4911
4912     case PROP_SHOW_ON_SET_PARENT:
4913       g_value_set_boolean (value, priv->show_on_set_parent);
4914       break;
4915
4916     case PROP_TEXT_DIRECTION:
4917       g_value_set_enum (value, priv->text_direction);
4918       break;
4919
4920     case PROP_HAS_POINTER:
4921       g_value_set_boolean (value, priv->has_pointer);
4922       break;
4923
4924     case PROP_LAYOUT_MANAGER:
4925       g_value_set_object (value, priv->layout_manager);
4926       break;
4927
4928     case PROP_X_ALIGN:
4929       {
4930         const ClutterLayoutInfo *info;
4931
4932         info = _clutter_actor_get_layout_info_or_defaults (actor);
4933         g_value_set_enum (value, info->x_align);
4934       }
4935       break;
4936
4937     case PROP_Y_ALIGN:
4938       {
4939         const ClutterLayoutInfo *info;
4940
4941         info = _clutter_actor_get_layout_info_or_defaults (actor);
4942         g_value_set_enum (value, info->y_align);
4943       }
4944       break;
4945
4946     case PROP_MARGIN_TOP:
4947       {
4948         const ClutterLayoutInfo *info;
4949
4950         info = _clutter_actor_get_layout_info_or_defaults (actor);
4951         g_value_set_float (value, info->margin.top);
4952       }
4953       break;
4954
4955     case PROP_MARGIN_BOTTOM:
4956       {
4957         const ClutterLayoutInfo *info;
4958
4959         info = _clutter_actor_get_layout_info_or_defaults (actor);
4960         g_value_set_float (value, info->margin.bottom);
4961       }
4962       break;
4963
4964     case PROP_MARGIN_LEFT:
4965       {
4966         const ClutterLayoutInfo *info;
4967
4968         info = _clutter_actor_get_layout_info_or_defaults (actor);
4969         g_value_set_float (value, info->margin.left);
4970       }
4971       break;
4972
4973     case PROP_MARGIN_RIGHT:
4974       {
4975         const ClutterLayoutInfo *info;
4976
4977         info = _clutter_actor_get_layout_info_or_defaults (actor);
4978         g_value_set_float (value, info->margin.right);
4979       }
4980       break;
4981
4982     case PROP_BACKGROUND_COLOR_SET:
4983       g_value_set_boolean (value, priv->bg_color_set);
4984       break;
4985
4986     case PROP_BACKGROUND_COLOR:
4987       g_value_set_boxed (value, &priv->bg_color);
4988       break;
4989
4990     case PROP_FIRST_CHILD:
4991       g_value_set_object (value, priv->first_child);
4992       break;
4993
4994     case PROP_LAST_CHILD:
4995       g_value_set_object (value, priv->last_child);
4996       break;
4997
4998     case PROP_CONTENT:
4999       g_value_set_object (value, priv->content);
5000       break;
5001
5002     case PROP_CONTENT_GRAVITY:
5003       g_value_set_enum (value, priv->content_gravity);
5004       break;
5005
5006     case PROP_CONTENT_BOX:
5007       {
5008         ClutterActorBox box = { 0, };
5009
5010         clutter_actor_get_content_box (actor, &box);
5011         g_value_set_boxed (value, &box);
5012       }
5013       break;
5014
5015     case PROP_MINIFICATION_FILTER:
5016       g_value_set_enum (value, priv->min_filter);
5017       break;
5018
5019     case PROP_MAGNIFICATION_FILTER:
5020       g_value_set_enum (value, priv->mag_filter);
5021       break;
5022
5023     default:
5024       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5025       break;
5026     }
5027 }
5028
5029 static void
5030 clutter_actor_dispose (GObject *object)
5031 {
5032   ClutterActor *self = CLUTTER_ACTOR (object);
5033   ClutterActorPrivate *priv = self->priv;
5034
5035   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5036                 priv->id,
5037                 g_type_name (G_OBJECT_TYPE (self)),
5038                 object->ref_count);
5039
5040   g_signal_emit (self, actor_signals[DESTROY], 0);
5041
5042   /* avoid recursing when called from clutter_actor_destroy() */
5043   if (priv->parent != NULL)
5044     {
5045       ClutterActor *parent = priv->parent;
5046
5047       /* go through the Container implementation unless this
5048        * is an internal child and has been marked as such.
5049        *
5050        * removing the actor from its parent will reset the
5051        * realized and mapped states.
5052        */
5053       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5054         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5055       else
5056         clutter_actor_remove_child_internal (parent, self,
5057                                              REMOVE_CHILD_LEGACY_FLAGS);
5058     }
5059
5060   /* parent must be gone at this point */
5061   g_assert (priv->parent == NULL);
5062
5063   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5064     {
5065       /* can't be mapped or realized with no parent */
5066       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5067       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5068     }
5069
5070   g_clear_object (&priv->pango_context);
5071   g_clear_object (&priv->actions);
5072   g_clear_object (&priv->constraints);
5073   g_clear_object (&priv->effects);
5074   g_clear_object (&priv->flatten_effect);
5075
5076   if (priv->layout_manager != NULL)
5077     {
5078       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5079       g_clear_object (&priv->layout_manager);
5080     }
5081
5082   if (priv->content != NULL)
5083     {
5084       _clutter_content_detached (priv->content, self);
5085       g_clear_object (&priv->content);
5086     }
5087
5088   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5089 }
5090
5091 static void
5092 clutter_actor_finalize (GObject *object)
5093 {
5094   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5095
5096   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5097                 priv->name != NULL ? priv->name : "<none>",
5098                 priv->id,
5099                 g_type_name (G_OBJECT_TYPE (object)));
5100
5101   _clutter_context_release_id (priv->id);
5102
5103   g_free (priv->name);
5104
5105   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5106 }
5107
5108
5109 /**
5110  * clutter_actor_get_accessible:
5111  * @self: a #ClutterActor
5112  *
5113  * Returns the accessible object that describes the actor to an
5114  * assistive technology.
5115  *
5116  * If no class-specific #AtkObject implementation is available for the
5117  * actor instance in question, it will inherit an #AtkObject
5118  * implementation from the first ancestor class for which such an
5119  * implementation is defined.
5120  *
5121  * The documentation of the <ulink
5122  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5123  * library contains more information about accessible objects and
5124  * their uses.
5125  *
5126  * Returns: (transfer none): the #AtkObject associated with @actor
5127  */
5128 AtkObject *
5129 clutter_actor_get_accessible (ClutterActor *self)
5130 {
5131   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5132
5133   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5134 }
5135
5136 static AtkObject *
5137 clutter_actor_real_get_accessible (ClutterActor *actor)
5138 {
5139   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5140 }
5141
5142 static AtkObject *
5143 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5144 {
5145   AtkObject *accessible;
5146
5147   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5148   if (accessible != NULL)
5149     g_object_ref (accessible);
5150
5151   return accessible;
5152 }
5153
5154 static void
5155 atk_implementor_iface_init (AtkImplementorIface *iface)
5156 {
5157   iface->ref_accessible = _clutter_actor_ref_accessible;
5158 }
5159
5160 static gboolean
5161 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5162                                            ClutterPaintVolume *volume)
5163 {
5164   ClutterActorPrivate *priv = self->priv;
5165   gboolean res = FALSE;
5166
5167   /* we start from the allocation */
5168   clutter_paint_volume_set_width (volume,
5169                                   priv->allocation.x2 - priv->allocation.x1);
5170   clutter_paint_volume_set_height (volume,
5171                                    priv->allocation.y2 - priv->allocation.y1);
5172
5173   /* if the actor has a clip set then we have a pretty definite
5174    * size for the paint volume: the actor cannot possibly paint
5175    * outside the clip region.
5176    */
5177   if (priv->clip_to_allocation)
5178     {
5179       /* the allocation has already been set, so we just flip the
5180        * return value
5181        */
5182       res = TRUE;
5183     }
5184   else
5185     {
5186       ClutterActor *child;
5187
5188       if (priv->has_clip &&
5189           priv->clip.width >= 0 &&
5190           priv->clip.height >= 0)
5191         {
5192           ClutterVertex origin;
5193
5194           origin.x = priv->clip.x;
5195           origin.y = priv->clip.y;
5196           origin.z = 0;
5197
5198           clutter_paint_volume_set_origin (volume, &origin);
5199           clutter_paint_volume_set_width (volume, priv->clip.width);
5200           clutter_paint_volume_set_height (volume, priv->clip.height);
5201
5202           res = TRUE;
5203         }
5204
5205       /* if we don't have children we just bail out here... */
5206       if (priv->n_children == 0)
5207         return res;
5208
5209       /* ...but if we have children then we ask for their paint volume in
5210        * our coordinates. if any of our children replies that it doesn't
5211        * have a paint volume, we bail out
5212        */
5213       for (child = priv->first_child;
5214            child != NULL;
5215            child = child->priv->next_sibling)
5216         {
5217           const ClutterPaintVolume *child_volume;
5218
5219           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5220           if (child_volume == NULL)
5221             {
5222               res = FALSE;
5223               break;
5224             }
5225
5226           clutter_paint_volume_union (volume, child_volume);
5227           res = TRUE;
5228         }
5229     }
5230
5231   return res;
5232
5233 }
5234
5235 static gboolean
5236 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5237                                      ClutterPaintVolume *volume)
5238 {
5239   ClutterActorClass *klass;
5240   gboolean res;
5241
5242   klass = CLUTTER_ACTOR_GET_CLASS (self);
5243
5244   /* XXX - this thoroughly sucks, but we don't want to penalize users
5245    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5246    * redraw. This should go away in 2.0.
5247    */
5248   if (klass->paint == clutter_actor_real_paint &&
5249       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5250     {
5251       res = TRUE;
5252     }
5253   else
5254     {
5255       /* this is the default return value: we cannot know if a class
5256        * is going to paint outside its allocation, so we take the
5257        * conservative approach.
5258        */
5259       res = FALSE;
5260     }
5261
5262   if (clutter_actor_update_default_paint_volume (self, volume))
5263     return res;
5264
5265   return FALSE;
5266 }
5267
5268 /**
5269  * clutter_actor_get_default_paint_volume:
5270  * @self: a #ClutterActor
5271  *
5272  * Retrieves the default paint volume for @self.
5273  *
5274  * This function provides the same #ClutterPaintVolume that would be
5275  * computed by the default implementation inside #ClutterActor of the
5276  * #ClutterActorClass.get_paint_volume() virtual function.
5277  *
5278  * This function should only be used by #ClutterActor subclasses that
5279  * cannot chain up to the parent implementation when computing their
5280  * paint volume.
5281  *
5282  * Return value: (transfer none): a pointer to the default
5283  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5284  *   the actor could not compute a valid paint volume. The returned value
5285  *   is not guaranteed to be stable across multiple frames, so if you
5286  *   want to retain it, you will need to copy it using
5287  *   clutter_paint_volume_copy().
5288  *
5289  * Since: 1.10
5290  */
5291 const ClutterPaintVolume *
5292 clutter_actor_get_default_paint_volume (ClutterActor *self)
5293 {
5294   ClutterPaintVolume volume;
5295   ClutterPaintVolume *res;
5296
5297   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5298
5299   res = NULL;
5300   _clutter_paint_volume_init_static (&volume, self);
5301   if (clutter_actor_update_default_paint_volume (self, &volume))
5302     {
5303       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5304
5305       if (stage != NULL)
5306         {
5307           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5308           _clutter_paint_volume_copy_static (&volume, res);
5309         }
5310     }
5311
5312   clutter_paint_volume_free (&volume);
5313
5314   return res;
5315 }
5316
5317 static gboolean
5318 clutter_actor_real_has_overlaps (ClutterActor *self)
5319 {
5320   /* By default we'll assume that all actors need an offscreen redirect to get
5321    * the correct opacity. Actors such as ClutterTexture that would never need
5322    * an offscreen redirect can override this to return FALSE. */
5323   return TRUE;
5324 }
5325
5326 static void
5327 clutter_actor_real_destroy (ClutterActor *actor)
5328 {
5329   ClutterActorIter iter;
5330
5331   g_object_freeze_notify (G_OBJECT (actor));
5332
5333   clutter_actor_iter_init (&iter, actor);
5334   while (clutter_actor_iter_next (&iter, NULL))
5335     clutter_actor_iter_destroy (&iter);
5336
5337   g_object_thaw_notify (G_OBJECT (actor));
5338 }
5339
5340 static GObject *
5341 clutter_actor_constructor (GType gtype,
5342                            guint n_props,
5343                            GObjectConstructParam *props)
5344 {
5345   GObjectClass *gobject_class;
5346   ClutterActor *self;
5347   GObject *retval;
5348
5349   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5350   retval = gobject_class->constructor (gtype, n_props, props);
5351   self = CLUTTER_ACTOR (retval);
5352
5353   if (self->priv->layout_manager == NULL)
5354     {
5355       ClutterLayoutManager *default_layout;
5356
5357       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5358
5359       default_layout = clutter_fixed_layout_new ();
5360       clutter_actor_set_layout_manager (self, default_layout);
5361     }
5362
5363   return retval;
5364 }
5365
5366 static void
5367 clutter_actor_class_init (ClutterActorClass *klass)
5368 {
5369   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5370
5371   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5372   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5373   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5374   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5375
5376   object_class->constructor = clutter_actor_constructor;
5377   object_class->set_property = clutter_actor_set_property;
5378   object_class->get_property = clutter_actor_get_property;
5379   object_class->dispose = clutter_actor_dispose;
5380   object_class->finalize = clutter_actor_finalize;
5381
5382   klass->show = clutter_actor_real_show;
5383   klass->show_all = clutter_actor_show;
5384   klass->hide = clutter_actor_real_hide;
5385   klass->hide_all = clutter_actor_hide;
5386   klass->map = clutter_actor_real_map;
5387   klass->unmap = clutter_actor_real_unmap;
5388   klass->unrealize = clutter_actor_real_unrealize;
5389   klass->pick = clutter_actor_real_pick;
5390   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5391   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5392   klass->allocate = clutter_actor_real_allocate;
5393   klass->queue_redraw = clutter_actor_real_queue_redraw;
5394   klass->queue_relayout = clutter_actor_real_queue_relayout;
5395   klass->apply_transform = clutter_actor_real_apply_transform;
5396   klass->get_accessible = clutter_actor_real_get_accessible;
5397   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5398   klass->has_overlaps = clutter_actor_real_has_overlaps;
5399   klass->paint = clutter_actor_real_paint;
5400   klass->destroy = clutter_actor_real_destroy;
5401
5402   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5403
5404   /**
5405    * ClutterActor:x:
5406    *
5407    * X coordinate of the actor in pixels. If written, forces a fixed
5408    * position for the actor. If read, returns the fixed position if any,
5409    * otherwise the allocation if available, otherwise 0.
5410    *
5411    * The #ClutterActor:x property is animatable.
5412    */
5413   obj_props[PROP_X] =
5414     g_param_spec_float ("x",
5415                         P_("X coordinate"),
5416                         P_("X coordinate of the actor"),
5417                         -G_MAXFLOAT, G_MAXFLOAT,
5418                         0.0,
5419                         G_PARAM_READWRITE |
5420                         G_PARAM_STATIC_STRINGS |
5421                         CLUTTER_PARAM_ANIMATABLE);
5422
5423   /**
5424    * ClutterActor:y:
5425    *
5426    * Y coordinate of the actor in pixels. If written, forces a fixed
5427    * position for the actor.  If read, returns the fixed position if
5428    * any, otherwise the allocation if available, otherwise 0.
5429    *
5430    * The #ClutterActor:y property is animatable.
5431    */
5432   obj_props[PROP_Y] =
5433     g_param_spec_float ("y",
5434                         P_("Y coordinate"),
5435                         P_("Y coordinate of the actor"),
5436                         -G_MAXFLOAT, G_MAXFLOAT,
5437                         0.0,
5438                         G_PARAM_READWRITE |
5439                         G_PARAM_STATIC_STRINGS |
5440                         CLUTTER_PARAM_ANIMATABLE);
5441
5442   /**
5443    * ClutterActor:width:
5444    *
5445    * Width of the actor (in pixels). If written, forces the minimum and
5446    * natural size request of the actor to the given width. If read, returns
5447    * the allocated width if available, otherwise the width request.
5448    *
5449    * The #ClutterActor:width property is animatable.
5450    */
5451   obj_props[PROP_WIDTH] =
5452     g_param_spec_float ("width",
5453                         P_("Width"),
5454                         P_("Width of the actor"),
5455                         0.0, G_MAXFLOAT,
5456                         0.0,
5457                         G_PARAM_READWRITE |
5458                         G_PARAM_STATIC_STRINGS |
5459                         CLUTTER_PARAM_ANIMATABLE);
5460
5461   /**
5462    * ClutterActor:height:
5463    *
5464    * Height of the actor (in pixels).  If written, forces the minimum and
5465    * natural size request of the actor to the given height. If read, returns
5466    * the allocated height if available, otherwise the height request.
5467    *
5468    * The #ClutterActor:height property is animatable.
5469    */
5470   obj_props[PROP_HEIGHT] =
5471     g_param_spec_float ("height",
5472                         P_("Height"),
5473                         P_("Height of the actor"),
5474                         0.0, G_MAXFLOAT,
5475                         0.0,
5476                         G_PARAM_READWRITE |
5477                         G_PARAM_STATIC_STRINGS |
5478                         CLUTTER_PARAM_ANIMATABLE);
5479
5480   /**
5481    * ClutterActor:fixed-x:
5482    *
5483    * The fixed X position of the actor in pixels.
5484    *
5485    * Writing this property sets #ClutterActor:fixed-position-set
5486    * property as well, as a side effect
5487    *
5488    * Since: 0.8
5489    */
5490   obj_props[PROP_FIXED_X] =
5491     g_param_spec_float ("fixed-x",
5492                         P_("Fixed X"),
5493                         P_("Forced X position of the actor"),
5494                         -G_MAXFLOAT, G_MAXFLOAT,
5495                         0.0,
5496                         CLUTTER_PARAM_READWRITE);
5497
5498   /**
5499    * ClutterActor:fixed-y:
5500    *
5501    * The fixed Y position of the actor in pixels.
5502    *
5503    * Writing this property sets the #ClutterActor:fixed-position-set
5504    * property as well, as a side effect
5505    *
5506    * Since: 0.8
5507    */
5508   obj_props[PROP_FIXED_Y] =
5509     g_param_spec_float ("fixed-y",
5510                         P_("Fixed Y"),
5511                         P_("Forced Y position of the actor"),
5512                         -G_MAXFLOAT, G_MAXFLOAT,
5513                         0,
5514                         CLUTTER_PARAM_READWRITE);
5515
5516   /**
5517    * ClutterActor:fixed-position-set:
5518    *
5519    * This flag controls whether the #ClutterActor:fixed-x and
5520    * #ClutterActor:fixed-y properties are used
5521    *
5522    * Since: 0.8
5523    */
5524   obj_props[PROP_FIXED_POSITION_SET] =
5525     g_param_spec_boolean ("fixed-position-set",
5526                           P_("Fixed position set"),
5527                           P_("Whether to use fixed positioning for the actor"),
5528                           FALSE,
5529                           CLUTTER_PARAM_READWRITE);
5530
5531   /**
5532    * ClutterActor:min-width:
5533    *
5534    * A forced minimum width request for the actor, in pixels
5535    *
5536    * Writing this property sets the #ClutterActor:min-width-set property
5537    * as well, as a side effect.
5538    *
5539    *This property overrides the usual width request of the actor.
5540    *
5541    * Since: 0.8
5542    */
5543   obj_props[PROP_MIN_WIDTH] =
5544     g_param_spec_float ("min-width",
5545                         P_("Min Width"),
5546                         P_("Forced minimum width request for the actor"),
5547                         0.0, G_MAXFLOAT,
5548                         0.0,
5549                         CLUTTER_PARAM_READWRITE);
5550
5551   /**
5552    * ClutterActor:min-height:
5553    *
5554    * A forced minimum height request for the actor, in pixels
5555    *
5556    * Writing this property sets the #ClutterActor:min-height-set property
5557    * as well, as a side effect. This property overrides the usual height
5558    * request of the actor.
5559    *
5560    * Since: 0.8
5561    */
5562   obj_props[PROP_MIN_HEIGHT] =
5563     g_param_spec_float ("min-height",
5564                         P_("Min Height"),
5565                         P_("Forced minimum height request for the actor"),
5566                         0.0, G_MAXFLOAT,
5567                         0.0,
5568                         CLUTTER_PARAM_READWRITE);
5569
5570   /**
5571    * ClutterActor:natural-width:
5572    *
5573    * A forced natural width request for the actor, in pixels
5574    *
5575    * Writing this property sets the #ClutterActor:natural-width-set
5576    * property as well, as a side effect. This property overrides the
5577    * usual width request of the actor
5578    *
5579    * Since: 0.8
5580    */
5581   obj_props[PROP_NATURAL_WIDTH] =
5582     g_param_spec_float ("natural-width",
5583                         P_("Natural Width"),
5584                         P_("Forced natural width request for the actor"),
5585                         0.0, G_MAXFLOAT,
5586                         0.0,
5587                         CLUTTER_PARAM_READWRITE);
5588
5589   /**
5590    * ClutterActor:natural-height:
5591    *
5592    * A forced natural height request for the actor, in pixels
5593    *
5594    * Writing this property sets the #ClutterActor:natural-height-set
5595    * property as well, as a side effect. This property overrides the
5596    * usual height request of the actor
5597    *
5598    * Since: 0.8
5599    */
5600   obj_props[PROP_NATURAL_HEIGHT] =
5601     g_param_spec_float ("natural-height",
5602                         P_("Natural Height"),
5603                         P_("Forced natural height request for the actor"),
5604                         0.0, G_MAXFLOAT,
5605                         0.0,
5606                         CLUTTER_PARAM_READWRITE);
5607
5608   /**
5609    * ClutterActor:min-width-set:
5610    *
5611    * This flag controls whether the #ClutterActor:min-width property
5612    * is used
5613    *
5614    * Since: 0.8
5615    */
5616   obj_props[PROP_MIN_WIDTH_SET] =
5617     g_param_spec_boolean ("min-width-set",
5618                           P_("Minimum width set"),
5619                           P_("Whether to use the min-width property"),
5620                           FALSE,
5621                           CLUTTER_PARAM_READWRITE);
5622
5623   /**
5624    * ClutterActor:min-height-set:
5625    *
5626    * This flag controls whether the #ClutterActor:min-height property
5627    * is used
5628    *
5629    * Since: 0.8
5630    */
5631   obj_props[PROP_MIN_HEIGHT_SET] =
5632     g_param_spec_boolean ("min-height-set",
5633                           P_("Minimum height set"),
5634                           P_("Whether to use the min-height property"),
5635                           FALSE,
5636                           CLUTTER_PARAM_READWRITE);
5637
5638   /**
5639    * ClutterActor:natural-width-set:
5640    *
5641    * This flag controls whether the #ClutterActor:natural-width property
5642    * is used
5643    *
5644    * Since: 0.8
5645    */
5646   obj_props[PROP_NATURAL_WIDTH_SET] =
5647     g_param_spec_boolean ("natural-width-set",
5648                           P_("Natural width set"),
5649                           P_("Whether to use the natural-width property"),
5650                           FALSE,
5651                           CLUTTER_PARAM_READWRITE);
5652
5653   /**
5654    * ClutterActor:natural-height-set:
5655    *
5656    * This flag controls whether the #ClutterActor:natural-height property
5657    * is used
5658    *
5659    * Since: 0.8
5660    */
5661   obj_props[PROP_NATURAL_HEIGHT_SET] =
5662     g_param_spec_boolean ("natural-height-set",
5663                           P_("Natural height set"),
5664                           P_("Whether to use the natural-height property"),
5665                           FALSE,
5666                           CLUTTER_PARAM_READWRITE);
5667
5668   /**
5669    * ClutterActor:allocation:
5670    *
5671    * The allocation for the actor, in pixels
5672    *
5673    * This is property is read-only, but you might monitor it to know when an
5674    * actor moves or resizes
5675    *
5676    * Since: 0.8
5677    */
5678   obj_props[PROP_ALLOCATION] =
5679     g_param_spec_boxed ("allocation",
5680                         P_("Allocation"),
5681                         P_("The actor's allocation"),
5682                         CLUTTER_TYPE_ACTOR_BOX,
5683                         CLUTTER_PARAM_READABLE);
5684
5685   /**
5686    * ClutterActor:request-mode:
5687    *
5688    * Request mode for the #ClutterActor. The request mode determines the
5689    * type of geometry management used by the actor, either height for width
5690    * (the default) or width for height.
5691    *
5692    * For actors implementing height for width, the parent container should get
5693    * the preferred width first, and then the preferred height for that width.
5694    *
5695    * For actors implementing width for height, the parent container should get
5696    * the preferred height first, and then the preferred width for that height.
5697    *
5698    * For instance:
5699    *
5700    * |[
5701    *   ClutterRequestMode mode;
5702    *   gfloat natural_width, min_width;
5703    *   gfloat natural_height, min_height;
5704    *
5705    *   mode = clutter_actor_get_request_mode (child);
5706    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5707    *     {
5708    *       clutter_actor_get_preferred_width (child, -1,
5709    *                                          &amp;min_width,
5710    *                                          &amp;natural_width);
5711    *       clutter_actor_get_preferred_height (child, natural_width,
5712    *                                           &amp;min_height,
5713    *                                           &amp;natural_height);
5714    *     }
5715    *   else
5716    *     {
5717    *       clutter_actor_get_preferred_height (child, -1,
5718    *                                           &amp;min_height,
5719    *                                           &amp;natural_height);
5720    *       clutter_actor_get_preferred_width (child, natural_height,
5721    *                                          &amp;min_width,
5722    *                                          &amp;natural_width);
5723    *     }
5724    * ]|
5725    *
5726    * will retrieve the minimum and natural width and height depending on the
5727    * preferred request mode of the #ClutterActor "child".
5728    *
5729    * The clutter_actor_get_preferred_size() function will implement this
5730    * check for you.
5731    *
5732    * Since: 0.8
5733    */
5734   obj_props[PROP_REQUEST_MODE] =
5735     g_param_spec_enum ("request-mode",
5736                        P_("Request Mode"),
5737                        P_("The actor's request mode"),
5738                        CLUTTER_TYPE_REQUEST_MODE,
5739                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5740                        CLUTTER_PARAM_READWRITE);
5741
5742   /**
5743    * ClutterActor:depth:
5744    *
5745    * The position of the actor on the Z axis.
5746    *
5747    * The #ClutterActor:depth property is relative to the parent's
5748    * modelview matrix.
5749    *
5750    * The #ClutterActor:depth property is animatable.
5751    *
5752    * Since: 0.6
5753    */
5754   obj_props[PROP_DEPTH] =
5755     g_param_spec_float ("depth",
5756                         P_("Depth"),
5757                         P_("Position on the Z axis"),
5758                         -G_MAXFLOAT, G_MAXFLOAT,
5759                         0.0,
5760                         G_PARAM_READWRITE |
5761                         G_PARAM_STATIC_STRINGS |
5762                         CLUTTER_PARAM_ANIMATABLE);
5763
5764   /**
5765    * ClutterActor:opacity:
5766    *
5767    * Opacity of an actor, between 0 (fully transparent) and
5768    * 255 (fully opaque)
5769    *
5770    * The #ClutterActor:opacity property is animatable.
5771    */
5772   obj_props[PROP_OPACITY] =
5773     g_param_spec_uint ("opacity",
5774                        P_("Opacity"),
5775                        P_("Opacity of an actor"),
5776                        0, 255,
5777                        255,
5778                        G_PARAM_READWRITE |
5779                        G_PARAM_STATIC_STRINGS |
5780                        CLUTTER_PARAM_ANIMATABLE);
5781
5782   /**
5783    * ClutterActor:offscreen-redirect:
5784    *
5785    * Determines the conditions in which the actor will be redirected
5786    * to an offscreen framebuffer while being painted. For example this
5787    * can be used to cache an actor in a framebuffer or for improved
5788    * handling of transparent actors. See
5789    * clutter_actor_set_offscreen_redirect() for details.
5790    *
5791    * Since: 1.8
5792    */
5793   obj_props[PROP_OFFSCREEN_REDIRECT] =
5794     g_param_spec_flags ("offscreen-redirect",
5795                         P_("Offscreen redirect"),
5796                         P_("Flags controlling when to flatten the actor into a single image"),
5797                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5798                         0,
5799                         CLUTTER_PARAM_READWRITE);
5800
5801   /**
5802    * ClutterActor:visible:
5803    *
5804    * Whether the actor is set to be visible or not
5805    *
5806    * See also #ClutterActor:mapped
5807    */
5808   obj_props[PROP_VISIBLE] =
5809     g_param_spec_boolean ("visible",
5810                           P_("Visible"),
5811                           P_("Whether the actor is visible or not"),
5812                           FALSE,
5813                           CLUTTER_PARAM_READWRITE);
5814
5815   /**
5816    * ClutterActor:mapped:
5817    *
5818    * Whether the actor is mapped (will be painted when the stage
5819    * to which it belongs is mapped)
5820    *
5821    * Since: 1.0
5822    */
5823   obj_props[PROP_MAPPED] =
5824     g_param_spec_boolean ("mapped",
5825                           P_("Mapped"),
5826                           P_("Whether the actor will be painted"),
5827                           FALSE,
5828                           CLUTTER_PARAM_READABLE);
5829
5830   /**
5831    * ClutterActor:realized:
5832    *
5833    * Whether the actor has been realized
5834    *
5835    * Since: 1.0
5836    */
5837   obj_props[PROP_REALIZED] =
5838     g_param_spec_boolean ("realized",
5839                           P_("Realized"),
5840                           P_("Whether the actor has been realized"),
5841                           FALSE,
5842                           CLUTTER_PARAM_READABLE);
5843
5844   /**
5845    * ClutterActor:reactive:
5846    *
5847    * Whether the actor is reactive to events or not
5848    *
5849    * Only reactive actors will emit event-related signals
5850    *
5851    * Since: 0.6
5852    */
5853   obj_props[PROP_REACTIVE] =
5854     g_param_spec_boolean ("reactive",
5855                           P_("Reactive"),
5856                           P_("Whether the actor is reactive to events"),
5857                           FALSE,
5858                           CLUTTER_PARAM_READWRITE);
5859
5860   /**
5861    * ClutterActor:has-clip:
5862    *
5863    * Whether the actor has the #ClutterActor:clip property set or not
5864    */
5865   obj_props[PROP_HAS_CLIP] =
5866     g_param_spec_boolean ("has-clip",
5867                           P_("Has Clip"),
5868                           P_("Whether the actor has a clip set"),
5869                           FALSE,
5870                           CLUTTER_PARAM_READABLE);
5871
5872   /**
5873    * ClutterActor:clip:
5874    *
5875    * The clip region for the actor, in actor-relative coordinates
5876    *
5877    * Every part of the actor outside the clip region will not be
5878    * painted
5879    */
5880   obj_props[PROP_CLIP] =
5881     g_param_spec_boxed ("clip",
5882                         P_("Clip"),
5883                         P_("The clip region for the actor"),
5884                         CLUTTER_TYPE_GEOMETRY,
5885                         CLUTTER_PARAM_READWRITE);
5886
5887   /**
5888    * ClutterActor:name:
5889    *
5890    * The name of the actor
5891    *
5892    * Since: 0.2
5893    */
5894   obj_props[PROP_NAME] =
5895     g_param_spec_string ("name",
5896                          P_("Name"),
5897                          P_("Name of the actor"),
5898                          NULL,
5899                          CLUTTER_PARAM_READWRITE);
5900
5901   /**
5902    * ClutterActor:scale-x:
5903    *
5904    * The horizontal scale of the actor.
5905    *
5906    * The #ClutterActor:scale-x property is animatable.
5907    *
5908    * Since: 0.6
5909    */
5910   obj_props[PROP_SCALE_X] =
5911     g_param_spec_double ("scale-x",
5912                          P_("Scale X"),
5913                          P_("Scale factor on the X axis"),
5914                          0.0, G_MAXDOUBLE,
5915                          1.0,
5916                          G_PARAM_READWRITE |
5917                          G_PARAM_STATIC_STRINGS |
5918                          CLUTTER_PARAM_ANIMATABLE);
5919
5920   /**
5921    * ClutterActor:scale-y:
5922    *
5923    * The vertical scale of the actor.
5924    *
5925    * The #ClutterActor:scale-y property is animatable.
5926    *
5927    * Since: 0.6
5928    */
5929   obj_props[PROP_SCALE_Y] =
5930     g_param_spec_double ("scale-y",
5931                          P_("Scale Y"),
5932                          P_("Scale factor on the Y axis"),
5933                          0.0, G_MAXDOUBLE,
5934                          1.0,
5935                          G_PARAM_READWRITE |
5936                          G_PARAM_STATIC_STRINGS |
5937                          CLUTTER_PARAM_ANIMATABLE);
5938
5939   /**
5940    * ClutterActor:scale-center-x:
5941    *
5942    * The horizontal center point for scaling
5943    *
5944    * Since: 1.0
5945    */
5946   obj_props[PROP_SCALE_CENTER_X] =
5947     g_param_spec_float ("scale-center-x",
5948                         P_("Scale Center X"),
5949                         P_("Horizontal scale center"),
5950                         -G_MAXFLOAT, G_MAXFLOAT,
5951                         0.0,
5952                         CLUTTER_PARAM_READWRITE);
5953
5954   /**
5955    * ClutterActor:scale-center-y:
5956    *
5957    * The vertical center point for scaling
5958    *
5959    * Since: 1.0
5960    */
5961   obj_props[PROP_SCALE_CENTER_Y] =
5962     g_param_spec_float ("scale-center-y",
5963                         P_("Scale Center Y"),
5964                         P_("Vertical scale center"),
5965                         -G_MAXFLOAT, G_MAXFLOAT,
5966                         0.0,
5967                         CLUTTER_PARAM_READWRITE);
5968
5969   /**
5970    * ClutterActor:scale-gravity:
5971    *
5972    * The center point for scaling expressed as a #ClutterGravity
5973    *
5974    * Since: 1.0
5975    */
5976   obj_props[PROP_SCALE_GRAVITY] =
5977     g_param_spec_enum ("scale-gravity",
5978                        P_("Scale Gravity"),
5979                        P_("The center of scaling"),
5980                        CLUTTER_TYPE_GRAVITY,
5981                        CLUTTER_GRAVITY_NONE,
5982                        CLUTTER_PARAM_READWRITE);
5983
5984   /**
5985    * ClutterActor:rotation-angle-x:
5986    *
5987    * The rotation angle on the X axis.
5988    *
5989    * The #ClutterActor:rotation-angle-x property is animatable.
5990    *
5991    * Since: 0.6
5992    */
5993   obj_props[PROP_ROTATION_ANGLE_X] =
5994     g_param_spec_double ("rotation-angle-x",
5995                          P_("Rotation Angle X"),
5996                          P_("The rotation angle on the X 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-angle-y:
6005    *
6006    * The rotation angle on the Y axis
6007    *
6008    * The #ClutterActor:rotation-angle-y property is animatable.
6009    *
6010    * Since: 0.6
6011    */
6012   obj_props[PROP_ROTATION_ANGLE_Y] =
6013     g_param_spec_double ("rotation-angle-y",
6014                          P_("Rotation Angle Y"),
6015                          P_("The rotation angle on the Y axis"),
6016                          -G_MAXDOUBLE, G_MAXDOUBLE,
6017                          0.0,
6018                          G_PARAM_READWRITE |
6019                          G_PARAM_STATIC_STRINGS |
6020                          CLUTTER_PARAM_ANIMATABLE);
6021
6022   /**
6023    * ClutterActor:rotation-angle-z:
6024    *
6025    * The rotation angle on the Z axis
6026    *
6027    * The #ClutterActor:rotation-angle-z property is animatable.
6028    *
6029    * Since: 0.6
6030    */
6031   obj_props[PROP_ROTATION_ANGLE_Z] =
6032     g_param_spec_double ("rotation-angle-z",
6033                          P_("Rotation Angle Z"),
6034                          P_("The rotation angle on the Z axis"),
6035                          -G_MAXDOUBLE, G_MAXDOUBLE,
6036                          0.0,
6037                          G_PARAM_READWRITE |
6038                          G_PARAM_STATIC_STRINGS |
6039                          CLUTTER_PARAM_ANIMATABLE);
6040
6041   /**
6042    * ClutterActor:rotation-center-x:
6043    *
6044    * The rotation center on the X axis.
6045    *
6046    * Since: 0.6
6047    */
6048   obj_props[PROP_ROTATION_CENTER_X] =
6049     g_param_spec_boxed ("rotation-center-x",
6050                         P_("Rotation Center X"),
6051                         P_("The rotation center on the X axis"),
6052                         CLUTTER_TYPE_VERTEX,
6053                         CLUTTER_PARAM_READWRITE);
6054
6055   /**
6056    * ClutterActor:rotation-center-y:
6057    *
6058    * The rotation center on the Y axis.
6059    *
6060    * Since: 0.6
6061    */
6062   obj_props[PROP_ROTATION_CENTER_Y] =
6063     g_param_spec_boxed ("rotation-center-y",
6064                         P_("Rotation Center Y"),
6065                         P_("The rotation center on the Y axis"),
6066                         CLUTTER_TYPE_VERTEX,
6067                         CLUTTER_PARAM_READWRITE);
6068
6069   /**
6070    * ClutterActor:rotation-center-z:
6071    *
6072    * The rotation center on the Z axis.
6073    *
6074    * Since: 0.6
6075    */
6076   obj_props[PROP_ROTATION_CENTER_Z] =
6077     g_param_spec_boxed ("rotation-center-z",
6078                         P_("Rotation Center Z"),
6079                         P_("The rotation center on the Z axis"),
6080                         CLUTTER_TYPE_VERTEX,
6081                         CLUTTER_PARAM_READWRITE);
6082
6083   /**
6084    * ClutterActor:rotation-center-z-gravity:
6085    *
6086    * The rotation center on the Z axis expressed as a #ClutterGravity.
6087    *
6088    * Since: 1.0
6089    */
6090   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6091     g_param_spec_enum ("rotation-center-z-gravity",
6092                        P_("Rotation Center Z Gravity"),
6093                        P_("Center point for rotation around the Z axis"),
6094                        CLUTTER_TYPE_GRAVITY,
6095                        CLUTTER_GRAVITY_NONE,
6096                        CLUTTER_PARAM_READWRITE);
6097
6098   /**
6099    * ClutterActor:anchor-x:
6100    *
6101    * The X coordinate of an actor's anchor point, relative to
6102    * the actor coordinate space, in pixels
6103    *
6104    * Since: 0.8
6105    */
6106   obj_props[PROP_ANCHOR_X] =
6107     g_param_spec_float ("anchor-x",
6108                         P_("Anchor X"),
6109                         P_("X coordinate of the anchor point"),
6110                         -G_MAXFLOAT, G_MAXFLOAT,
6111                         0,
6112                         CLUTTER_PARAM_READWRITE);
6113
6114   /**
6115    * ClutterActor:anchor-y:
6116    *
6117    * The Y coordinate of an actor's anchor point, relative to
6118    * the actor coordinate space, in pixels
6119    *
6120    * Since: 0.8
6121    */
6122   obj_props[PROP_ANCHOR_Y] =
6123     g_param_spec_float ("anchor-y",
6124                         P_("Anchor Y"),
6125                         P_("Y coordinate of the anchor point"),
6126                         -G_MAXFLOAT, G_MAXFLOAT,
6127                         0,
6128                         CLUTTER_PARAM_READWRITE);
6129
6130   /**
6131    * ClutterActor:anchor-gravity:
6132    *
6133    * The anchor point expressed as a #ClutterGravity
6134    *
6135    * Since: 1.0
6136    */
6137   obj_props[PROP_ANCHOR_GRAVITY] =
6138     g_param_spec_enum ("anchor-gravity",
6139                        P_("Anchor Gravity"),
6140                        P_("The anchor point as a ClutterGravity"),
6141                        CLUTTER_TYPE_GRAVITY,
6142                        CLUTTER_GRAVITY_NONE,
6143                        CLUTTER_PARAM_READWRITE);
6144
6145   /**
6146    * ClutterActor:show-on-set-parent:
6147    *
6148    * If %TRUE, the actor is automatically shown when parented.
6149    *
6150    * Calling clutter_actor_hide() on an actor which has not been
6151    * parented will set this property to %FALSE as a side effect.
6152    *
6153    * Since: 0.8
6154    */
6155   obj_props[PROP_SHOW_ON_SET_PARENT] =
6156     g_param_spec_boolean ("show-on-set-parent",
6157                           P_("Show on set parent"),
6158                           P_("Whether the actor is shown when parented"),
6159                           TRUE,
6160                           CLUTTER_PARAM_READWRITE);
6161
6162   /**
6163    * ClutterActor:clip-to-allocation:
6164    *
6165    * Whether the clip region should track the allocated area
6166    * of the actor.
6167    *
6168    * This property is ignored if a clip area has been explicitly
6169    * set using clutter_actor_set_clip().
6170    *
6171    * Since: 1.0
6172    */
6173   obj_props[PROP_CLIP_TO_ALLOCATION] =
6174     g_param_spec_boolean ("clip-to-allocation",
6175                           P_("Clip to Allocation"),
6176                           P_("Sets the clip region to track the actor's allocation"),
6177                           FALSE,
6178                           CLUTTER_PARAM_READWRITE);
6179
6180   /**
6181    * ClutterActor:text-direction:
6182    *
6183    * The direction of the text inside a #ClutterActor.
6184    *
6185    * Since: 1.0
6186    */
6187   obj_props[PROP_TEXT_DIRECTION] =
6188     g_param_spec_enum ("text-direction",
6189                        P_("Text Direction"),
6190                        P_("Direction of the text"),
6191                        CLUTTER_TYPE_TEXT_DIRECTION,
6192                        CLUTTER_TEXT_DIRECTION_LTR,
6193                        CLUTTER_PARAM_READWRITE);
6194
6195   /**
6196    * ClutterActor:has-pointer:
6197    *
6198    * Whether the actor contains the pointer of a #ClutterInputDevice
6199    * or not.
6200    *
6201    * Since: 1.2
6202    */
6203   obj_props[PROP_HAS_POINTER] =
6204     g_param_spec_boolean ("has-pointer",
6205                           P_("Has Pointer"),
6206                           P_("Whether the actor contains the pointer of an input device"),
6207                           FALSE,
6208                           CLUTTER_PARAM_READABLE);
6209
6210   /**
6211    * ClutterActor:actions:
6212    *
6213    * Adds a #ClutterAction to the actor
6214    *
6215    * Since: 1.4
6216    */
6217   obj_props[PROP_ACTIONS] =
6218     g_param_spec_object ("actions",
6219                          P_("Actions"),
6220                          P_("Adds an action to the actor"),
6221                          CLUTTER_TYPE_ACTION,
6222                          CLUTTER_PARAM_WRITABLE);
6223
6224   /**
6225    * ClutterActor:constraints:
6226    *
6227    * Adds a #ClutterConstraint to the actor
6228    *
6229    * Since: 1.4
6230    */
6231   obj_props[PROP_CONSTRAINTS] =
6232     g_param_spec_object ("constraints",
6233                          P_("Constraints"),
6234                          P_("Adds a constraint to the actor"),
6235                          CLUTTER_TYPE_CONSTRAINT,
6236                          CLUTTER_PARAM_WRITABLE);
6237
6238   /**
6239    * ClutterActor:effect:
6240    *
6241    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6242    *
6243    * Since: 1.4
6244    */
6245   obj_props[PROP_EFFECT] =
6246     g_param_spec_object ("effect",
6247                          P_("Effect"),
6248                          P_("Add an effect to be applied on the actor"),
6249                          CLUTTER_TYPE_EFFECT,
6250                          CLUTTER_PARAM_WRITABLE);
6251
6252   /**
6253    * ClutterActor:layout-manager:
6254    *
6255    * A delegate object for controlling the layout of the children of
6256    * an actor.
6257    *
6258    * Since: 1.10
6259    */
6260   obj_props[PROP_LAYOUT_MANAGER] =
6261     g_param_spec_object ("layout-manager",
6262                          P_("Layout Manager"),
6263                          P_("The object controlling the layout of an actor's children"),
6264                          CLUTTER_TYPE_LAYOUT_MANAGER,
6265                          CLUTTER_PARAM_READWRITE);
6266
6267
6268   /**
6269    * ClutterActor:x-align:
6270    *
6271    * The alignment of an actor on the X axis, if the actor has been given
6272    * extra space for its allocation.
6273    *
6274    * Since: 1.10
6275    */
6276   obj_props[PROP_X_ALIGN] =
6277     g_param_spec_enum ("x-align",
6278                        P_("X Alignment"),
6279                        P_("The alignment of the actor on the X axis within its allocation"),
6280                        CLUTTER_TYPE_ACTOR_ALIGN,
6281                        CLUTTER_ACTOR_ALIGN_FILL,
6282                        CLUTTER_PARAM_READWRITE);
6283
6284   /**
6285    * ClutterActor:y-align:
6286    *
6287    * The alignment of an actor on the Y axis, if the actor has been given
6288    * extra space for its allocation.
6289    *
6290    * Since: 1.10
6291    */
6292   obj_props[PROP_Y_ALIGN] =
6293     g_param_spec_enum ("y-align",
6294                        P_("Y Alignment"),
6295                        P_("The alignment of the actor on the Y axis within its allocation"),
6296                        CLUTTER_TYPE_ACTOR_ALIGN,
6297                        CLUTTER_ACTOR_ALIGN_FILL,
6298                        CLUTTER_PARAM_READWRITE);
6299
6300   /**
6301    * ClutterActor:margin-top:
6302    *
6303    * The margin (in pixels) from the top of the actor.
6304    *
6305    * This property adds a margin to the actor's preferred size; the margin
6306    * will be automatically taken into account when allocating the actor.
6307    *
6308    * Since: 1.10
6309    */
6310   obj_props[PROP_MARGIN_TOP] =
6311     g_param_spec_float ("margin-top",
6312                         P_("Margin Top"),
6313                         P_("Extra space at the top"),
6314                         0.0, G_MAXFLOAT,
6315                         0.0,
6316                         CLUTTER_PARAM_READWRITE);
6317
6318   /**
6319    * ClutterActor:margin-bottom:
6320    *
6321    * The margin (in pixels) from the bottom of the actor.
6322    *
6323    * This property adds a margin to the actor's preferred size; the margin
6324    * will be automatically taken into account when allocating the actor.
6325    *
6326    * Since: 1.10
6327    */
6328   obj_props[PROP_MARGIN_BOTTOM] =
6329     g_param_spec_float ("margin-bottom",
6330                         P_("Margin Bottom"),
6331                         P_("Extra space at the bottom"),
6332                         0.0, G_MAXFLOAT,
6333                         0.0,
6334                         CLUTTER_PARAM_READWRITE);
6335
6336   /**
6337    * ClutterActor:margin-left:
6338    *
6339    * The margin (in pixels) from the left of the actor.
6340    *
6341    * This property adds a margin to the actor's preferred size; the margin
6342    * will be automatically taken into account when allocating the actor.
6343    *
6344    * Since: 1.10
6345    */
6346   obj_props[PROP_MARGIN_LEFT] =
6347     g_param_spec_float ("margin-left",
6348                         P_("Margin Left"),
6349                         P_("Extra space at the left"),
6350                         0.0, G_MAXFLOAT,
6351                         0.0,
6352                         CLUTTER_PARAM_READWRITE);
6353
6354   /**
6355    * ClutterActor:margin-right:
6356    *
6357    * The margin (in pixels) from the right of the actor.
6358    *
6359    * This property adds a margin to the actor's preferred size; the margin
6360    * will be automatically taken into account when allocating the actor.
6361    *
6362    * Since: 1.10
6363    */
6364   obj_props[PROP_MARGIN_RIGHT] =
6365     g_param_spec_float ("margin-right",
6366                         P_("Margin Right"),
6367                         P_("Extra space at the right"),
6368                         0.0, G_MAXFLOAT,
6369                         0.0,
6370                         CLUTTER_PARAM_READWRITE);
6371
6372   /**
6373    * ClutterActor:background-color-set:
6374    *
6375    * Whether the #ClutterActor:background-color property has been set.
6376    *
6377    * Since: 1.10
6378    */
6379   obj_props[PROP_BACKGROUND_COLOR_SET] =
6380     g_param_spec_boolean ("background-color-set",
6381                           P_("Background Color Set"),
6382                           P_("Whether the background color is set"),
6383                           FALSE,
6384                           CLUTTER_PARAM_READABLE);
6385
6386   /**
6387    * ClutterActor:background-color:
6388    *
6389    * Paints a solid fill of the actor's allocation using the specified
6390    * color.
6391    *
6392    * The #ClutterActor:background-color property is animatable.
6393    *
6394    * Since: 1.10
6395    */
6396   obj_props[PROP_BACKGROUND_COLOR] =
6397     clutter_param_spec_color ("background-color",
6398                               P_("Background color"),
6399                               P_("The actor's background color"),
6400                               CLUTTER_COLOR_Transparent,
6401                               G_PARAM_READWRITE |
6402                               G_PARAM_STATIC_STRINGS |
6403                               CLUTTER_PARAM_ANIMATABLE);
6404
6405   /**
6406    * ClutterActor:first-child:
6407    *
6408    * The actor's first child.
6409    *
6410    * Since: 1.10
6411    */
6412   obj_props[PROP_FIRST_CHILD] =
6413     g_param_spec_object ("first-child",
6414                          P_("First Child"),
6415                          P_("The actor's first child"),
6416                          CLUTTER_TYPE_ACTOR,
6417                          CLUTTER_PARAM_READABLE);
6418
6419   /**
6420    * ClutterActor:last-child:
6421    *
6422    * The actor's last child.
6423    *
6424    * Since: 1.10
6425    */
6426   obj_props[PROP_LAST_CHILD] =
6427     g_param_spec_object ("last-child",
6428                          P_("Last Child"),
6429                          P_("The actor's last child"),
6430                          CLUTTER_TYPE_ACTOR,
6431                          CLUTTER_PARAM_READABLE);
6432
6433   /**
6434    * ClutterActor:content:
6435    *
6436    * The #ClutterContent implementation that controls the content
6437    * of the actor.
6438    *
6439    * Since: 1.10
6440    */
6441   obj_props[PROP_CONTENT] =
6442     g_param_spec_object ("content",
6443                          P_("Content"),
6444                          P_("Delegate object for painting the actor's content"),
6445                          CLUTTER_TYPE_CONTENT,
6446                          CLUTTER_PARAM_READWRITE);
6447
6448   /**
6449    * ClutterActor:content-gravity:
6450    *
6451    * The alignment that should be honoured by the #ClutterContent
6452    * set with the #ClutterActor:content property.
6453    *
6454    * Changing the value of this property will change the bounding box of
6455    * the content; you can use the #ClutterActor:content-box property to
6456    * get the position and size of the content within the actor's
6457    * allocation.
6458    *
6459    * This property is meaningful only for #ClutterContent implementations
6460    * that have a preferred size, and if the preferred size is smaller than
6461    * the actor's allocation.
6462    *
6463    * Since: 1.10
6464    */
6465   obj_props[PROP_CONTENT_GRAVITY] =
6466     g_param_spec_enum ("content-gravity",
6467                        P_("Content Gravity"),
6468                        P_("Alignment of the actor's content"),
6469                        CLUTTER_TYPE_CONTENT_GRAVITY,
6470                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6471                        CLUTTER_PARAM_READWRITE);
6472
6473   /**
6474    * ClutterActor:content-box:
6475    *
6476    * The bounding box for the #ClutterContent used by the actor.
6477    *
6478    * The value of this property is controlled by the #ClutterActor:allocation
6479    * and #ClutterActor:content-gravity properties of #ClutterActor.
6480    *
6481    * The bounding box for the content is guaranteed to never exceed the
6482    * allocation's of the actor.
6483    *
6484    * Since: 1.10
6485    */
6486   obj_props[PROP_CONTENT_BOX] =
6487     g_param_spec_boxed ("content-box",
6488                         P_("Content Box"),
6489                         P_("The bounding box of the actor's content"),
6490                         CLUTTER_TYPE_ACTOR_BOX,
6491                         CLUTTER_PARAM_READABLE);
6492
6493   obj_props[PROP_MINIFICATION_FILTER] =
6494     g_param_spec_enum ("minification-filter",
6495                        P_("Minification Filter"),
6496                        P_("The filter used when reducing the size of the content"),
6497                        CLUTTER_TYPE_SCALING_FILTER,
6498                        CLUTTER_SCALING_FILTER_LINEAR,
6499                        CLUTTER_PARAM_READWRITE);
6500
6501   obj_props[PROP_MAGNIFICATION_FILTER] =
6502     g_param_spec_enum ("magnification-filter",
6503                        P_("Magnification Filter"),
6504                        P_("The filter used when increasing the size of the content"),
6505                        CLUTTER_TYPE_SCALING_FILTER,
6506                        CLUTTER_SCALING_FILTER_LINEAR,
6507                        CLUTTER_PARAM_READWRITE);
6508
6509   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6510
6511   /**
6512    * ClutterActor::destroy:
6513    * @actor: the #ClutterActor which emitted the signal
6514    *
6515    * The ::destroy signal notifies that all references held on the
6516    * actor which emitted it should be released.
6517    *
6518    * The ::destroy signal should be used by all holders of a reference
6519    * on @actor.
6520    *
6521    * This signal might result in the finalization of the #ClutterActor
6522    * if all references are released.
6523    *
6524    * Composite actors and actors implementing the #ClutterContainer
6525    * interface should override the default implementation of the
6526    * class handler of this signal and call clutter_actor_destroy() on
6527    * their children. When overriding the default class handler, it is
6528    * required to chain up to the parent's implementation.
6529    *
6530    * Since: 0.2
6531    */
6532   actor_signals[DESTROY] =
6533     g_signal_new (I_("destroy"),
6534                   G_TYPE_FROM_CLASS (object_class),
6535                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6536                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6537                   NULL, NULL,
6538                   _clutter_marshal_VOID__VOID,
6539                   G_TYPE_NONE, 0);
6540   /**
6541    * ClutterActor::show:
6542    * @actor: the object which received the signal
6543    *
6544    * The ::show signal is emitted when an actor is visible and
6545    * rendered on the stage.
6546    *
6547    * Since: 0.2
6548    */
6549   actor_signals[SHOW] =
6550     g_signal_new (I_("show"),
6551                   G_TYPE_FROM_CLASS (object_class),
6552                   G_SIGNAL_RUN_FIRST,
6553                   G_STRUCT_OFFSET (ClutterActorClass, show),
6554                   NULL, NULL,
6555                   _clutter_marshal_VOID__VOID,
6556                   G_TYPE_NONE, 0);
6557   /**
6558    * ClutterActor::hide:
6559    * @actor: the object which received the signal
6560    *
6561    * The ::hide signal is emitted when an actor is no longer rendered
6562    * on the stage.
6563    *
6564    * Since: 0.2
6565    */
6566   actor_signals[HIDE] =
6567     g_signal_new (I_("hide"),
6568                   G_TYPE_FROM_CLASS (object_class),
6569                   G_SIGNAL_RUN_FIRST,
6570                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6571                   NULL, NULL,
6572                   _clutter_marshal_VOID__VOID,
6573                   G_TYPE_NONE, 0);
6574   /**
6575    * ClutterActor::parent-set:
6576    * @actor: the object which received the signal
6577    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6578    *
6579    * This signal is emitted when the parent of the actor changes.
6580    *
6581    * Since: 0.2
6582    */
6583   actor_signals[PARENT_SET] =
6584     g_signal_new (I_("parent-set"),
6585                   G_TYPE_FROM_CLASS (object_class),
6586                   G_SIGNAL_RUN_LAST,
6587                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6588                   NULL, NULL,
6589                   _clutter_marshal_VOID__OBJECT,
6590                   G_TYPE_NONE, 1,
6591                   CLUTTER_TYPE_ACTOR);
6592
6593   /**
6594    * ClutterActor::queue-redraw:
6595    * @actor: the actor we're bubbling the redraw request through
6596    * @origin: the actor which initiated the redraw request
6597    *
6598    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6599    * is called on @origin.
6600    *
6601    * The default implementation for #ClutterActor chains up to the
6602    * parent actor and queues a redraw on the parent, thus "bubbling"
6603    * the redraw queue up through the actor graph. The default
6604    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6605    * in a main loop idle handler.
6606    *
6607    * Note that the @origin actor may be the stage, or a container; it
6608    * does not have to be a leaf node in the actor graph.
6609    *
6610    * Toolkits embedding a #ClutterStage which require a redraw and
6611    * relayout cycle can stop the emission of this signal using the
6612    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6613    * themselves, like:
6614    *
6615    * |[
6616    *   static void
6617    *   on_redraw_complete (gpointer data)
6618    *   {
6619    *     ClutterStage *stage = data;
6620    *
6621    *     /&ast; execute the Clutter drawing pipeline &ast;/
6622    *     clutter_stage_ensure_redraw (stage);
6623    *   }
6624    *
6625    *   static void
6626    *   on_stage_queue_redraw (ClutterStage *stage)
6627    *   {
6628    *     /&ast; this prevents the default handler to run &ast;/
6629    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6630    *
6631    *     /&ast; queue a redraw with the host toolkit and call
6632    *      &ast; a function when the redraw has been completed
6633    *      &ast;/
6634    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6635    *   }
6636    * ]|
6637    *
6638    * <note><para>This signal is emitted before the Clutter paint
6639    * pipeline is executed. If you want to know when the pipeline has
6640    * been completed you should connect to the ::paint signal on the
6641    * Stage with g_signal_connect_after().</para></note>
6642    *
6643    * Since: 1.0
6644    */
6645   actor_signals[QUEUE_REDRAW] =
6646     g_signal_new (I_("queue-redraw"),
6647                   G_TYPE_FROM_CLASS (object_class),
6648                   G_SIGNAL_RUN_LAST |
6649                   G_SIGNAL_NO_HOOKS,
6650                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6651                   NULL, NULL,
6652                   _clutter_marshal_VOID__OBJECT,
6653                   G_TYPE_NONE, 1,
6654                   CLUTTER_TYPE_ACTOR);
6655
6656   /**
6657    * ClutterActor::queue-relayout
6658    * @actor: the actor being queued for relayout
6659    *
6660    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6661    * is called on an actor.
6662    *
6663    * The default implementation for #ClutterActor chains up to the
6664    * parent actor and queues a relayout on the parent, thus "bubbling"
6665    * the relayout queue up through the actor graph.
6666    *
6667    * The main purpose of this signal is to allow relayout to be propagated
6668    * properly in the procense of #ClutterClone actors. Applications will
6669    * not normally need to connect to this signal.
6670    *
6671    * Since: 1.2
6672    */
6673   actor_signals[QUEUE_RELAYOUT] =
6674     g_signal_new (I_("queue-relayout"),
6675                   G_TYPE_FROM_CLASS (object_class),
6676                   G_SIGNAL_RUN_LAST |
6677                   G_SIGNAL_NO_HOOKS,
6678                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6679                   NULL, NULL,
6680                   _clutter_marshal_VOID__VOID,
6681                   G_TYPE_NONE, 0);
6682
6683   /**
6684    * ClutterActor::event:
6685    * @actor: the actor which received the event
6686    * @event: a #ClutterEvent
6687    *
6688    * The ::event signal is emitted each time an event is received
6689    * by the @actor. This signal will be emitted on every actor,
6690    * following the hierarchy chain, until it reaches the top-level
6691    * container (the #ClutterStage).
6692    *
6693    * Return value: %TRUE if the event has been handled by the actor,
6694    *   or %FALSE to continue the emission.
6695    *
6696    * Since: 0.6
6697    */
6698   actor_signals[EVENT] =
6699     g_signal_new (I_("event"),
6700                   G_TYPE_FROM_CLASS (object_class),
6701                   G_SIGNAL_RUN_LAST,
6702                   G_STRUCT_OFFSET (ClutterActorClass, event),
6703                   _clutter_boolean_handled_accumulator, NULL,
6704                   _clutter_marshal_BOOLEAN__BOXED,
6705                   G_TYPE_BOOLEAN, 1,
6706                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6707   /**
6708    * ClutterActor::button-press-event:
6709    * @actor: the actor which received the event
6710    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6711    *
6712    * The ::button-press-event signal is emitted each time a mouse button
6713    * is pressed on @actor.
6714    *
6715    * Return value: %TRUE if the event has been handled by the actor,
6716    *   or %FALSE to continue the emission.
6717    *
6718    * Since: 0.6
6719    */
6720   actor_signals[BUTTON_PRESS_EVENT] =
6721     g_signal_new (I_("button-press-event"),
6722                   G_TYPE_FROM_CLASS (object_class),
6723                   G_SIGNAL_RUN_LAST,
6724                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6725                   _clutter_boolean_handled_accumulator, NULL,
6726                   _clutter_marshal_BOOLEAN__BOXED,
6727                   G_TYPE_BOOLEAN, 1,
6728                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6729   /**
6730    * ClutterActor::button-release-event:
6731    * @actor: the actor which received the event
6732    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6733    *
6734    * The ::button-release-event signal is emitted each time a mouse button
6735    * is released on @actor.
6736    *
6737    * Return value: %TRUE if the event has been handled by the actor,
6738    *   or %FALSE to continue the emission.
6739    *
6740    * Since: 0.6
6741    */
6742   actor_signals[BUTTON_RELEASE_EVENT] =
6743     g_signal_new (I_("button-release-event"),
6744                   G_TYPE_FROM_CLASS (object_class),
6745                   G_SIGNAL_RUN_LAST,
6746                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6747                   _clutter_boolean_handled_accumulator, NULL,
6748                   _clutter_marshal_BOOLEAN__BOXED,
6749                   G_TYPE_BOOLEAN, 1,
6750                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6751   /**
6752    * ClutterActor::scroll-event:
6753    * @actor: the actor which received the event
6754    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6755    *
6756    * The ::scroll-event signal is emitted each time the mouse is
6757    * scrolled on @actor
6758    *
6759    * Return value: %TRUE if the event has been handled by the actor,
6760    *   or %FALSE to continue the emission.
6761    *
6762    * Since: 0.6
6763    */
6764   actor_signals[SCROLL_EVENT] =
6765     g_signal_new (I_("scroll-event"),
6766                   G_TYPE_FROM_CLASS (object_class),
6767                   G_SIGNAL_RUN_LAST,
6768                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6769                   _clutter_boolean_handled_accumulator, NULL,
6770                   _clutter_marshal_BOOLEAN__BOXED,
6771                   G_TYPE_BOOLEAN, 1,
6772                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6773   /**
6774    * ClutterActor::key-press-event:
6775    * @actor: the actor which received the event
6776    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6777    *
6778    * The ::key-press-event signal is emitted each time a keyboard button
6779    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6780    *
6781    * Return value: %TRUE if the event has been handled by the actor,
6782    *   or %FALSE to continue the emission.
6783    *
6784    * Since: 0.6
6785    */
6786   actor_signals[KEY_PRESS_EVENT] =
6787     g_signal_new (I_("key-press-event"),
6788                   G_TYPE_FROM_CLASS (object_class),
6789                   G_SIGNAL_RUN_LAST,
6790                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6791                   _clutter_boolean_handled_accumulator, NULL,
6792                   _clutter_marshal_BOOLEAN__BOXED,
6793                   G_TYPE_BOOLEAN, 1,
6794                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6795   /**
6796    * ClutterActor::key-release-event:
6797    * @actor: the actor which received the event
6798    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6799    *
6800    * The ::key-release-event signal is emitted each time a keyboard button
6801    * is released while @actor has key focus (see
6802    * clutter_stage_set_key_focus()).
6803    *
6804    * Return value: %TRUE if the event has been handled by the actor,
6805    *   or %FALSE to continue the emission.
6806    *
6807    * Since: 0.6
6808    */
6809   actor_signals[KEY_RELEASE_EVENT] =
6810     g_signal_new (I_("key-release-event"),
6811                   G_TYPE_FROM_CLASS (object_class),
6812                   G_SIGNAL_RUN_LAST,
6813                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6814                   _clutter_boolean_handled_accumulator, NULL,
6815                   _clutter_marshal_BOOLEAN__BOXED,
6816                   G_TYPE_BOOLEAN, 1,
6817                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6818   /**
6819    * ClutterActor::motion-event:
6820    * @actor: the actor which received the event
6821    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6822    *
6823    * The ::motion-event signal is emitted each time the mouse pointer is
6824    * moved over @actor.
6825    *
6826    * Return value: %TRUE if the event has been handled by the actor,
6827    *   or %FALSE to continue the emission.
6828    *
6829    * Since: 0.6
6830    */
6831   actor_signals[MOTION_EVENT] =
6832     g_signal_new (I_("motion-event"),
6833                   G_TYPE_FROM_CLASS (object_class),
6834                   G_SIGNAL_RUN_LAST,
6835                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6836                   _clutter_boolean_handled_accumulator, NULL,
6837                   _clutter_marshal_BOOLEAN__BOXED,
6838                   G_TYPE_BOOLEAN, 1,
6839                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6840
6841   /**
6842    * ClutterActor::key-focus-in:
6843    * @actor: the actor which now has key focus
6844    *
6845    * The ::key-focus-in signal is emitted when @actor receives key focus.
6846    *
6847    * Since: 0.6
6848    */
6849   actor_signals[KEY_FOCUS_IN] =
6850     g_signal_new (I_("key-focus-in"),
6851                   G_TYPE_FROM_CLASS (object_class),
6852                   G_SIGNAL_RUN_LAST,
6853                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6854                   NULL, NULL,
6855                   _clutter_marshal_VOID__VOID,
6856                   G_TYPE_NONE, 0);
6857
6858   /**
6859    * ClutterActor::key-focus-out:
6860    * @actor: the actor which now has key focus
6861    *
6862    * The ::key-focus-out signal is emitted when @actor loses key focus.
6863    *
6864    * Since: 0.6
6865    */
6866   actor_signals[KEY_FOCUS_OUT] =
6867     g_signal_new (I_("key-focus-out"),
6868                   G_TYPE_FROM_CLASS (object_class),
6869                   G_SIGNAL_RUN_LAST,
6870                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6871                   NULL, NULL,
6872                   _clutter_marshal_VOID__VOID,
6873                   G_TYPE_NONE, 0);
6874
6875   /**
6876    * ClutterActor::enter-event:
6877    * @actor: the actor which the pointer has entered.
6878    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6879    *
6880    * The ::enter-event signal is emitted when the pointer enters the @actor
6881    *
6882    * Return value: %TRUE if the event has been handled by the actor,
6883    *   or %FALSE to continue the emission.
6884    *
6885    * Since: 0.6
6886    */
6887   actor_signals[ENTER_EVENT] =
6888     g_signal_new (I_("enter-event"),
6889                   G_TYPE_FROM_CLASS (object_class),
6890                   G_SIGNAL_RUN_LAST,
6891                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6892                   _clutter_boolean_handled_accumulator, NULL,
6893                   _clutter_marshal_BOOLEAN__BOXED,
6894                   G_TYPE_BOOLEAN, 1,
6895                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6896
6897   /**
6898    * ClutterActor::leave-event:
6899    * @actor: the actor which the pointer has left
6900    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6901    *
6902    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6903    *
6904    * Return value: %TRUE if the event has been handled by the actor,
6905    *   or %FALSE to continue the emission.
6906    *
6907    * Since: 0.6
6908    */
6909   actor_signals[LEAVE_EVENT] =
6910     g_signal_new (I_("leave-event"),
6911                   G_TYPE_FROM_CLASS (object_class),
6912                   G_SIGNAL_RUN_LAST,
6913                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6914                   _clutter_boolean_handled_accumulator, NULL,
6915                   _clutter_marshal_BOOLEAN__BOXED,
6916                   G_TYPE_BOOLEAN, 1,
6917                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6918
6919   /**
6920    * ClutterActor::captured-event:
6921    * @actor: the actor which received the signal
6922    * @event: a #ClutterEvent
6923    *
6924    * The ::captured-event signal is emitted when an event is captured
6925    * by Clutter. This signal will be emitted starting from the top-level
6926    * container (the #ClutterStage) to the actor which received the event
6927    * going down the hierarchy. This signal can be used to intercept every
6928    * event before the specialized events (like
6929    * ClutterActor::button-press-event or ::key-released-event) are
6930    * emitted.
6931    *
6932    * Return value: %TRUE if the event has been handled by the actor,
6933    *   or %FALSE to continue the emission.
6934    *
6935    * Since: 0.6
6936    */
6937   actor_signals[CAPTURED_EVENT] =
6938     g_signal_new (I_("captured-event"),
6939                   G_TYPE_FROM_CLASS (object_class),
6940                   G_SIGNAL_RUN_LAST,
6941                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6942                   _clutter_boolean_handled_accumulator, NULL,
6943                   _clutter_marshal_BOOLEAN__BOXED,
6944                   G_TYPE_BOOLEAN, 1,
6945                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6946
6947   /**
6948    * ClutterActor::paint:
6949    * @actor: the #ClutterActor that received the signal
6950    *
6951    * The ::paint signal is emitted each time an actor is being painted.
6952    *
6953    * Subclasses of #ClutterActor should override the class signal handler
6954    * and paint themselves in that function.
6955    *
6956    * It is possible to connect a handler to the ::paint signal in order
6957    * to set up some custom aspect of a paint.
6958    *
6959    * Since: 0.8
6960    */
6961   actor_signals[PAINT] =
6962     g_signal_new (I_("paint"),
6963                   G_TYPE_FROM_CLASS (object_class),
6964                   G_SIGNAL_RUN_LAST |
6965                   G_SIGNAL_NO_HOOKS,
6966                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6967                   NULL, NULL,
6968                   _clutter_marshal_VOID__VOID,
6969                   G_TYPE_NONE, 0);
6970   /**
6971    * ClutterActor::realize:
6972    * @actor: the #ClutterActor that received the signal
6973    *
6974    * The ::realize signal is emitted each time an actor is being
6975    * realized.
6976    *
6977    * Since: 0.8
6978    */
6979   actor_signals[REALIZE] =
6980     g_signal_new (I_("realize"),
6981                   G_TYPE_FROM_CLASS (object_class),
6982                   G_SIGNAL_RUN_LAST,
6983                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6984                   NULL, NULL,
6985                   _clutter_marshal_VOID__VOID,
6986                   G_TYPE_NONE, 0);
6987   /**
6988    * ClutterActor::unrealize:
6989    * @actor: the #ClutterActor that received the signal
6990    *
6991    * The ::unrealize signal is emitted each time an actor is being
6992    * unrealized.
6993    *
6994    * Since: 0.8
6995    */
6996   actor_signals[UNREALIZE] =
6997     g_signal_new (I_("unrealize"),
6998                   G_TYPE_FROM_CLASS (object_class),
6999                   G_SIGNAL_RUN_LAST,
7000                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7001                   NULL, NULL,
7002                   _clutter_marshal_VOID__VOID,
7003                   G_TYPE_NONE, 0);
7004
7005   /**
7006    * ClutterActor::pick:
7007    * @actor: the #ClutterActor that received the signal
7008    * @color: the #ClutterColor to be used when picking
7009    *
7010    * The ::pick signal is emitted each time an actor is being painted
7011    * in "pick mode". The pick mode is used to identify the actor during
7012    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7013    * The actor should paint its shape using the passed @pick_color.
7014    *
7015    * Subclasses of #ClutterActor should override the class signal handler
7016    * and paint themselves in that function.
7017    *
7018    * It is possible to connect a handler to the ::pick signal in order
7019    * to set up some custom aspect of a paint in pick mode.
7020    *
7021    * Since: 1.0
7022    */
7023   actor_signals[PICK] =
7024     g_signal_new (I_("pick"),
7025                   G_TYPE_FROM_CLASS (object_class),
7026                   G_SIGNAL_RUN_LAST,
7027                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7028                   NULL, NULL,
7029                   _clutter_marshal_VOID__BOXED,
7030                   G_TYPE_NONE, 1,
7031                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7032
7033   /**
7034    * ClutterActor::allocation-changed:
7035    * @actor: the #ClutterActor that emitted the signal
7036    * @box: a #ClutterActorBox with the new allocation
7037    * @flags: #ClutterAllocationFlags for the allocation
7038    *
7039    * The ::allocation-changed signal is emitted when the
7040    * #ClutterActor:allocation property changes. Usually, application
7041    * code should just use the notifications for the :allocation property
7042    * but if you want to track the allocation flags as well, for instance
7043    * to know whether the absolute origin of @actor changed, then you might
7044    * want use this signal instead.
7045    *
7046    * Since: 1.0
7047    */
7048   actor_signals[ALLOCATION_CHANGED] =
7049     g_signal_new (I_("allocation-changed"),
7050                   G_TYPE_FROM_CLASS (object_class),
7051                   G_SIGNAL_RUN_LAST,
7052                   0,
7053                   NULL, NULL,
7054                   _clutter_marshal_VOID__BOXED_FLAGS,
7055                   G_TYPE_NONE, 2,
7056                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7057                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7058
7059   /**
7060    * ClutterActor::transitions-completed:
7061    * @actor: a #ClutterActor
7062    *
7063    * The ::transitions-completed signal is emitted once all transitions
7064    * involving @actor are complete.
7065    *
7066    * Since: 1.10
7067    */
7068   actor_signals[TRANSITIONS_COMPLETED] =
7069     g_signal_new (I_("transitions-completed"),
7070                   G_TYPE_FROM_CLASS (object_class),
7071                   G_SIGNAL_RUN_LAST,
7072                   0,
7073                   NULL, NULL,
7074                   _clutter_marshal_VOID__VOID,
7075                   G_TYPE_NONE, 0);
7076 }
7077
7078 static void
7079 clutter_actor_init (ClutterActor *self)
7080 {
7081   ClutterActorPrivate *priv;
7082
7083   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7084
7085   priv->id = _clutter_context_acquire_id (self);
7086   priv->pick_id = -1;
7087
7088   priv->opacity = 0xff;
7089   priv->show_on_set_parent = TRUE;
7090
7091   priv->needs_width_request = TRUE;
7092   priv->needs_height_request = TRUE;
7093   priv->needs_allocation = TRUE;
7094
7095   priv->cached_width_age = 1;
7096   priv->cached_height_age = 1;
7097
7098   priv->opacity_override = -1;
7099   priv->enable_model_view_transform = TRUE;
7100
7101   /* Initialize an empty paint volume to start with */
7102   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7103   priv->last_paint_volume_valid = TRUE;
7104
7105   priv->transform_valid = FALSE;
7106
7107   /* the default is to stretch the content, to match the
7108    * current behaviour of basically all actors. also, it's
7109    * the easiest thing to compute.
7110    */
7111   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7112   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7113   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7114 }
7115
7116 /**
7117  * clutter_actor_new:
7118  *
7119  * Creates a new #ClutterActor.
7120  *
7121  * A newly created actor has a floating reference, which will be sunk
7122  * when it is added to another actor.
7123  *
7124  * Return value: (transfer full): the newly created #ClutterActor
7125  *
7126  * Since: 1.10
7127  */
7128 ClutterActor *
7129 clutter_actor_new (void)
7130 {
7131   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7132 }
7133
7134 /**
7135  * clutter_actor_destroy:
7136  * @self: a #ClutterActor
7137  *
7138  * Destroys an actor.  When an actor is destroyed, it will break any
7139  * references it holds to other objects.  If the actor is inside a
7140  * container, the actor will be removed.
7141  *
7142  * When you destroy a container, its children will be destroyed as well.
7143  *
7144  * Note: you cannot destroy the #ClutterStage returned by
7145  * clutter_stage_get_default().
7146  */
7147 void
7148 clutter_actor_destroy (ClutterActor *self)
7149 {
7150   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7151
7152   g_object_ref (self);
7153
7154   /* avoid recursion while destroying */
7155   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7156     {
7157       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7158
7159       g_object_run_dispose (G_OBJECT (self));
7160
7161       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7162     }
7163
7164   g_object_unref (self);
7165 }
7166
7167 void
7168 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7169                                     ClutterPaintVolume *clip)
7170 {
7171   ClutterActorPrivate *priv = self->priv;
7172   ClutterPaintVolume *pv;
7173   gboolean clipped;
7174
7175   /* Remove queue entry early in the process, otherwise a new
7176      queue_redraw() during signal handling could put back this
7177      object in the stage redraw list (but the entry is freed as
7178      soon as we return from this function, causing a segfault
7179      later)
7180   */
7181   priv->queue_redraw_entry = NULL;
7182
7183   /* If we've been explicitly passed a clip volume then there's
7184    * nothing more to calculate, but otherwise the only thing we know
7185    * is that the change is constrained to the given actor.
7186    *
7187    * The idea is that if we know the paint volume for where the actor
7188    * was last drawn (in eye coordinates) and we also have the paint
7189    * volume for where it will be drawn next (in actor coordinates)
7190    * then if we queue a redraw for both these volumes that will cover
7191    * everything that needs to be redrawn to clear the old view and
7192    * show the latest view of the actor.
7193    *
7194    * Don't clip this redraw if we don't know what position we had for
7195    * the previous redraw since we don't know where to set the clip so
7196    * it will clear the actor as it is currently.
7197    */
7198   if (clip)
7199     {
7200       _clutter_actor_set_queue_redraw_clip (self, clip);
7201       clipped = TRUE;
7202     }
7203   else if (G_LIKELY (priv->last_paint_volume_valid))
7204     {
7205       pv = _clutter_actor_get_paint_volume_mutable (self);
7206       if (pv)
7207         {
7208           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7209
7210           /* make sure we redraw the actors old position... */
7211           _clutter_actor_set_queue_redraw_clip (stage,
7212                                                 &priv->last_paint_volume);
7213           _clutter_actor_signal_queue_redraw (stage, stage);
7214           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7215
7216           /* XXX: Ideally the redraw signal would take a clip volume
7217            * argument, but that would be an ABI break. Until we can
7218            * break the ABI we pass the argument out-of-band
7219            */
7220
7221           /* setup the clip for the actors new position... */
7222           _clutter_actor_set_queue_redraw_clip (self, pv);
7223           clipped = TRUE;
7224         }
7225       else
7226         clipped = FALSE;
7227     }
7228   else
7229     clipped = FALSE;
7230
7231   _clutter_actor_signal_queue_redraw (self, self);
7232
7233   /* Just in case anyone is manually firing redraw signals without
7234    * using the public queue_redraw() API we are careful to ensure that
7235    * our out-of-band clip member is cleared before returning...
7236    *
7237    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7238    */
7239   if (G_LIKELY (clipped))
7240     _clutter_actor_set_queue_redraw_clip (self, NULL);
7241 }
7242
7243 static void
7244 _clutter_actor_get_allocation_clip (ClutterActor *self,
7245                                     ClutterActorBox *clip)
7246 {
7247   ClutterActorBox allocation;
7248
7249   /* XXX: we don't care if we get an out of date allocation here
7250    * because clutter_actor_queue_redraw_with_clip knows to ignore
7251    * the clip if the actor's allocation is invalid.
7252    *
7253    * This is noted because clutter_actor_get_allocation_box does some
7254    * unnecessary work to support buggy code with a comment suggesting
7255    * that it could be changed later which would be good for this use
7256    * case!
7257    */
7258   clutter_actor_get_allocation_box (self, &allocation);
7259
7260   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7261    * actor's own coordinate space but the allocation is in parent
7262    * coordinates */
7263   clip->x1 = 0;
7264   clip->y1 = 0;
7265   clip->x2 = allocation.x2 - allocation.x1;
7266   clip->y2 = allocation.y2 - allocation.y1;
7267 }
7268
7269 void
7270 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7271                                   ClutterRedrawFlags  flags,
7272                                   ClutterPaintVolume *volume,
7273                                   ClutterEffect      *effect)
7274 {
7275   ClutterActorPrivate *priv = self->priv;
7276   ClutterPaintVolume allocation_pv;
7277   ClutterPaintVolume *pv;
7278   gboolean should_free_pv;
7279   ClutterActor *stage;
7280
7281   /* Here's an outline of the actor queue redraw mechanism:
7282    *
7283    * The process starts in one of the following two functions which
7284    * are wrappers for this function:
7285    * clutter_actor_queue_redraw
7286    * _clutter_actor_queue_redraw_with_clip
7287    *
7288    * additionally, an effect can queue a redraw by wrapping this
7289    * function in clutter_effect_queue_rerun
7290    *
7291    * This functions queues an entry in a list associated with the
7292    * stage which is a list of actors that queued a redraw while
7293    * updating the timelines, performing layouting and processing other
7294    * mainloop sources before the next paint starts.
7295    *
7296    * We aim to minimize the processing done at this point because
7297    * there is a good chance other events will happen while updating
7298    * the scenegraph that would invalidate any expensive work we might
7299    * otherwise try to do here. For example we don't try and resolve
7300    * the screen space bounding box of an actor at this stage so as to
7301    * minimize how much of the screen redraw because it's possible
7302    * something else will happen which will force a full redraw anyway.
7303    *
7304    * When all updates are complete and we come to paint the stage then
7305    * we iterate this list and actually emit the "queue-redraw" signals
7306    * for each of the listed actors which will bubble up to the stage
7307    * for each actor and at that point we will transform the actors
7308    * paint volume into screen coordinates to determine the clip region
7309    * for what needs to be redrawn in the next paint.
7310    *
7311    * Besides minimizing redundant work another reason for this
7312    * deferred design is that it's more likely we will be able to
7313    * determine the paint volume of an actor once we've finished
7314    * updating the scenegraph because its allocation should be up to
7315    * date. NB: If we can't determine an actors paint volume then we
7316    * can't automatically queue a clipped redraw which can make a big
7317    * difference to performance.
7318    *
7319    * So the control flow goes like this:
7320    * One of clutter_actor_queue_redraw,
7321    *        _clutter_actor_queue_redraw_with_clip
7322    *     or clutter_effect_queue_rerun
7323    *
7324    * then control moves to:
7325    *   _clutter_stage_queue_actor_redraw
7326    *
7327    * later during _clutter_stage_do_update, once relayouting is done
7328    * and the scenegraph has been updated we will call:
7329    * _clutter_stage_finish_queue_redraws
7330    *
7331    * _clutter_stage_finish_queue_redraws will call
7332    * _clutter_actor_finish_queue_redraw for each listed actor.
7333    * Note: actors *are* allowed to queue further redraws during this
7334    * process (considering clone actors or texture_new_from_actor which
7335    * respond to their source queueing a redraw by queuing a redraw
7336    * themselves). We repeat the process until the list is empty.
7337    *
7338    * This will result in the "queue-redraw" signal being fired for
7339    * each actor which will pass control to the default signal handler:
7340    * clutter_actor_real_queue_redraw
7341    *
7342    * This will bubble up to the stages handler:
7343    * clutter_stage_real_queue_redraw
7344    *
7345    * clutter_stage_real_queue_redraw will transform the actors paint
7346    * volume into screen space and add it as a clip region for the next
7347    * paint.
7348    */
7349
7350   /* ignore queueing a redraw for actors being destroyed */
7351   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7352     return;
7353
7354   stage = _clutter_actor_get_stage_internal (self);
7355
7356   /* Ignore queueing a redraw for actors not descended from a stage */
7357   if (stage == NULL)
7358     return;
7359
7360   /* ignore queueing a redraw on stages that are being destroyed */
7361   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7362     return;
7363
7364   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7365     {
7366       ClutterActorBox allocation_clip;
7367       ClutterVertex origin;
7368
7369       /* If the actor doesn't have a valid allocation then we will
7370        * queue a full stage redraw. */
7371       if (priv->needs_allocation)
7372         {
7373           /* NB: NULL denotes an undefined clip which will result in a
7374            * full redraw... */
7375           _clutter_actor_set_queue_redraw_clip (self, NULL);
7376           _clutter_actor_signal_queue_redraw (self, self);
7377           return;
7378         }
7379
7380       _clutter_paint_volume_init_static (&allocation_pv, self);
7381       pv = &allocation_pv;
7382
7383       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7384
7385       origin.x = allocation_clip.x1;
7386       origin.y = allocation_clip.y1;
7387       origin.z = 0;
7388       clutter_paint_volume_set_origin (pv, &origin);
7389       clutter_paint_volume_set_width (pv,
7390                                       allocation_clip.x2 - allocation_clip.x1);
7391       clutter_paint_volume_set_height (pv,
7392                                        allocation_clip.y2 -
7393                                        allocation_clip.y1);
7394       should_free_pv = TRUE;
7395     }
7396   else
7397     {
7398       pv = volume;
7399       should_free_pv = FALSE;
7400     }
7401
7402   self->priv->queue_redraw_entry =
7403     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7404                                        priv->queue_redraw_entry,
7405                                        self,
7406                                        pv);
7407
7408   if (should_free_pv)
7409     clutter_paint_volume_free (pv);
7410
7411   /* If this is the first redraw queued then we can directly use the
7412      effect parameter */
7413   if (!priv->is_dirty)
7414     priv->effect_to_redraw = effect;
7415   /* Otherwise we need to merge it with the existing effect parameter */
7416   else if (effect != NULL)
7417     {
7418       /* If there's already an effect then we need to use whichever is
7419          later in the chain of actors. Otherwise a full redraw has
7420          already been queued on the actor so we need to ignore the
7421          effect parameter */
7422       if (priv->effect_to_redraw != NULL)
7423         {
7424           if (priv->effects == NULL)
7425             g_warning ("Redraw queued with an effect that is "
7426                        "not applied to the actor");
7427           else
7428             {
7429               const GList *l;
7430
7431               for (l = _clutter_meta_group_peek_metas (priv->effects);
7432                    l != NULL;
7433                    l = l->next)
7434                 {
7435                   if (l->data == priv->effect_to_redraw ||
7436                       l->data == effect)
7437                     priv->effect_to_redraw = l->data;
7438                 }
7439             }
7440         }
7441     }
7442   else
7443     {
7444       /* If no effect is specified then we need to redraw the whole
7445          actor */
7446       priv->effect_to_redraw = NULL;
7447     }
7448
7449   priv->is_dirty = TRUE;
7450 }
7451
7452 /**
7453  * clutter_actor_queue_redraw:
7454  * @self: A #ClutterActor
7455  *
7456  * Queues up a redraw of an actor and any children. The redraw occurs
7457  * once the main loop becomes idle (after the current batch of events
7458  * has been processed, roughly).
7459  *
7460  * Applications rarely need to call this, as redraws are handled
7461  * automatically by modification functions.
7462  *
7463  * This function will not do anything if @self is not visible, or
7464  * if the actor is inside an invisible part of the scenegraph.
7465  *
7466  * Also be aware that painting is a NOP for actors with an opacity of
7467  * 0
7468  *
7469  * When you are implementing a custom actor you must queue a redraw
7470  * whenever some private state changes that will affect painting or
7471  * picking of your actor.
7472  */
7473 void
7474 clutter_actor_queue_redraw (ClutterActor *self)
7475 {
7476   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7477
7478   _clutter_actor_queue_redraw_full (self,
7479                                     0, /* flags */
7480                                     NULL, /* clip volume */
7481                                     NULL /* effect */);
7482 }
7483
7484 /*< private >
7485  * _clutter_actor_queue_redraw_with_clip:
7486  * @self: A #ClutterActor
7487  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7488  *   this queue redraw.
7489  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7490  *   redrawn or %NULL if you are just using a @flag to state your
7491  *   desired clipping.
7492  *
7493  * Queues up a clipped redraw of an actor and any children. The redraw
7494  * occurs once the main loop becomes idle (after the current batch of
7495  * events has been processed, roughly).
7496  *
7497  * If no flags are given the clip volume is defined by @volume
7498  * specified in actor coordinates and tells Clutter that only content
7499  * within this volume has been changed so Clutter can optionally
7500  * optimize the redraw.
7501  *
7502  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7503  * should be %NULL and this tells Clutter to use the actor's current
7504  * allocation as a clip box. This flag can only be used for 2D actors,
7505  * because any actor with depth may be projected outside its
7506  * allocation.
7507  *
7508  * Applications rarely need to call this, as redraws are handled
7509  * automatically by modification functions.
7510  *
7511  * This function will not do anything if @self is not visible, or if
7512  * the actor is inside an invisible part of the scenegraph.
7513  *
7514  * Also be aware that painting is a NOP for actors with an opacity of
7515  * 0
7516  *
7517  * When you are implementing a custom actor you must queue a redraw
7518  * whenever some private state changes that will affect painting or
7519  * picking of your actor.
7520  */
7521 void
7522 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7523                                        ClutterRedrawFlags  flags,
7524                                        ClutterPaintVolume *volume)
7525 {
7526   _clutter_actor_queue_redraw_full (self,
7527                                     flags, /* flags */
7528                                     volume, /* clip volume */
7529                                     NULL /* effect */);
7530 }
7531
7532 static void
7533 _clutter_actor_queue_only_relayout (ClutterActor *self)
7534 {
7535   ClutterActorPrivate *priv = self->priv;
7536
7537   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7538     return;
7539
7540   if (priv->needs_width_request &&
7541       priv->needs_height_request &&
7542       priv->needs_allocation)
7543     return; /* save some cpu cycles */
7544
7545 #if CLUTTER_ENABLE_DEBUG
7546   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7547     {
7548       g_warning ("The actor '%s' is currently inside an allocation "
7549                  "cycle; calling clutter_actor_queue_relayout() is "
7550                  "not recommended",
7551                  _clutter_actor_get_debug_name (self));
7552     }
7553 #endif /* CLUTTER_ENABLE_DEBUG */
7554
7555   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7556 }
7557
7558 /**
7559  * clutter_actor_queue_redraw_with_clip:
7560  * @self: a #ClutterActor
7561  * @clip: (allow-none): a rectangular clip region, or %NULL
7562  *
7563  * Queues a redraw on @self limited to a specific, actor-relative
7564  * rectangular area.
7565  *
7566  * If @clip is %NULL this function is equivalent to
7567  * clutter_actor_queue_redraw().
7568  *
7569  * Since: 1.10
7570  */
7571 void
7572 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7573                                       const cairo_rectangle_int_t *clip)
7574 {
7575   ClutterPaintVolume volume;
7576   ClutterVertex origin;
7577
7578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7579
7580   if (clip == NULL)
7581     {
7582       clutter_actor_queue_redraw (self);
7583       return;
7584     }
7585
7586   _clutter_paint_volume_init_static (&volume, self);
7587
7588   origin.x = clip->x;
7589   origin.y = clip->y;
7590   origin.z = 0.0f;
7591
7592   clutter_paint_volume_set_origin (&volume, &origin);
7593   clutter_paint_volume_set_width (&volume, clip->width);
7594   clutter_paint_volume_set_height (&volume, clip->height);
7595
7596   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7597
7598   clutter_paint_volume_free (&volume);
7599 }
7600
7601 /**
7602  * clutter_actor_queue_relayout:
7603  * @self: A #ClutterActor
7604  *
7605  * Indicates that the actor's size request or other layout-affecting
7606  * properties may have changed. This function is used inside #ClutterActor
7607  * subclass implementations, not by applications directly.
7608  *
7609  * Queueing a new layout automatically queues a redraw as well.
7610  *
7611  * Since: 0.8
7612  */
7613 void
7614 clutter_actor_queue_relayout (ClutterActor *self)
7615 {
7616   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7617
7618   _clutter_actor_queue_only_relayout (self);
7619   clutter_actor_queue_redraw (self);
7620 }
7621
7622 /**
7623  * clutter_actor_get_preferred_size:
7624  * @self: a #ClutterActor
7625  * @min_width_p: (out) (allow-none): return location for the minimum
7626  *   width, or %NULL
7627  * @min_height_p: (out) (allow-none): return location for the minimum
7628  *   height, or %NULL
7629  * @natural_width_p: (out) (allow-none): return location for the natural
7630  *   width, or %NULL
7631  * @natural_height_p: (out) (allow-none): return location for the natural
7632  *   height, or %NULL
7633  *
7634  * Computes the preferred minimum and natural size of an actor, taking into
7635  * account the actor's geometry management (either height-for-width
7636  * or width-for-height).
7637  *
7638  * The width and height used to compute the preferred height and preferred
7639  * width are the actor's natural ones.
7640  *
7641  * If you need to control the height for the preferred width, or the width for
7642  * the preferred height, you should use clutter_actor_get_preferred_width()
7643  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7644  * geometry management using the #ClutterActor:request-mode property.
7645  *
7646  * Since: 0.8
7647  */
7648 void
7649 clutter_actor_get_preferred_size (ClutterActor *self,
7650                                   gfloat       *min_width_p,
7651                                   gfloat       *min_height_p,
7652                                   gfloat       *natural_width_p,
7653                                   gfloat       *natural_height_p)
7654 {
7655   ClutterActorPrivate *priv;
7656   gfloat min_width, min_height;
7657   gfloat natural_width, natural_height;
7658
7659   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7660
7661   priv = self->priv;
7662
7663   min_width = min_height = 0;
7664   natural_width = natural_height = 0;
7665
7666   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7667     {
7668       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7669       clutter_actor_get_preferred_width (self, -1,
7670                                          &min_width,
7671                                          &natural_width);
7672       clutter_actor_get_preferred_height (self, natural_width,
7673                                           &min_height,
7674                                           &natural_height);
7675     }
7676   else
7677     {
7678       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7679       clutter_actor_get_preferred_height (self, -1,
7680                                           &min_height,
7681                                           &natural_height);
7682       clutter_actor_get_preferred_width (self, natural_height,
7683                                          &min_width,
7684                                          &natural_width);
7685     }
7686
7687   if (min_width_p)
7688     *min_width_p = min_width;
7689
7690   if (min_height_p)
7691     *min_height_p = min_height;
7692
7693   if (natural_width_p)
7694     *natural_width_p = natural_width;
7695
7696   if (natural_height_p)
7697     *natural_height_p = natural_height;
7698 }
7699
7700 /*< private >
7701  * effective_align:
7702  * @align: a #ClutterActorAlign
7703  * @direction: a #ClutterTextDirection
7704  *
7705  * Retrieves the correct alignment depending on the text direction
7706  *
7707  * Return value: the effective alignment
7708  */
7709 static ClutterActorAlign
7710 effective_align (ClutterActorAlign    align,
7711                  ClutterTextDirection direction)
7712 {
7713   ClutterActorAlign res;
7714
7715   switch (align)
7716     {
7717     case CLUTTER_ACTOR_ALIGN_START:
7718       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7719           ? CLUTTER_ACTOR_ALIGN_END
7720           : CLUTTER_ACTOR_ALIGN_START;
7721       break;
7722
7723     case CLUTTER_ACTOR_ALIGN_END:
7724       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7725           ? CLUTTER_ACTOR_ALIGN_START
7726           : CLUTTER_ACTOR_ALIGN_END;
7727       break;
7728
7729     default:
7730       res = align;
7731       break;
7732     }
7733
7734   return res;
7735 }
7736
7737 static inline void
7738 adjust_for_margin (float  margin_start,
7739                    float  margin_end,
7740                    float *minimum_size,
7741                    float *natural_size,
7742                    float *allocated_start,
7743                    float *allocated_end)
7744 {
7745   *minimum_size -= (margin_start + margin_end);
7746   *natural_size -= (margin_start + margin_end);
7747   *allocated_start += margin_start;
7748   *allocated_end -= margin_end;
7749 }
7750
7751 static inline void
7752 adjust_for_alignment (ClutterActorAlign  alignment,
7753                       float              natural_size,
7754                       float             *allocated_start,
7755                       float             *allocated_end)
7756 {
7757   float allocated_size = *allocated_end - *allocated_start;
7758
7759   switch (alignment)
7760     {
7761     case CLUTTER_ACTOR_ALIGN_FILL:
7762       /* do nothing */
7763       break;
7764
7765     case CLUTTER_ACTOR_ALIGN_START:
7766       /* keep start */
7767       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7768       break;
7769
7770     case CLUTTER_ACTOR_ALIGN_END:
7771       if (allocated_size > natural_size)
7772         {
7773           *allocated_start += (allocated_size - natural_size);
7774           *allocated_end = *allocated_start + natural_size;
7775         }
7776       break;
7777
7778     case CLUTTER_ACTOR_ALIGN_CENTER:
7779       if (allocated_size > natural_size)
7780         {
7781           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7782           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7783         }
7784       break;
7785     }
7786 }
7787
7788 /*< private >
7789  * clutter_actor_adjust_width:
7790  * @self: a #ClutterActor
7791  * @minimum_width: (inout): the actor's preferred minimum width, which
7792  *   will be adjusted depending on the margin
7793  * @natural_width: (inout): the actor's preferred natural width, which
7794  *   will be adjusted depending on the margin
7795  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7796  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7797  *
7798  * Adjusts the preferred and allocated position and size of an actor,
7799  * depending on the margin and alignment properties.
7800  */
7801 static void
7802 clutter_actor_adjust_width (ClutterActor *self,
7803                             gfloat       *minimum_width,
7804                             gfloat       *natural_width,
7805                             gfloat       *adjusted_x1,
7806                             gfloat       *adjusted_x2)
7807 {
7808   ClutterTextDirection text_dir;
7809   const ClutterLayoutInfo *info;
7810
7811   info = _clutter_actor_get_layout_info_or_defaults (self);
7812   text_dir = clutter_actor_get_text_direction (self);
7813
7814   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7815
7816   /* this will tweak natural_width to remove the margin, so that
7817    * adjust_for_alignment() will use the correct size
7818    */
7819   adjust_for_margin (info->margin.left, info->margin.right,
7820                      minimum_width, natural_width,
7821                      adjusted_x1, adjusted_x2);
7822
7823   adjust_for_alignment (effective_align (info->x_align, text_dir),
7824                         *natural_width,
7825                         adjusted_x1, adjusted_x2);
7826 }
7827
7828 /*< private >
7829  * clutter_actor_adjust_height:
7830  * @self: a #ClutterActor
7831  * @minimum_height: (inout): the actor's preferred minimum height, which
7832  *   will be adjusted depending on the margin
7833  * @natural_height: (inout): the actor's preferred natural height, which
7834  *   will be adjusted depending on the margin
7835  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7836  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7837  *
7838  * Adjusts the preferred and allocated position and size of an actor,
7839  * depending on the margin and alignment properties.
7840  */
7841 static void
7842 clutter_actor_adjust_height (ClutterActor *self,
7843                              gfloat       *minimum_height,
7844                              gfloat       *natural_height,
7845                              gfloat       *adjusted_y1,
7846                              gfloat       *adjusted_y2)
7847 {
7848   const ClutterLayoutInfo *info;
7849
7850   info = _clutter_actor_get_layout_info_or_defaults (self);
7851
7852   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7853
7854   /* this will tweak natural_height to remove the margin, so that
7855    * adjust_for_alignment() will use the correct size
7856    */
7857   adjust_for_margin (info->margin.top, info->margin.bottom,
7858                      minimum_height, natural_height,
7859                      adjusted_y1,
7860                      adjusted_y2);
7861
7862   /* we don't use effective_align() here, because text direction
7863    * only affects the horizontal axis
7864    */
7865   adjust_for_alignment (info->y_align,
7866                         *natural_height,
7867                         adjusted_y1,
7868                         adjusted_y2);
7869
7870 }
7871
7872 /* looks for a cached size request for this for_size. If not
7873  * found, returns the oldest entry so it can be overwritten */
7874 static gboolean
7875 _clutter_actor_get_cached_size_request (gfloat         for_size,
7876                                         SizeRequest   *cached_size_requests,
7877                                         SizeRequest  **result)
7878 {
7879   guint i;
7880
7881   *result = &cached_size_requests[0];
7882
7883   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7884     {
7885       SizeRequest *sr;
7886
7887       sr = &cached_size_requests[i];
7888
7889       if (sr->age > 0 &&
7890           sr->for_size == for_size)
7891         {
7892           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7893           *result = sr;
7894           return TRUE;
7895         }
7896       else if (sr->age < (*result)->age)
7897         {
7898           *result = sr;
7899         }
7900     }
7901
7902   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7903
7904   return FALSE;
7905 }
7906
7907 /**
7908  * clutter_actor_get_preferred_width:
7909  * @self: A #ClutterActor
7910  * @for_height: available height when computing the preferred width,
7911  *   or a negative value to indicate that no height is defined
7912  * @min_width_p: (out) (allow-none): return location for minimum width,
7913  *   or %NULL
7914  * @natural_width_p: (out) (allow-none): return location for the natural
7915  *   width, or %NULL
7916  *
7917  * Computes the requested minimum and natural widths for an actor,
7918  * optionally depending on the specified height, or if they are
7919  * already computed, returns the cached values.
7920  *
7921  * An actor may not get its request - depending on the layout
7922  * manager that's in effect.
7923  *
7924  * A request should not incorporate the actor's scale or anchor point;
7925  * those transformations do not affect layout, only rendering.
7926  *
7927  * Since: 0.8
7928  */
7929 void
7930 clutter_actor_get_preferred_width (ClutterActor *self,
7931                                    gfloat        for_height,
7932                                    gfloat       *min_width_p,
7933                                    gfloat       *natural_width_p)
7934 {
7935   float request_min_width, request_natural_width;
7936   SizeRequest *cached_size_request;
7937   const ClutterLayoutInfo *info;
7938   ClutterActorPrivate *priv;
7939   gboolean found_in_cache;
7940
7941   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7942
7943   priv = self->priv;
7944
7945   info = _clutter_actor_get_layout_info_or_defaults (self);
7946
7947   /* we shortcircuit the case of a fixed size set using set_width() */
7948   if (priv->min_width_set && priv->natural_width_set)
7949     {
7950       if (min_width_p != NULL)
7951         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7952
7953       if (natural_width_p != NULL)
7954         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7955
7956       return;
7957     }
7958
7959   /* the remaining cases are:
7960    *
7961    *   - either min_width or natural_width have been set
7962    *   - neither min_width or natural_width have been set
7963    *
7964    * in both cases, we go through the cache (and through the actor in case
7965    * of cache misses) and determine the authoritative value depending on
7966    * the *_set flags.
7967    */
7968
7969   if (!priv->needs_width_request)
7970     {
7971       found_in_cache =
7972         _clutter_actor_get_cached_size_request (for_height,
7973                                                 priv->width_requests,
7974                                                 &cached_size_request);
7975     }
7976   else
7977     {
7978       /* if the actor needs a width request we use the first slot */
7979       found_in_cache = FALSE;
7980       cached_size_request = &priv->width_requests[0];
7981     }
7982
7983   if (!found_in_cache)
7984     {
7985       gfloat minimum_width, natural_width;
7986       ClutterActorClass *klass;
7987
7988       minimum_width = natural_width = 0;
7989
7990       /* adjust for the margin */
7991       if (for_height >= 0)
7992         {
7993           for_height -= (info->margin.top + info->margin.bottom);
7994           if (for_height < 0)
7995             for_height = 0;
7996         }
7997
7998       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7999
8000       klass = CLUTTER_ACTOR_GET_CLASS (self);
8001       klass->get_preferred_width (self, for_height,
8002                                   &minimum_width,
8003                                   &natural_width);
8004
8005       /* adjust for the margin */
8006       minimum_width += (info->margin.left + info->margin.right);
8007       natural_width += (info->margin.left + info->margin.right);
8008
8009       /* Due to accumulated float errors, it's better not to warn
8010        * on this, but just fix it.
8011        */
8012       if (natural_width < minimum_width)
8013         natural_width = minimum_width;
8014
8015       cached_size_request->min_size = minimum_width;
8016       cached_size_request->natural_size = natural_width;
8017       cached_size_request->for_size = for_height;
8018       cached_size_request->age = priv->cached_width_age;
8019
8020       priv->cached_width_age += 1;
8021       priv->needs_width_request = FALSE;
8022     }
8023
8024   if (!priv->min_width_set)
8025     request_min_width = cached_size_request->min_size;
8026   else
8027     request_min_width = info->min_width;
8028
8029   if (!priv->natural_width_set)
8030     request_natural_width = cached_size_request->natural_size;
8031   else
8032     request_natural_width = info->natural_width;
8033
8034   if (min_width_p)
8035     *min_width_p = request_min_width;
8036
8037   if (natural_width_p)
8038     *natural_width_p = request_natural_width;
8039 }
8040
8041 /**
8042  * clutter_actor_get_preferred_height:
8043  * @self: A #ClutterActor
8044  * @for_width: available width to assume in computing desired height,
8045  *   or a negative value to indicate that no width is defined
8046  * @min_height_p: (out) (allow-none): return location for minimum height,
8047  *   or %NULL
8048  * @natural_height_p: (out) (allow-none): return location for natural
8049  *   height, or %NULL
8050  *
8051  * Computes the requested minimum and natural heights for an actor,
8052  * or if they are already computed, returns the cached values.
8053  *
8054  * An actor may not get its request - depending on the layout
8055  * manager that's in effect.
8056  *
8057  * A request should not incorporate the actor's scale or anchor point;
8058  * those transformations do not affect layout, only rendering.
8059  *
8060  * Since: 0.8
8061  */
8062 void
8063 clutter_actor_get_preferred_height (ClutterActor *self,
8064                                     gfloat        for_width,
8065                                     gfloat       *min_height_p,
8066                                     gfloat       *natural_height_p)
8067 {
8068   float request_min_height, request_natural_height;
8069   SizeRequest *cached_size_request;
8070   const ClutterLayoutInfo *info;
8071   ClutterActorPrivate *priv;
8072   gboolean found_in_cache;
8073
8074   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8075
8076   priv = self->priv;
8077
8078   info = _clutter_actor_get_layout_info_or_defaults (self);
8079
8080   /* we shortcircuit the case of a fixed size set using set_height() */
8081   if (priv->min_height_set && priv->natural_height_set)
8082     {
8083       if (min_height_p != NULL)
8084         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8085
8086       if (natural_height_p != NULL)
8087         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8088
8089       return;
8090     }
8091
8092   /* the remaining cases are:
8093    *
8094    *   - either min_height or natural_height have been set
8095    *   - neither min_height or natural_height have been set
8096    *
8097    * in both cases, we go through the cache (and through the actor in case
8098    * of cache misses) and determine the authoritative value depending on
8099    * the *_set flags.
8100    */
8101
8102   if (!priv->needs_height_request)
8103     {
8104       found_in_cache =
8105         _clutter_actor_get_cached_size_request (for_width,
8106                                                 priv->height_requests,
8107                                                 &cached_size_request);
8108     }
8109   else
8110     {
8111       found_in_cache = FALSE;
8112       cached_size_request = &priv->height_requests[0];
8113     }
8114
8115   if (!found_in_cache)
8116     {
8117       gfloat minimum_height, natural_height;
8118       ClutterActorClass *klass;
8119
8120       minimum_height = natural_height = 0;
8121
8122       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8123
8124       /* adjust for margin */
8125       if (for_width >= 0)
8126         {
8127           for_width -= (info->margin.left + info->margin.right);
8128           if (for_width < 0)
8129             for_width = 0;
8130         }
8131
8132       klass = CLUTTER_ACTOR_GET_CLASS (self);
8133       klass->get_preferred_height (self, for_width,
8134                                    &minimum_height,
8135                                    &natural_height);
8136
8137       /* adjust for margin */
8138       minimum_height += (info->margin.top + info->margin.bottom);
8139       natural_height += (info->margin.top + info->margin.bottom);
8140
8141       /* Due to accumulated float errors, it's better not to warn
8142        * on this, but just fix it.
8143        */
8144       if (natural_height < minimum_height)
8145         natural_height = minimum_height;
8146
8147       cached_size_request->min_size = minimum_height;
8148       cached_size_request->natural_size = natural_height;
8149       cached_size_request->for_size = for_width;
8150       cached_size_request->age = priv->cached_height_age;
8151
8152       priv->cached_height_age += 1;
8153       priv->needs_height_request = FALSE;
8154     }
8155
8156   if (!priv->min_height_set)
8157     request_min_height = cached_size_request->min_size;
8158   else
8159     request_min_height = info->min_height;
8160
8161   if (!priv->natural_height_set)
8162     request_natural_height = cached_size_request->natural_size;
8163   else
8164     request_natural_height = info->natural_height;
8165
8166   if (min_height_p)
8167     *min_height_p = request_min_height;
8168
8169   if (natural_height_p)
8170     *natural_height_p = request_natural_height;
8171 }
8172
8173 /**
8174  * clutter_actor_get_allocation_box:
8175  * @self: A #ClutterActor
8176  * @box: (out): the function fills this in with the actor's allocation
8177  *
8178  * Gets the layout box an actor has been assigned. The allocation can
8179  * only be assumed valid inside a paint() method; anywhere else, it
8180  * may be out-of-date.
8181  *
8182  * An allocation does not incorporate the actor's scale or anchor point;
8183  * those transformations do not affect layout, only rendering.
8184  *
8185  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8186  * of functions inside the implementation of the get_preferred_width()
8187  * or get_preferred_height() virtual functions.</note>
8188  *
8189  * Since: 0.8
8190  */
8191 void
8192 clutter_actor_get_allocation_box (ClutterActor    *self,
8193                                   ClutterActorBox *box)
8194 {
8195   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8196
8197   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8198    * which limits calling get_allocation to inside paint() basically; or
8199    * we can 2) force a layout, which could be expensive if someone calls
8200    * get_allocation somewhere silly; or we can 3) just return the latest
8201    * value, allowing it to be out-of-date, and assume people know what
8202    * they are doing.
8203    *
8204    * The least-surprises approach that keeps existing code working is
8205    * likely to be 2). People can end up doing some inefficient things,
8206    * though, and in general code that requires 2) is probably broken.
8207    */
8208
8209   /* this implements 2) */
8210   if (G_UNLIKELY (self->priv->needs_allocation))
8211     {
8212       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8213
8214       /* do not queue a relayout on an unparented actor */
8215       if (stage)
8216         _clutter_stage_maybe_relayout (stage);
8217     }
8218
8219   /* commenting out the code above and just keeping this assigment
8220    * implements 3)
8221    */
8222   *box = self->priv->allocation;
8223 }
8224
8225 /**
8226  * clutter_actor_get_allocation_geometry:
8227  * @self: A #ClutterActor
8228  * @geom: (out): allocation geometry in pixels
8229  *
8230  * Gets the layout box an actor has been assigned.  The allocation can
8231  * only be assumed valid inside a paint() method; anywhere else, it
8232  * may be out-of-date.
8233  *
8234  * An allocation does not incorporate the actor's scale or anchor point;
8235  * those transformations do not affect layout, only rendering.
8236  *
8237  * The returned rectangle is in pixels.
8238  *
8239  * Since: 0.8
8240  */
8241 void
8242 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8243                                        ClutterGeometry *geom)
8244 {
8245   ClutterActorBox box;
8246
8247   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8248   g_return_if_fail (geom != NULL);
8249
8250   clutter_actor_get_allocation_box (self, &box);
8251
8252   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8253   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8254   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8255   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8256 }
8257
8258 static void
8259 clutter_actor_update_constraints (ClutterActor    *self,
8260                                   ClutterActorBox *allocation)
8261 {
8262   ClutterActorPrivate *priv = self->priv;
8263   const GList *constraints, *l;
8264
8265   if (priv->constraints == NULL)
8266     return;
8267
8268   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8269   for (l = constraints; l != NULL; l = l->next)
8270     {
8271       ClutterConstraint *constraint = l->data;
8272       ClutterActorMeta *meta = l->data;
8273
8274       if (clutter_actor_meta_get_enabled (meta))
8275         {
8276           _clutter_constraint_update_allocation (constraint,
8277                                                  self,
8278                                                  allocation);
8279
8280           CLUTTER_NOTE (LAYOUT,
8281                         "Allocation of '%s' after constraint '%s': "
8282                         "{ %.2f, %.2f, %.2f, %.2f }",
8283                         _clutter_actor_get_debug_name (self),
8284                         _clutter_actor_meta_get_debug_name (meta),
8285                         allocation->x1,
8286                         allocation->y1,
8287                         allocation->x2,
8288                         allocation->y2);
8289         }
8290     }
8291 }
8292
8293 /*< private >
8294  * clutter_actor_adjust_allocation:
8295  * @self: a #ClutterActor
8296  * @allocation: (inout): the allocation to adjust
8297  *
8298  * Adjusts the passed allocation box taking into account the actor's
8299  * layout information, like alignment, expansion, and margin.
8300  */
8301 static void
8302 clutter_actor_adjust_allocation (ClutterActor    *self,
8303                                  ClutterActorBox *allocation)
8304 {
8305   ClutterActorBox adj_allocation;
8306   float alloc_width, alloc_height;
8307   float min_width, min_height;
8308   float nat_width, nat_height;
8309   ClutterRequestMode req_mode;
8310
8311   adj_allocation = *allocation;
8312
8313   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8314
8315   /* we want to hit the cache, so we use the public API */
8316   req_mode = clutter_actor_get_request_mode (self);
8317
8318   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8319     {
8320       clutter_actor_get_preferred_width (self, -1,
8321                                          &min_width,
8322                                          &nat_width);
8323       clutter_actor_get_preferred_height (self, alloc_width,
8324                                           &min_height,
8325                                           &nat_height);
8326     }
8327   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8328     {
8329       clutter_actor_get_preferred_height (self, -1,
8330                                           &min_height,
8331                                           &nat_height);
8332       clutter_actor_get_preferred_height (self, alloc_height,
8333                                           &min_width,
8334                                           &nat_width);
8335     }
8336
8337 #ifdef CLUTTER_ENABLE_DEBUG
8338   /* warn about underallocations */
8339   if (_clutter_diagnostic_enabled () &&
8340       (floorf (min_width - alloc_width) > 0 ||
8341        floorf (min_height - alloc_height) > 0))
8342     {
8343       ClutterActor *parent = clutter_actor_get_parent (self);
8344
8345       /* the only actors that are allowed to be underallocated are the Stage,
8346        * as it doesn't have an implicit size, and Actors that specifically
8347        * told us that they want to opt-out from layout control mechanisms
8348        * through the NO_LAYOUT escape hatch.
8349        */
8350       if (parent != NULL &&
8351           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8352         {
8353           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8354                      "of %.2f x %.2f from its parent actor '%s', but its "
8355                      "requested minimum size is of %.2f x %.2f",
8356                      _clutter_actor_get_debug_name (self),
8357                      alloc_width, alloc_height,
8358                      _clutter_actor_get_debug_name (parent),
8359                      min_width, min_height);
8360         }
8361     }
8362 #endif
8363
8364   clutter_actor_adjust_width (self,
8365                               &min_width,
8366                               &nat_width,
8367                               &adj_allocation.x1,
8368                               &adj_allocation.x2);
8369
8370   clutter_actor_adjust_height (self,
8371                                &min_height,
8372                                &nat_height,
8373                                &adj_allocation.y1,
8374                                &adj_allocation.y2);
8375
8376   /* we maintain the invariant that an allocation cannot be adjusted
8377    * to be outside the parent-given box
8378    */
8379   if (adj_allocation.x1 < allocation->x1 ||
8380       adj_allocation.y1 < allocation->y1 ||
8381       adj_allocation.x2 > allocation->x2 ||
8382       adj_allocation.y2 > allocation->y2)
8383     {
8384       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8385                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8386                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8387                  _clutter_actor_get_debug_name (self),
8388                  adj_allocation.x1, adj_allocation.y1,
8389                  adj_allocation.x2 - adj_allocation.x1,
8390                  adj_allocation.y2 - adj_allocation.y1,
8391                  allocation->x1, allocation->y1,
8392                  allocation->x2 - allocation->x1,
8393                  allocation->y2 - allocation->y1);
8394       return;
8395     }
8396
8397   *allocation = adj_allocation;
8398 }
8399
8400 /**
8401  * clutter_actor_allocate:
8402  * @self: A #ClutterActor
8403  * @box: new allocation of the actor, in parent-relative coordinates
8404  * @flags: flags that control the allocation
8405  *
8406  * Called by the parent of an actor to assign the actor its size.
8407  * Should never be called by applications (except when implementing
8408  * a container or layout manager).
8409  *
8410  * Actors can know from their allocation box whether they have moved
8411  * with respect to their parent actor. The @flags parameter describes
8412  * additional information about the allocation, for instance whether
8413  * the parent has moved with respect to the stage, for example because
8414  * a grandparent's origin has moved.
8415  *
8416  * Since: 0.8
8417  */
8418 void
8419 clutter_actor_allocate (ClutterActor           *self,
8420                         const ClutterActorBox  *box,
8421                         ClutterAllocationFlags  flags)
8422 {
8423   ClutterActorPrivate *priv;
8424   ClutterActorClass *klass;
8425   ClutterActorBox old_allocation, real_allocation;
8426   gboolean origin_changed, child_moved, size_changed;
8427   gboolean stage_allocation_changed;
8428
8429   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8430   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8431     {
8432       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8433                  "which isn't a descendent of the stage!\n",
8434                  self, _clutter_actor_get_debug_name (self));
8435       return;
8436     }
8437
8438   priv = self->priv;
8439
8440   old_allocation = priv->allocation;
8441   real_allocation = *box;
8442
8443   /* constraints are allowed to modify the allocation only here; we do
8444    * this prior to all the other checks so that we can bail out if the
8445    * allocation did not change
8446    */
8447   clutter_actor_update_constraints (self, &real_allocation);
8448
8449   /* adjust the allocation depending on the align/margin properties */
8450   clutter_actor_adjust_allocation (self, &real_allocation);
8451
8452   if (real_allocation.x2 < real_allocation.x1 ||
8453       real_allocation.y2 < real_allocation.y1)
8454     {
8455       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8456                  _clutter_actor_get_debug_name (self),
8457                  real_allocation.x2 - real_allocation.x1,
8458                  real_allocation.y2 - real_allocation.y1);
8459     }
8460
8461   /* we allow 0-sized actors, but not negative-sized ones */
8462   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8463   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8464
8465   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8466
8467   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8468                  real_allocation.y1 != old_allocation.y1);
8469
8470   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8471                   real_allocation.y2 != old_allocation.y2);
8472
8473   if (origin_changed || child_moved || size_changed)
8474     stage_allocation_changed = TRUE;
8475   else
8476     stage_allocation_changed = FALSE;
8477
8478   /* If we get an allocation "out of the blue"
8479    * (we did not queue relayout), then we want to
8480    * ignore it. But if we have needs_allocation set,
8481    * we want to guarantee that allocate() virtual
8482    * method is always called, i.e. that queue_relayout()
8483    * always results in an allocate() invocation on
8484    * an actor.
8485    *
8486    * The optimization here is to avoid re-allocating
8487    * actors that did not queue relayout and were
8488    * not moved.
8489    */
8490   if (!priv->needs_allocation && !stage_allocation_changed)
8491     {
8492       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8493       return;
8494     }
8495
8496   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8497    * clutter_actor_allocate(), it indicates whether the parent has its
8498    * absolute origin moved; when passed in to ClutterActor::allocate()
8499    * virtual method though, it indicates whether the child has its
8500    * absolute origin moved.  So we set it when child_moved is TRUE
8501    */
8502   if (child_moved)
8503     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8504
8505   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8506
8507   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8508                 _clutter_actor_get_debug_name (self));
8509
8510   klass = CLUTTER_ACTOR_GET_CLASS (self);
8511   klass->allocate (self, &real_allocation, flags);
8512
8513   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8514
8515   if (stage_allocation_changed)
8516     clutter_actor_queue_redraw (self);
8517 }
8518
8519 /**
8520  * clutter_actor_set_allocation:
8521  * @self: a #ClutterActor
8522  * @box: a #ClutterActorBox
8523  * @flags: allocation flags
8524  *
8525  * Stores the allocation of @self as defined by @box.
8526  *
8527  * This function can only be called from within the implementation of
8528  * the #ClutterActorClass.allocate() virtual function.
8529  *
8530  * The allocation should have been adjusted to take into account constraints,
8531  * alignment, and margin properties. If you are implementing a #ClutterActor
8532  * subclass that provides its own layout management policy for its children
8533  * instead of using a #ClutterLayoutManager delegate, you should not call
8534  * this function on the children of @self; instead, you should call
8535  * clutter_actor_allocate(), which will adjust the allocation box for
8536  * you.
8537  *
8538  * This function should only be used by subclasses of #ClutterActor
8539  * that wish to store their allocation but cannot chain up to the
8540  * parent's implementation; the default implementation of the
8541  * #ClutterActorClass.allocate() virtual function will call this
8542  * function.
8543  *
8544  * It is important to note that, while chaining up was the recommended
8545  * behaviour for #ClutterActor subclasses prior to the introduction of
8546  * this function, it is recommended to call clutter_actor_set_allocation()
8547  * instead.
8548  *
8549  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8550  * to handle the allocation of its children, this function will call
8551  * the clutter_layout_manager_allocate() function only if the
8552  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8553  * expected that the subclass will call clutter_layout_manager_allocate()
8554  * by itself. For instance, the following code:
8555  *
8556  * |[
8557  * static void
8558  * my_actor_allocate (ClutterActor *actor,
8559  *                    const ClutterActorBox *allocation,
8560  *                    ClutterAllocationFlags flags)
8561  * {
8562  *   ClutterActorBox new_alloc;
8563  *   ClutterAllocationFlags new_flags;
8564  *
8565  *   adjust_allocation (allocation, &amp;new_alloc);
8566  *
8567  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8568  *
8569  *   /&ast; this will use the layout manager set on the actor &ast;/
8570  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8571  * }
8572  * ]|
8573  *
8574  * is equivalent to this:
8575  *
8576  * |[
8577  * static void
8578  * my_actor_allocate (ClutterActor *actor,
8579  *                    const ClutterActorBox *allocation,
8580  *                    ClutterAllocationFlags flags)
8581  * {
8582  *   ClutterLayoutManager *layout;
8583  *   ClutterActorBox new_alloc;
8584  *
8585  *   adjust_allocation (allocation, &amp;new_alloc);
8586  *
8587  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8588  *
8589  *   layout = clutter_actor_get_layout_manager (actor);
8590  *   clutter_layout_manager_allocate (layout,
8591  *                                    CLUTTER_CONTAINER (actor),
8592  *                                    &amp;new_alloc,
8593  *                                    flags);
8594  * }
8595  * ]|
8596  *
8597  * Since: 1.10
8598  */
8599 void
8600 clutter_actor_set_allocation (ClutterActor           *self,
8601                               const ClutterActorBox  *box,
8602                               ClutterAllocationFlags  flags)
8603 {
8604   ClutterActorPrivate *priv;
8605   gboolean changed;
8606
8607   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8608   g_return_if_fail (box != NULL);
8609
8610   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8611     {
8612       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8613                   "can only be called from within the implementation of "
8614                   "the ClutterActor::allocate() virtual function.");
8615       return;
8616     }
8617
8618   priv = self->priv;
8619
8620   g_object_freeze_notify (G_OBJECT (self));
8621
8622   changed = clutter_actor_set_allocation_internal (self, box, flags);
8623
8624   /* we allocate our children before we notify changes in our geometry,
8625    * so that people connecting to properties will be able to get valid
8626    * data out of the sub-tree of the scene graph that has this actor at
8627    * the root.
8628    */
8629   clutter_actor_maybe_layout_children (self, box, flags);
8630
8631   if (changed)
8632     {
8633       ClutterActorBox signal_box = priv->allocation;
8634       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8635
8636       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8637                      &signal_box,
8638                      signal_flags);
8639     }
8640
8641   g_object_thaw_notify (G_OBJECT (self));
8642 }
8643
8644 /**
8645  * clutter_actor_set_geometry:
8646  * @self: A #ClutterActor
8647  * @geometry: A #ClutterGeometry
8648  *
8649  * Sets the actor's fixed position and forces its minimum and natural
8650  * size, in pixels. This means the untransformed actor will have the
8651  * given geometry. This is the same as calling clutter_actor_set_position()
8652  * and clutter_actor_set_size().
8653  *
8654  * Deprecated: 1.10: Use clutter_actor_set_position() and
8655  *   clutter_actor_set_size() instead.
8656  */
8657 void
8658 clutter_actor_set_geometry (ClutterActor          *self,
8659                             const ClutterGeometry *geometry)
8660 {
8661   g_object_freeze_notify (G_OBJECT (self));
8662
8663   clutter_actor_set_position (self, geometry->x, geometry->y);
8664   clutter_actor_set_size (self, geometry->width, geometry->height);
8665
8666   g_object_thaw_notify (G_OBJECT (self));
8667 }
8668
8669 /**
8670  * clutter_actor_get_geometry:
8671  * @self: A #ClutterActor
8672  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8673  *
8674  * Gets the size and position of an actor relative to its parent
8675  * actor. This is the same as calling clutter_actor_get_position() and
8676  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8677  * requested size and position if the actor's allocation is invalid.
8678  *
8679  * Deprecated: 1.10: Use clutter_actor_get_position() and
8680  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8681  *   instead.
8682  */
8683 void
8684 clutter_actor_get_geometry (ClutterActor    *self,
8685                             ClutterGeometry *geometry)
8686 {
8687   gfloat x, y, width, height;
8688
8689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8690   g_return_if_fail (geometry != NULL);
8691
8692   clutter_actor_get_position (self, &x, &y);
8693   clutter_actor_get_size (self, &width, &height);
8694
8695   geometry->x = (int) x;
8696   geometry->y = (int) y;
8697   geometry->width = (int) width;
8698   geometry->height = (int) height;
8699 }
8700
8701 /**
8702  * clutter_actor_set_position:
8703  * @self: A #ClutterActor
8704  * @x: New left position of actor in pixels.
8705  * @y: New top position of actor in pixels.
8706  *
8707  * Sets the actor's fixed position in pixels relative to any parent
8708  * actor.
8709  *
8710  * If a layout manager is in use, this position will override the
8711  * layout manager and force a fixed position.
8712  */
8713 void
8714 clutter_actor_set_position (ClutterActor *self,
8715                             gfloat        x,
8716                             gfloat        y)
8717 {
8718   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8719
8720   g_object_freeze_notify (G_OBJECT (self));
8721
8722   clutter_actor_set_x (self, x);
8723   clutter_actor_set_y (self, y);
8724
8725   g_object_thaw_notify (G_OBJECT (self));
8726 }
8727
8728 /**
8729  * clutter_actor_get_fixed_position_set:
8730  * @self: A #ClutterActor
8731  *
8732  * Checks whether an actor has a fixed position set (and will thus be
8733  * unaffected by any layout manager).
8734  *
8735  * Return value: %TRUE if the fixed position is set on the actor
8736  *
8737  * Since: 0.8
8738  */
8739 gboolean
8740 clutter_actor_get_fixed_position_set (ClutterActor *self)
8741 {
8742   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8743
8744   return self->priv->position_set;
8745 }
8746
8747 /**
8748  * clutter_actor_set_fixed_position_set:
8749  * @self: A #ClutterActor
8750  * @is_set: whether to use fixed position
8751  *
8752  * Sets whether an actor has a fixed position set (and will thus be
8753  * unaffected by any layout manager).
8754  *
8755  * Since: 0.8
8756  */
8757 void
8758 clutter_actor_set_fixed_position_set (ClutterActor *self,
8759                                       gboolean      is_set)
8760 {
8761   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8762
8763   if (self->priv->position_set == (is_set != FALSE))
8764     return;
8765
8766   self->priv->position_set = is_set != FALSE;
8767   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8768
8769   clutter_actor_queue_relayout (self);
8770 }
8771
8772 /**
8773  * clutter_actor_move_by:
8774  * @self: A #ClutterActor
8775  * @dx: Distance to move Actor on X axis.
8776  * @dy: Distance to move Actor on Y axis.
8777  *
8778  * Moves an actor by the specified distance relative to its current
8779  * position in pixels.
8780  *
8781  * This function modifies the fixed position of an actor and thus removes
8782  * it from any layout management. Another way to move an actor is with an
8783  * anchor point, see clutter_actor_set_anchor_point().
8784  *
8785  * Since: 0.2
8786  */
8787 void
8788 clutter_actor_move_by (ClutterActor *self,
8789                        gfloat        dx,
8790                        gfloat        dy)
8791 {
8792   const ClutterLayoutInfo *info;
8793   gfloat x, y;
8794
8795   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8796
8797   info = _clutter_actor_get_layout_info_or_defaults (self);
8798   x = info->fixed_x;
8799   y = info->fixed_y;
8800
8801   clutter_actor_set_position (self, x + dx, y + dy);
8802 }
8803
8804 static void
8805 clutter_actor_set_min_width (ClutterActor *self,
8806                              gfloat        min_width)
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_width_set && min_width == info->min_width)
8824     return;
8825
8826   g_object_freeze_notify (G_OBJECT (self));
8827
8828   clutter_actor_store_old_geometry (self, &old);
8829
8830   info->min_width = min_width;
8831   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8832   clutter_actor_set_min_width_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_min_height (ClutterActor *self,
8843                               gfloat        min_height)
8844
8845 {
8846   ClutterActorPrivate *priv = self->priv;
8847   ClutterActorBox old = { 0, };
8848   ClutterLayoutInfo *info;
8849
8850   /* if we are setting the size on a top-level actor and the
8851    * backend only supports static top-levels (e.g. framebuffers)
8852    * then we ignore the passed value and we override it with
8853    * the stage implementation's preferred size.
8854    */
8855   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8856       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8857     return;
8858
8859   info = _clutter_actor_get_layout_info (self);
8860
8861   if (priv->min_height_set && min_height == info->min_height)
8862     return;
8863
8864   g_object_freeze_notify (G_OBJECT (self));
8865
8866   clutter_actor_store_old_geometry (self, &old);
8867
8868   info->min_height = min_height;
8869   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8870   clutter_actor_set_min_height_set (self, TRUE);
8871
8872   clutter_actor_notify_if_geometry_changed (self, &old);
8873
8874   g_object_thaw_notify (G_OBJECT (self));
8875
8876   clutter_actor_queue_relayout (self);
8877 }
8878
8879 static void
8880 clutter_actor_set_natural_width (ClutterActor *self,
8881                                  gfloat        natural_width)
8882 {
8883   ClutterActorPrivate *priv = self->priv;
8884   ClutterActorBox old = { 0, };
8885   ClutterLayoutInfo *info;
8886
8887   /* if we are setting the size on a top-level actor and the
8888    * backend only supports static top-levels (e.g. framebuffers)
8889    * then we ignore the passed value and we override it with
8890    * the stage implementation's preferred size.
8891    */
8892   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8893       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8894     return;
8895
8896   info = _clutter_actor_get_layout_info (self);
8897
8898   if (priv->natural_width_set && natural_width == info->natural_width)
8899     return;
8900
8901   g_object_freeze_notify (G_OBJECT (self));
8902
8903   clutter_actor_store_old_geometry (self, &old);
8904
8905   info->natural_width = natural_width;
8906   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8907   clutter_actor_set_natural_width_set (self, TRUE);
8908
8909   clutter_actor_notify_if_geometry_changed (self, &old);
8910
8911   g_object_thaw_notify (G_OBJECT (self));
8912
8913   clutter_actor_queue_relayout (self);
8914 }
8915
8916 static void
8917 clutter_actor_set_natural_height (ClutterActor *self,
8918                                   gfloat        natural_height)
8919 {
8920   ClutterActorPrivate *priv = self->priv;
8921   ClutterActorBox old = { 0, };
8922   ClutterLayoutInfo *info;
8923
8924   /* if we are setting the size on a top-level actor and the
8925    * backend only supports static top-levels (e.g. framebuffers)
8926    * then we ignore the passed value and we override it with
8927    * the stage implementation's preferred size.
8928    */
8929   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8930       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8931     return;
8932
8933   info = _clutter_actor_get_layout_info (self);
8934
8935   if (priv->natural_height_set && natural_height == info->natural_height)
8936     return;
8937
8938   g_object_freeze_notify (G_OBJECT (self));
8939
8940   clutter_actor_store_old_geometry (self, &old);
8941
8942   info->natural_height = natural_height;
8943   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8944   clutter_actor_set_natural_height_set (self, TRUE);
8945
8946   clutter_actor_notify_if_geometry_changed (self, &old);
8947
8948   g_object_thaw_notify (G_OBJECT (self));
8949
8950   clutter_actor_queue_relayout (self);
8951 }
8952
8953 static void
8954 clutter_actor_set_min_width_set (ClutterActor *self,
8955                                  gboolean      use_min_width)
8956 {
8957   ClutterActorPrivate *priv = self->priv;
8958   ClutterActorBox old = { 0, };
8959
8960   if (priv->min_width_set == (use_min_width != FALSE))
8961     return;
8962
8963   clutter_actor_store_old_geometry (self, &old);
8964
8965   priv->min_width_set = use_min_width != FALSE;
8966   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8967
8968   clutter_actor_notify_if_geometry_changed (self, &old);
8969
8970   clutter_actor_queue_relayout (self);
8971 }
8972
8973 static void
8974 clutter_actor_set_min_height_set (ClutterActor *self,
8975                                   gboolean      use_min_height)
8976 {
8977   ClutterActorPrivate *priv = self->priv;
8978   ClutterActorBox old = { 0, };
8979
8980   if (priv->min_height_set == (use_min_height != FALSE))
8981     return;
8982
8983   clutter_actor_store_old_geometry (self, &old);
8984
8985   priv->min_height_set = use_min_height != FALSE;
8986   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8987
8988   clutter_actor_notify_if_geometry_changed (self, &old);
8989
8990   clutter_actor_queue_relayout (self);
8991 }
8992
8993 static void
8994 clutter_actor_set_natural_width_set (ClutterActor *self,
8995                                      gboolean      use_natural_width)
8996 {
8997   ClutterActorPrivate *priv = self->priv;
8998   ClutterActorBox old = { 0, };
8999
9000   if (priv->natural_width_set == (use_natural_width != FALSE))
9001     return;
9002
9003   clutter_actor_store_old_geometry (self, &old);
9004
9005   priv->natural_width_set = use_natural_width != FALSE;
9006   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9007
9008   clutter_actor_notify_if_geometry_changed (self, &old);
9009
9010   clutter_actor_queue_relayout (self);
9011 }
9012
9013 static void
9014 clutter_actor_set_natural_height_set (ClutterActor *self,
9015                                       gboolean      use_natural_height)
9016 {
9017   ClutterActorPrivate *priv = self->priv;
9018   ClutterActorBox old = { 0, };
9019
9020   if (priv->natural_height_set == (use_natural_height != FALSE))
9021     return;
9022
9023   clutter_actor_store_old_geometry (self, &old);
9024
9025   priv->natural_height_set = use_natural_height != FALSE;
9026   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9027
9028   clutter_actor_notify_if_geometry_changed (self, &old);
9029
9030   clutter_actor_queue_relayout (self);
9031 }
9032
9033 /**
9034  * clutter_actor_set_request_mode:
9035  * @self: a #ClutterActor
9036  * @mode: the request mode
9037  *
9038  * Sets the geometry request mode of @self.
9039  *
9040  * The @mode determines the order for invoking
9041  * clutter_actor_get_preferred_width() and
9042  * clutter_actor_get_preferred_height()
9043  *
9044  * Since: 1.2
9045  */
9046 void
9047 clutter_actor_set_request_mode (ClutterActor       *self,
9048                                 ClutterRequestMode  mode)
9049 {
9050   ClutterActorPrivate *priv;
9051
9052   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9053
9054   priv = self->priv;
9055
9056   if (priv->request_mode == mode)
9057     return;
9058
9059   priv->request_mode = mode;
9060
9061   priv->needs_width_request = TRUE;
9062   priv->needs_height_request = TRUE;
9063
9064   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9065
9066   clutter_actor_queue_relayout (self);
9067 }
9068
9069 /**
9070  * clutter_actor_get_request_mode:
9071  * @self: a #ClutterActor
9072  *
9073  * Retrieves the geometry request mode of @self
9074  *
9075  * Return value: the request mode for the actor
9076  *
9077  * Since: 1.2
9078  */
9079 ClutterRequestMode
9080 clutter_actor_get_request_mode (ClutterActor *self)
9081 {
9082   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9083                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9084
9085   return self->priv->request_mode;
9086 }
9087
9088 /* variant of set_width() without checks and without notification
9089  * freeze+thaw, for internal usage only
9090  */
9091 static inline void
9092 clutter_actor_set_width_internal (ClutterActor *self,
9093                                   gfloat        width)
9094 {
9095   if (width >= 0)
9096     {
9097       /* the Stage will use the :min-width to control the minimum
9098        * width to be resized to, so we should not be setting it
9099        * along with the :natural-width
9100        */
9101       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9102         clutter_actor_set_min_width (self, width);
9103
9104       clutter_actor_set_natural_width (self, width);
9105     }
9106   else
9107     {
9108       /* we only unset the :natural-width for the Stage */
9109       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9110         clutter_actor_set_min_width_set (self, FALSE);
9111
9112       clutter_actor_set_natural_width_set (self, FALSE);
9113     }
9114 }
9115
9116 /* variant of set_height() without checks and without notification
9117  * freeze+thaw, for internal usage only
9118  */
9119 static inline void
9120 clutter_actor_set_height_internal (ClutterActor *self,
9121                                    gfloat        height)
9122 {
9123   if (height >= 0)
9124     {
9125       /* see the comment above in set_width_internal() */
9126       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9127         clutter_actor_set_min_height (self, height);
9128
9129       clutter_actor_set_natural_height (self, height);
9130     }
9131   else
9132     {
9133       /* see the comment above in set_width_internal() */
9134       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9135         clutter_actor_set_min_height_set (self, FALSE);
9136
9137       clutter_actor_set_natural_height_set (self, FALSE);
9138     }
9139 }
9140
9141 /**
9142  * clutter_actor_set_size:
9143  * @self: A #ClutterActor
9144  * @width: New width of actor in pixels, or -1
9145  * @height: New height of actor in pixels, or -1
9146  *
9147  * Sets the actor's size request in pixels. This overrides any
9148  * "normal" size request the actor would have. For example
9149  * a text actor might normally request the size of the text;
9150  * this function would force a specific size instead.
9151  *
9152  * If @width and/or @height are -1 the actor will use its
9153  * "normal" size request instead of overriding it, i.e.
9154  * you can "unset" the size with -1.
9155  *
9156  * This function sets or unsets both the minimum and natural size.
9157  */
9158 void
9159 clutter_actor_set_size (ClutterActor *self,
9160                         gfloat        width,
9161                         gfloat        height)
9162 {
9163   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9164
9165   g_object_freeze_notify (G_OBJECT (self));
9166
9167   clutter_actor_set_width (self, width);
9168   clutter_actor_set_height (self, height);
9169
9170   g_object_thaw_notify (G_OBJECT (self));
9171 }
9172
9173 /**
9174  * clutter_actor_get_size:
9175  * @self: A #ClutterActor
9176  * @width: (out) (allow-none): return location for the width, or %NULL.
9177  * @height: (out) (allow-none): return location for the height, or %NULL.
9178  *
9179  * This function tries to "do what you mean" and return
9180  * the size an actor will have. If the actor has a valid
9181  * allocation, the allocation will be returned; otherwise,
9182  * the actors natural size request will be returned.
9183  *
9184  * If you care whether you get the request vs. the allocation, you
9185  * should probably call a different function like
9186  * clutter_actor_get_allocation_box() or
9187  * clutter_actor_get_preferred_width().
9188  *
9189  * Since: 0.2
9190  */
9191 void
9192 clutter_actor_get_size (ClutterActor *self,
9193                         gfloat       *width,
9194                         gfloat       *height)
9195 {
9196   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9197
9198   if (width)
9199     *width = clutter_actor_get_width (self);
9200
9201   if (height)
9202     *height = clutter_actor_get_height (self);
9203 }
9204
9205 /**
9206  * clutter_actor_get_position:
9207  * @self: a #ClutterActor
9208  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9209  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9210  *
9211  * This function tries to "do what you mean" and tell you where the
9212  * actor is, prior to any transformations. Retrieves the fixed
9213  * position of an actor in pixels, if one has been set; otherwise, if
9214  * the allocation is valid, returns the actor's allocated position;
9215  * otherwise, returns 0,0.
9216  *
9217  * The returned position is in pixels.
9218  *
9219  * Since: 0.6
9220  */
9221 void
9222 clutter_actor_get_position (ClutterActor *self,
9223                             gfloat       *x,
9224                             gfloat       *y)
9225 {
9226   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9227
9228   if (x)
9229     *x = clutter_actor_get_x (self);
9230
9231   if (y)
9232     *y = clutter_actor_get_y (self);
9233 }
9234
9235 /**
9236  * clutter_actor_get_transformed_position:
9237  * @self: A #ClutterActor
9238  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9239  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9240  *
9241  * Gets the absolute position of an actor, in pixels relative to the stage.
9242  *
9243  * Since: 0.8
9244  */
9245 void
9246 clutter_actor_get_transformed_position (ClutterActor *self,
9247                                         gfloat       *x,
9248                                         gfloat       *y)
9249 {
9250   ClutterVertex v1;
9251   ClutterVertex v2;
9252
9253   v1.x = v1.y = v1.z = 0;
9254   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9255
9256   if (x)
9257     *x = v2.x;
9258
9259   if (y)
9260     *y = v2.y;
9261 }
9262
9263 /**
9264  * clutter_actor_get_transformed_size:
9265  * @self: A #ClutterActor
9266  * @width: (out) (allow-none): return location for the width, or %NULL
9267  * @height: (out) (allow-none): return location for the height, or %NULL
9268  *
9269  * Gets the absolute size of an actor in pixels, taking into account the
9270  * scaling factors.
9271  *
9272  * If the actor has a valid allocation, the allocated size will be used.
9273  * If the actor has not a valid allocation then the preferred size will
9274  * be transformed and returned.
9275  *
9276  * If you want the transformed allocation, see
9277  * clutter_actor_get_abs_allocation_vertices() instead.
9278  *
9279  * <note>When the actor (or one of its ancestors) is rotated around the
9280  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9281  * as a generic quadrangle; in that case this function returns the size
9282  * of the smallest rectangle that encapsulates the entire quad. Please
9283  * note that in this case no assumptions can be made about the relative
9284  * position of this envelope to the absolute position of the actor, as
9285  * returned by clutter_actor_get_transformed_position(); if you need this
9286  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9287  * to get the coords of the actual quadrangle.</note>
9288  *
9289  * Since: 0.8
9290  */
9291 void
9292 clutter_actor_get_transformed_size (ClutterActor *self,
9293                                     gfloat       *width,
9294                                     gfloat       *height)
9295 {
9296   ClutterActorPrivate *priv;
9297   ClutterVertex v[4];
9298   gfloat x_min, x_max, y_min, y_max;
9299   gint i;
9300
9301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9302
9303   priv = self->priv;
9304
9305   /* if the actor hasn't been allocated yet, get the preferred
9306    * size and transform that
9307    */
9308   if (priv->needs_allocation)
9309     {
9310       gfloat natural_width, natural_height;
9311       ClutterActorBox box;
9312
9313       /* Make a fake allocation to transform.
9314        *
9315        * NB: _clutter_actor_transform_and_project_box expects a box in
9316        * the actor's coordinate space... */
9317
9318       box.x1 = 0;
9319       box.y1 = 0;
9320
9321       natural_width = natural_height = 0;
9322       clutter_actor_get_preferred_size (self, NULL, NULL,
9323                                         &natural_width,
9324                                         &natural_height);
9325
9326       box.x2 = natural_width;
9327       box.y2 = natural_height;
9328
9329       _clutter_actor_transform_and_project_box (self, &box, v);
9330     }
9331   else
9332     clutter_actor_get_abs_allocation_vertices (self, v);
9333
9334   x_min = x_max = v[0].x;
9335   y_min = y_max = v[0].y;
9336
9337   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9338     {
9339       if (v[i].x < x_min)
9340         x_min = v[i].x;
9341
9342       if (v[i].x > x_max)
9343         x_max = v[i].x;
9344
9345       if (v[i].y < y_min)
9346         y_min = v[i].y;
9347
9348       if (v[i].y > y_max)
9349         y_max = v[i].y;
9350     }
9351
9352   if (width)
9353     *width  = x_max - x_min;
9354
9355   if (height)
9356     *height = y_max - y_min;
9357 }
9358
9359 /**
9360  * clutter_actor_get_width:
9361  * @self: A #ClutterActor
9362  *
9363  * Retrieves the width of a #ClutterActor.
9364  *
9365  * If the actor has a valid allocation, this function will return the
9366  * width of the allocated area given to the actor.
9367  *
9368  * If the actor does not have a valid allocation, this function will
9369  * return the actor's natural width, that is the preferred width of
9370  * the actor.
9371  *
9372  * If you care whether you get the preferred width or the width that
9373  * has been assigned to the actor, you should probably call a different
9374  * function like clutter_actor_get_allocation_box() to retrieve the
9375  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9376  * preferred width.
9377  *
9378  * If an actor has a fixed width, for instance a width that has been
9379  * assigned using clutter_actor_set_width(), the width returned will
9380  * be the same value.
9381  *
9382  * Return value: the width of the actor, in pixels
9383  */
9384 gfloat
9385 clutter_actor_get_width (ClutterActor *self)
9386 {
9387   ClutterActorPrivate *priv;
9388
9389   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9390
9391   priv = self->priv;
9392
9393   if (priv->needs_allocation)
9394     {
9395       gfloat natural_width = 0;
9396
9397       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9398         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9399       else
9400         {
9401           gfloat natural_height = 0;
9402
9403           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9404           clutter_actor_get_preferred_width (self, natural_height,
9405                                              NULL,
9406                                              &natural_width);
9407         }
9408
9409       return natural_width;
9410     }
9411   else
9412     return priv->allocation.x2 - priv->allocation.x1;
9413 }
9414
9415 /**
9416  * clutter_actor_get_height:
9417  * @self: A #ClutterActor
9418  *
9419  * Retrieves the height of a #ClutterActor.
9420  *
9421  * If the actor has a valid allocation, this function will return the
9422  * height of the allocated area given to the actor.
9423  *
9424  * If the actor does not have a valid allocation, this function will
9425  * return the actor's natural height, that is the preferred height of
9426  * the actor.
9427  *
9428  * If you care whether you get the preferred height or the height that
9429  * has been assigned to the actor, you should probably call a different
9430  * function like clutter_actor_get_allocation_box() to retrieve the
9431  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9432  * preferred height.
9433  *
9434  * If an actor has a fixed height, for instance a height that has been
9435  * assigned using clutter_actor_set_height(), the height returned will
9436  * be the same value.
9437  *
9438  * Return value: the height of the actor, in pixels
9439  */
9440 gfloat
9441 clutter_actor_get_height (ClutterActor *self)
9442 {
9443   ClutterActorPrivate *priv;
9444
9445   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9446
9447   priv = self->priv;
9448
9449   if (priv->needs_allocation)
9450     {
9451       gfloat natural_height = 0;
9452
9453       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9454         {
9455           gfloat natural_width = 0;
9456
9457           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9458           clutter_actor_get_preferred_height (self, natural_width,
9459                                               NULL, &natural_height);
9460         }
9461       else
9462         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9463
9464       return natural_height;
9465     }
9466   else
9467     return priv->allocation.y2 - priv->allocation.y1;
9468 }
9469
9470 /**
9471  * clutter_actor_set_width:
9472  * @self: A #ClutterActor
9473  * @width: Requested new width for the actor, in pixels, or -1
9474  *
9475  * Forces a width on an actor, causing the actor's preferred width
9476  * and height (if any) to be ignored.
9477  *
9478  * If @width is -1 the actor will use its preferred width request
9479  * instead of overriding it, i.e. you can "unset" the width with -1.
9480  *
9481  * This function sets both the minimum and natural size of the actor.
9482  *
9483  * since: 0.2
9484  */
9485 void
9486 clutter_actor_set_width (ClutterActor *self,
9487                          gfloat        width)
9488 {
9489   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9490
9491   if (clutter_actor_get_easing_duration (self) != 0)
9492     {
9493       ClutterTransition *transition;
9494
9495       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9496       if (transition == NULL)
9497         {
9498           float old_width = clutter_actor_get_width (self);
9499
9500           transition = _clutter_actor_create_transition (self,
9501                                                          obj_props[PROP_WIDTH],
9502                                                          old_width,
9503                                                          width);
9504         }
9505       else
9506         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9507
9508       clutter_actor_queue_relayout (self);
9509     }
9510   else
9511     {
9512       g_object_freeze_notify (G_OBJECT (self));
9513
9514       clutter_actor_set_width_internal (self, width);
9515
9516       g_object_thaw_notify (G_OBJECT (self));
9517     }
9518 }
9519
9520 /**
9521  * clutter_actor_set_height:
9522  * @self: A #ClutterActor
9523  * @height: Requested new height for the actor, in pixels, or -1
9524  *
9525  * Forces a height on an actor, causing the actor's preferred width
9526  * and height (if any) to be ignored.
9527  *
9528  * If @height is -1 the actor will use its preferred height instead of
9529  * overriding it, i.e. you can "unset" the height with -1.
9530  *
9531  * This function sets both the minimum and natural size of the actor.
9532  *
9533  * since: 0.2
9534  */
9535 void
9536 clutter_actor_set_height (ClutterActor *self,
9537                           gfloat        height)
9538 {
9539   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9540
9541   if (clutter_actor_get_easing_duration (self) != 0)
9542     {
9543       ClutterTransition *transition;
9544
9545       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9546       if (transition ==  NULL)
9547         {
9548           float old_height = clutter_actor_get_height (self);
9549
9550           transition = _clutter_actor_create_transition (self,
9551                                                          obj_props[PROP_HEIGHT],
9552                                                          old_height,
9553                                                          height);
9554         }
9555       else
9556         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9557
9558       clutter_actor_queue_relayout (self);
9559     }
9560   else
9561     {
9562       g_object_freeze_notify (G_OBJECT (self));
9563
9564       clutter_actor_set_height_internal (self, height);
9565
9566       g_object_thaw_notify (G_OBJECT (self));
9567     }
9568 }
9569
9570 static inline void
9571 clutter_actor_set_x_internal (ClutterActor *self,
9572                               float         x)
9573 {
9574   ClutterActorPrivate *priv = self->priv;
9575   ClutterLayoutInfo *linfo;
9576   ClutterActorBox old = { 0, };
9577
9578   linfo = _clutter_actor_get_layout_info (self);
9579
9580   if (priv->position_set && linfo->fixed_x == x)
9581     return;
9582
9583   clutter_actor_store_old_geometry (self, &old);
9584
9585   linfo->fixed_x = x;
9586   clutter_actor_set_fixed_position_set (self, TRUE);
9587
9588   clutter_actor_notify_if_geometry_changed (self, &old);
9589
9590   clutter_actor_queue_relayout (self);
9591 }
9592
9593 static inline void
9594 clutter_actor_set_y_internal (ClutterActor *self,
9595                               float         y)
9596 {
9597   ClutterActorPrivate *priv = self->priv;
9598   ClutterLayoutInfo *linfo;
9599   ClutterActorBox old = { 0, };
9600
9601   linfo = _clutter_actor_get_layout_info (self);
9602
9603   if (priv->position_set && linfo->fixed_y == y)
9604     return;
9605
9606   clutter_actor_store_old_geometry (self, &old);
9607
9608   linfo->fixed_y = y;
9609   clutter_actor_set_fixed_position_set (self, TRUE);
9610
9611   clutter_actor_notify_if_geometry_changed (self, &old);
9612
9613   clutter_actor_queue_relayout (self);
9614 }
9615
9616 /**
9617  * clutter_actor_set_x:
9618  * @self: a #ClutterActor
9619  * @x: the actor's position on the X axis
9620  *
9621  * Sets the actor's X coordinate, relative to its parent, in pixels.
9622  *
9623  * Overrides any layout manager and forces a fixed position for
9624  * the actor.
9625  *
9626  * The #ClutterActor:x property is animatable.
9627  *
9628  * Since: 0.6
9629  */
9630 void
9631 clutter_actor_set_x (ClutterActor *self,
9632                      gfloat        x)
9633 {
9634   const ClutterLayoutInfo *linfo;
9635
9636   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9637
9638   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9639
9640   if (clutter_actor_get_easing_duration (self) != 0)
9641     {
9642       ClutterTransition *transition;
9643
9644       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9645       if (transition == NULL)
9646         {
9647           transition = _clutter_actor_create_transition (self,
9648                                                          obj_props[PROP_X],
9649                                                          linfo->fixed_x,
9650                                                          x);
9651         }
9652       else
9653         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9654
9655       clutter_actor_queue_relayout (self);
9656     }
9657   else
9658     clutter_actor_set_x_internal (self, x);
9659 }
9660
9661 /**
9662  * clutter_actor_set_y:
9663  * @self: a #ClutterActor
9664  * @y: the actor's position on the Y axis
9665  *
9666  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9667  *
9668  * Overrides any layout manager and forces a fixed position for
9669  * the actor.
9670  *
9671  * The #ClutterActor:y property is animatable.
9672  *
9673  * Since: 0.6
9674  */
9675 void
9676 clutter_actor_set_y (ClutterActor *self,
9677                      gfloat        y)
9678 {
9679   const ClutterLayoutInfo *linfo;
9680
9681   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9682
9683   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9684
9685   if (clutter_actor_get_easing_duration (self) != 0)
9686     {
9687       ClutterTransition *transition;
9688
9689       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9690       if (transition == NULL)
9691         {
9692           transition = _clutter_actor_create_transition (self,
9693                                                          obj_props[PROP_Y],
9694                                                          linfo->fixed_y,
9695                                                          y);
9696         }
9697       else
9698         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9699
9700       clutter_actor_queue_relayout (self);
9701     }
9702   else
9703     clutter_actor_set_y_internal (self, y);
9704
9705   clutter_actor_queue_relayout (self);
9706 }
9707
9708 /**
9709  * clutter_actor_get_x:
9710  * @self: A #ClutterActor
9711  *
9712  * Retrieves the X coordinate of a #ClutterActor.
9713  *
9714  * This function tries to "do what you mean", by returning the
9715  * correct value depending on the actor's state.
9716  *
9717  * If the actor has a valid allocation, this function will return
9718  * the X coordinate of the origin of the allocation box.
9719  *
9720  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9721  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9722  * function will return that coordinate.
9723  *
9724  * If both the allocation and a fixed position are missing, this function
9725  * will return 0.
9726  *
9727  * Return value: the X coordinate, in pixels, ignoring any
9728  *   transformation (i.e. scaling, rotation)
9729  */
9730 gfloat
9731 clutter_actor_get_x (ClutterActor *self)
9732 {
9733   ClutterActorPrivate *priv;
9734
9735   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9736
9737   priv = self->priv;
9738
9739   if (priv->needs_allocation)
9740     {
9741       if (priv->position_set)
9742         {
9743           const ClutterLayoutInfo *info;
9744
9745           info = _clutter_actor_get_layout_info_or_defaults (self);
9746
9747           return info->fixed_x;
9748         }
9749       else
9750         return 0;
9751     }
9752   else
9753     return priv->allocation.x1;
9754 }
9755
9756 /**
9757  * clutter_actor_get_y:
9758  * @self: A #ClutterActor
9759  *
9760  * Retrieves the Y coordinate of a #ClutterActor.
9761  *
9762  * This function tries to "do what you mean", by returning the
9763  * correct value depending on the actor's state.
9764  *
9765  * If the actor has a valid allocation, this function will return
9766  * the Y coordinate of the origin of the allocation box.
9767  *
9768  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9769  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9770  * function will return that coordinate.
9771  *
9772  * If both the allocation and a fixed position are missing, this function
9773  * will return 0.
9774  *
9775  * Return value: the Y coordinate, in pixels, ignoring any
9776  *   transformation (i.e. scaling, rotation)
9777  */
9778 gfloat
9779 clutter_actor_get_y (ClutterActor *self)
9780 {
9781   ClutterActorPrivate *priv;
9782
9783   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9784
9785   priv = self->priv;
9786
9787   if (priv->needs_allocation)
9788     {
9789       if (priv->position_set)
9790         {
9791           const ClutterLayoutInfo *info;
9792
9793           info = _clutter_actor_get_layout_info_or_defaults (self);
9794
9795           return info->fixed_y;
9796         }
9797       else
9798         return 0;
9799     }
9800   else
9801     return priv->allocation.y1;
9802 }
9803
9804 /**
9805  * clutter_actor_set_scale:
9806  * @self: A #ClutterActor
9807  * @scale_x: double factor to scale actor by horizontally.
9808  * @scale_y: double factor to scale actor by vertically.
9809  *
9810  * Scales an actor with the given factors. The scaling is relative to
9811  * the scale center and the anchor point. The scale center is
9812  * unchanged by this function and defaults to 0,0.
9813  *
9814  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9815  * animatable.
9816  *
9817  * Since: 0.2
9818  */
9819 void
9820 clutter_actor_set_scale (ClutterActor *self,
9821                          gdouble       scale_x,
9822                          gdouble       scale_y)
9823 {
9824   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9825
9826   g_object_freeze_notify (G_OBJECT (self));
9827
9828   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9829   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9830
9831   g_object_thaw_notify (G_OBJECT (self));
9832 }
9833
9834 /**
9835  * clutter_actor_set_scale_full:
9836  * @self: A #ClutterActor
9837  * @scale_x: double factor to scale actor by horizontally.
9838  * @scale_y: double factor to scale actor by vertically.
9839  * @center_x: X coordinate of the center of the scale.
9840  * @center_y: Y coordinate of the center of the scale
9841  *
9842  * Scales an actor with the given factors around the given center
9843  * point. The center point is specified in pixels relative to the
9844  * anchor point (usually the top left corner of the actor).
9845  *
9846  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9847  * are animatable.
9848  *
9849  * Since: 1.0
9850  */
9851 void
9852 clutter_actor_set_scale_full (ClutterActor *self,
9853                               gdouble       scale_x,
9854                               gdouble       scale_y,
9855                               gfloat        center_x,
9856                               gfloat        center_y)
9857 {
9858   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9859
9860   g_object_freeze_notify (G_OBJECT (self));
9861
9862   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9863   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9864   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9865   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9866
9867   g_object_thaw_notify (G_OBJECT (self));
9868 }
9869
9870 /**
9871  * clutter_actor_set_scale_with_gravity:
9872  * @self: A #ClutterActor
9873  * @scale_x: double factor to scale actor by horizontally.
9874  * @scale_y: double factor to scale actor by vertically.
9875  * @gravity: the location of the scale center expressed as a compass
9876  * direction.
9877  *
9878  * Scales an actor with the given factors around the given
9879  * center point. The center point is specified as one of the compass
9880  * directions in #ClutterGravity. For example, setting it to north
9881  * will cause the top of the actor to remain unchanged and the rest of
9882  * the actor to expand left, right and downwards.
9883  *
9884  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9885  * animatable.
9886  *
9887  * Since: 1.0
9888  */
9889 void
9890 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9891                                       gdouble         scale_x,
9892                                       gdouble         scale_y,
9893                                       ClutterGravity  gravity)
9894 {
9895   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9896
9897   g_object_freeze_notify (G_OBJECT (self));
9898
9899   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9900   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9901   clutter_actor_set_scale_gravity (self, gravity);
9902
9903   g_object_thaw_notify (G_OBJECT (self));
9904 }
9905
9906 /**
9907  * clutter_actor_get_scale:
9908  * @self: A #ClutterActor
9909  * @scale_x: (out) (allow-none): Location to store horizonal
9910  *   scale factor, or %NULL.
9911  * @scale_y: (out) (allow-none): Location to store vertical
9912  *   scale factor, or %NULL.
9913  *
9914  * Retrieves an actors scale factors.
9915  *
9916  * Since: 0.2
9917  */
9918 void
9919 clutter_actor_get_scale (ClutterActor *self,
9920                          gdouble      *scale_x,
9921                          gdouble      *scale_y)
9922 {
9923   const ClutterTransformInfo *info;
9924
9925   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9926
9927   info = _clutter_actor_get_transform_info_or_defaults (self);
9928
9929   if (scale_x)
9930     *scale_x = info->scale_x;
9931
9932   if (scale_y)
9933     *scale_y = info->scale_y;
9934 }
9935
9936 /**
9937  * clutter_actor_get_scale_center:
9938  * @self: A #ClutterActor
9939  * @center_x: (out) (allow-none): Location to store the X position
9940  *   of the scale center, or %NULL.
9941  * @center_y: (out) (allow-none): Location to store the Y position
9942  *   of the scale center, or %NULL.
9943  *
9944  * Retrieves the scale center coordinate in pixels relative to the top
9945  * left corner of the actor. If the scale center was specified using a
9946  * #ClutterGravity this will calculate the pixel offset using the
9947  * current size of the actor.
9948  *
9949  * Since: 1.0
9950  */
9951 void
9952 clutter_actor_get_scale_center (ClutterActor *self,
9953                                 gfloat       *center_x,
9954                                 gfloat       *center_y)
9955 {
9956   const ClutterTransformInfo *info;
9957
9958   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9959
9960   info = _clutter_actor_get_transform_info_or_defaults (self);
9961
9962   clutter_anchor_coord_get_units (self, &info->scale_center,
9963                                   center_x,
9964                                   center_y,
9965                                   NULL);
9966 }
9967
9968 /**
9969  * clutter_actor_get_scale_gravity:
9970  * @self: A #ClutterActor
9971  *
9972  * Retrieves the scale center as a compass direction. If the scale
9973  * center was specified in pixels or units this will return
9974  * %CLUTTER_GRAVITY_NONE.
9975  *
9976  * Return value: the scale gravity
9977  *
9978  * Since: 1.0
9979  */
9980 ClutterGravity
9981 clutter_actor_get_scale_gravity (ClutterActor *self)
9982 {
9983   const ClutterTransformInfo *info;
9984
9985   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9986
9987   info = _clutter_actor_get_transform_info_or_defaults (self);
9988
9989   return clutter_anchor_coord_get_gravity (&info->scale_center);
9990 }
9991
9992 static inline void
9993 clutter_actor_set_opacity_internal (ClutterActor *self,
9994                                     guint8        opacity)
9995 {
9996   ClutterActorPrivate *priv = self->priv;
9997
9998   if (priv->opacity != opacity)
9999     {
10000       priv->opacity = opacity;
10001
10002       /* Queue a redraw from the flatten effect so that it can use
10003          its cached image if available instead of having to redraw the
10004          actual actor. If it doesn't end up using the FBO then the
10005          effect is still able to continue the paint anyway. If there
10006          is no flatten effect yet then this is equivalent to queueing
10007          a full redraw */
10008       _clutter_actor_queue_redraw_full (self,
10009                                         0, /* flags */
10010                                         NULL, /* clip */
10011                                         priv->flatten_effect);
10012
10013       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10014     }
10015 }
10016
10017 /**
10018  * clutter_actor_set_opacity:
10019  * @self: A #ClutterActor
10020  * @opacity: New opacity value for the actor.
10021  *
10022  * Sets the actor's opacity, with zero being completely transparent and
10023  * 255 (0xff) being fully opaque.
10024  *
10025  * The #ClutterActor:opacity property is animatable.
10026  */
10027 void
10028 clutter_actor_set_opacity (ClutterActor *self,
10029                            guint8        opacity)
10030 {
10031   ClutterActorPrivate *priv;
10032
10033   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10034
10035   priv = self->priv;
10036
10037   if (clutter_actor_get_easing_duration (self) != 0)
10038     {
10039       ClutterTransition *transition;
10040
10041       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
10042       if (transition == NULL)
10043         {
10044           transition = _clutter_actor_create_transition (self,
10045                                                          obj_props[PROP_OPACITY],
10046                                                          priv->opacity,
10047                                                          opacity);
10048         }
10049       else
10050         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10051
10052       clutter_actor_queue_redraw (self);
10053     }
10054   else
10055     clutter_actor_set_opacity_internal (self, opacity);
10056 }
10057
10058 /*
10059  * clutter_actor_get_paint_opacity_internal:
10060  * @self: a #ClutterActor
10061  *
10062  * Retrieves the absolute opacity of the actor, as it appears on the stage
10063  *
10064  * This function does not do type checks
10065  *
10066  * Return value: the absolute opacity of the actor
10067  */
10068 static guint8
10069 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10070 {
10071   ClutterActorPrivate *priv = self->priv;
10072   ClutterActor *parent;
10073
10074   /* override the top-level opacity to always be 255; even in
10075    * case of ClutterStage:use-alpha being TRUE we want the rest
10076    * of the scene to be painted
10077    */
10078   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10079     return 255;
10080
10081   if (priv->opacity_override >= 0)
10082     return priv->opacity_override;
10083
10084   parent = priv->parent;
10085
10086   /* Factor in the actual actors opacity with parents */
10087   if (parent != NULL)
10088     {
10089       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10090
10091       if (opacity != 0xff)
10092         return (opacity * priv->opacity) / 0xff;
10093     }
10094
10095   return priv->opacity;
10096
10097 }
10098
10099 /**
10100  * clutter_actor_get_paint_opacity:
10101  * @self: A #ClutterActor
10102  *
10103  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10104  *
10105  * This function traverses the hierarchy chain and composites the opacity of
10106  * the actor with that of its parents.
10107  *
10108  * This function is intended for subclasses to use in the paint virtual
10109  * function, to paint themselves with the correct opacity.
10110  *
10111  * Return value: The actor opacity value.
10112  *
10113  * Since: 0.8
10114  */
10115 guint8
10116 clutter_actor_get_paint_opacity (ClutterActor *self)
10117 {
10118   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10119
10120   return clutter_actor_get_paint_opacity_internal (self);
10121 }
10122
10123 /**
10124  * clutter_actor_get_opacity:
10125  * @self: a #ClutterActor
10126  *
10127  * Retrieves the opacity value of an actor, as set by
10128  * clutter_actor_set_opacity().
10129  *
10130  * For retrieving the absolute opacity of the actor inside a paint
10131  * virtual function, see clutter_actor_get_paint_opacity().
10132  *
10133  * Return value: the opacity of the actor
10134  */
10135 guint8
10136 clutter_actor_get_opacity (ClutterActor *self)
10137 {
10138   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10139
10140   return self->priv->opacity;
10141 }
10142
10143 /**
10144  * clutter_actor_set_offscreen_redirect:
10145  * @self: A #ClutterActor
10146  * @redirect: New offscreen redirect flags for the actor.
10147  *
10148  * Defines the circumstances where the actor should be redirected into
10149  * an offscreen image. The offscreen image is used to flatten the
10150  * actor into a single image while painting for two main reasons.
10151  * Firstly, when the actor is painted a second time without any of its
10152  * contents changing it can simply repaint the cached image without
10153  * descending further down the actor hierarchy. Secondly, it will make
10154  * the opacity look correct even if there are overlapping primitives
10155  * in the actor.
10156  *
10157  * Caching the actor could in some cases be a performance win and in
10158  * some cases be a performance lose so it is important to determine
10159  * which value is right for an actor before modifying this value. For
10160  * example, there is never any reason to flatten an actor that is just
10161  * a single texture (such as a #ClutterTexture) because it is
10162  * effectively already cached in an image so the offscreen would be
10163  * redundant. Also if the actor contains primitives that are far apart
10164  * with a large transparent area in the middle (such as a large
10165  * CluterGroup with a small actor in the top left and a small actor in
10166  * the bottom right) then the cached image will contain the entire
10167  * image of the large area and the paint will waste time blending all
10168  * of the transparent pixels in the middle.
10169  *
10170  * The default method of implementing opacity on a container simply
10171  * forwards on the opacity to all of the children. If the children are
10172  * overlapping then it will appear as if they are two separate glassy
10173  * objects and there will be a break in the color where they
10174  * overlap. By redirecting to an offscreen buffer it will be as if the
10175  * two opaque objects are combined into one and then made transparent
10176  * which is usually what is expected.
10177  *
10178  * The image below demonstrates the difference between redirecting and
10179  * not. The image shows two Clutter groups, each containing a red and
10180  * a green rectangle which overlap. The opacity on the group is set to
10181  * 128 (which is 50%). When the offscreen redirect is not used, the
10182  * red rectangle can be seen through the blue rectangle as if the two
10183  * rectangles were separately transparent. When the redirect is used
10184  * the group as a whole is transparent instead so the red rectangle is
10185  * not visible where they overlap.
10186  *
10187  * <figure id="offscreen-redirect">
10188  *   <title>Sample of using an offscreen redirect for transparency</title>
10189  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10190  * </figure>
10191  *
10192  * The default value for this property is 0, so we effectively will
10193  * never redirect an actor offscreen by default. This means that there
10194  * are times that transparent actors may look glassy as described
10195  * above. The reason this is the default is because there is a
10196  * performance trade off between quality and performance here. In many
10197  * cases the default form of glassy opacity looks good enough, but if
10198  * it's not you will need to set the
10199  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10200  * redirection for opacity.
10201  *
10202  * Custom actors that don't contain any overlapping primitives are
10203  * recommended to override the has_overlaps() virtual to return %FALSE
10204  * for maximum efficiency.
10205  *
10206  * Since: 1.8
10207  */
10208 void
10209 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10210                                       ClutterOffscreenRedirect redirect)
10211 {
10212   ClutterActorPrivate *priv;
10213
10214   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10215
10216   priv = self->priv;
10217
10218   if (priv->offscreen_redirect != redirect)
10219     {
10220       priv->offscreen_redirect = redirect;
10221
10222       /* Queue a redraw from the effect so that it can use its cached
10223          image if available instead of having to redraw the actual
10224          actor. If it doesn't end up using the FBO then the effect is
10225          still able to continue the paint anyway. If there is no
10226          effect then this is equivalent to queuing a full redraw */
10227       _clutter_actor_queue_redraw_full (self,
10228                                         0, /* flags */
10229                                         NULL, /* clip */
10230                                         priv->flatten_effect);
10231
10232       g_object_notify_by_pspec (G_OBJECT (self),
10233                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10234     }
10235 }
10236
10237 /**
10238  * clutter_actor_get_offscreen_redirect:
10239  * @self: a #ClutterActor
10240  *
10241  * Retrieves whether to redirect the actor to an offscreen buffer, as
10242  * set by clutter_actor_set_offscreen_redirect().
10243  *
10244  * Return value: the value of the offscreen-redirect property of the actor
10245  *
10246  * Since: 1.8
10247  */
10248 ClutterOffscreenRedirect
10249 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10250 {
10251   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10252
10253   return self->priv->offscreen_redirect;
10254 }
10255
10256 /**
10257  * clutter_actor_set_name:
10258  * @self: A #ClutterActor
10259  * @name: Textual tag to apply to actor
10260  *
10261  * Sets the given name to @self. The name can be used to identify
10262  * a #ClutterActor.
10263  */
10264 void
10265 clutter_actor_set_name (ClutterActor *self,
10266                         const gchar  *name)
10267 {
10268   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10269
10270   g_free (self->priv->name);
10271   self->priv->name = g_strdup (name);
10272
10273   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10274 }
10275
10276 /**
10277  * clutter_actor_get_name:
10278  * @self: A #ClutterActor
10279  *
10280  * Retrieves the name of @self.
10281  *
10282  * Return value: the name of the actor, or %NULL. The returned string is
10283  *   owned by the actor and should not be modified or freed.
10284  */
10285 const gchar *
10286 clutter_actor_get_name (ClutterActor *self)
10287 {
10288   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10289
10290   return self->priv->name;
10291 }
10292
10293 /**
10294  * clutter_actor_get_gid:
10295  * @self: A #ClutterActor
10296  *
10297  * Retrieves the unique id for @self.
10298  *
10299  * Return value: Globally unique value for this object instance.
10300  *
10301  * Since: 0.6
10302  *
10303  * Deprecated: 1.8: The id is not used any longer.
10304  */
10305 guint32
10306 clutter_actor_get_gid (ClutterActor *self)
10307 {
10308   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10309
10310   return self->priv->id;
10311 }
10312
10313 static inline void
10314 clutter_actor_set_depth_internal (ClutterActor *self,
10315                                   float         depth)
10316 {
10317   ClutterTransformInfo *info;
10318
10319   info = _clutter_actor_get_transform_info (self);
10320
10321   if (info->depth != depth)
10322     {
10323       /* Sets Z value - XXX 2.0: should we invert? */
10324       info->depth = depth;
10325
10326       self->priv->transform_valid = FALSE;
10327
10328       /* FIXME - remove this crap; sadly, there are still containers
10329        * in Clutter that depend on this utter brain damage
10330        */
10331       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10332
10333       clutter_actor_queue_redraw (self);
10334
10335       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10336     }
10337 }
10338
10339 /**
10340  * clutter_actor_set_depth:
10341  * @self: a #ClutterActor
10342  * @depth: Z co-ord
10343  *
10344  * Sets the Z coordinate of @self to @depth.
10345  *
10346  * The unit used by @depth is dependant on the perspective setup. See
10347  * also clutter_stage_set_perspective().
10348  */
10349 void
10350 clutter_actor_set_depth (ClutterActor *self,
10351                          gfloat        depth)
10352 {
10353   const ClutterTransformInfo *tinfo;
10354
10355   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10356
10357   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10358
10359   if (clutter_actor_get_easing_duration (self) != 0)
10360     {
10361       ClutterTransition *transition;
10362
10363       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10364       if (transition == NULL)
10365         {
10366           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10367                                                          tinfo->depth,
10368                                                          depth);
10369         }
10370       else
10371         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10372
10373       clutter_actor_queue_redraw (self);
10374     }
10375   else
10376     clutter_actor_set_depth_internal (self, depth);
10377 }
10378
10379 /**
10380  * clutter_actor_get_depth:
10381  * @self: a #ClutterActor
10382  *
10383  * Retrieves the depth of @self.
10384  *
10385  * Return value: the depth of the actor
10386  */
10387 gfloat
10388 clutter_actor_get_depth (ClutterActor *self)
10389 {
10390   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10391
10392   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10393 }
10394
10395 /**
10396  * clutter_actor_set_rotation:
10397  * @self: a #ClutterActor
10398  * @axis: the axis of rotation
10399  * @angle: the angle of rotation
10400  * @x: X coordinate of the rotation center
10401  * @y: Y coordinate of the rotation center
10402  * @z: Z coordinate of the rotation center
10403  *
10404  * Sets the rotation angle of @self around the given axis.
10405  *
10406  * The rotation center coordinates used depend on the value of @axis:
10407  * <itemizedlist>
10408  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10409  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10410  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10411  * </itemizedlist>
10412  *
10413  * The rotation coordinates are relative to the anchor point of the
10414  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10415  * point is set, the upper left corner is assumed as the origin.
10416  *
10417  * Since: 0.8
10418  */
10419 void
10420 clutter_actor_set_rotation (ClutterActor      *self,
10421                             ClutterRotateAxis  axis,
10422                             gdouble            angle,
10423                             gfloat             x,
10424                             gfloat             y,
10425                             gfloat             z)
10426 {
10427   ClutterVertex v;
10428
10429   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10430
10431   v.x = x;
10432   v.y = y;
10433   v.z = z;
10434
10435   g_object_freeze_notify (G_OBJECT (self));
10436
10437   clutter_actor_set_rotation_angle (self, axis, angle);
10438   clutter_actor_set_rotation_center_internal (self, axis, &v);
10439
10440   g_object_thaw_notify (G_OBJECT (self));
10441 }
10442
10443 /**
10444  * clutter_actor_set_z_rotation_from_gravity:
10445  * @self: a #ClutterActor
10446  * @angle: the angle of rotation
10447  * @gravity: the center point of the rotation
10448  *
10449  * Sets the rotation angle of @self around the Z axis using the center
10450  * point specified as a compass point. For example to rotate such that
10451  * the center of the actor remains static you can use
10452  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10453  * will move accordingly.
10454  *
10455  * Since: 1.0
10456  */
10457 void
10458 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10459                                            gdouble         angle,
10460                                            ClutterGravity  gravity)
10461 {
10462   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10463
10464   if (gravity == CLUTTER_GRAVITY_NONE)
10465     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10466   else
10467     {
10468       GObject *obj = G_OBJECT (self);
10469       ClutterTransformInfo *info;
10470
10471       info = _clutter_actor_get_transform_info (self);
10472
10473       g_object_freeze_notify (obj);
10474
10475       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10476
10477       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10478       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10479       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10480
10481       g_object_thaw_notify (obj);
10482     }
10483 }
10484
10485 /**
10486  * clutter_actor_get_rotation:
10487  * @self: a #ClutterActor
10488  * @axis: the axis of rotation
10489  * @x: (out): return value for the X coordinate of the center of rotation
10490  * @y: (out): return value for the Y coordinate of the center of rotation
10491  * @z: (out): return value for the Z coordinate of the center of rotation
10492  *
10493  * Retrieves the angle and center of rotation on the given axis,
10494  * set using clutter_actor_set_rotation().
10495  *
10496  * Return value: the angle of rotation
10497  *
10498  * Since: 0.8
10499  */
10500 gdouble
10501 clutter_actor_get_rotation (ClutterActor      *self,
10502                             ClutterRotateAxis  axis,
10503                             gfloat            *x,
10504                             gfloat            *y,
10505                             gfloat            *z)
10506 {
10507   const ClutterTransformInfo *info;
10508   const AnchorCoord *anchor_coord;
10509   gdouble retval = 0;
10510
10511   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10512
10513   info = _clutter_actor_get_transform_info_or_defaults (self);
10514
10515   switch (axis)
10516     {
10517     case CLUTTER_X_AXIS:
10518       anchor_coord = &info->rx_center;
10519       retval = info->rx_angle;
10520       break;
10521
10522     case CLUTTER_Y_AXIS:
10523       anchor_coord = &info->ry_center;
10524       retval = info->ry_angle;
10525       break;
10526
10527     case CLUTTER_Z_AXIS:
10528       anchor_coord = &info->rz_center;
10529       retval = info->rz_angle;
10530       break;
10531
10532     default:
10533       anchor_coord = NULL;
10534       retval = 0.0;
10535       break;
10536     }
10537
10538   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10539
10540   return retval;
10541 }
10542
10543 /**
10544  * clutter_actor_get_z_rotation_gravity:
10545  * @self: A #ClutterActor
10546  *
10547  * Retrieves the center for the rotation around the Z axis as a
10548  * compass direction. If the center was specified in pixels or units
10549  * this will return %CLUTTER_GRAVITY_NONE.
10550  *
10551  * Return value: the Z rotation center
10552  *
10553  * Since: 1.0
10554  */
10555 ClutterGravity
10556 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10557 {
10558   const ClutterTransformInfo *info;
10559
10560   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10561
10562   info = _clutter_actor_get_transform_info_or_defaults (self);
10563
10564   return clutter_anchor_coord_get_gravity (&info->rz_center);
10565 }
10566
10567 /**
10568  * clutter_actor_set_clip:
10569  * @self: A #ClutterActor
10570  * @xoff: X offset of the clip rectangle
10571  * @yoff: Y offset of the clip rectangle
10572  * @width: Width of the clip rectangle
10573  * @height: Height of the clip rectangle
10574  *
10575  * Sets clip area for @self. The clip area is always computed from the
10576  * upper left corner of the actor, even if the anchor point is set
10577  * otherwise.
10578  *
10579  * Since: 0.6
10580  */
10581 void
10582 clutter_actor_set_clip (ClutterActor *self,
10583                         gfloat        xoff,
10584                         gfloat        yoff,
10585                         gfloat        width,
10586                         gfloat        height)
10587 {
10588   ClutterActorPrivate *priv;
10589
10590   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10591
10592   priv = self->priv;
10593
10594   if (priv->has_clip &&
10595       priv->clip.x == xoff &&
10596       priv->clip.y == yoff &&
10597       priv->clip.width == width &&
10598       priv->clip.height == height)
10599     return;
10600
10601   priv->clip.x = xoff;
10602   priv->clip.y = yoff;
10603   priv->clip.width = width;
10604   priv->clip.height = height;
10605
10606   priv->has_clip = TRUE;
10607
10608   clutter_actor_queue_redraw (self);
10609
10610   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10611   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10612 }
10613
10614 /**
10615  * clutter_actor_remove_clip:
10616  * @self: A #ClutterActor
10617  *
10618  * Removes clip area from @self.
10619  */
10620 void
10621 clutter_actor_remove_clip (ClutterActor *self)
10622 {
10623   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10624
10625   if (!self->priv->has_clip)
10626     return;
10627
10628   self->priv->has_clip = FALSE;
10629
10630   clutter_actor_queue_redraw (self);
10631
10632   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10633 }
10634
10635 /**
10636  * clutter_actor_has_clip:
10637  * @self: a #ClutterActor
10638  *
10639  * Determines whether the actor has a clip area set or not.
10640  *
10641  * Return value: %TRUE if the actor has a clip area set.
10642  *
10643  * Since: 0.1.1
10644  */
10645 gboolean
10646 clutter_actor_has_clip (ClutterActor *self)
10647 {
10648   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10649
10650   return self->priv->has_clip;
10651 }
10652
10653 /**
10654  * clutter_actor_get_clip:
10655  * @self: a #ClutterActor
10656  * @xoff: (out) (allow-none): return location for the X offset of
10657  *   the clip rectangle, or %NULL
10658  * @yoff: (out) (allow-none): return location for the Y offset of
10659  *   the clip rectangle, or %NULL
10660  * @width: (out) (allow-none): return location for the width of
10661  *   the clip rectangle, or %NULL
10662  * @height: (out) (allow-none): return location for the height of
10663  *   the clip rectangle, or %NULL
10664  *
10665  * Gets the clip area for @self, if any is set
10666  *
10667  * Since: 0.6
10668  */
10669 void
10670 clutter_actor_get_clip (ClutterActor *self,
10671                         gfloat       *xoff,
10672                         gfloat       *yoff,
10673                         gfloat       *width,
10674                         gfloat       *height)
10675 {
10676   ClutterActorPrivate *priv;
10677
10678   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10679
10680   priv = self->priv;
10681
10682   if (!priv->has_clip)
10683     return;
10684
10685   if (xoff != NULL)
10686     *xoff = priv->clip.x;
10687
10688   if (yoff != NULL)
10689     *yoff = priv->clip.y;
10690
10691   if (width != NULL)
10692     *width = priv->clip.width;
10693
10694   if (height != NULL)
10695     *height = priv->clip.height;
10696 }
10697
10698 /**
10699  * clutter_actor_get_children:
10700  * @self: a #ClutterActor
10701  *
10702  * Retrieves the list of children of @self.
10703  *
10704  * Return value: (transfer container) (element-type ClutterActor): A newly
10705  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10706  *   done.
10707  *
10708  * Since: 1.10
10709  */
10710 GList *
10711 clutter_actor_get_children (ClutterActor *self)
10712 {
10713   ClutterActor *iter;
10714   GList *res;
10715
10716   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10717
10718   /* we walk the list backward so that we can use prepend(),
10719    * which is O(1)
10720    */
10721   for (iter = self->priv->last_child, res = NULL;
10722        iter != NULL;
10723        iter = iter->priv->prev_sibling)
10724     {
10725       res = g_list_prepend (res, iter);
10726     }
10727
10728   return res;
10729 }
10730
10731 /*< private >
10732  * insert_child_at_depth:
10733  * @self: a #ClutterActor
10734  * @child: a #ClutterActor
10735  *
10736  * Inserts @child inside the list of children held by @self, using
10737  * the depth as the insertion criteria.
10738  *
10739  * This sadly makes the insertion not O(1), but we can keep the
10740  * list sorted so that the painters algorithm we use for painting
10741  * the children will work correctly.
10742  */
10743 static void
10744 insert_child_at_depth (ClutterActor *self,
10745                        ClutterActor *child,
10746                        gpointer      dummy G_GNUC_UNUSED)
10747 {
10748   ClutterActor *iter;
10749   float child_depth;
10750
10751   child->priv->parent = self;
10752
10753   child_depth =
10754     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10755
10756   /* special-case the first child */
10757   if (self->priv->n_children == 0)
10758     {
10759       self->priv->first_child = child;
10760       self->priv->last_child = child;
10761
10762       child->priv->next_sibling = NULL;
10763       child->priv->prev_sibling = NULL;
10764
10765       return;
10766     }
10767
10768   /* Find the right place to insert the child so that it will still be
10769      sorted and the child will be after all of the actors at the same
10770      dept */
10771   for (iter = self->priv->first_child;
10772        iter != NULL;
10773        iter = iter->priv->next_sibling)
10774     {
10775       float iter_depth;
10776
10777       iter_depth =
10778         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10779
10780       if (iter_depth > child_depth)
10781         break;
10782     }
10783
10784   if (iter != NULL)
10785     {
10786       ClutterActor *tmp = iter->priv->prev_sibling;
10787
10788       if (tmp != NULL)
10789         tmp->priv->next_sibling = child;
10790
10791       /* Insert the node before the found one */
10792       child->priv->prev_sibling = iter->priv->prev_sibling;
10793       child->priv->next_sibling = iter;
10794       iter->priv->prev_sibling = child;
10795     }
10796   else
10797     {
10798       ClutterActor *tmp = self->priv->last_child;
10799
10800       if (tmp != NULL)
10801         tmp->priv->next_sibling = child;
10802
10803       /* insert the node at the end of the list */
10804       child->priv->prev_sibling = self->priv->last_child;
10805       child->priv->next_sibling = NULL;
10806     }
10807
10808   if (child->priv->prev_sibling == NULL)
10809     self->priv->first_child = child;
10810
10811   if (child->priv->next_sibling == NULL)
10812     self->priv->last_child = child;
10813 }
10814
10815 static void
10816 insert_child_at_index (ClutterActor *self,
10817                        ClutterActor *child,
10818                        gpointer      data_)
10819 {
10820   gint index_ = GPOINTER_TO_INT (data_);
10821
10822   child->priv->parent = self;
10823
10824   if (index_ == 0)
10825     {
10826       ClutterActor *tmp = self->priv->first_child;
10827
10828       if (tmp != NULL)
10829         tmp->priv->prev_sibling = child;
10830
10831       child->priv->prev_sibling = NULL;
10832       child->priv->next_sibling = tmp;
10833     }
10834   else if (index_ < 0 || index_ >= self->priv->n_children)
10835     {
10836       ClutterActor *tmp = self->priv->last_child;
10837
10838       if (tmp != NULL)
10839         tmp->priv->next_sibling = child;
10840
10841       child->priv->prev_sibling = tmp;
10842       child->priv->next_sibling = NULL;
10843     }
10844   else
10845     {
10846       ClutterActor *iter;
10847       int i;
10848
10849       for (iter = self->priv->first_child, i = 0;
10850            iter != NULL;
10851            iter = iter->priv->next_sibling, i += 1)
10852         {
10853           if (index_ == i)
10854             {
10855               ClutterActor *tmp = iter->priv->prev_sibling;
10856
10857               child->priv->prev_sibling = tmp;
10858               child->priv->next_sibling = iter;
10859
10860               iter->priv->prev_sibling = child;
10861
10862               if (tmp != NULL)
10863                 tmp->priv->next_sibling = child;
10864
10865               break;
10866             }
10867         }
10868     }
10869
10870   if (child->priv->prev_sibling == NULL)
10871     self->priv->first_child = child;
10872
10873   if (child->priv->next_sibling == NULL)
10874     self->priv->last_child = child;
10875 }
10876
10877 static void
10878 insert_child_above (ClutterActor *self,
10879                     ClutterActor *child,
10880                     gpointer      data)
10881 {
10882   ClutterActor *sibling = data;
10883
10884   child->priv->parent = self;
10885
10886   if (sibling == NULL)
10887     sibling = self->priv->last_child;
10888
10889   child->priv->prev_sibling = sibling;
10890
10891   if (sibling != NULL)
10892     {
10893       ClutterActor *tmp = sibling->priv->next_sibling;
10894
10895       child->priv->next_sibling = tmp;
10896
10897       if (tmp != NULL)
10898         tmp->priv->prev_sibling = child;
10899
10900       sibling->priv->next_sibling = child;
10901     }
10902   else
10903     child->priv->next_sibling = NULL;
10904
10905   if (child->priv->prev_sibling == NULL)
10906     self->priv->first_child = child;
10907
10908   if (child->priv->next_sibling == NULL)
10909     self->priv->last_child = child;
10910 }
10911
10912 static void
10913 insert_child_below (ClutterActor *self,
10914                     ClutterActor *child,
10915                     gpointer      data)
10916 {
10917   ClutterActor *sibling = data;
10918
10919   child->priv->parent = self;
10920
10921   if (sibling == NULL)
10922     sibling = self->priv->first_child;
10923
10924   child->priv->next_sibling = sibling;
10925
10926   if (sibling != NULL)
10927     {
10928       ClutterActor *tmp = sibling->priv->prev_sibling;
10929
10930       child->priv->prev_sibling = tmp;
10931
10932       if (tmp != NULL)
10933         tmp->priv->next_sibling = child;
10934
10935       sibling->priv->prev_sibling = child;
10936     }
10937   else
10938     child->priv->prev_sibling = NULL;
10939
10940   if (child->priv->prev_sibling == NULL)
10941     self->priv->first_child = child;
10942
10943   if (child->priv->next_sibling == NULL)
10944     self->priv->last_child = child;
10945 }
10946
10947 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10948                                            ClutterActor *child,
10949                                            gpointer      data);
10950
10951 typedef enum {
10952   ADD_CHILD_CREATE_META       = 1 << 0,
10953   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10954   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10955   ADD_CHILD_CHECK_STATE       = 1 << 3,
10956   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10957
10958   /* default flags for public API */
10959   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10960                                ADD_CHILD_EMIT_PARENT_SET |
10961                                ADD_CHILD_EMIT_ACTOR_ADDED |
10962                                ADD_CHILD_CHECK_STATE |
10963                                ADD_CHILD_NOTIFY_FIRST_LAST,
10964
10965   /* flags for legacy/deprecated API */
10966   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10967                                ADD_CHILD_CHECK_STATE |
10968                                ADD_CHILD_NOTIFY_FIRST_LAST
10969 } ClutterActorAddChildFlags;
10970
10971 /*< private >
10972  * clutter_actor_add_child_internal:
10973  * @self: a #ClutterActor
10974  * @child: a #ClutterActor
10975  * @flags: control flags for actions
10976  * @add_func: delegate function
10977  * @data: (closure): data to pass to @add_func
10978  *
10979  * Adds @child to the list of children of @self.
10980  *
10981  * The actual insertion inside the list is delegated to @add_func: this
10982  * function will just set up the state, perform basic checks, and emit
10983  * signals.
10984  *
10985  * The @flags argument is used to perform additional operations.
10986  */
10987 static inline void
10988 clutter_actor_add_child_internal (ClutterActor              *self,
10989                                   ClutterActor              *child,
10990                                   ClutterActorAddChildFlags  flags,
10991                                   ClutterActorAddChildFunc   add_func,
10992                                   gpointer                   data)
10993 {
10994   ClutterTextDirection text_dir;
10995   gboolean create_meta;
10996   gboolean emit_parent_set, emit_actor_added;
10997   gboolean check_state;
10998   gboolean notify_first_last;
10999   ClutterActor *old_first_child, *old_last_child;
11000
11001   if (child->priv->parent != NULL)
11002     {
11003       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11004                  "use clutter_actor_remove_child() first.",
11005                  _clutter_actor_get_debug_name (child),
11006                  _clutter_actor_get_debug_name (child->priv->parent));
11007       return;
11008     }
11009
11010   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11011     {
11012       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11013                  "a child of another actor.",
11014                  _clutter_actor_get_debug_name (child));
11015       return;
11016     }
11017
11018 #if 0
11019   /* XXX - this check disallows calling methods that change the stacking
11020    * order within the destruction sequence, by triggering a critical
11021    * warning first, and leaving the actor in an undefined state, which
11022    * then ends up being caught by an assertion.
11023    *
11024    * the reproducible sequence is:
11025    *
11026    *   - actor gets destroyed;
11027    *   - another actor, linked to the first, will try to change the
11028    *     stacking order of the first actor;
11029    *   - changing the stacking order is a composite operation composed
11030    *     by the following steps:
11031    *     1. ref() the child;
11032    *     2. remove_child_internal(), which removes the reference;
11033    *     3. add_child_internal(), which adds a reference;
11034    *   - the state of the actor is not changed between (2) and (3), as
11035    *     it could be an expensive recomputation;
11036    *   - if (3) bails out, then the actor is in an undefined state, but
11037    *     still alive;
11038    *   - the destruction sequence terminates, but the actor is unparented
11039    *     while its state indicates being parented instead.
11040    *   - assertion failure.
11041    *
11042    * the obvious fix would be to decompose each set_child_*_sibling()
11043    * method into proper remove_child()/add_child(), with state validation;
11044    * this may cause excessive work, though, and trigger a cascade of other
11045    * bugs in code that assumes that a change in the stacking order is an
11046    * atomic operation.
11047    *
11048    * another potential fix is to just remove this check here, and let
11049    * code doing stacking order changes inside the destruction sequence
11050    * of an actor continue doing the work.
11051    *
11052    * the third fix is to silently bail out early from every
11053    * set_child_*_sibling() and set_child_at_index() method, and avoid
11054    * doing work.
11055    *
11056    * I have a preference for the second solution, since it involves the
11057    * least amount of work, and the least amount of code duplication.
11058    *
11059    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11060    */
11061   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11062     {
11063       g_warning ("The actor '%s' is currently being destroyed, and "
11064                  "cannot be added as a child of another actor.",
11065                  _clutter_actor_get_debug_name (child));
11066       return;
11067     }
11068 #endif
11069
11070   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11071   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11072   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11073   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11074   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11075
11076   old_first_child = self->priv->first_child;
11077   old_last_child = self->priv->last_child;
11078
11079   g_object_freeze_notify (G_OBJECT (self));
11080
11081   if (create_meta)
11082     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11083
11084   g_object_ref_sink (child);
11085   child->priv->parent = NULL;
11086   child->priv->next_sibling = NULL;
11087   child->priv->prev_sibling = NULL;
11088
11089   /* delegate the actual insertion */
11090   add_func (self, child, data);
11091
11092   g_assert (child->priv->parent == self);
11093
11094   self->priv->n_children += 1;
11095
11096   self->priv->age += 1;
11097
11098   /* if push_internal() has been called then we automatically set
11099    * the flag on the actor
11100    */
11101   if (self->priv->internal_child)
11102     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11103
11104   /* clutter_actor_reparent() will emit ::parent-set for us */
11105   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11106     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11107
11108   if (check_state)
11109     {
11110       /* If parent is mapped or realized, we need to also be mapped or
11111        * realized once we're inside the parent.
11112        */
11113       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11114
11115       /* propagate the parent's text direction to the child */
11116       text_dir = clutter_actor_get_text_direction (self);
11117       clutter_actor_set_text_direction (child, text_dir);
11118     }
11119
11120   if (child->priv->show_on_set_parent)
11121     clutter_actor_show (child);
11122
11123   if (CLUTTER_ACTOR_IS_MAPPED (child))
11124     clutter_actor_queue_redraw (child);
11125
11126   /* maintain the invariant that if an actor needs layout,
11127    * its parents do as well
11128    */
11129   if (child->priv->needs_width_request ||
11130       child->priv->needs_height_request ||
11131       child->priv->needs_allocation)
11132     {
11133       /* we work around the short-circuiting we do
11134        * in clutter_actor_queue_relayout() since we
11135        * want to force a relayout
11136        */
11137       child->priv->needs_width_request = TRUE;
11138       child->priv->needs_height_request = TRUE;
11139       child->priv->needs_allocation = TRUE;
11140
11141       clutter_actor_queue_relayout (child->priv->parent);
11142     }
11143
11144   if (emit_actor_added)
11145     g_signal_emit_by_name (self, "actor-added", child);
11146
11147   if (notify_first_last)
11148     {
11149       if (old_first_child != self->priv->first_child)
11150         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11151
11152       if (old_last_child != self->priv->last_child)
11153         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11154     }
11155
11156   g_object_thaw_notify (G_OBJECT (self));
11157 }
11158
11159 /**
11160  * clutter_actor_add_child:
11161  * @self: a #ClutterActor
11162  * @child: a #ClutterActor
11163  *
11164  * Adds @child to the children of @self.
11165  *
11166  * This function will acquire a reference on @child that will only
11167  * be released when calling clutter_actor_remove_child().
11168  *
11169  * This function will take into consideration the #ClutterActor:depth
11170  * of @child, and will keep the list of children sorted.
11171  *
11172  * This function will emit the #ClutterContainer::actor-added signal
11173  * on @self.
11174  *
11175  * Since: 1.10
11176  */
11177 void
11178 clutter_actor_add_child (ClutterActor *self,
11179                          ClutterActor *child)
11180 {
11181   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11182   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11183   g_return_if_fail (self != child);
11184   g_return_if_fail (child->priv->parent == NULL);
11185
11186   clutter_actor_add_child_internal (self, child,
11187                                     ADD_CHILD_DEFAULT_FLAGS,
11188                                     insert_child_at_depth,
11189                                     NULL);
11190 }
11191
11192 /**
11193  * clutter_actor_insert_child_at_index:
11194  * @self: a #ClutterActor
11195  * @child: a #ClutterActor
11196  * @index_: the index
11197  *
11198  * Inserts @child into the list of children of @self, using the
11199  * given @index_. If @index_ is greater than the number of children
11200  * in @self, or is less than 0, then the new child is added at the end.
11201  *
11202  * This function will acquire a reference on @child that will only
11203  * be released when calling clutter_actor_remove_child().
11204  *
11205  * This function will not take into consideration the #ClutterActor:depth
11206  * of @child.
11207  *
11208  * This function will emit the #ClutterContainer::actor-added signal
11209  * on @self.
11210  *
11211  * Since: 1.10
11212  */
11213 void
11214 clutter_actor_insert_child_at_index (ClutterActor *self,
11215                                      ClutterActor *child,
11216                                      gint          index_)
11217 {
11218   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11219   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11220   g_return_if_fail (self != child);
11221   g_return_if_fail (child->priv->parent == NULL);
11222
11223   clutter_actor_add_child_internal (self, child,
11224                                     ADD_CHILD_DEFAULT_FLAGS,
11225                                     insert_child_at_index,
11226                                     GINT_TO_POINTER (index_));
11227 }
11228
11229 /**
11230  * clutter_actor_insert_child_above:
11231  * @self: a #ClutterActor
11232  * @child: a #ClutterActor
11233  * @sibling: (allow-none): a child of @self, or %NULL
11234  *
11235  * Inserts @child into the list of children of @self, above another
11236  * child of @self or, if @sibling is %NULL, above all the children
11237  * of @self.
11238  *
11239  * This function will acquire a reference on @child that will only
11240  * be released when calling clutter_actor_remove_child().
11241  *
11242  * This function will not take into consideration the #ClutterActor:depth
11243  * of @child.
11244  *
11245  * This function will emit the #ClutterContainer::actor-added signal
11246  * on @self.
11247  *
11248  * Since: 1.10
11249  */
11250 void
11251 clutter_actor_insert_child_above (ClutterActor *self,
11252                                   ClutterActor *child,
11253                                   ClutterActor *sibling)
11254 {
11255   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11256   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11257   g_return_if_fail (self != child);
11258   g_return_if_fail (child != sibling);
11259   g_return_if_fail (child->priv->parent == NULL);
11260   g_return_if_fail (sibling == NULL ||
11261                     (CLUTTER_IS_ACTOR (sibling) &&
11262                      sibling->priv->parent == self));
11263
11264   clutter_actor_add_child_internal (self, child,
11265                                     ADD_CHILD_DEFAULT_FLAGS,
11266                                     insert_child_above,
11267                                     sibling);
11268 }
11269
11270 /**
11271  * clutter_actor_insert_child_below:
11272  * @self: a #ClutterActor
11273  * @child: a #ClutterActor
11274  * @sibling: (allow-none): a child of @self, or %NULL
11275  *
11276  * Inserts @child into the list of children of @self, below another
11277  * child of @self or, if @sibling is %NULL, below all the children
11278  * of @self.
11279  *
11280  * This function will acquire a reference on @child that will only
11281  * be released when calling clutter_actor_remove_child().
11282  *
11283  * This function will not take into consideration the #ClutterActor:depth
11284  * of @child.
11285  *
11286  * This function will emit the #ClutterContainer::actor-added signal
11287  * on @self.
11288  *
11289  * Since: 1.10
11290  */
11291 void
11292 clutter_actor_insert_child_below (ClutterActor *self,
11293                                   ClutterActor *child,
11294                                   ClutterActor *sibling)
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 != sibling);
11300   g_return_if_fail (child->priv->parent == NULL);
11301   g_return_if_fail (sibling == NULL ||
11302                     (CLUTTER_IS_ACTOR (sibling) &&
11303                      sibling->priv->parent == self));
11304
11305   clutter_actor_add_child_internal (self, child,
11306                                     ADD_CHILD_DEFAULT_FLAGS,
11307                                     insert_child_below,
11308                                     sibling);
11309 }
11310
11311 /**
11312  * clutter_actor_set_parent:
11313  * @self: A #ClutterActor
11314  * @parent: A new #ClutterActor parent
11315  *
11316  * Sets the parent of @self to @parent.
11317  *
11318  * This function will result in @parent acquiring a reference on @self,
11319  * eventually by sinking its floating reference first. The reference
11320  * will be released by clutter_actor_unparent().
11321  *
11322  * This function should only be called by legacy #ClutterActor<!-- -->s
11323  * implementing the #ClutterContainer interface.
11324  *
11325  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11326  */
11327 void
11328 clutter_actor_set_parent (ClutterActor *self,
11329                           ClutterActor *parent)
11330 {
11331   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11332   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11333   g_return_if_fail (self != parent);
11334   g_return_if_fail (self->priv->parent == NULL);
11335
11336   /* as this function will be called inside ClutterContainer::add
11337    * implementations or when building up a composite actor, we have
11338    * to preserve the old behaviour, and not create child meta or
11339    * emit the ::actor-added signal, to avoid recursion or double
11340    * emissions
11341    */
11342   clutter_actor_add_child_internal (parent, self,
11343                                     ADD_CHILD_LEGACY_FLAGS,
11344                                     insert_child_at_depth,
11345                                     NULL);
11346 }
11347
11348 /**
11349  * clutter_actor_get_parent:
11350  * @self: A #ClutterActor
11351  *
11352  * Retrieves the parent of @self.
11353  *
11354  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11355  *  if no parent is set
11356  */
11357 ClutterActor *
11358 clutter_actor_get_parent (ClutterActor *self)
11359 {
11360   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11361
11362   return self->priv->parent;
11363 }
11364
11365 /**
11366  * clutter_actor_get_paint_visibility:
11367  * @self: A #ClutterActor
11368  *
11369  * Retrieves the 'paint' visibility of an actor recursively checking for non
11370  * visible parents.
11371  *
11372  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11373  *
11374  * Return Value: %TRUE if the actor is visibile and will be painted.
11375  *
11376  * Since: 0.8.4
11377  */
11378 gboolean
11379 clutter_actor_get_paint_visibility (ClutterActor *actor)
11380 {
11381   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11382
11383   return CLUTTER_ACTOR_IS_MAPPED (actor);
11384 }
11385
11386 /**
11387  * clutter_actor_remove_child:
11388  * @self: a #ClutterActor
11389  * @child: a #ClutterActor
11390  *
11391  * Removes @child from the children of @self.
11392  *
11393  * This function will release the reference added by
11394  * clutter_actor_add_child(), so if you want to keep using @child
11395  * you will have to acquire a referenced on it before calling this
11396  * function.
11397  *
11398  * This function will emit the #ClutterContainer::actor-removed
11399  * signal on @self.
11400  *
11401  * Since: 1.10
11402  */
11403 void
11404 clutter_actor_remove_child (ClutterActor *self,
11405                             ClutterActor *child)
11406 {
11407   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11408   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11409   g_return_if_fail (self != child);
11410   g_return_if_fail (child->priv->parent != NULL);
11411   g_return_if_fail (child->priv->parent == self);
11412
11413   clutter_actor_remove_child_internal (self, child,
11414                                        REMOVE_CHILD_DEFAULT_FLAGS);
11415 }
11416
11417 /**
11418  * clutter_actor_remove_all_children:
11419  * @self: a #ClutterActor
11420  *
11421  * Removes all children of @self.
11422  *
11423  * This function releases the reference added by inserting a child actor
11424  * in the list of children of @self.
11425  *
11426  * If the reference count of a child drops to zero, the child will be
11427  * destroyed. If you want to ensure the destruction of all the children
11428  * of @self, use clutter_actor_destroy_all_children().
11429  *
11430  * Since: 1.10
11431  */
11432 void
11433 clutter_actor_remove_all_children (ClutterActor *self)
11434 {
11435   ClutterActorIter iter;
11436
11437   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11438
11439   if (self->priv->n_children == 0)
11440     return;
11441
11442   g_object_freeze_notify (G_OBJECT (self));
11443
11444   clutter_actor_iter_init (&iter, self);
11445   while (clutter_actor_iter_next (&iter, NULL))
11446     clutter_actor_iter_remove (&iter);
11447
11448   g_object_thaw_notify (G_OBJECT (self));
11449
11450   /* sanity check */
11451   g_assert (self->priv->first_child == NULL);
11452   g_assert (self->priv->last_child == NULL);
11453   g_assert (self->priv->n_children == 0);
11454 }
11455
11456 /**
11457  * clutter_actor_destroy_all_children:
11458  * @self: a #ClutterActor
11459  *
11460  * Destroys all children of @self.
11461  *
11462  * This function releases the reference added by inserting a child
11463  * actor in the list of children of @self, and ensures that the
11464  * #ClutterActor::destroy signal is emitted on each child of the
11465  * actor.
11466  *
11467  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11468  * when its reference count drops to 0; the default handler of the
11469  * #ClutterActor::destroy signal will destroy all the children of an
11470  * actor. This function ensures that all children are destroyed, instead
11471  * of just removed from @self, unlike clutter_actor_remove_all_children()
11472  * which will merely release the reference and remove each child.
11473  *
11474  * Unless you acquired an additional reference on each child of @self
11475  * prior to calling clutter_actor_remove_all_children() and want to reuse
11476  * the actors, you should use clutter_actor_destroy_all_children() in
11477  * order to make sure that children are destroyed and signal handlers
11478  * are disconnected even in cases where circular references prevent this
11479  * from automatically happening through reference counting alone.
11480  *
11481  * Since: 1.10
11482  */
11483 void
11484 clutter_actor_destroy_all_children (ClutterActor *self)
11485 {
11486   ClutterActorIter iter;
11487
11488   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11489
11490   if (self->priv->n_children == 0)
11491     return;
11492
11493   g_object_freeze_notify (G_OBJECT (self));
11494
11495   clutter_actor_iter_init (&iter, self);
11496   while (clutter_actor_iter_next (&iter, NULL))
11497     clutter_actor_iter_destroy (&iter);
11498
11499   g_object_thaw_notify (G_OBJECT (self));
11500
11501   /* sanity check */
11502   g_assert (self->priv->first_child == NULL);
11503   g_assert (self->priv->last_child == NULL);
11504   g_assert (self->priv->n_children == 0);
11505 }
11506
11507 typedef struct _InsertBetweenData {
11508   ClutterActor *prev_sibling;
11509   ClutterActor *next_sibling;
11510 } InsertBetweenData;
11511
11512 static void
11513 insert_child_between (ClutterActor *self,
11514                       ClutterActor *child,
11515                       gpointer      data_)
11516 {
11517   InsertBetweenData *data = data_;
11518   ClutterActor *prev_sibling = data->prev_sibling;
11519   ClutterActor *next_sibling = data->next_sibling;
11520
11521   child->priv->parent = self;
11522   child->priv->prev_sibling = prev_sibling;
11523   child->priv->next_sibling = next_sibling;
11524
11525   if (prev_sibling != NULL)
11526     prev_sibling->priv->next_sibling = child;
11527
11528   if (next_sibling != NULL)
11529     next_sibling->priv->prev_sibling = child;
11530
11531   if (child->priv->prev_sibling == NULL)
11532     self->priv->first_child = child;
11533
11534   if (child->priv->next_sibling == NULL)
11535     self->priv->last_child = child;
11536 }
11537
11538 /**
11539  * clutter_actor_replace_child:
11540  * @self: a #ClutterActor
11541  * @old_child: the child of @self to replace
11542  * @new_child: the #ClutterActor to replace @old_child
11543  *
11544  * Replaces @old_child with @new_child in the list of children of @self.
11545  *
11546  * Since: 1.10
11547  */
11548 void
11549 clutter_actor_replace_child (ClutterActor *self,
11550                              ClutterActor *old_child,
11551                              ClutterActor *new_child)
11552 {
11553   ClutterActor *prev_sibling, *next_sibling;
11554   InsertBetweenData clos;
11555
11556   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11557   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11558   g_return_if_fail (old_child->priv->parent == self);
11559   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11560   g_return_if_fail (old_child != new_child);
11561   g_return_if_fail (new_child != self);
11562   g_return_if_fail (new_child->priv->parent == NULL);
11563
11564   prev_sibling = old_child->priv->prev_sibling;
11565   next_sibling = old_child->priv->next_sibling;
11566   clutter_actor_remove_child_internal (self, old_child,
11567                                        REMOVE_CHILD_DEFAULT_FLAGS);
11568
11569   clos.prev_sibling = prev_sibling;
11570   clos.next_sibling = next_sibling;
11571   clutter_actor_add_child_internal (self, new_child,
11572                                     ADD_CHILD_DEFAULT_FLAGS,
11573                                     insert_child_between,
11574                                     &clos);
11575 }
11576
11577 /**
11578  * clutter_actor_unparent:
11579  * @self: a #ClutterActor
11580  *
11581  * Removes the parent of @self.
11582  *
11583  * This will cause the parent of @self to release the reference
11584  * acquired when calling clutter_actor_set_parent(), so if you
11585  * want to keep @self you will have to acquire a reference of
11586  * your own, through g_object_ref().
11587  *
11588  * This function should only be called by legacy #ClutterActor<!-- -->s
11589  * implementing the #ClutterContainer interface.
11590  *
11591  * Since: 0.1.1
11592  *
11593  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11594  */
11595 void
11596 clutter_actor_unparent (ClutterActor *self)
11597 {
11598   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11599
11600   if (self->priv->parent == NULL)
11601     return;
11602
11603   clutter_actor_remove_child_internal (self->priv->parent, self,
11604                                        REMOVE_CHILD_LEGACY_FLAGS);
11605 }
11606
11607 /**
11608  * clutter_actor_reparent:
11609  * @self: a #ClutterActor
11610  * @new_parent: the new #ClutterActor parent
11611  *
11612  * Resets the parent actor of @self.
11613  *
11614  * This function is logically equivalent to calling clutter_actor_unparent()
11615  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11616  * ensures the child is not finalized when unparented, and emits the
11617  * #ClutterActor::parent-set signal only once.
11618  *
11619  * In reality, calling this function is less useful than it sounds, as some
11620  * application code may rely on changes in the intermediate state between
11621  * removal and addition of the actor from its old parent to the @new_parent.
11622  * Thus, it is strongly encouraged to avoid using this function in application
11623  * code.
11624  *
11625  * Since: 0.2
11626  *
11627  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11628  *   clutter_actor_add_child() instead; remember to take a reference on
11629  *   the actor being removed before calling clutter_actor_remove_child()
11630  *   to avoid the reference count dropping to zero and the actor being
11631  *   destroyed.
11632  */
11633 void
11634 clutter_actor_reparent (ClutterActor *self,
11635                         ClutterActor *new_parent)
11636 {
11637   ClutterActorPrivate *priv;
11638
11639   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11640   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11641   g_return_if_fail (self != new_parent);
11642
11643   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11644     {
11645       g_warning ("Cannot set a parent on a toplevel actor");
11646       return;
11647     }
11648
11649   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11650     {
11651       g_warning ("Cannot set a parent currently being destroyed");
11652       return;
11653     }
11654
11655   priv = self->priv;
11656
11657   if (priv->parent != new_parent)
11658     {
11659       ClutterActor *old_parent;
11660
11661       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11662
11663       old_parent = priv->parent;
11664
11665       g_object_ref (self);
11666
11667       if (old_parent != NULL)
11668         {
11669          /* go through the Container implementation if this is a regular
11670           * child and not an internal one
11671           */
11672          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11673            {
11674              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11675
11676              /* this will have to call unparent() */
11677              clutter_container_remove_actor (parent, self);
11678            }
11679          else
11680            clutter_actor_remove_child_internal (old_parent, self,
11681                                                 REMOVE_CHILD_LEGACY_FLAGS);
11682         }
11683
11684       /* Note, will call set_parent() */
11685       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11686         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11687       else
11688         clutter_actor_add_child_internal (new_parent, self,
11689                                           ADD_CHILD_LEGACY_FLAGS,
11690                                           insert_child_at_depth,
11691                                           NULL);
11692
11693       /* we emit the ::parent-set signal once */
11694       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11695
11696       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11697
11698       /* the IN_REPARENT flag suspends state updates */
11699       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11700
11701       g_object_unref (self);
11702    }
11703 }
11704
11705 /**
11706  * clutter_actor_contains:
11707  * @self: A #ClutterActor
11708  * @descendant: A #ClutterActor, possibly contained in @self
11709  *
11710  * Determines if @descendant is contained inside @self (either as an
11711  * immediate child, or as a deeper descendant). If @self and
11712  * @descendant point to the same actor then it will also return %TRUE.
11713  *
11714  * Return value: whether @descendent is contained within @self
11715  *
11716  * Since: 1.4
11717  */
11718 gboolean
11719 clutter_actor_contains (ClutterActor *self,
11720                         ClutterActor *descendant)
11721 {
11722   ClutterActor *actor;
11723
11724   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11725   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11726
11727   for (actor = descendant; actor; actor = actor->priv->parent)
11728     if (actor == self)
11729       return TRUE;
11730
11731   return FALSE;
11732 }
11733
11734 /**
11735  * clutter_actor_set_child_above_sibling:
11736  * @self: a #ClutterActor
11737  * @child: a #ClutterActor child of @self
11738  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11739  *
11740  * Sets @child to be above @sibling in the list of children of @self.
11741  *
11742  * If @sibling is %NULL, @child will be the new last child of @self.
11743  *
11744  * This function is logically equivalent to removing @child and using
11745  * clutter_actor_insert_child_above(), but it will not emit signals
11746  * or change state on @child.
11747  *
11748  * Since: 1.10
11749  */
11750 void
11751 clutter_actor_set_child_above_sibling (ClutterActor *self,
11752                                        ClutterActor *child,
11753                                        ClutterActor *sibling)
11754 {
11755   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11756   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11757   g_return_if_fail (child->priv->parent == self);
11758   g_return_if_fail (child != sibling);
11759   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11760
11761   if (sibling != NULL)
11762     g_return_if_fail (sibling->priv->parent == self);
11763
11764   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11765       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11766       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11767     return;
11768
11769   /* we don't want to change the state of child, or emit signals, or
11770    * regenerate ChildMeta instances here, but we still want to follow
11771    * the correct sequence of steps encoded in remove_child() and
11772    * add_child(), so that correctness is ensured, and we only go
11773    * through one known code path.
11774    */
11775   g_object_ref (child);
11776   clutter_actor_remove_child_internal (self, child, 0);
11777   clutter_actor_add_child_internal (self, child,
11778                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11779                                     insert_child_above,
11780                                     sibling);
11781
11782   clutter_actor_queue_relayout (self);
11783 }
11784
11785 /**
11786  * clutter_actor_set_child_below_sibling:
11787  * @self: a #ClutterActor
11788  * @child: a #ClutterActor child of @self
11789  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11790  *
11791  * Sets @child to be below @sibling in the list of children of @self.
11792  *
11793  * If @sibling is %NULL, @child will be the new first child of @self.
11794  *
11795  * This function is logically equivalent to removing @self and using
11796  * clutter_actor_insert_child_below(), but it will not emit signals
11797  * or change state on @child.
11798  *
11799  * Since: 1.10
11800  */
11801 void
11802 clutter_actor_set_child_below_sibling (ClutterActor *self,
11803                                        ClutterActor *child,
11804                                        ClutterActor *sibling)
11805 {
11806   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11807   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11808   g_return_if_fail (child->priv->parent == self);
11809   g_return_if_fail (child != sibling);
11810   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11811
11812   if (sibling != NULL)
11813     g_return_if_fail (sibling->priv->parent == self);
11814
11815   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11816       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11817       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11818     return;
11819
11820   /* see the comment in set_child_above_sibling() */
11821   g_object_ref (child);
11822   clutter_actor_remove_child_internal (self, child, 0);
11823   clutter_actor_add_child_internal (self, child,
11824                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11825                                     insert_child_below,
11826                                     sibling);
11827
11828   clutter_actor_queue_relayout (self);
11829 }
11830
11831 /**
11832  * clutter_actor_set_child_at_index:
11833  * @self: a #ClutterActor
11834  * @child: a #ClutterActor child of @self
11835  * @index_: the new index for @child
11836  *
11837  * Changes the index of @child in the list of children of @self.
11838  *
11839  * This function is logically equivalent to removing @child and
11840  * calling clutter_actor_insert_child_at_index(), but it will not
11841  * emit signals or change state on @child.
11842  *
11843  * Since: 1.10
11844  */
11845 void
11846 clutter_actor_set_child_at_index (ClutterActor *self,
11847                                   ClutterActor *child,
11848                                   gint          index_)
11849 {
11850   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11851   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11852   g_return_if_fail (child->priv->parent == self);
11853   g_return_if_fail (index_ <= self->priv->n_children);
11854
11855   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11856       CLUTTER_ACTOR_IN_DESTRUCTION (child))
11857     return;
11858
11859   g_object_ref (child);
11860   clutter_actor_remove_child_internal (self, child, 0);
11861   clutter_actor_add_child_internal (self, child,
11862                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11863                                     insert_child_at_index,
11864                                     GINT_TO_POINTER (index_));
11865
11866   clutter_actor_queue_relayout (self);
11867 }
11868
11869 /**
11870  * clutter_actor_raise:
11871  * @self: A #ClutterActor
11872  * @below: (allow-none): A #ClutterActor to raise above.
11873  *
11874  * Puts @self above @below.
11875  *
11876  * Both actors must have the same parent, and the parent must implement
11877  * the #ClutterContainer interface
11878  *
11879  * This function calls clutter_container_raise_child() internally.
11880  *
11881  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11882  */
11883 void
11884 clutter_actor_raise (ClutterActor *self,
11885                      ClutterActor *below)
11886 {
11887   ClutterActor *parent;
11888
11889   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11890
11891   parent = clutter_actor_get_parent (self);
11892   if (parent == NULL)
11893     {
11894       g_warning ("%s: Actor '%s' is not inside a container",
11895                  G_STRFUNC,
11896                  _clutter_actor_get_debug_name (self));
11897       return;
11898     }
11899
11900   if (below != NULL)
11901     {
11902       if (parent != clutter_actor_get_parent (below))
11903         {
11904           g_warning ("%s Actor '%s' is not in the same container as "
11905                      "actor '%s'",
11906                      G_STRFUNC,
11907                      _clutter_actor_get_debug_name (self),
11908                      _clutter_actor_get_debug_name (below));
11909           return;
11910         }
11911     }
11912
11913   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11914 }
11915
11916 /**
11917  * clutter_actor_lower:
11918  * @self: A #ClutterActor
11919  * @above: (allow-none): A #ClutterActor to lower below
11920  *
11921  * Puts @self below @above.
11922  *
11923  * Both actors must have the same parent, and the parent must implement
11924  * the #ClutterContainer interface.
11925  *
11926  * This function calls clutter_container_lower_child() internally.
11927  *
11928  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11929  */
11930 void
11931 clutter_actor_lower (ClutterActor *self,
11932                      ClutterActor *above)
11933 {
11934   ClutterActor *parent;
11935
11936   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11937
11938   parent = clutter_actor_get_parent (self);
11939   if (parent == NULL)
11940     {
11941       g_warning ("%s: Actor of type %s is not inside a container",
11942                  G_STRFUNC,
11943                  _clutter_actor_get_debug_name (self));
11944       return;
11945     }
11946
11947   if (above)
11948     {
11949       if (parent != clutter_actor_get_parent (above))
11950         {
11951           g_warning ("%s: Actor '%s' is not in the same container as "
11952                      "actor '%s'",
11953                      G_STRFUNC,
11954                      _clutter_actor_get_debug_name (self),
11955                      _clutter_actor_get_debug_name (above));
11956           return;
11957         }
11958     }
11959
11960   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11961 }
11962
11963 /**
11964  * clutter_actor_raise_top:
11965  * @self: A #ClutterActor
11966  *
11967  * Raises @self to the top.
11968  *
11969  * This function calls clutter_actor_raise() internally.
11970  *
11971  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11972  *   a %NULL sibling, instead.
11973  */
11974 void
11975 clutter_actor_raise_top (ClutterActor *self)
11976 {
11977   clutter_actor_raise (self, NULL);
11978 }
11979
11980 /**
11981  * clutter_actor_lower_bottom:
11982  * @self: A #ClutterActor
11983  *
11984  * Lowers @self to the bottom.
11985  *
11986  * This function calls clutter_actor_lower() internally.
11987  *
11988  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11989  *   a %NULL sibling, instead.
11990  */
11991 void
11992 clutter_actor_lower_bottom (ClutterActor *self)
11993 {
11994   clutter_actor_lower (self, NULL);
11995 }
11996
11997 /*
11998  * Event handling
11999  */
12000
12001 /**
12002  * clutter_actor_event:
12003  * @actor: a #ClutterActor
12004  * @event: a #ClutterEvent
12005  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12006  *
12007  * This function is used to emit an event on the main stage.
12008  * You should rarely need to use this function, except for
12009  * synthetising events.
12010  *
12011  * Return value: the return value from the signal emission: %TRUE
12012  *   if the actor handled the event, or %FALSE if the event was
12013  *   not handled
12014  *
12015  * Since: 0.6
12016  */
12017 gboolean
12018 clutter_actor_event (ClutterActor *actor,
12019                      ClutterEvent *event,
12020                      gboolean      capture)
12021 {
12022   gboolean retval = FALSE;
12023   gint signal_num = -1;
12024
12025   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12026   g_return_val_if_fail (event != NULL, FALSE);
12027
12028   g_object_ref (actor);
12029
12030   if (capture)
12031     {
12032       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12033                      event,
12034                      &retval);
12035       goto out;
12036     }
12037
12038   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12039
12040   if (!retval)
12041     {
12042       switch (event->type)
12043         {
12044         case CLUTTER_NOTHING:
12045           break;
12046         case CLUTTER_BUTTON_PRESS:
12047           signal_num = BUTTON_PRESS_EVENT;
12048           break;
12049         case CLUTTER_BUTTON_RELEASE:
12050           signal_num = BUTTON_RELEASE_EVENT;
12051           break;
12052         case CLUTTER_SCROLL:
12053           signal_num = SCROLL_EVENT;
12054           break;
12055         case CLUTTER_KEY_PRESS:
12056           signal_num = KEY_PRESS_EVENT;
12057           break;
12058         case CLUTTER_KEY_RELEASE:
12059           signal_num = KEY_RELEASE_EVENT;
12060           break;
12061         case CLUTTER_MOTION:
12062           signal_num = MOTION_EVENT;
12063           break;
12064         case CLUTTER_ENTER:
12065           signal_num = ENTER_EVENT;
12066           break;
12067         case CLUTTER_LEAVE:
12068           signal_num = LEAVE_EVENT;
12069           break;
12070         case CLUTTER_DELETE:
12071         case CLUTTER_DESTROY_NOTIFY:
12072         case CLUTTER_CLIENT_MESSAGE:
12073         default:
12074           signal_num = -1;
12075           break;
12076         }
12077
12078       if (signal_num != -1)
12079         g_signal_emit (actor, actor_signals[signal_num], 0,
12080                        event, &retval);
12081     }
12082
12083 out:
12084   g_object_unref (actor);
12085
12086   return retval;
12087 }
12088
12089 /**
12090  * clutter_actor_set_reactive:
12091  * @actor: a #ClutterActor
12092  * @reactive: whether the actor should be reactive to events
12093  *
12094  * Sets @actor as reactive. Reactive actors will receive events.
12095  *
12096  * Since: 0.6
12097  */
12098 void
12099 clutter_actor_set_reactive (ClutterActor *actor,
12100                             gboolean      reactive)
12101 {
12102   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12103
12104   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12105     return;
12106
12107   if (reactive)
12108     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12109   else
12110     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12111
12112   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12113 }
12114
12115 /**
12116  * clutter_actor_get_reactive:
12117  * @actor: a #ClutterActor
12118  *
12119  * Checks whether @actor is marked as reactive.
12120  *
12121  * Return value: %TRUE if the actor is reactive
12122  *
12123  * Since: 0.6
12124  */
12125 gboolean
12126 clutter_actor_get_reactive (ClutterActor *actor)
12127 {
12128   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12129
12130   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12131 }
12132
12133 /**
12134  * clutter_actor_get_anchor_point:
12135  * @self: a #ClutterActor
12136  * @anchor_x: (out): return location for the X coordinate of the anchor point
12137  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12138  *
12139  * Gets the current anchor point of the @actor in pixels.
12140  *
12141  * Since: 0.6
12142  */
12143 void
12144 clutter_actor_get_anchor_point (ClutterActor *self,
12145                                 gfloat       *anchor_x,
12146                                 gfloat       *anchor_y)
12147 {
12148   const ClutterTransformInfo *info;
12149
12150   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12151
12152   info = _clutter_actor_get_transform_info_or_defaults (self);
12153   clutter_anchor_coord_get_units (self, &info->anchor,
12154                                   anchor_x,
12155                                   anchor_y,
12156                                   NULL);
12157 }
12158
12159 /**
12160  * clutter_actor_set_anchor_point:
12161  * @self: a #ClutterActor
12162  * @anchor_x: X coordinate of the anchor point
12163  * @anchor_y: Y coordinate of the anchor point
12164  *
12165  * Sets an anchor point for @self. The anchor point is a point in the
12166  * coordinate space of an actor to which the actor position within its
12167  * parent is relative; the default is (0, 0), i.e. the top-left corner
12168  * of the actor.
12169  *
12170  * Since: 0.6
12171  */
12172 void
12173 clutter_actor_set_anchor_point (ClutterActor *self,
12174                                 gfloat        anchor_x,
12175                                 gfloat        anchor_y)
12176 {
12177   ClutterTransformInfo *info;
12178   ClutterActorPrivate *priv;
12179   gboolean changed = FALSE;
12180   gfloat old_anchor_x, old_anchor_y;
12181   GObject *obj;
12182
12183   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12184
12185   obj = G_OBJECT (self);
12186   priv = self->priv;
12187   info = _clutter_actor_get_transform_info (self);
12188
12189   g_object_freeze_notify (obj);
12190
12191   clutter_anchor_coord_get_units (self, &info->anchor,
12192                                   &old_anchor_x,
12193                                   &old_anchor_y,
12194                                   NULL);
12195
12196   if (info->anchor.is_fractional)
12197     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12198
12199   if (old_anchor_x != anchor_x)
12200     {
12201       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12202       changed = TRUE;
12203     }
12204
12205   if (old_anchor_y != anchor_y)
12206     {
12207       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12208       changed = TRUE;
12209     }
12210
12211   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12212
12213   if (changed)
12214     {
12215       priv->transform_valid = FALSE;
12216       clutter_actor_queue_redraw (self);
12217     }
12218
12219   g_object_thaw_notify (obj);
12220 }
12221
12222 /**
12223  * clutter_actor_get_anchor_point_gravity:
12224  * @self: a #ClutterActor
12225  *
12226  * Retrieves the anchor position expressed as a #ClutterGravity. If
12227  * the anchor point was specified using pixels or units this will
12228  * return %CLUTTER_GRAVITY_NONE.
12229  *
12230  * Return value: the #ClutterGravity used by the anchor point
12231  *
12232  * Since: 1.0
12233  */
12234 ClutterGravity
12235 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12236 {
12237   const ClutterTransformInfo *info;
12238
12239   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12240
12241   info = _clutter_actor_get_transform_info_or_defaults (self);
12242
12243   return clutter_anchor_coord_get_gravity (&info->anchor);
12244 }
12245
12246 /**
12247  * clutter_actor_move_anchor_point:
12248  * @self: a #ClutterActor
12249  * @anchor_x: X coordinate of the anchor point
12250  * @anchor_y: Y coordinate of the anchor point
12251  *
12252  * Sets an anchor point for the actor, and adjusts the actor postion so that
12253  * the relative position of the actor toward its parent remains the same.
12254  *
12255  * Since: 0.6
12256  */
12257 void
12258 clutter_actor_move_anchor_point (ClutterActor *self,
12259                                  gfloat        anchor_x,
12260                                  gfloat        anchor_y)
12261 {
12262   gfloat old_anchor_x, old_anchor_y;
12263   const ClutterTransformInfo *info;
12264
12265   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12266
12267   info = _clutter_actor_get_transform_info (self);
12268   clutter_anchor_coord_get_units (self, &info->anchor,
12269                                   &old_anchor_x,
12270                                   &old_anchor_y,
12271                                   NULL);
12272
12273   g_object_freeze_notify (G_OBJECT (self));
12274
12275   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12276
12277   if (self->priv->position_set)
12278     clutter_actor_move_by (self,
12279                            anchor_x - old_anchor_x,
12280                            anchor_y - old_anchor_y);
12281
12282   g_object_thaw_notify (G_OBJECT (self));
12283 }
12284
12285 /**
12286  * clutter_actor_move_anchor_point_from_gravity:
12287  * @self: a #ClutterActor
12288  * @gravity: #ClutterGravity.
12289  *
12290  * Sets an anchor point on the actor based on the given gravity, adjusting the
12291  * actor postion so that its relative position within its parent remains
12292  * unchanged.
12293  *
12294  * Since version 1.0 the anchor point will be stored as a gravity so
12295  * that if the actor changes size then the anchor point will move. For
12296  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12297  * and later double the size of the actor, the anchor point will move
12298  * to the bottom right.
12299  *
12300  * Since: 0.6
12301  */
12302 void
12303 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12304                                               ClutterGravity  gravity)
12305 {
12306   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12307   const ClutterTransformInfo *info;
12308   ClutterActorPrivate *priv;
12309
12310   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12311
12312   priv = self->priv;
12313   info = _clutter_actor_get_transform_info (self);
12314
12315   g_object_freeze_notify (G_OBJECT (self));
12316
12317   clutter_anchor_coord_get_units (self, &info->anchor,
12318                                   &old_anchor_x,
12319                                   &old_anchor_y,
12320                                   NULL);
12321   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12322   clutter_anchor_coord_get_units (self, &info->anchor,
12323                                   &new_anchor_x,
12324                                   &new_anchor_y,
12325                                   NULL);
12326
12327   if (priv->position_set)
12328     clutter_actor_move_by (self,
12329                            new_anchor_x - old_anchor_x,
12330                            new_anchor_y - old_anchor_y);
12331
12332   g_object_thaw_notify (G_OBJECT (self));
12333 }
12334
12335 /**
12336  * clutter_actor_set_anchor_point_from_gravity:
12337  * @self: a #ClutterActor
12338  * @gravity: #ClutterGravity.
12339  *
12340  * Sets an anchor point on the actor, based on the given gravity (this is a
12341  * convenience function wrapping clutter_actor_set_anchor_point()).
12342  *
12343  * Since version 1.0 the anchor point will be stored as a gravity so
12344  * that if the actor changes size then the anchor point will move. For
12345  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12346  * and later double the size of the actor, the anchor point will move
12347  * to the bottom right.
12348  *
12349  * Since: 0.6
12350  */
12351 void
12352 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12353                                              ClutterGravity  gravity)
12354 {
12355   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12356
12357   if (gravity == CLUTTER_GRAVITY_NONE)
12358     clutter_actor_set_anchor_point (self, 0, 0);
12359   else
12360     {
12361       GObject *obj = G_OBJECT (self);
12362       ClutterTransformInfo *info;
12363
12364       g_object_freeze_notify (obj);
12365
12366       info = _clutter_actor_get_transform_info (self);
12367       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12368
12369       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12370       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12371       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12372
12373       self->priv->transform_valid = FALSE;
12374
12375       clutter_actor_queue_redraw (self);
12376
12377       g_object_thaw_notify (obj);
12378     }
12379 }
12380
12381 static void
12382 clutter_container_iface_init (ClutterContainerIface *iface)
12383 {
12384   /* we don't override anything, as ClutterContainer already has a default
12385    * implementation that we can use, and which calls into our own API.
12386    */
12387 }
12388
12389 typedef enum
12390 {
12391   PARSE_X,
12392   PARSE_Y,
12393   PARSE_WIDTH,
12394   PARSE_HEIGHT,
12395   PARSE_ANCHOR_X,
12396   PARSE_ANCHOR_Y
12397 } ParseDimension;
12398
12399 static gfloat
12400 parse_units (ClutterActor   *self,
12401              ParseDimension  dimension,
12402              JsonNode       *node)
12403 {
12404   GValue value = G_VALUE_INIT;
12405   gfloat retval = 0;
12406
12407   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12408     return 0;
12409
12410   json_node_get_value (node, &value);
12411
12412   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12413     {
12414       retval = (gfloat) g_value_get_int64 (&value);
12415     }
12416   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12417     {
12418       retval = g_value_get_double (&value);
12419     }
12420   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12421     {
12422       ClutterUnits units;
12423       gboolean res;
12424
12425       res = clutter_units_from_string (&units, g_value_get_string (&value));
12426       if (res)
12427         retval = clutter_units_to_pixels (&units);
12428       else
12429         {
12430           g_warning ("Invalid value '%s': integers, strings or floating point "
12431                      "values can be used for the x, y, width and height "
12432                      "properties. Valid modifiers for strings are 'px', 'mm', "
12433                      "'pt' and 'em'.",
12434                      g_value_get_string (&value));
12435           retval = 0;
12436         }
12437     }
12438   else
12439     {
12440       g_warning ("Invalid value of type '%s': integers, strings of floating "
12441                  "point values can be used for the x, y, width, height "
12442                  "anchor-x and anchor-y properties.",
12443                  g_type_name (G_VALUE_TYPE (&value)));
12444     }
12445
12446   g_value_unset (&value);
12447
12448   return retval;
12449 }
12450
12451 typedef struct {
12452   ClutterRotateAxis axis;
12453
12454   gdouble angle;
12455
12456   gfloat center_x;
12457   gfloat center_y;
12458   gfloat center_z;
12459 } RotationInfo;
12460
12461 static inline gboolean
12462 parse_rotation_array (ClutterActor *actor,
12463                       JsonArray    *array,
12464                       RotationInfo *info)
12465 {
12466   JsonNode *element;
12467
12468   if (json_array_get_length (array) != 2)
12469     return FALSE;
12470
12471   /* angle */
12472   element = json_array_get_element (array, 0);
12473   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12474     info->angle = json_node_get_double (element);
12475   else
12476     return FALSE;
12477
12478   /* center */
12479   element = json_array_get_element (array, 1);
12480   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12481     {
12482       JsonArray *center = json_node_get_array (element);
12483
12484       if (json_array_get_length (center) != 2)
12485         return FALSE;
12486
12487       switch (info->axis)
12488         {
12489         case CLUTTER_X_AXIS:
12490           info->center_y = parse_units (actor, PARSE_Y,
12491                                         json_array_get_element (center, 0));
12492           info->center_z = parse_units (actor, PARSE_Y,
12493                                         json_array_get_element (center, 1));
12494           return TRUE;
12495
12496         case CLUTTER_Y_AXIS:
12497           info->center_x = parse_units (actor, PARSE_X,
12498                                         json_array_get_element (center, 0));
12499           info->center_z = parse_units (actor, PARSE_X,
12500                                         json_array_get_element (center, 1));
12501           return TRUE;
12502
12503         case CLUTTER_Z_AXIS:
12504           info->center_x = parse_units (actor, PARSE_X,
12505                                         json_array_get_element (center, 0));
12506           info->center_y = parse_units (actor, PARSE_Y,
12507                                         json_array_get_element (center, 1));
12508           return TRUE;
12509         }
12510     }
12511
12512   return FALSE;
12513 }
12514
12515 static gboolean
12516 parse_rotation (ClutterActor *actor,
12517                 JsonNode     *node,
12518                 RotationInfo *info)
12519 {
12520   JsonArray *array;
12521   guint len, i;
12522   gboolean retval = FALSE;
12523
12524   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12525     {
12526       g_warning ("Invalid node of type '%s' found, expecting an array",
12527                  json_node_type_name (node));
12528       return FALSE;
12529     }
12530
12531   array = json_node_get_array (node);
12532   len = json_array_get_length (array);
12533
12534   for (i = 0; i < len; i++)
12535     {
12536       JsonNode *element = json_array_get_element (array, i);
12537       JsonObject *object;
12538       JsonNode *member;
12539
12540       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12541         {
12542           g_warning ("Invalid node of type '%s' found, expecting an object",
12543                      json_node_type_name (element));
12544           return FALSE;
12545         }
12546
12547       object = json_node_get_object (element);
12548
12549       if (json_object_has_member (object, "x-axis"))
12550         {
12551           member = json_object_get_member (object, "x-axis");
12552
12553           info->axis = CLUTTER_X_AXIS;
12554
12555           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12556             {
12557               info->angle = json_node_get_double (member);
12558               retval = TRUE;
12559             }
12560           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12561             retval = parse_rotation_array (actor,
12562                                            json_node_get_array (member),
12563                                            info);
12564           else
12565             retval = FALSE;
12566         }
12567       else if (json_object_has_member (object, "y-axis"))
12568         {
12569           member = json_object_get_member (object, "y-axis");
12570
12571           info->axis = CLUTTER_Y_AXIS;
12572
12573           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12574             {
12575               info->angle = json_node_get_double (member);
12576               retval = TRUE;
12577             }
12578           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12579             retval = parse_rotation_array (actor,
12580                                            json_node_get_array (member),
12581                                            info);
12582           else
12583             retval = FALSE;
12584         }
12585       else if (json_object_has_member (object, "z-axis"))
12586         {
12587           member = json_object_get_member (object, "z-axis");
12588
12589           info->axis = CLUTTER_Z_AXIS;
12590
12591           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12592             {
12593               info->angle = json_node_get_double (member);
12594               retval = TRUE;
12595             }
12596           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12597             retval = parse_rotation_array (actor,
12598                                            json_node_get_array (member),
12599                                            info);
12600           else
12601             retval = FALSE;
12602         }
12603     }
12604
12605   return retval;
12606 }
12607
12608 static GSList *
12609 parse_actor_metas (ClutterScript *script,
12610                    ClutterActor  *actor,
12611                    JsonNode      *node)
12612 {
12613   GList *elements, *l;
12614   GSList *retval = NULL;
12615
12616   if (!JSON_NODE_HOLDS_ARRAY (node))
12617     return NULL;
12618
12619   elements = json_array_get_elements (json_node_get_array (node));
12620
12621   for (l = elements; l != NULL; l = l->next)
12622     {
12623       JsonNode *element = l->data;
12624       const gchar *id_ = _clutter_script_get_id_from_node (element);
12625       GObject *meta;
12626
12627       if (id_ == NULL || *id_ == '\0')
12628         continue;
12629
12630       meta = clutter_script_get_object (script, id_);
12631       if (meta == NULL)
12632         continue;
12633
12634       retval = g_slist_prepend (retval, meta);
12635     }
12636
12637   g_list_free (elements);
12638
12639   return g_slist_reverse (retval);
12640 }
12641
12642 static GSList *
12643 parse_behaviours (ClutterScript *script,
12644                   ClutterActor  *actor,
12645                   JsonNode      *node)
12646 {
12647   GList *elements, *l;
12648   GSList *retval = NULL;
12649
12650   if (!JSON_NODE_HOLDS_ARRAY (node))
12651     return NULL;
12652
12653   elements = json_array_get_elements (json_node_get_array (node));
12654
12655   for (l = elements; l != NULL; l = l->next)
12656     {
12657       JsonNode *element = l->data;
12658       const gchar *id_ = _clutter_script_get_id_from_node (element);
12659       GObject *behaviour;
12660
12661       if (id_ == NULL || *id_ == '\0')
12662         continue;
12663
12664       behaviour = clutter_script_get_object (script, id_);
12665       if (behaviour == NULL)
12666         continue;
12667
12668       retval = g_slist_prepend (retval, behaviour);
12669     }
12670
12671   g_list_free (elements);
12672
12673   return g_slist_reverse (retval);
12674 }
12675
12676 static gboolean
12677 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12678                                  ClutterScript     *script,
12679                                  GValue            *value,
12680                                  const gchar       *name,
12681                                  JsonNode          *node)
12682 {
12683   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12684   gboolean retval = FALSE;
12685
12686   if ((name[0] == 'x' && name[1] == '\0') ||
12687       (name[0] == 'y' && name[1] == '\0') ||
12688       (strcmp (name, "width") == 0) ||
12689       (strcmp (name, "height") == 0) ||
12690       (strcmp (name, "anchor_x") == 0) ||
12691       (strcmp (name, "anchor_y") == 0))
12692     {
12693       ParseDimension dimension;
12694       gfloat units;
12695
12696       if (name[0] == 'x')
12697         dimension = PARSE_X;
12698       else if (name[0] == 'y')
12699         dimension = PARSE_Y;
12700       else if (name[0] == 'w')
12701         dimension = PARSE_WIDTH;
12702       else if (name[0] == 'h')
12703         dimension = PARSE_HEIGHT;
12704       else if (name[0] == 'a' && name[7] == 'x')
12705         dimension = PARSE_ANCHOR_X;
12706       else if (name[0] == 'a' && name[7] == 'y')
12707         dimension = PARSE_ANCHOR_Y;
12708       else
12709         return FALSE;
12710
12711       units = parse_units (actor, dimension, node);
12712
12713       /* convert back to pixels: all properties are pixel-based */
12714       g_value_init (value, G_TYPE_FLOAT);
12715       g_value_set_float (value, units);
12716
12717       retval = TRUE;
12718     }
12719   else if (strcmp (name, "rotation") == 0)
12720     {
12721       RotationInfo *info;
12722
12723       info = g_slice_new0 (RotationInfo);
12724       retval = parse_rotation (actor, node, info);
12725
12726       if (retval)
12727         {
12728           g_value_init (value, G_TYPE_POINTER);
12729           g_value_set_pointer (value, info);
12730         }
12731       else
12732         g_slice_free (RotationInfo, info);
12733     }
12734   else if (strcmp (name, "behaviours") == 0)
12735     {
12736       GSList *l;
12737
12738 #ifdef CLUTTER_ENABLE_DEBUG
12739       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12740         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12741                                      "and it should not be used in newly "
12742                                      "written ClutterScript definitions.");
12743 #endif
12744
12745       l = parse_behaviours (script, actor, node);
12746
12747       g_value_init (value, G_TYPE_POINTER);
12748       g_value_set_pointer (value, l);
12749
12750       retval = TRUE;
12751     }
12752   else if (strcmp (name, "actions") == 0 ||
12753            strcmp (name, "constraints") == 0 ||
12754            strcmp (name, "effects") == 0)
12755     {
12756       GSList *l;
12757
12758       l = parse_actor_metas (script, actor, node);
12759
12760       g_value_init (value, G_TYPE_POINTER);
12761       g_value_set_pointer (value, l);
12762
12763       retval = TRUE;
12764     }
12765
12766   return retval;
12767 }
12768
12769 static void
12770 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12771                                    ClutterScript     *script,
12772                                    const gchar       *name,
12773                                    const GValue      *value)
12774 {
12775   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12776
12777 #ifdef CLUTTER_ENABLE_DEBUG
12778   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12779     {
12780       gchar *tmp = g_strdup_value_contents (value);
12781
12782       CLUTTER_NOTE (SCRIPT,
12783                     "in ClutterActor::set_custom_property('%s') = %s",
12784                     name,
12785                     tmp);
12786
12787       g_free (tmp);
12788     }
12789 #endif /* CLUTTER_ENABLE_DEBUG */
12790
12791   if (strcmp (name, "rotation") == 0)
12792     {
12793       RotationInfo *info;
12794
12795       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12796         return;
12797
12798       info = g_value_get_pointer (value);
12799
12800       clutter_actor_set_rotation (actor,
12801                                   info->axis, info->angle,
12802                                   info->center_x,
12803                                   info->center_y,
12804                                   info->center_z);
12805
12806       g_slice_free (RotationInfo, info);
12807
12808       return;
12809     }
12810
12811   if (strcmp (name, "behaviours") == 0)
12812     {
12813       GSList *behaviours, *l;
12814
12815       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12816         return;
12817
12818       behaviours = g_value_get_pointer (value);
12819       for (l = behaviours; l != NULL; l = l->next)
12820         {
12821           ClutterBehaviour *behaviour = l->data;
12822
12823           clutter_behaviour_apply (behaviour, actor);
12824         }
12825
12826       g_slist_free (behaviours);
12827
12828       return;
12829     }
12830
12831   if (strcmp (name, "actions") == 0 ||
12832       strcmp (name, "constraints") == 0 ||
12833       strcmp (name, "effects") == 0)
12834     {
12835       GSList *metas, *l;
12836
12837       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12838         return;
12839
12840       metas = g_value_get_pointer (value);
12841       for (l = metas; l != NULL; l = l->next)
12842         {
12843           if (name[0] == 'a')
12844             clutter_actor_add_action (actor, l->data);
12845
12846           if (name[0] == 'c')
12847             clutter_actor_add_constraint (actor, l->data);
12848
12849           if (name[0] == 'e')
12850             clutter_actor_add_effect (actor, l->data);
12851         }
12852
12853       g_slist_free (metas);
12854
12855       return;
12856     }
12857
12858   g_object_set_property (G_OBJECT (scriptable), name, value);
12859 }
12860
12861 static void
12862 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12863 {
12864   iface->parse_custom_node = clutter_actor_parse_custom_node;
12865   iface->set_custom_property = clutter_actor_set_custom_property;
12866 }
12867
12868 static ClutterActorMeta *
12869 get_meta_from_animation_property (ClutterActor  *actor,
12870                                   const gchar   *name,
12871                                   gchar        **name_p)
12872 {
12873   ClutterActorPrivate *priv = actor->priv;
12874   ClutterActorMeta *meta = NULL;
12875   gchar **tokens;
12876
12877   /* if this is not a special property, fall through */
12878   if (name[0] != '@')
12879     return NULL;
12880
12881   /* detect the properties named using the following spec:
12882    *
12883    *   @<section>.<meta-name>.<property-name>
12884    *
12885    * where <section> can be one of the following:
12886    *
12887    *   - actions
12888    *   - constraints
12889    *   - effects
12890    *
12891    * and <meta-name> is the name set on a specific ActorMeta
12892    */
12893
12894   tokens = g_strsplit (name + 1, ".", -1);
12895   if (tokens == NULL || g_strv_length (tokens) != 3)
12896     {
12897       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12898                     name + 1);
12899       g_strfreev (tokens);
12900       return NULL;
12901     }
12902
12903   if (strcmp (tokens[0], "actions") == 0)
12904     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12905
12906   if (strcmp (tokens[0], "constraints") == 0)
12907     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12908
12909   if (strcmp (tokens[0], "effects") == 0)
12910     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12911
12912   if (name_p != NULL)
12913     *name_p = g_strdup (tokens[2]);
12914
12915   CLUTTER_NOTE (ANIMATION,
12916                 "Looking for property '%s' of object '%s' in section '%s'",
12917                 tokens[2],
12918                 tokens[1],
12919                 tokens[0]);
12920
12921   g_strfreev (tokens);
12922
12923   return meta;
12924 }
12925
12926 static GParamSpec *
12927 clutter_actor_find_property (ClutterAnimatable *animatable,
12928                              const gchar       *property_name)
12929 {
12930   ClutterActorMeta *meta = NULL;
12931   GObjectClass *klass = NULL;
12932   GParamSpec *pspec = NULL;
12933   gchar *p_name = NULL;
12934
12935   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12936                                            property_name,
12937                                            &p_name);
12938
12939   if (meta != NULL)
12940     {
12941       klass = G_OBJECT_GET_CLASS (meta);
12942
12943       pspec = g_object_class_find_property (klass, p_name);
12944     }
12945   else
12946     {
12947       klass = G_OBJECT_GET_CLASS (animatable);
12948
12949       pspec = g_object_class_find_property (klass, property_name);
12950     }
12951
12952   g_free (p_name);
12953
12954   return pspec;
12955 }
12956
12957 static void
12958 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12959                                  const gchar       *property_name,
12960                                  GValue            *initial)
12961 {
12962   ClutterActorMeta *meta = NULL;
12963   gchar *p_name = NULL;
12964
12965   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12966                                            property_name,
12967                                            &p_name);
12968
12969   if (meta != NULL)
12970     g_object_get_property (G_OBJECT (meta), p_name, initial);
12971   else
12972     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12973
12974   g_free (p_name);
12975 }
12976
12977 /*
12978  * clutter_actor_set_animatable_property:
12979  * @actor: a #ClutterActor
12980  * @prop_id: the paramspec id
12981  * @value: the value to set
12982  * @pspec: the paramspec
12983  *
12984  * Sets values of animatable properties.
12985  *
12986  * This is a variant of clutter_actor_set_property() that gets called
12987  * by the #ClutterAnimatable implementation of #ClutterActor for the
12988  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12989  * #GParamSpec.
12990  *
12991  * Unlike the implementation of #GObjectClass.set_property(), this
12992  * function will not update the interval if a transition involving an
12993  * animatable property is in progress - this avoids cycles with the
12994  * transition API calling the public API.
12995  */
12996 static void
12997 clutter_actor_set_animatable_property (ClutterActor *actor,
12998                                        guint         prop_id,
12999                                        const GValue *value,
13000                                        GParamSpec   *pspec)
13001 {
13002   switch (prop_id)
13003     {
13004     case PROP_X:
13005       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13006       break;
13007
13008     case PROP_Y:
13009       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13010       break;
13011
13012     case PROP_WIDTH:
13013       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13014       break;
13015
13016     case PROP_HEIGHT:
13017       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13018       break;
13019
13020     case PROP_DEPTH:
13021       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13022       break;
13023
13024     case PROP_OPACITY:
13025       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13026       break;
13027
13028     case PROP_BACKGROUND_COLOR:
13029       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13030       break;
13031
13032     case PROP_SCALE_X:
13033       clutter_actor_set_scale_factor_internal (actor,
13034                                                g_value_get_double (value),
13035                                                pspec);
13036       break;
13037
13038     case PROP_SCALE_Y:
13039       clutter_actor_set_scale_factor_internal (actor,
13040                                                g_value_get_double (value),
13041                                                pspec);
13042       break;
13043
13044     case PROP_ROTATION_ANGLE_X:
13045       clutter_actor_set_rotation_angle_internal (actor,
13046                                                  CLUTTER_X_AXIS,
13047                                                  g_value_get_double (value));
13048       break;
13049
13050     case PROP_ROTATION_ANGLE_Y:
13051       clutter_actor_set_rotation_angle_internal (actor,
13052                                                  CLUTTER_Y_AXIS,
13053                                                  g_value_get_double (value));
13054       break;
13055
13056     case PROP_ROTATION_ANGLE_Z:
13057       clutter_actor_set_rotation_angle_internal (actor,
13058                                                  CLUTTER_Z_AXIS,
13059                                                  g_value_get_double (value));
13060       break;
13061
13062     default:
13063       g_object_set_property (G_OBJECT (actor), pspec->name, value);
13064       break;
13065     }
13066 }
13067
13068 static void
13069 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13070                                const gchar       *property_name,
13071                                const GValue      *final)
13072 {
13073   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13074   ClutterActorMeta *meta = NULL;
13075   gchar *p_name = NULL;
13076
13077   meta = get_meta_from_animation_property (actor,
13078                                            property_name,
13079                                            &p_name);
13080   if (meta != NULL)
13081     g_object_set_property (G_OBJECT (meta), p_name, final);
13082   else
13083     {
13084       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13085       GParamSpec *pspec;
13086
13087       pspec = g_object_class_find_property (obj_class, property_name);
13088
13089       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13090         {
13091           /* XXX - I'm going to the special hell for this */
13092           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13093         }
13094       else
13095         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13096     }
13097
13098   g_free (p_name);
13099 }
13100
13101 static void
13102 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13103 {
13104   iface->find_property = clutter_actor_find_property;
13105   iface->get_initial_state = clutter_actor_get_initial_state;
13106   iface->set_final_state = clutter_actor_set_final_state;
13107 }
13108
13109 /**
13110  * clutter_actor_transform_stage_point:
13111  * @self: A #ClutterActor
13112  * @x: (in): x screen coordinate of the point to unproject
13113  * @y: (in): y screen coordinate of the point to unproject
13114  * @x_out: (out): return location for the unprojected x coordinance
13115  * @y_out: (out): return location for the unprojected y coordinance
13116  *
13117  * This function translates screen coordinates (@x, @y) to
13118  * coordinates relative to the actor. For example, it can be used to translate
13119  * screen events from global screen coordinates into actor-local coordinates.
13120  *
13121  * The conversion can fail, notably if the transform stack results in the
13122  * actor being projected on the screen as a mere line.
13123  *
13124  * The conversion should not be expected to be pixel-perfect due to the
13125  * nature of the operation. In general the error grows when the skewing
13126  * of the actor rectangle on screen increases.
13127  *
13128  * <note><para>This function can be computationally intensive.</para></note>
13129  *
13130  * <note><para>This function only works when the allocation is up-to-date,
13131  * i.e. inside of paint().</para></note>
13132  *
13133  * Return value: %TRUE if conversion was successful.
13134  *
13135  * Since: 0.6
13136  */
13137 gboolean
13138 clutter_actor_transform_stage_point (ClutterActor *self,
13139                                      gfloat        x,
13140                                      gfloat        y,
13141                                      gfloat       *x_out,
13142                                      gfloat       *y_out)
13143 {
13144   ClutterVertex v[4];
13145   float ST[3][3];
13146   float RQ[3][3];
13147   int du, dv, xi, yi;
13148   float px, py;
13149   float xf, yf, wf, det;
13150   ClutterActorPrivate *priv;
13151
13152   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13153
13154   priv = self->priv;
13155
13156   /* This implementation is based on the quad -> quad projection algorithm
13157    * described by Paul Heckbert in:
13158    *
13159    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13160    *
13161    * and the sample implementation at:
13162    *
13163    *   http://www.cs.cmu.edu/~ph/src/texfund/
13164    *
13165    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13166    * quad to rectangle only, which significantly simplifies things; the
13167    * function calls have been unrolled, and most of the math is done in fixed
13168    * point.
13169    */
13170
13171   clutter_actor_get_abs_allocation_vertices (self, v);
13172
13173   /* Keeping these as ints simplifies the multiplication (no significant
13174    * loss of precision here).
13175    */
13176   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13177   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13178
13179   if (!du || !dv)
13180     return FALSE;
13181
13182 #define UX2FP(x)        (x)
13183 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13184
13185   /* First, find mapping from unit uv square to xy quadrilateral; this
13186    * equivalent to the pmap_square_quad() functions in the sample
13187    * implementation, which we can simplify, since our target is always
13188    * a rectangle.
13189    */
13190   px = v[0].x - v[1].x + v[3].x - v[2].x;
13191   py = v[0].y - v[1].y + v[3].y - v[2].y;
13192
13193   if (!px && !py)
13194     {
13195       /* affine transform */
13196       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13197       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13198       RQ[2][0] = UX2FP (v[0].x);
13199       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13200       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13201       RQ[2][1] = UX2FP (v[0].y);
13202       RQ[0][2] = 0;
13203       RQ[1][2] = 0;
13204       RQ[2][2] = 1.0;
13205     }
13206   else
13207     {
13208       /* projective transform */
13209       double dx1, dx2, dy1, dy2, del;
13210
13211       dx1 = UX2FP (v[1].x - v[3].x);
13212       dx2 = UX2FP (v[2].x - v[3].x);
13213       dy1 = UX2FP (v[1].y - v[3].y);
13214       dy2 = UX2FP (v[2].y - v[3].y);
13215
13216       del = DET2FP (dx1, dx2, dy1, dy2);
13217       if (!del)
13218         return FALSE;
13219
13220       /*
13221        * The division here needs to be done in floating point for
13222        * precisions reasons.
13223        */
13224       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13225       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13226       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13227       RQ[2][2] = 1.0;
13228       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13229       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13230       RQ[2][0] = UX2FP (v[0].x);
13231       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13232       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13233       RQ[2][1] = UX2FP (v[0].y);
13234     }
13235
13236   /*
13237    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13238    * square. Since our rectangle is based at 0,0 we only need to scale.
13239    */
13240   RQ[0][0] /= du;
13241   RQ[1][0] /= dv;
13242   RQ[0][1] /= du;
13243   RQ[1][1] /= dv;
13244   RQ[0][2] /= du;
13245   RQ[1][2] /= dv;
13246
13247   /*
13248    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13249    * inverse of that.
13250    */
13251   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13252   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13253   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13254   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13255   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13256   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13257   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13258   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13259   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13260
13261   /*
13262    * Check the resulting matrix is OK.
13263    */
13264   det = (RQ[0][0] * ST[0][0])
13265       + (RQ[0][1] * ST[0][1])
13266       + (RQ[0][2] * ST[0][2]);
13267   if (!det)
13268     return FALSE;
13269
13270   /*
13271    * Now transform our point with the ST matrix; the notional w
13272    * coordinate is 1, hence the last part is simply added.
13273    */
13274   xi = (int) x;
13275   yi = (int) y;
13276
13277   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13278   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13279   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13280
13281   if (x_out)
13282     *x_out = xf / wf;
13283
13284   if (y_out)
13285     *y_out = yf / wf;
13286
13287 #undef UX2FP
13288 #undef DET2FP
13289
13290   return TRUE;
13291 }
13292
13293 /*
13294  * ClutterGeometry
13295  */
13296
13297 static ClutterGeometry*
13298 clutter_geometry_copy (const ClutterGeometry *geometry)
13299 {
13300   return g_slice_dup (ClutterGeometry, geometry);
13301 }
13302
13303 static void
13304 clutter_geometry_free (ClutterGeometry *geometry)
13305 {
13306   if (G_LIKELY (geometry != NULL))
13307     g_slice_free (ClutterGeometry, geometry);
13308 }
13309
13310 /**
13311  * clutter_geometry_union:
13312  * @geometry_a: a #ClutterGeometry
13313  * @geometry_b: another #ClutterGeometry
13314  * @result: (out): location to store the result
13315  *
13316  * Find the union of two rectangles represented as #ClutterGeometry.
13317  *
13318  * Since: 1.4
13319  */
13320 void
13321 clutter_geometry_union (const ClutterGeometry *geometry_a,
13322                         const ClutterGeometry *geometry_b,
13323                         ClutterGeometry       *result)
13324 {
13325   /* We don't try to handle rectangles that can't be represented
13326    * as a signed integer box */
13327   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13328   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13329   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13330                   geometry_b->x + (gint)geometry_b->width);
13331   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13332                   geometry_b->y + (gint)geometry_b->height);
13333   result->x = x_1;
13334   result->y = y_1;
13335   result->width = x_2 - x_1;
13336   result->height = y_2 - y_1;
13337 }
13338
13339 /**
13340  * clutter_geometry_intersects:
13341  * @geometry0: The first geometry to test
13342  * @geometry1: The second geometry to test
13343  *
13344  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13345  * they do else %FALSE.
13346  *
13347  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13348  * %FALSE.
13349  *
13350  * Since: 1.4
13351  */
13352 gboolean
13353 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13354                              const ClutterGeometry *geometry1)
13355 {
13356   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13357       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13358       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13359       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13360     return FALSE;
13361   else
13362     return TRUE;
13363 }
13364
13365 static gboolean
13366 clutter_geometry_progress (const GValue *a,
13367                            const GValue *b,
13368                            gdouble       progress,
13369                            GValue       *retval)
13370 {
13371   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13372   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13373   ClutterGeometry res = { 0, };
13374   gint a_width = a_geom->width;
13375   gint b_width = b_geom->width;
13376   gint a_height = a_geom->height;
13377   gint b_height = b_geom->height;
13378
13379   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13380   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13381
13382   res.width = a_width + (b_width - a_width) * progress;
13383   res.height = a_height + (b_height - a_height) * progress;
13384
13385   g_value_set_boxed (retval, &res);
13386
13387   return TRUE;
13388 }
13389
13390 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13391                                clutter_geometry_copy,
13392                                clutter_geometry_free,
13393                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13394
13395 /*
13396  * ClutterVertices
13397  */
13398
13399 /**
13400  * clutter_vertex_new:
13401  * @x: X coordinate
13402  * @y: Y coordinate
13403  * @z: Z coordinate
13404  *
13405  * Creates a new #ClutterVertex for the point in 3D space
13406  * identified by the 3 coordinates @x, @y, @z
13407  *
13408  * Return value: the newly allocate #ClutterVertex. Use
13409  *   clutter_vertex_free() to free the resources
13410  *
13411  * Since: 1.0
13412  */
13413 ClutterVertex *
13414 clutter_vertex_new (gfloat x,
13415                     gfloat y,
13416                     gfloat z)
13417 {
13418   ClutterVertex *vertex;
13419
13420   vertex = g_slice_new (ClutterVertex);
13421   clutter_vertex_init (vertex, x, y, z);
13422
13423   return vertex;
13424 }
13425
13426 /**
13427  * clutter_vertex_init:
13428  * @vertex: a #ClutterVertex
13429  * @x: X coordinate
13430  * @y: Y coordinate
13431  * @z: Z coordinate
13432  *
13433  * Initializes @vertex with the given coordinates.
13434  *
13435  * Since: 1.10
13436  */
13437 void
13438 clutter_vertex_init (ClutterVertex *vertex,
13439                      gfloat         x,
13440                      gfloat         y,
13441                      gfloat         z)
13442 {
13443   g_return_if_fail (vertex != NULL);
13444
13445   vertex->x = x;
13446   vertex->y = y;
13447   vertex->z = z;
13448 }
13449
13450 /**
13451  * clutter_vertex_copy:
13452  * @vertex: a #ClutterVertex
13453  *
13454  * Copies @vertex
13455  *
13456  * Return value: a newly allocated copy of #ClutterVertex. Use
13457  *   clutter_vertex_free() to free the allocated resources
13458  *
13459  * Since: 1.0
13460  */
13461 ClutterVertex *
13462 clutter_vertex_copy (const ClutterVertex *vertex)
13463 {
13464   if (G_LIKELY (vertex != NULL))
13465     return g_slice_dup (ClutterVertex, vertex);
13466
13467   return NULL;
13468 }
13469
13470 /**
13471  * clutter_vertex_free:
13472  * @vertex: a #ClutterVertex
13473  *
13474  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13475  *
13476  * Since: 1.0
13477  */
13478 void
13479 clutter_vertex_free (ClutterVertex *vertex)
13480 {
13481   if (G_UNLIKELY (vertex != NULL))
13482     g_slice_free (ClutterVertex, vertex);
13483 }
13484
13485 /**
13486  * clutter_vertex_equal:
13487  * @vertex_a: a #ClutterVertex
13488  * @vertex_b: a #ClutterVertex
13489  *
13490  * Compares @vertex_a and @vertex_b for equality
13491  *
13492  * Return value: %TRUE if the passed #ClutterVertex are equal
13493  *
13494  * Since: 1.0
13495  */
13496 gboolean
13497 clutter_vertex_equal (const ClutterVertex *vertex_a,
13498                       const ClutterVertex *vertex_b)
13499 {
13500   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13501
13502   if (vertex_a == vertex_b)
13503     return TRUE;
13504
13505   return vertex_a->x == vertex_b->x &&
13506          vertex_a->y == vertex_b->y &&
13507          vertex_a->z == vertex_b->z;
13508 }
13509
13510 static gboolean
13511 clutter_vertex_progress (const GValue *a,
13512                          const GValue *b,
13513                          gdouble       progress,
13514                          GValue       *retval)
13515 {
13516   const ClutterVertex *av = g_value_get_boxed (a);
13517   const ClutterVertex *bv = g_value_get_boxed (b);
13518   ClutterVertex res = { 0, };
13519
13520   res.x = av->x + (bv->x - av->x) * progress;
13521   res.y = av->y + (bv->y - av->y) * progress;
13522   res.z = av->z + (bv->z - av->z) * progress;
13523
13524   g_value_set_boxed (retval, &res);
13525
13526   return TRUE;
13527 }
13528
13529 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13530                                clutter_vertex_copy,
13531                                clutter_vertex_free,
13532                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13533
13534 /**
13535  * clutter_actor_is_rotated:
13536  * @self: a #ClutterActor
13537  *
13538  * Checks whether any rotation is applied to the actor.
13539  *
13540  * Return value: %TRUE if the actor is rotated.
13541  *
13542  * Since: 0.6
13543  */
13544 gboolean
13545 clutter_actor_is_rotated (ClutterActor *self)
13546 {
13547   const ClutterTransformInfo *info;
13548
13549   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13550
13551   info = _clutter_actor_get_transform_info_or_defaults (self);
13552
13553   if (info->rx_angle || info->ry_angle || info->rz_angle)
13554     return TRUE;
13555
13556   return FALSE;
13557 }
13558
13559 /**
13560  * clutter_actor_is_scaled:
13561  * @self: a #ClutterActor
13562  *
13563  * Checks whether the actor is scaled in either dimension.
13564  *
13565  * Return value: %TRUE if the actor is scaled.
13566  *
13567  * Since: 0.6
13568  */
13569 gboolean
13570 clutter_actor_is_scaled (ClutterActor *self)
13571 {
13572   const ClutterTransformInfo *info;
13573
13574   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13575
13576   info = _clutter_actor_get_transform_info_or_defaults (self);
13577
13578   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13579     return TRUE;
13580
13581   return FALSE;
13582 }
13583
13584 ClutterActor *
13585 _clutter_actor_get_stage_internal (ClutterActor *actor)
13586 {
13587   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13588     actor = actor->priv->parent;
13589
13590   return actor;
13591 }
13592
13593 /**
13594  * clutter_actor_get_stage:
13595  * @actor: a #ClutterActor
13596  *
13597  * Retrieves the #ClutterStage where @actor is contained.
13598  *
13599  * Return value: (transfer none) (type Clutter.Stage): the stage
13600  *   containing the actor, or %NULL
13601  *
13602  * Since: 0.8
13603  */
13604 ClutterActor *
13605 clutter_actor_get_stage (ClutterActor *actor)
13606 {
13607   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13608
13609   return _clutter_actor_get_stage_internal (actor);
13610 }
13611
13612 /**
13613  * clutter_actor_allocate_available_size:
13614  * @self: a #ClutterActor
13615  * @x: the actor's X coordinate
13616  * @y: the actor's Y coordinate
13617  * @available_width: the maximum available width, or -1 to use the
13618  *   actor's natural width
13619  * @available_height: the maximum available height, or -1 to use the
13620  *   actor's natural height
13621  * @flags: flags controlling the allocation
13622  *
13623  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13624  * preferred size, but limiting it to the maximum available width
13625  * and height provided.
13626  *
13627  * This function will do the right thing when dealing with the
13628  * actor's request mode.
13629  *
13630  * The implementation of this function is equivalent to:
13631  *
13632  * |[
13633  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13634  *     {
13635  *       clutter_actor_get_preferred_width (self, available_height,
13636  *                                          &amp;min_width,
13637  *                                          &amp;natural_width);
13638  *       width = CLAMP (natural_width, min_width, available_width);
13639  *
13640  *       clutter_actor_get_preferred_height (self, width,
13641  *                                           &amp;min_height,
13642  *                                           &amp;natural_height);
13643  *       height = CLAMP (natural_height, min_height, available_height);
13644  *     }
13645  *   else
13646  *     {
13647  *       clutter_actor_get_preferred_height (self, available_width,
13648  *                                           &amp;min_height,
13649  *                                           &amp;natural_height);
13650  *       height = CLAMP (natural_height, min_height, available_height);
13651  *
13652  *       clutter_actor_get_preferred_width (self, height,
13653  *                                          &amp;min_width,
13654  *                                          &amp;natural_width);
13655  *       width = CLAMP (natural_width, min_width, available_width);
13656  *     }
13657  *
13658  *   box.x1 = x; box.y1 = y;
13659  *   box.x2 = box.x1 + available_width;
13660  *   box.y2 = box.y1 + available_height;
13661  *   clutter_actor_allocate (self, &amp;box, flags);
13662  * ]|
13663  *
13664  * This function can be used by fluid layout managers to allocate
13665  * an actor's preferred size without making it bigger than the area
13666  * available for the container.
13667  *
13668  * Since: 1.0
13669  */
13670 void
13671 clutter_actor_allocate_available_size (ClutterActor           *self,
13672                                        gfloat                  x,
13673                                        gfloat                  y,
13674                                        gfloat                  available_width,
13675                                        gfloat                  available_height,
13676                                        ClutterAllocationFlags  flags)
13677 {
13678   ClutterActorPrivate *priv;
13679   gfloat width, height;
13680   gfloat min_width, min_height;
13681   gfloat natural_width, natural_height;
13682   ClutterActorBox box;
13683
13684   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13685
13686   priv = self->priv;
13687
13688   width = height = 0.0;
13689
13690   switch (priv->request_mode)
13691     {
13692     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13693       clutter_actor_get_preferred_width (self, available_height,
13694                                          &min_width,
13695                                          &natural_width);
13696       width  = CLAMP (natural_width, min_width, available_width);
13697
13698       clutter_actor_get_preferred_height (self, width,
13699                                           &min_height,
13700                                           &natural_height);
13701       height = CLAMP (natural_height, min_height, available_height);
13702       break;
13703
13704     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13705       clutter_actor_get_preferred_height (self, available_width,
13706                                           &min_height,
13707                                           &natural_height);
13708       height = CLAMP (natural_height, min_height, available_height);
13709
13710       clutter_actor_get_preferred_width (self, height,
13711                                          &min_width,
13712                                          &natural_width);
13713       width  = CLAMP (natural_width, min_width, available_width);
13714       break;
13715     }
13716
13717
13718   box.x1 = x;
13719   box.y1 = y;
13720   box.x2 = box.x1 + width;
13721   box.y2 = box.y1 + height;
13722   clutter_actor_allocate (self, &box, flags);
13723 }
13724
13725 /**
13726  * clutter_actor_allocate_preferred_size:
13727  * @self: a #ClutterActor
13728  * @flags: flags controlling the allocation
13729  *
13730  * Allocates the natural size of @self.
13731  *
13732  * This function is a utility call for #ClutterActor implementations
13733  * that allocates the actor's preferred natural size. It can be used
13734  * by fixed layout managers (like #ClutterGroup or so called
13735  * 'composite actors') inside the ClutterActor::allocate
13736  * implementation to give each child exactly how much space it
13737  * requires.
13738  *
13739  * This function is not meant to be used by applications. It is also
13740  * not meant to be used outside the implementation of the
13741  * ClutterActor::allocate virtual function.
13742  *
13743  * Since: 0.8
13744  */
13745 void
13746 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13747                                        ClutterAllocationFlags  flags)
13748 {
13749   gfloat actor_x, actor_y;
13750   gfloat natural_width, natural_height;
13751   ClutterActorBox actor_box;
13752
13753   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13754
13755   actor_x = clutter_actor_get_x (self);
13756   actor_y = clutter_actor_get_y (self);
13757
13758   clutter_actor_get_preferred_size (self,
13759                                     NULL, NULL,
13760                                     &natural_width,
13761                                     &natural_height);
13762
13763   actor_box.x1 = actor_x;
13764   actor_box.y1 = actor_y;
13765   actor_box.x2 = actor_box.x1 + natural_width;
13766   actor_box.y2 = actor_box.y1 + natural_height;
13767
13768   clutter_actor_allocate (self, &actor_box, flags);
13769 }
13770
13771 /**
13772  * clutter_actor_allocate_align_fill:
13773  * @self: a #ClutterActor
13774  * @box: a #ClutterActorBox, containing the available width and height
13775  * @x_align: the horizontal alignment, between 0 and 1
13776  * @y_align: the vertical alignment, between 0 and 1
13777  * @x_fill: whether the actor should fill horizontally
13778  * @y_fill: whether the actor should fill vertically
13779  * @flags: allocation flags to be passed to clutter_actor_allocate()
13780  *
13781  * Allocates @self by taking into consideration the available allocation
13782  * area; an alignment factor on either axis; and whether the actor should
13783  * fill the allocation on either axis.
13784  *
13785  * The @box should contain the available allocation width and height;
13786  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13787  * allocation will be offset by their value.
13788  *
13789  * This function takes into consideration the geometry request specified by
13790  * the #ClutterActor:request-mode property, and the text direction.
13791  *
13792  * This function is useful for fluid layout managers, like #ClutterBinLayout
13793  * or #ClutterTableLayout
13794  *
13795  * Since: 1.4
13796  */
13797 void
13798 clutter_actor_allocate_align_fill (ClutterActor           *self,
13799                                    const ClutterActorBox  *box,
13800                                    gdouble                 x_align,
13801                                    gdouble                 y_align,
13802                                    gboolean                x_fill,
13803                                    gboolean                y_fill,
13804                                    ClutterAllocationFlags  flags)
13805 {
13806   ClutterActorPrivate *priv;
13807   ClutterActorBox allocation = { 0, };
13808   gfloat x_offset, y_offset;
13809   gfloat available_width, available_height;
13810   gfloat child_width, child_height;
13811
13812   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13813   g_return_if_fail (box != NULL);
13814   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13815   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13816
13817   priv = self->priv;
13818
13819   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13820   clutter_actor_box_get_size (box, &available_width, &available_height);
13821
13822   if (available_width < 0)
13823     available_width = 0;
13824
13825   if (available_height < 0)
13826     available_height = 0;
13827
13828   if (x_fill)
13829     {
13830       allocation.x1 = x_offset;
13831       allocation.x2 = allocation.x1 + available_width;
13832     }
13833
13834   if (y_fill)
13835     {
13836       allocation.y1 = y_offset;
13837       allocation.y2 = allocation.y1 + available_height;
13838     }
13839
13840   /* if we are filling horizontally and vertically then we're done */
13841   if (x_fill && y_fill)
13842     goto out;
13843
13844   child_width = child_height = 0.0f;
13845
13846   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13847     {
13848       gfloat min_width, natural_width;
13849       gfloat min_height, natural_height;
13850
13851       clutter_actor_get_preferred_width (self, available_height,
13852                                          &min_width,
13853                                          &natural_width);
13854
13855       child_width = CLAMP (natural_width, min_width, available_width);
13856
13857       if (!y_fill)
13858         {
13859           clutter_actor_get_preferred_height (self, child_width,
13860                                               &min_height,
13861                                               &natural_height);
13862
13863           child_height = CLAMP (natural_height, min_height, available_height);
13864         }
13865     }
13866   else
13867     {
13868       gfloat min_width, natural_width;
13869       gfloat min_height, natural_height;
13870
13871       clutter_actor_get_preferred_height (self, available_width,
13872                                           &min_height,
13873                                           &natural_height);
13874
13875       child_height = CLAMP (natural_height, min_height, available_height);
13876
13877       if (!x_fill)
13878         {
13879           clutter_actor_get_preferred_width (self, child_height,
13880                                              &min_width,
13881                                              &natural_width);
13882
13883           child_width = CLAMP (natural_width, min_width, available_width);
13884         }
13885     }
13886
13887   /* invert the horizontal alignment for RTL languages */
13888   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13889     x_align = 1.0 - x_align;
13890
13891   if (!x_fill)
13892     {
13893       allocation.x1 = x_offset
13894                     + ((available_width - child_width) * x_align);
13895       allocation.x2 = allocation.x1 + child_width;
13896     }
13897
13898   if (!y_fill)
13899     {
13900       allocation.y1 = y_offset
13901                     + ((available_height - child_height) * y_align);
13902       allocation.y2 = allocation.y1 + child_height;
13903     }
13904
13905 out:
13906   clutter_actor_box_clamp_to_pixel (&allocation);
13907   clutter_actor_allocate (self, &allocation, flags);
13908 }
13909
13910 /**
13911  * clutter_actor_grab_key_focus:
13912  * @self: a #ClutterActor
13913  *
13914  * Sets the key focus of the #ClutterStage including @self
13915  * to this #ClutterActor.
13916  *
13917  * Since: 1.0
13918  */
13919 void
13920 clutter_actor_grab_key_focus (ClutterActor *self)
13921 {
13922   ClutterActor *stage;
13923
13924   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13925
13926   stage = _clutter_actor_get_stage_internal (self);
13927   if (stage != NULL)
13928     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13929 }
13930
13931 /**
13932  * clutter_actor_get_pango_context:
13933  * @self: a #ClutterActor
13934  *
13935  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13936  * is already configured using the appropriate font map, resolution
13937  * and font options.
13938  *
13939  * Unlike clutter_actor_create_pango_context(), this context is owend
13940  * by the #ClutterActor and it will be updated each time the options
13941  * stored by the #ClutterBackend change.
13942  *
13943  * You can use the returned #PangoContext to create a #PangoLayout
13944  * and render text using cogl_pango_render_layout() to reuse the
13945  * glyphs cache also used by Clutter.
13946  *
13947  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13948  *   The returned #PangoContext is owned by the actor and should not be
13949  *   unreferenced by the application code
13950  *
13951  * Since: 1.0
13952  */
13953 PangoContext *
13954 clutter_actor_get_pango_context (ClutterActor *self)
13955 {
13956   ClutterActorPrivate *priv;
13957
13958   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13959
13960   priv = self->priv;
13961
13962   if (priv->pango_context != NULL)
13963     return priv->pango_context;
13964
13965   priv->pango_context = _clutter_context_get_pango_context ();
13966   g_object_ref (priv->pango_context);
13967
13968   return priv->pango_context;
13969 }
13970
13971 /**
13972  * clutter_actor_create_pango_context:
13973  * @self: a #ClutterActor
13974  *
13975  * Creates a #PangoContext for the given actor. The #PangoContext
13976  * is already configured using the appropriate font map, resolution
13977  * and font options.
13978  *
13979  * See also clutter_actor_get_pango_context().
13980  *
13981  * Return value: (transfer full): the newly created #PangoContext.
13982  *   Use g_object_unref() on the returned value to deallocate its
13983  *   resources
13984  *
13985  * Since: 1.0
13986  */
13987 PangoContext *
13988 clutter_actor_create_pango_context (ClutterActor *self)
13989 {
13990   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13991
13992   return _clutter_context_create_pango_context ();
13993 }
13994
13995 /**
13996  * clutter_actor_create_pango_layout:
13997  * @self: a #ClutterActor
13998  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13999  *
14000  * Creates a new #PangoLayout from the same #PangoContext used
14001  * by the #ClutterActor. The #PangoLayout is already configured
14002  * with the font map, resolution and font options, and the
14003  * given @text.
14004  *
14005  * If you want to keep around a #PangoLayout created by this
14006  * function you will have to connect to the #ClutterBackend::font-changed
14007  * and #ClutterBackend::resolution-changed signals, and call
14008  * pango_layout_context_changed() in response to them.
14009  *
14010  * Return value: (transfer full): the newly created #PangoLayout.
14011  *   Use g_object_unref() when done
14012  *
14013  * Since: 1.0
14014  */
14015 PangoLayout *
14016 clutter_actor_create_pango_layout (ClutterActor *self,
14017                                    const gchar  *text)
14018 {
14019   PangoContext *context;
14020   PangoLayout *layout;
14021
14022   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14023
14024   context = clutter_actor_get_pango_context (self);
14025   layout = pango_layout_new (context);
14026
14027   if (text)
14028     pango_layout_set_text (layout, text, -1);
14029
14030   return layout;
14031 }
14032
14033 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14034  * ClutterOffscreenEffect.
14035  */
14036 void
14037 _clutter_actor_set_opacity_override (ClutterActor *self,
14038                                      gint          opacity)
14039 {
14040   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14041
14042   self->priv->opacity_override = opacity;
14043 }
14044
14045 gint
14046 _clutter_actor_get_opacity_override (ClutterActor *self)
14047 {
14048   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14049
14050   return self->priv->opacity_override;
14051 }
14052
14053 /* Allows you to disable applying the actors model view transform during
14054  * a paint. Used by ClutterClone. */
14055 void
14056 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14057                                                 gboolean      enable)
14058 {
14059   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14060
14061   self->priv->enable_model_view_transform = enable;
14062 }
14063
14064 void
14065 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14066                                           gboolean      enable)
14067 {
14068   ClutterActorPrivate *priv;
14069
14070   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14071
14072   priv = self->priv;
14073
14074   priv->enable_paint_unmapped = enable;
14075
14076   if (priv->enable_paint_unmapped)
14077     {
14078       /* Make sure that the parents of the widget are realized first;
14079        * otherwise checks in clutter_actor_update_map_state() will
14080        * fail.
14081        */
14082       clutter_actor_realize (self);
14083
14084       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14085     }
14086   else
14087     {
14088       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14089     }
14090 }
14091
14092 static void
14093 clutter_anchor_coord_get_units (ClutterActor      *self,
14094                                 const AnchorCoord *coord,
14095                                 gfloat            *x,
14096                                 gfloat            *y,
14097                                 gfloat            *z)
14098 {
14099   if (coord->is_fractional)
14100     {
14101       gfloat actor_width, actor_height;
14102
14103       clutter_actor_get_size (self, &actor_width, &actor_height);
14104
14105       if (x)
14106         *x = actor_width * coord->v.fraction.x;
14107
14108       if (y)
14109         *y = actor_height * coord->v.fraction.y;
14110
14111       if (z)
14112         *z = 0;
14113     }
14114   else
14115     {
14116       if (x)
14117         *x = coord->v.units.x;
14118
14119       if (y)
14120         *y = coord->v.units.y;
14121
14122       if (z)
14123         *z = coord->v.units.z;
14124     }
14125 }
14126
14127 static void
14128 clutter_anchor_coord_set_units (AnchorCoord *coord,
14129                                 gfloat       x,
14130                                 gfloat       y,
14131                                 gfloat       z)
14132 {
14133   coord->is_fractional = FALSE;
14134   coord->v.units.x = x;
14135   coord->v.units.y = y;
14136   coord->v.units.z = z;
14137 }
14138
14139 static ClutterGravity
14140 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14141 {
14142   if (coord->is_fractional)
14143     {
14144       if (coord->v.fraction.x == 0.0)
14145         {
14146           if (coord->v.fraction.y == 0.0)
14147             return CLUTTER_GRAVITY_NORTH_WEST;
14148           else if (coord->v.fraction.y == 0.5)
14149             return CLUTTER_GRAVITY_WEST;
14150           else if (coord->v.fraction.y == 1.0)
14151             return CLUTTER_GRAVITY_SOUTH_WEST;
14152           else
14153             return CLUTTER_GRAVITY_NONE;
14154         }
14155       else if (coord->v.fraction.x == 0.5)
14156         {
14157           if (coord->v.fraction.y == 0.0)
14158             return CLUTTER_GRAVITY_NORTH;
14159           else if (coord->v.fraction.y == 0.5)
14160             return CLUTTER_GRAVITY_CENTER;
14161           else if (coord->v.fraction.y == 1.0)
14162             return CLUTTER_GRAVITY_SOUTH;
14163           else
14164             return CLUTTER_GRAVITY_NONE;
14165         }
14166       else if (coord->v.fraction.x == 1.0)
14167         {
14168           if (coord->v.fraction.y == 0.0)
14169             return CLUTTER_GRAVITY_NORTH_EAST;
14170           else if (coord->v.fraction.y == 0.5)
14171             return CLUTTER_GRAVITY_EAST;
14172           else if (coord->v.fraction.y == 1.0)
14173             return CLUTTER_GRAVITY_SOUTH_EAST;
14174           else
14175             return CLUTTER_GRAVITY_NONE;
14176         }
14177       else
14178         return CLUTTER_GRAVITY_NONE;
14179     }
14180   else
14181     return CLUTTER_GRAVITY_NONE;
14182 }
14183
14184 static void
14185 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14186                                   ClutterGravity  gravity)
14187 {
14188   switch (gravity)
14189     {
14190     case CLUTTER_GRAVITY_NORTH:
14191       coord->v.fraction.x = 0.5;
14192       coord->v.fraction.y = 0.0;
14193       break;
14194
14195     case CLUTTER_GRAVITY_NORTH_EAST:
14196       coord->v.fraction.x = 1.0;
14197       coord->v.fraction.y = 0.0;
14198       break;
14199
14200     case CLUTTER_GRAVITY_EAST:
14201       coord->v.fraction.x = 1.0;
14202       coord->v.fraction.y = 0.5;
14203       break;
14204
14205     case CLUTTER_GRAVITY_SOUTH_EAST:
14206       coord->v.fraction.x = 1.0;
14207       coord->v.fraction.y = 1.0;
14208       break;
14209
14210     case CLUTTER_GRAVITY_SOUTH:
14211       coord->v.fraction.x = 0.5;
14212       coord->v.fraction.y = 1.0;
14213       break;
14214
14215     case CLUTTER_GRAVITY_SOUTH_WEST:
14216       coord->v.fraction.x = 0.0;
14217       coord->v.fraction.y = 1.0;
14218       break;
14219
14220     case CLUTTER_GRAVITY_WEST:
14221       coord->v.fraction.x = 0.0;
14222       coord->v.fraction.y = 0.5;
14223       break;
14224
14225     case CLUTTER_GRAVITY_NORTH_WEST:
14226       coord->v.fraction.x = 0.0;
14227       coord->v.fraction.y = 0.0;
14228       break;
14229
14230     case CLUTTER_GRAVITY_CENTER:
14231       coord->v.fraction.x = 0.5;
14232       coord->v.fraction.y = 0.5;
14233       break;
14234
14235     default:
14236       coord->v.fraction.x = 0.0;
14237       coord->v.fraction.y = 0.0;
14238       break;
14239     }
14240
14241   coord->is_fractional = TRUE;
14242 }
14243
14244 static gboolean
14245 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14246 {
14247   if (coord->is_fractional)
14248     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14249   else
14250     return (coord->v.units.x == 0.0
14251             && coord->v.units.y == 0.0
14252             && coord->v.units.z == 0.0);
14253 }
14254
14255 /**
14256  * clutter_actor_get_flags:
14257  * @self: a #ClutterActor
14258  *
14259  * Retrieves the flags set on @self
14260  *
14261  * Return value: a bitwise or of #ClutterActorFlags or 0
14262  *
14263  * Since: 1.0
14264  */
14265 ClutterActorFlags
14266 clutter_actor_get_flags (ClutterActor *self)
14267 {
14268   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14269
14270   return self->flags;
14271 }
14272
14273 /**
14274  * clutter_actor_set_flags:
14275  * @self: a #ClutterActor
14276  * @flags: the flags to set
14277  *
14278  * Sets @flags on @self
14279  *
14280  * This function will emit notifications for the changed properties
14281  *
14282  * Since: 1.0
14283  */
14284 void
14285 clutter_actor_set_flags (ClutterActor      *self,
14286                          ClutterActorFlags  flags)
14287 {
14288   ClutterActorFlags old_flags;
14289   GObject *obj;
14290   gboolean was_reactive_set, reactive_set;
14291   gboolean was_realized_set, realized_set;
14292   gboolean was_mapped_set, mapped_set;
14293   gboolean was_visible_set, visible_set;
14294
14295   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14296
14297   if (self->flags == flags)
14298     return;
14299
14300   obj = G_OBJECT (self);
14301   g_object_ref (obj);
14302   g_object_freeze_notify (obj);
14303
14304   old_flags = self->flags;
14305
14306   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14307   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14308   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14309   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14310
14311   self->flags |= flags;
14312
14313   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14314   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14315   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14316   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14317
14318   if (reactive_set != was_reactive_set)
14319     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14320
14321   if (realized_set != was_realized_set)
14322     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14323
14324   if (mapped_set != was_mapped_set)
14325     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14326
14327   if (visible_set != was_visible_set)
14328     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14329
14330   g_object_thaw_notify (obj);
14331   g_object_unref (obj);
14332 }
14333
14334 /**
14335  * clutter_actor_unset_flags:
14336  * @self: a #ClutterActor
14337  * @flags: the flags to unset
14338  *
14339  * Unsets @flags on @self
14340  *
14341  * This function will emit notifications for the changed properties
14342  *
14343  * Since: 1.0
14344  */
14345 void
14346 clutter_actor_unset_flags (ClutterActor      *self,
14347                            ClutterActorFlags  flags)
14348 {
14349   ClutterActorFlags old_flags;
14350   GObject *obj;
14351   gboolean was_reactive_set, reactive_set;
14352   gboolean was_realized_set, realized_set;
14353   gboolean was_mapped_set, mapped_set;
14354   gboolean was_visible_set, visible_set;
14355
14356   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14357
14358   obj = G_OBJECT (self);
14359   g_object_freeze_notify (obj);
14360
14361   old_flags = self->flags;
14362
14363   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14364   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14365   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14366   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14367
14368   self->flags &= ~flags;
14369
14370   if (self->flags == old_flags)
14371     return;
14372
14373   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14374   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14375   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14376   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14377
14378   if (reactive_set != was_reactive_set)
14379     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14380
14381   if (realized_set != was_realized_set)
14382     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14383
14384   if (mapped_set != was_mapped_set)
14385     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14386
14387   if (visible_set != was_visible_set)
14388     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14389
14390   g_object_thaw_notify (obj);
14391 }
14392
14393 /**
14394  * clutter_actor_get_transformation_matrix:
14395  * @self: a #ClutterActor
14396  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14397  *
14398  * Retrieves the transformations applied to @self relative to its
14399  * parent.
14400  *
14401  * Since: 1.0
14402  */
14403 void
14404 clutter_actor_get_transformation_matrix (ClutterActor *self,
14405                                          CoglMatrix   *matrix)
14406 {
14407   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14408
14409   cogl_matrix_init_identity (matrix);
14410
14411   _clutter_actor_apply_modelview_transform (self, matrix);
14412 }
14413
14414 void
14415 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14416                                    gboolean      is_in_clone_paint)
14417 {
14418   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14419   self->priv->in_clone_paint = is_in_clone_paint;
14420 }
14421
14422 /**
14423  * clutter_actor_is_in_clone_paint:
14424  * @self: a #ClutterActor
14425  *
14426  * Checks whether @self is being currently painted by a #ClutterClone
14427  *
14428  * This function is useful only inside the ::paint virtual function
14429  * implementations or within handlers for the #ClutterActor::paint
14430  * signal
14431  *
14432  * This function should not be used by applications
14433  *
14434  * Return value: %TRUE if the #ClutterActor is currently being painted
14435  *   by a #ClutterClone, and %FALSE otherwise
14436  *
14437  * Since: 1.0
14438  */
14439 gboolean
14440 clutter_actor_is_in_clone_paint (ClutterActor *self)
14441 {
14442   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14443
14444   return self->priv->in_clone_paint;
14445 }
14446
14447 static gboolean
14448 set_direction_recursive (ClutterActor *actor,
14449                          gpointer      user_data)
14450 {
14451   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14452
14453   clutter_actor_set_text_direction (actor, text_dir);
14454
14455   return TRUE;
14456 }
14457
14458 /**
14459  * clutter_actor_set_text_direction:
14460  * @self: a #ClutterActor
14461  * @text_dir: the text direction for @self
14462  *
14463  * Sets the #ClutterTextDirection for an actor
14464  *
14465  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14466  *
14467  * If @self implements #ClutterContainer then this function will recurse
14468  * inside all the children of @self (including the internal ones).
14469  *
14470  * Composite actors not implementing #ClutterContainer, or actors requiring
14471  * special handling when the text direction changes, should connect to
14472  * the #GObject::notify signal for the #ClutterActor:text-direction property
14473  *
14474  * Since: 1.2
14475  */
14476 void
14477 clutter_actor_set_text_direction (ClutterActor         *self,
14478                                   ClutterTextDirection  text_dir)
14479 {
14480   ClutterActorPrivate *priv;
14481
14482   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14483   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14484
14485   priv = self->priv;
14486
14487   if (priv->text_direction != text_dir)
14488     {
14489       priv->text_direction = text_dir;
14490
14491       /* we need to emit the notify::text-direction first, so that
14492        * the sub-classes can catch that and do specific handling of
14493        * the text direction; see clutter_text_direction_changed_cb()
14494        * inside clutter-text.c
14495        */
14496       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14497
14498       _clutter_actor_foreach_child (self, set_direction_recursive,
14499                                     GINT_TO_POINTER (text_dir));
14500
14501       clutter_actor_queue_relayout (self);
14502     }
14503 }
14504
14505 void
14506 _clutter_actor_set_has_pointer (ClutterActor *self,
14507                                 gboolean      has_pointer)
14508 {
14509   ClutterActorPrivate *priv = self->priv;
14510
14511   if (priv->has_pointer != has_pointer)
14512     {
14513       priv->has_pointer = has_pointer;
14514
14515       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14516     }
14517 }
14518
14519 /**
14520  * clutter_actor_get_text_direction:
14521  * @self: a #ClutterActor
14522  *
14523  * Retrieves the value set using clutter_actor_set_text_direction()
14524  *
14525  * If no text direction has been previously set, the default text
14526  * direction, as returned by clutter_get_default_text_direction(), will
14527  * be returned instead
14528  *
14529  * Return value: the #ClutterTextDirection for the actor
14530  *
14531  * Since: 1.2
14532  */
14533 ClutterTextDirection
14534 clutter_actor_get_text_direction (ClutterActor *self)
14535 {
14536   ClutterActorPrivate *priv;
14537
14538   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14539                         CLUTTER_TEXT_DIRECTION_LTR);
14540
14541   priv = self->priv;
14542
14543   /* if no direction has been set yet use the default */
14544   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14545     priv->text_direction = clutter_get_default_text_direction ();
14546
14547   return priv->text_direction;
14548 }
14549
14550 /**
14551  * clutter_actor_push_internal:
14552  * @self: a #ClutterActor
14553  *
14554  * Should be used by actors implementing the #ClutterContainer and with
14555  * internal children added through clutter_actor_set_parent(), for instance:
14556  *
14557  * |[
14558  *   static void
14559  *   my_actor_init (MyActor *self)
14560  *   {
14561  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14562  *
14563  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14564  *
14565  *     /&ast; calling clutter_actor_set_parent() now will result in
14566  *      &ast; the internal flag being set on a child of MyActor
14567  *      &ast;/
14568  *
14569  *     /&ast; internal child - a background texture &ast;/
14570  *     self->priv->background_tex = clutter_texture_new ();
14571  *     clutter_actor_set_parent (self->priv->background_tex,
14572  *                               CLUTTER_ACTOR (self));
14573  *
14574  *     /&ast; internal child - a label &ast;/
14575  *     self->priv->label = clutter_text_new ();
14576  *     clutter_actor_set_parent (self->priv->label,
14577  *                               CLUTTER_ACTOR (self));
14578  *
14579  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14580  *
14581  *     /&ast; calling clutter_actor_set_parent() now will not result in
14582  *      &ast; the internal flag being set on a child of MyActor
14583  *      &ast;/
14584  *   }
14585  * ]|
14586  *
14587  * This function will be used by Clutter to toggle an "internal child"
14588  * flag whenever clutter_actor_set_parent() is called; internal children
14589  * are handled differently by Clutter, specifically when destroying their
14590  * parent.
14591  *
14592  * Call clutter_actor_pop_internal() when you finished adding internal
14593  * children.
14594  *
14595  * Nested calls to clutter_actor_push_internal() are allowed, but each
14596  * one must by followed by a clutter_actor_pop_internal() call.
14597  *
14598  * Since: 1.2
14599  *
14600  * Deprecated: 1.10: All children of an actor are accessible through
14601  *   the #ClutterActor API, and #ClutterActor implements the
14602  *   #ClutterContainer interface, so this function is only useful
14603  *   for legacy containers overriding the default implementation.
14604  */
14605 void
14606 clutter_actor_push_internal (ClutterActor *self)
14607 {
14608   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14609
14610   self->priv->internal_child += 1;
14611 }
14612
14613 /**
14614  * clutter_actor_pop_internal:
14615  * @self: a #ClutterActor
14616  *
14617  * Disables the effects of clutter_actor_push_internal().
14618  *
14619  * Since: 1.2
14620  *
14621  * Deprecated: 1.10: All children of an actor are accessible through
14622  *   the #ClutterActor API. This function is only useful for legacy
14623  *   containers overriding the default implementation of the
14624  *   #ClutterContainer interface.
14625  */
14626 void
14627 clutter_actor_pop_internal (ClutterActor *self)
14628 {
14629   ClutterActorPrivate *priv;
14630
14631   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14632
14633   priv = self->priv;
14634
14635   if (priv->internal_child == 0)
14636     {
14637       g_warning ("Mismatched %s: you need to call "
14638                  "clutter_actor_push_composite() at least once before "
14639                  "calling this function", G_STRFUNC);
14640       return;
14641     }
14642
14643   priv->internal_child -= 1;
14644 }
14645
14646 /**
14647  * clutter_actor_has_pointer:
14648  * @self: a #ClutterActor
14649  *
14650  * Checks whether an actor contains the pointer of a
14651  * #ClutterInputDevice
14652  *
14653  * Return value: %TRUE if the actor contains the pointer, and
14654  *   %FALSE otherwise
14655  *
14656  * Since: 1.2
14657  */
14658 gboolean
14659 clutter_actor_has_pointer (ClutterActor *self)
14660 {
14661   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14662
14663   return self->priv->has_pointer;
14664 }
14665
14666 /* XXX: This is a workaround for not being able to break the ABI of
14667  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14668  * clutter_actor_queue_clipped_redraw() for details.
14669  */
14670 ClutterPaintVolume *
14671 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14672 {
14673   return g_object_get_data (G_OBJECT (self),
14674                             "-clutter-actor-queue-redraw-clip");
14675 }
14676
14677 void
14678 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14679                                       ClutterPaintVolume *clip)
14680 {
14681   g_object_set_data (G_OBJECT (self),
14682                      "-clutter-actor-queue-redraw-clip",
14683                      clip);
14684 }
14685
14686 /**
14687  * clutter_actor_has_allocation:
14688  * @self: a #ClutterActor
14689  *
14690  * Checks if the actor has an up-to-date allocation assigned to
14691  * it. This means that the actor should have an allocation: it's
14692  * visible and has a parent. It also means that there is no
14693  * outstanding relayout request in progress for the actor or its
14694  * children (There might be other outstanding layout requests in
14695  * progress that will cause the actor to get a new allocation
14696  * when the stage is laid out, however).
14697  *
14698  * If this function returns %FALSE, then the actor will normally
14699  * be allocated before it is next drawn on the screen.
14700  *
14701  * Return value: %TRUE if the actor has an up-to-date allocation
14702  *
14703  * Since: 1.4
14704  */
14705 gboolean
14706 clutter_actor_has_allocation (ClutterActor *self)
14707 {
14708   ClutterActorPrivate *priv;
14709
14710   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14711
14712   priv = self->priv;
14713
14714   return priv->parent != NULL &&
14715          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14716          !priv->needs_allocation;
14717 }
14718
14719 /**
14720  * clutter_actor_add_action:
14721  * @self: a #ClutterActor
14722  * @action: a #ClutterAction
14723  *
14724  * Adds @action to the list of actions applied to @self
14725  *
14726  * A #ClutterAction can only belong to one actor at a time
14727  *
14728  * The #ClutterActor will hold a reference on @action until either
14729  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14730  * is called
14731  *
14732  * Since: 1.4
14733  */
14734 void
14735 clutter_actor_add_action (ClutterActor  *self,
14736                           ClutterAction *action)
14737 {
14738   ClutterActorPrivate *priv;
14739
14740   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14741   g_return_if_fail (CLUTTER_IS_ACTION (action));
14742
14743   priv = self->priv;
14744
14745   if (priv->actions == NULL)
14746     {
14747       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14748       priv->actions->actor = self;
14749     }
14750
14751   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14752
14753   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14754 }
14755
14756 /**
14757  * clutter_actor_add_action_with_name:
14758  * @self: a #ClutterActor
14759  * @name: the name to set on the action
14760  * @action: a #ClutterAction
14761  *
14762  * A convenience function for setting the name of a #ClutterAction
14763  * while adding it to the list of actions applied to @self
14764  *
14765  * This function is the logical equivalent of:
14766  *
14767  * |[
14768  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14769  *   clutter_actor_add_action (self, action);
14770  * ]|
14771  *
14772  * Since: 1.4
14773  */
14774 void
14775 clutter_actor_add_action_with_name (ClutterActor  *self,
14776                                     const gchar   *name,
14777                                     ClutterAction *action)
14778 {
14779   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14780   g_return_if_fail (name != NULL);
14781   g_return_if_fail (CLUTTER_IS_ACTION (action));
14782
14783   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14784   clutter_actor_add_action (self, action);
14785 }
14786
14787 /**
14788  * clutter_actor_remove_action:
14789  * @self: a #ClutterActor
14790  * @action: a #ClutterAction
14791  *
14792  * Removes @action from the list of actions applied to @self
14793  *
14794  * The reference held by @self on the #ClutterAction will be released
14795  *
14796  * Since: 1.4
14797  */
14798 void
14799 clutter_actor_remove_action (ClutterActor  *self,
14800                              ClutterAction *action)
14801 {
14802   ClutterActorPrivate *priv;
14803
14804   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14805   g_return_if_fail (CLUTTER_IS_ACTION (action));
14806
14807   priv = self->priv;
14808
14809   if (priv->actions == NULL)
14810     return;
14811
14812   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14813
14814   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14815 }
14816
14817 /**
14818  * clutter_actor_remove_action_by_name:
14819  * @self: a #ClutterActor
14820  * @name: the name of the action to remove
14821  *
14822  * Removes the #ClutterAction with the given name from the list
14823  * of actions applied to @self
14824  *
14825  * Since: 1.4
14826  */
14827 void
14828 clutter_actor_remove_action_by_name (ClutterActor *self,
14829                                      const gchar  *name)
14830 {
14831   ClutterActorPrivate *priv;
14832   ClutterActorMeta *meta;
14833
14834   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14835   g_return_if_fail (name != NULL);
14836
14837   priv = self->priv;
14838
14839   if (priv->actions == NULL)
14840     return;
14841
14842   meta = _clutter_meta_group_get_meta (priv->actions, name);
14843   if (meta == NULL)
14844     return;
14845
14846   _clutter_meta_group_remove_meta (priv->actions, meta);
14847
14848   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14849 }
14850
14851 /**
14852  * clutter_actor_get_actions:
14853  * @self: a #ClutterActor
14854  *
14855  * Retrieves the list of actions applied to @self
14856  *
14857  * Return value: (transfer container) (element-type Clutter.Action): a copy
14858  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14859  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14860  *   allocated by the returned #GList
14861  *
14862  * Since: 1.4
14863  */
14864 GList *
14865 clutter_actor_get_actions (ClutterActor *self)
14866 {
14867   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14868
14869   if (self->priv->actions == NULL)
14870     return NULL;
14871
14872   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14873 }
14874
14875 /**
14876  * clutter_actor_get_action:
14877  * @self: a #ClutterActor
14878  * @name: the name of the action to retrieve
14879  *
14880  * Retrieves the #ClutterAction with the given name in the list
14881  * of actions applied to @self
14882  *
14883  * Return value: (transfer none): a #ClutterAction for the given
14884  *   name, or %NULL. The returned #ClutterAction is owned by the
14885  *   actor and it should not be unreferenced directly
14886  *
14887  * Since: 1.4
14888  */
14889 ClutterAction *
14890 clutter_actor_get_action (ClutterActor *self,
14891                           const gchar  *name)
14892 {
14893   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14894   g_return_val_if_fail (name != NULL, NULL);
14895
14896   if (self->priv->actions == NULL)
14897     return NULL;
14898
14899   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14900 }
14901
14902 /**
14903  * clutter_actor_clear_actions:
14904  * @self: a #ClutterActor
14905  *
14906  * Clears the list of actions applied to @self
14907  *
14908  * Since: 1.4
14909  */
14910 void
14911 clutter_actor_clear_actions (ClutterActor *self)
14912 {
14913   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14914
14915   if (self->priv->actions == NULL)
14916     return;
14917
14918   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14919 }
14920
14921 /**
14922  * clutter_actor_add_constraint:
14923  * @self: a #ClutterActor
14924  * @constraint: a #ClutterConstraint
14925  *
14926  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14927  * to @self
14928  *
14929  * The #ClutterActor will hold a reference on the @constraint until
14930  * either clutter_actor_remove_constraint() or
14931  * clutter_actor_clear_constraints() is called.
14932  *
14933  * Since: 1.4
14934  */
14935 void
14936 clutter_actor_add_constraint (ClutterActor      *self,
14937                               ClutterConstraint *constraint)
14938 {
14939   ClutterActorPrivate *priv;
14940
14941   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14942   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14943
14944   priv = self->priv;
14945
14946   if (priv->constraints == NULL)
14947     {
14948       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14949       priv->constraints->actor = self;
14950     }
14951
14952   _clutter_meta_group_add_meta (priv->constraints,
14953                                 CLUTTER_ACTOR_META (constraint));
14954   clutter_actor_queue_relayout (self);
14955
14956   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14957 }
14958
14959 /**
14960  * clutter_actor_add_constraint_with_name:
14961  * @self: a #ClutterActor
14962  * @name: the name to set on the constraint
14963  * @constraint: a #ClutterConstraint
14964  *
14965  * A convenience function for setting the name of a #ClutterConstraint
14966  * while adding it to the list of constraints applied to @self
14967  *
14968  * This function is the logical equivalent of:
14969  *
14970  * |[
14971  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14972  *   clutter_actor_add_constraint (self, constraint);
14973  * ]|
14974  *
14975  * Since: 1.4
14976  */
14977 void
14978 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14979                                         const gchar       *name,
14980                                         ClutterConstraint *constraint)
14981 {
14982   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14983   g_return_if_fail (name != NULL);
14984   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14985
14986   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14987   clutter_actor_add_constraint (self, constraint);
14988 }
14989
14990 /**
14991  * clutter_actor_remove_constraint:
14992  * @self: a #ClutterActor
14993  * @constraint: a #ClutterConstraint
14994  *
14995  * Removes @constraint from the list of constraints applied to @self
14996  *
14997  * The reference held by @self on the #ClutterConstraint will be released
14998  *
14999  * Since: 1.4
15000  */
15001 void
15002 clutter_actor_remove_constraint (ClutterActor      *self,
15003                                  ClutterConstraint *constraint)
15004 {
15005   ClutterActorPrivate *priv;
15006
15007   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15008   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15009
15010   priv = self->priv;
15011
15012   if (priv->constraints == NULL)
15013     return;
15014
15015   _clutter_meta_group_remove_meta (priv->constraints,
15016                                    CLUTTER_ACTOR_META (constraint));
15017   clutter_actor_queue_relayout (self);
15018
15019   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15020 }
15021
15022 /**
15023  * clutter_actor_remove_constraint_by_name:
15024  * @self: a #ClutterActor
15025  * @name: the name of the constraint to remove
15026  *
15027  * Removes the #ClutterConstraint with the given name from the list
15028  * of constraints applied to @self
15029  *
15030  * Since: 1.4
15031  */
15032 void
15033 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15034                                          const gchar  *name)
15035 {
15036   ClutterActorPrivate *priv;
15037   ClutterActorMeta *meta;
15038
15039   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15040   g_return_if_fail (name != NULL);
15041
15042   priv = self->priv;
15043
15044   if (priv->constraints == NULL)
15045     return;
15046
15047   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15048   if (meta == NULL)
15049     return;
15050
15051   _clutter_meta_group_remove_meta (priv->constraints, meta);
15052   clutter_actor_queue_relayout (self);
15053 }
15054
15055 /**
15056  * clutter_actor_get_constraints:
15057  * @self: a #ClutterActor
15058  *
15059  * Retrieves the list of constraints applied to @self
15060  *
15061  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15062  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15063  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15064  *   allocated by the returned #GList
15065  *
15066  * Since: 1.4
15067  */
15068 GList *
15069 clutter_actor_get_constraints (ClutterActor *self)
15070 {
15071   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15072
15073   if (self->priv->constraints == NULL)
15074     return NULL;
15075
15076   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15077 }
15078
15079 /**
15080  * clutter_actor_get_constraint:
15081  * @self: a #ClutterActor
15082  * @name: the name of the constraint to retrieve
15083  *
15084  * Retrieves the #ClutterConstraint with the given name in the list
15085  * of constraints applied to @self
15086  *
15087  * Return value: (transfer none): a #ClutterConstraint for the given
15088  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15089  *   actor and it should not be unreferenced directly
15090  *
15091  * Since: 1.4
15092  */
15093 ClutterConstraint *
15094 clutter_actor_get_constraint (ClutterActor *self,
15095                               const gchar  *name)
15096 {
15097   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15098   g_return_val_if_fail (name != NULL, NULL);
15099
15100   if (self->priv->constraints == NULL)
15101     return NULL;
15102
15103   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15104 }
15105
15106 /**
15107  * clutter_actor_clear_constraints:
15108  * @self: a #ClutterActor
15109  *
15110  * Clears the list of constraints applied to @self
15111  *
15112  * Since: 1.4
15113  */
15114 void
15115 clutter_actor_clear_constraints (ClutterActor *self)
15116 {
15117   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15118
15119   if (self->priv->constraints == NULL)
15120     return;
15121
15122   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15123
15124   clutter_actor_queue_relayout (self);
15125 }
15126
15127 /**
15128  * clutter_actor_set_clip_to_allocation:
15129  * @self: a #ClutterActor
15130  * @clip_set: %TRUE to apply a clip tracking the allocation
15131  *
15132  * Sets whether @self should be clipped to the same size as its
15133  * allocation
15134  *
15135  * Since: 1.4
15136  */
15137 void
15138 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15139                                       gboolean      clip_set)
15140 {
15141   ClutterActorPrivate *priv;
15142
15143   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15144
15145   clip_set = !!clip_set;
15146
15147   priv = self->priv;
15148
15149   if (priv->clip_to_allocation != clip_set)
15150     {
15151       priv->clip_to_allocation = clip_set;
15152
15153       clutter_actor_queue_redraw (self);
15154
15155       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15156     }
15157 }
15158
15159 /**
15160  * clutter_actor_get_clip_to_allocation:
15161  * @self: a #ClutterActor
15162  *
15163  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15164  *
15165  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15166  *
15167  * Since: 1.4
15168  */
15169 gboolean
15170 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15171 {
15172   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15173
15174   return self->priv->clip_to_allocation;
15175 }
15176
15177 /**
15178  * clutter_actor_add_effect:
15179  * @self: a #ClutterActor
15180  * @effect: a #ClutterEffect
15181  *
15182  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15183  *
15184  * The #ClutterActor will hold a reference on the @effect until either
15185  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15186  * called.
15187  *
15188  * Since: 1.4
15189  */
15190 void
15191 clutter_actor_add_effect (ClutterActor  *self,
15192                           ClutterEffect *effect)
15193 {
15194   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15195   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15196
15197   _clutter_actor_add_effect_internal (self, effect);
15198
15199   clutter_actor_queue_redraw (self);
15200
15201   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15202 }
15203
15204 /**
15205  * clutter_actor_add_effect_with_name:
15206  * @self: a #ClutterActor
15207  * @name: the name to set on the effect
15208  * @effect: a #ClutterEffect
15209  *
15210  * A convenience function for setting the name of a #ClutterEffect
15211  * while adding it to the list of effectss applied to @self
15212  *
15213  * This function is the logical equivalent of:
15214  *
15215  * |[
15216  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15217  *   clutter_actor_add_effect (self, effect);
15218  * ]|
15219  *
15220  * Since: 1.4
15221  */
15222 void
15223 clutter_actor_add_effect_with_name (ClutterActor  *self,
15224                                     const gchar   *name,
15225                                     ClutterEffect *effect)
15226 {
15227   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15228   g_return_if_fail (name != NULL);
15229   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15230
15231   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15232   clutter_actor_add_effect (self, effect);
15233 }
15234
15235 /**
15236  * clutter_actor_remove_effect:
15237  * @self: a #ClutterActor
15238  * @effect: a #ClutterEffect
15239  *
15240  * Removes @effect from the list of effects applied to @self
15241  *
15242  * The reference held by @self on the #ClutterEffect will be released
15243  *
15244  * Since: 1.4
15245  */
15246 void
15247 clutter_actor_remove_effect (ClutterActor  *self,
15248                              ClutterEffect *effect)
15249 {
15250   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15251   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15252
15253   _clutter_actor_remove_effect_internal (self, effect);
15254
15255   clutter_actor_queue_redraw (self);
15256
15257   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15258 }
15259
15260 /**
15261  * clutter_actor_remove_effect_by_name:
15262  * @self: a #ClutterActor
15263  * @name: the name of the effect to remove
15264  *
15265  * Removes the #ClutterEffect with the given name from the list
15266  * of effects applied to @self
15267  *
15268  * Since: 1.4
15269  */
15270 void
15271 clutter_actor_remove_effect_by_name (ClutterActor *self,
15272                                      const gchar  *name)
15273 {
15274   ClutterActorPrivate *priv;
15275   ClutterActorMeta *meta;
15276
15277   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15278   g_return_if_fail (name != NULL);
15279
15280   priv = self->priv;
15281
15282   if (priv->effects == NULL)
15283     return;
15284
15285   meta = _clutter_meta_group_get_meta (priv->effects, name);
15286   if (meta == NULL)
15287     return;
15288
15289   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15290 }
15291
15292 /**
15293  * clutter_actor_get_effects:
15294  * @self: a #ClutterActor
15295  *
15296  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15297  *
15298  * Return value: (transfer container) (element-type Clutter.Effect): a list
15299  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15300  *   list are owned by Clutter and they should not be freed. You should
15301  *   free the returned list using g_list_free() when done
15302  *
15303  * Since: 1.4
15304  */
15305 GList *
15306 clutter_actor_get_effects (ClutterActor *self)
15307 {
15308   ClutterActorPrivate *priv;
15309
15310   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15311
15312   priv = self->priv;
15313
15314   if (priv->effects == NULL)
15315     return NULL;
15316
15317   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15318 }
15319
15320 /**
15321  * clutter_actor_get_effect:
15322  * @self: a #ClutterActor
15323  * @name: the name of the effect to retrieve
15324  *
15325  * Retrieves the #ClutterEffect with the given name in the list
15326  * of effects applied to @self
15327  *
15328  * Return value: (transfer none): a #ClutterEffect for the given
15329  *   name, or %NULL. The returned #ClutterEffect is owned by the
15330  *   actor and it should not be unreferenced directly
15331  *
15332  * Since: 1.4
15333  */
15334 ClutterEffect *
15335 clutter_actor_get_effect (ClutterActor *self,
15336                           const gchar  *name)
15337 {
15338   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15339   g_return_val_if_fail (name != NULL, NULL);
15340
15341   if (self->priv->effects == NULL)
15342     return NULL;
15343
15344   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15345 }
15346
15347 /**
15348  * clutter_actor_clear_effects:
15349  * @self: a #ClutterActor
15350  *
15351  * Clears the list of effects applied to @self
15352  *
15353  * Since: 1.4
15354  */
15355 void
15356 clutter_actor_clear_effects (ClutterActor *self)
15357 {
15358   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15359
15360   if (self->priv->effects == NULL)
15361     return;
15362
15363   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15364
15365   clutter_actor_queue_redraw (self);
15366 }
15367
15368 /**
15369  * clutter_actor_has_key_focus:
15370  * @self: a #ClutterActor
15371  *
15372  * Checks whether @self is the #ClutterActor that has key focus
15373  *
15374  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15375  *
15376  * Since: 1.4
15377  */
15378 gboolean
15379 clutter_actor_has_key_focus (ClutterActor *self)
15380 {
15381   ClutterActor *stage;
15382
15383   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15384
15385   stage = _clutter_actor_get_stage_internal (self);
15386   if (stage == NULL)
15387     return FALSE;
15388
15389   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15390 }
15391
15392 static gboolean
15393 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15394                                       ClutterPaintVolume *pv)
15395 {
15396   ClutterActorPrivate *priv = self->priv;
15397
15398   /* Actors are only expected to report a valid paint volume
15399    * while they have a valid allocation. */
15400   if (G_UNLIKELY (priv->needs_allocation))
15401     {
15402       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15403                     "Actor needs allocation",
15404                     _clutter_actor_get_debug_name (self));
15405       return FALSE;
15406     }
15407
15408   /* Check if there are any handlers connected to the paint
15409    * signal. If there are then all bets are off for what the paint
15410    * volume for this actor might possibly be!
15411    *
15412    * XXX: It's expected that this is going to end up being quite a
15413    * costly check to have to do here, but we haven't come up with
15414    * another solution that can reliably catch paint signal handlers at
15415    * the right time to either avoid artefacts due to invalid stage
15416    * clipping or due to incorrect culling.
15417    *
15418    * Previously we checked in clutter_actor_paint(), but at that time
15419    * we may already be using a stage clip that could be derived from
15420    * an invalid paint-volume. We used to try and handle that by
15421    * queuing a follow up, unclipped, redraw but still the previous
15422    * checking wasn't enough to catch invalid volumes involved in
15423    * culling (considering that containers may derive their volume from
15424    * children that haven't yet been painted)
15425    *
15426    * Longer term, improved solutions could be:
15427    * - Disallow painting in the paint signal, only allow using it
15428    *   for tracking when paints happen. We can add another API that
15429    *   allows monkey patching the paint of arbitrary actors but in a
15430    *   more controlled way and that also supports modifying the
15431    *   paint-volume.
15432    * - If we could be notified somehow when signal handlers are
15433    *   connected we wouldn't have to poll for handlers like this.
15434    */
15435   if (g_signal_has_handler_pending (self,
15436                                     actor_signals[PAINT],
15437                                     0,
15438                                     TRUE))
15439     {
15440       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15441                     "Actor has \"paint\" signal handlers",
15442                     _clutter_actor_get_debug_name (self));
15443       return FALSE;
15444     }
15445
15446   _clutter_paint_volume_init_static (pv, self);
15447
15448   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15449     {
15450       clutter_paint_volume_free (pv);
15451       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15452                     "Actor failed to report a volume",
15453                     _clutter_actor_get_debug_name (self));
15454       return FALSE;
15455     }
15456
15457   /* since effects can modify the paint volume, we allow them to actually
15458    * do this by making get_paint_volume() "context sensitive"
15459    */
15460   if (priv->effects != NULL)
15461     {
15462       if (priv->current_effect != NULL)
15463         {
15464           const GList *effects, *l;
15465
15466           /* if we are being called from within the paint sequence of
15467            * an actor, get the paint volume up to the current effect
15468            */
15469           effects = _clutter_meta_group_peek_metas (priv->effects);
15470           for (l = effects;
15471                l != NULL || (l != NULL && l->data != priv->current_effect);
15472                l = l->next)
15473             {
15474               if (!_clutter_effect_get_paint_volume (l->data, pv))
15475                 {
15476                   clutter_paint_volume_free (pv);
15477                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15478                                 "Effect (%s) failed to report a volume",
15479                                 _clutter_actor_get_debug_name (self),
15480                                 _clutter_actor_meta_get_debug_name (l->data));
15481                   return FALSE;
15482                 }
15483             }
15484         }
15485       else
15486         {
15487           const GList *effects, *l;
15488
15489           /* otherwise, get the cumulative volume */
15490           effects = _clutter_meta_group_peek_metas (priv->effects);
15491           for (l = effects; l != NULL; l = l->next)
15492             if (!_clutter_effect_get_paint_volume (l->data, pv))
15493               {
15494                 clutter_paint_volume_free (pv);
15495                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15496                               "Effect (%s) failed to report a volume",
15497                               _clutter_actor_get_debug_name (self),
15498                               _clutter_actor_meta_get_debug_name (l->data));
15499                 return FALSE;
15500               }
15501         }
15502     }
15503
15504   return TRUE;
15505 }
15506
15507 /* The public clutter_actor_get_paint_volume API returns a const
15508  * pointer since we return a pointer directly to the cached
15509  * PaintVolume associated with the actor and don't want the user to
15510  * inadvertently modify it, but for internal uses we sometimes need
15511  * access to the same PaintVolume but need to apply some book-keeping
15512  * modifications to it so we don't want a const pointer.
15513  */
15514 static ClutterPaintVolume *
15515 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15516 {
15517   ClutterActorPrivate *priv;
15518
15519   priv = self->priv;
15520
15521   if (priv->paint_volume_valid)
15522     clutter_paint_volume_free (&priv->paint_volume);
15523
15524   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15525     {
15526       priv->paint_volume_valid = TRUE;
15527       return &priv->paint_volume;
15528     }
15529   else
15530     {
15531       priv->paint_volume_valid = FALSE;
15532       return NULL;
15533     }
15534 }
15535
15536 /**
15537  * clutter_actor_get_paint_volume:
15538  * @self: a #ClutterActor
15539  *
15540  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15541  * when a paint volume can't be determined.
15542  *
15543  * The paint volume is defined as the 3D space occupied by an actor
15544  * when being painted.
15545  *
15546  * This function will call the <function>get_paint_volume()</function>
15547  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15548  * should not usually care about overriding the default implementation,
15549  * unless they are, for instance: painting outside their allocation, or
15550  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15551  * 3D depth).
15552  *
15553  * <note>2D actors overriding <function>get_paint_volume()</function>
15554  * ensure their volume has a depth of 0. (This will be true so long as
15555  * you don't call clutter_paint_volume_set_depth().)</note>
15556  *
15557  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15558  *   or %NULL if no volume could be determined. The returned pointer
15559  *   is not guaranteed to be valid across multiple frames; if you want
15560  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15561  *
15562  * Since: 1.6
15563  */
15564 const ClutterPaintVolume *
15565 clutter_actor_get_paint_volume (ClutterActor *self)
15566 {
15567   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15568
15569   return _clutter_actor_get_paint_volume_mutable (self);
15570 }
15571
15572 /**
15573  * clutter_actor_get_transformed_paint_volume:
15574  * @self: a #ClutterActor
15575  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15576  *    (or %NULL for the stage)
15577  *
15578  * Retrieves the 3D paint volume of an actor like
15579  * clutter_actor_get_paint_volume() does (Please refer to the
15580  * documentation of clutter_actor_get_paint_volume() for more
15581  * details.) and it additionally transforms the paint volume into the
15582  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15583  * is passed for @relative_to_ancestor)
15584  *
15585  * This can be used by containers that base their paint volume on
15586  * the volume of their children. Such containers can query the
15587  * transformed paint volume of all of its children and union them
15588  * together using clutter_paint_volume_union().
15589  *
15590  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15591  *   or %NULL if no volume could be determined. The returned pointer is
15592  *   not guaranteed to be valid across multiple frames; if you wish to
15593  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15594  *
15595  * Since: 1.6
15596  */
15597 const ClutterPaintVolume *
15598 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15599                                             ClutterActor *relative_to_ancestor)
15600 {
15601   const ClutterPaintVolume *volume;
15602   ClutterActor *stage;
15603   ClutterPaintVolume *transformed_volume;
15604
15605   stage = _clutter_actor_get_stage_internal (self);
15606   if (G_UNLIKELY (stage == NULL))
15607     return NULL;
15608
15609   if (relative_to_ancestor == NULL)
15610     relative_to_ancestor = stage;
15611
15612   volume = clutter_actor_get_paint_volume (self);
15613   if (volume == NULL)
15614     return NULL;
15615
15616   transformed_volume =
15617     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15618
15619   _clutter_paint_volume_copy_static (volume, transformed_volume);
15620
15621   _clutter_paint_volume_transform_relative (transformed_volume,
15622                                             relative_to_ancestor);
15623
15624   return transformed_volume;
15625 }
15626
15627 /**
15628  * clutter_actor_get_paint_box:
15629  * @self: a #ClutterActor
15630  * @box: (out): return location for a #ClutterActorBox
15631  *
15632  * Retrieves the paint volume of the passed #ClutterActor, and
15633  * transforms it into a 2D bounding box in stage coordinates.
15634  *
15635  * This function is useful to determine the on screen area occupied by
15636  * the actor. The box is only an approximation and may often be
15637  * considerably larger due to the optimizations used to calculate the
15638  * box. The box is never smaller though, so it can reliably be used
15639  * for culling.
15640  *
15641  * There are times when a 2D paint box can't be determined, e.g.
15642  * because the actor isn't yet parented under a stage or because
15643  * the actor is unable to determine a paint volume.
15644  *
15645  * Return value: %TRUE if a 2D paint box could be determined, else
15646  * %FALSE.
15647  *
15648  * Since: 1.6
15649  */
15650 gboolean
15651 clutter_actor_get_paint_box (ClutterActor    *self,
15652                              ClutterActorBox *box)
15653 {
15654   ClutterActor *stage;
15655   ClutterPaintVolume *pv;
15656
15657   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15658   g_return_val_if_fail (box != NULL, FALSE);
15659
15660   stage = _clutter_actor_get_stage_internal (self);
15661   if (G_UNLIKELY (!stage))
15662     return FALSE;
15663
15664   pv = _clutter_actor_get_paint_volume_mutable (self);
15665   if (G_UNLIKELY (!pv))
15666     return FALSE;
15667
15668   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15669
15670   return TRUE;
15671 }
15672
15673 /**
15674  * clutter_actor_has_overlaps:
15675  * @self: A #ClutterActor
15676  *
15677  * Asks the actor's implementation whether it may contain overlapping
15678  * primitives.
15679  *
15680  * For example; Clutter may use this to determine whether the painting
15681  * should be redirected to an offscreen buffer to correctly implement
15682  * the opacity property.
15683  *
15684  * Custom actors can override the default response by implementing the
15685  * #ClutterActor <function>has_overlaps</function> virtual function. See
15686  * clutter_actor_set_offscreen_redirect() for more information.
15687  *
15688  * Return value: %TRUE if the actor may have overlapping primitives, and
15689  *   %FALSE otherwise
15690  *
15691  * Since: 1.8
15692  */
15693 gboolean
15694 clutter_actor_has_overlaps (ClutterActor *self)
15695 {
15696   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15697
15698   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15699 }
15700
15701 /**
15702  * clutter_actor_has_effects:
15703  * @self: A #ClutterActor
15704  *
15705  * Returns whether the actor has any effects applied.
15706  *
15707  * Return value: %TRUE if the actor has any effects,
15708  *   %FALSE otherwise
15709  *
15710  * Since: 1.10
15711  */
15712 gboolean
15713 clutter_actor_has_effects (ClutterActor *self)
15714 {
15715   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15716
15717   if (self->priv->effects == NULL)
15718     return FALSE;
15719
15720   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15721 }
15722
15723 /**
15724  * clutter_actor_has_constraints:
15725  * @self: A #ClutterActor
15726  *
15727  * Returns whether the actor has any constraints applied.
15728  *
15729  * Return value: %TRUE if the actor has any constraints,
15730  *   %FALSE otherwise
15731  *
15732  * Since: 1.10
15733  */
15734 gboolean
15735 clutter_actor_has_constraints (ClutterActor *self)
15736 {
15737   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15738
15739   return self->priv->constraints != NULL;
15740 }
15741
15742 /**
15743  * clutter_actor_has_actions:
15744  * @self: A #ClutterActor
15745  *
15746  * Returns whether the actor has any actions applied.
15747  *
15748  * Return value: %TRUE if the actor has any actions,
15749  *   %FALSE otherwise
15750  *
15751  * Since: 1.10
15752  */
15753 gboolean
15754 clutter_actor_has_actions (ClutterActor *self)
15755 {
15756   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15757
15758   return self->priv->actions != NULL;
15759 }
15760
15761 /**
15762  * clutter_actor_get_n_children:
15763  * @self: a #ClutterActor
15764  *
15765  * Retrieves the number of children of @self.
15766  *
15767  * Return value: the number of children of an actor
15768  *
15769  * Since: 1.10
15770  */
15771 gint
15772 clutter_actor_get_n_children (ClutterActor *self)
15773 {
15774   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15775
15776   return self->priv->n_children;
15777 }
15778
15779 /**
15780  * clutter_actor_get_child_at_index:
15781  * @self: a #ClutterActor
15782  * @index_: the position in the list of children
15783  *
15784  * Retrieves the actor at the given @index_ inside the list of
15785  * children of @self.
15786  *
15787  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15788  *
15789  * Since: 1.10
15790  */
15791 ClutterActor *
15792 clutter_actor_get_child_at_index (ClutterActor *self,
15793                                   gint          index_)
15794 {
15795   ClutterActor *iter;
15796   int i;
15797
15798   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15799   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15800
15801   for (iter = self->priv->first_child, i = 0;
15802        iter != NULL && i < index_;
15803        iter = iter->priv->next_sibling, i += 1)
15804     ;
15805
15806   return iter;
15807 }
15808
15809 /*< private >
15810  * _clutter_actor_foreach_child:
15811  * @actor: The actor whos children you want to iterate
15812  * @callback: The function to call for each child
15813  * @user_data: Private data to pass to @callback
15814  *
15815  * Calls a given @callback once for each child of the specified @actor and
15816  * passing the @user_data pointer each time.
15817  *
15818  * Return value: returns %TRUE if all children were iterated, else
15819  *    %FALSE if a callback broke out of iteration early.
15820  */
15821 gboolean
15822 _clutter_actor_foreach_child (ClutterActor           *self,
15823                               ClutterForeachCallback  callback,
15824                               gpointer                user_data)
15825 {
15826   ClutterActorPrivate *priv = self->priv;
15827   ClutterActor *iter;
15828   gboolean cont;
15829
15830   for (cont = TRUE, iter = priv->first_child;
15831        cont && iter != NULL;
15832        iter = iter->priv->next_sibling)
15833     {
15834       cont = callback (iter, user_data);
15835     }
15836
15837   return cont;
15838 }
15839
15840 #if 0
15841 /* For debugging purposes this gives us a simple way to print out
15842  * the scenegraph e.g in gdb using:
15843  * [|
15844  *   _clutter_actor_traverse (stage,
15845  *                            0,
15846  *                            clutter_debug_print_actor_cb,
15847  *                            NULL,
15848  *                            NULL);
15849  * |]
15850  */
15851 static ClutterActorTraverseVisitFlags
15852 clutter_debug_print_actor_cb (ClutterActor *actor,
15853                               int depth,
15854                               void *user_data)
15855 {
15856   g_print ("%*s%s:%p\n",
15857            depth * 2, "",
15858            _clutter_actor_get_debug_name (actor),
15859            actor);
15860
15861   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15862 }
15863 #endif
15864
15865 static void
15866 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15867                                  ClutterTraverseCallback callback,
15868                                  gpointer                user_data)
15869 {
15870   GQueue *queue = g_queue_new ();
15871   ClutterActor dummy;
15872   int current_depth = 0;
15873
15874   g_queue_push_tail (queue, actor);
15875   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15876
15877   while ((actor = g_queue_pop_head (queue)))
15878     {
15879       ClutterActorTraverseVisitFlags flags;
15880
15881       if (actor == &dummy)
15882         {
15883           current_depth++;
15884           g_queue_push_tail (queue, &dummy);
15885           continue;
15886         }
15887
15888       flags = callback (actor, current_depth, user_data);
15889       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15890         break;
15891       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15892         {
15893           ClutterActor *iter;
15894
15895           for (iter = actor->priv->first_child;
15896                iter != NULL;
15897                iter = iter->priv->next_sibling)
15898             {
15899               g_queue_push_tail (queue, iter);
15900             }
15901         }
15902     }
15903
15904   g_queue_free (queue);
15905 }
15906
15907 static ClutterActorTraverseVisitFlags
15908 _clutter_actor_traverse_depth (ClutterActor           *actor,
15909                                ClutterTraverseCallback before_children_callback,
15910                                ClutterTraverseCallback after_children_callback,
15911                                int                     current_depth,
15912                                gpointer                user_data)
15913 {
15914   ClutterActorTraverseVisitFlags flags;
15915
15916   flags = before_children_callback (actor, current_depth, user_data);
15917   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15918     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15919
15920   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15921     {
15922       ClutterActor *iter;
15923
15924       for (iter = actor->priv->first_child;
15925            iter != NULL;
15926            iter = iter->priv->next_sibling)
15927         {
15928           flags = _clutter_actor_traverse_depth (iter,
15929                                                  before_children_callback,
15930                                                  after_children_callback,
15931                                                  current_depth + 1,
15932                                                  user_data);
15933
15934           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15935             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15936         }
15937     }
15938
15939   if (after_children_callback)
15940     return after_children_callback (actor, current_depth, user_data);
15941   else
15942     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15943 }
15944
15945 /* _clutter_actor_traverse:
15946  * @actor: The actor to start traversing the graph from
15947  * @flags: These flags may affect how the traversal is done
15948  * @before_children_callback: A function to call before visiting the
15949  *   children of the current actor.
15950  * @after_children_callback: A function to call after visiting the
15951  *   children of the current actor. (Ignored if
15952  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15953  * @user_data: The private data to pass to the callbacks
15954  *
15955  * Traverses the scenegraph starting at the specified @actor and
15956  * descending through all its children and its children's children.
15957  * For each actor traversed @before_children_callback and
15958  * @after_children_callback are called with the specified
15959  * @user_data, before and after visiting that actor's children.
15960  *
15961  * The callbacks can return flags that affect the ongoing traversal
15962  * such as by skipping over an actors children or bailing out of
15963  * any further traversing.
15964  */
15965 void
15966 _clutter_actor_traverse (ClutterActor              *actor,
15967                          ClutterActorTraverseFlags  flags,
15968                          ClutterTraverseCallback    before_children_callback,
15969                          ClutterTraverseCallback    after_children_callback,
15970                          gpointer                   user_data)
15971 {
15972   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15973     _clutter_actor_traverse_breadth (actor,
15974                                      before_children_callback,
15975                                      user_data);
15976   else /* DEPTH_FIRST */
15977     _clutter_actor_traverse_depth (actor,
15978                                    before_children_callback,
15979                                    after_children_callback,
15980                                    0, /* start depth */
15981                                    user_data);
15982 }
15983
15984 static void
15985 on_layout_manager_changed (ClutterLayoutManager *manager,
15986                            ClutterActor         *self)
15987 {
15988   clutter_actor_queue_relayout (self);
15989 }
15990
15991 /**
15992  * clutter_actor_set_layout_manager:
15993  * @self: a #ClutterActor
15994  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15995  *
15996  * Sets the #ClutterLayoutManager delegate object that will be used to
15997  * lay out the children of @self.
15998  *
15999  * The #ClutterActor will take a reference on the passed @manager which
16000  * will be released either when the layout manager is removed, or when
16001  * the actor is destroyed.
16002  *
16003  * Since: 1.10
16004  */
16005 void
16006 clutter_actor_set_layout_manager (ClutterActor         *self,
16007                                   ClutterLayoutManager *manager)
16008 {
16009   ClutterActorPrivate *priv;
16010
16011   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16012   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16013
16014   priv = self->priv;
16015
16016   if (priv->layout_manager != NULL)
16017     {
16018       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16019                                             G_CALLBACK (on_layout_manager_changed),
16020                                             self);
16021       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16022       g_clear_object (&priv->layout_manager);
16023     }
16024
16025   priv->layout_manager = manager;
16026
16027   if (priv->layout_manager != NULL)
16028     {
16029       g_object_ref_sink (priv->layout_manager);
16030       clutter_layout_manager_set_container (priv->layout_manager,
16031                                             CLUTTER_CONTAINER (self));
16032       g_signal_connect (priv->layout_manager, "layout-changed",
16033                         G_CALLBACK (on_layout_manager_changed),
16034                         self);
16035     }
16036
16037   clutter_actor_queue_relayout (self);
16038
16039   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16040 }
16041
16042 /**
16043  * clutter_actor_get_layout_manager:
16044  * @self: a #ClutterActor
16045  *
16046  * Retrieves the #ClutterLayoutManager used by @self.
16047  *
16048  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16049  *   or %NULL
16050  *
16051  * Since: 1.10
16052  */
16053 ClutterLayoutManager *
16054 clutter_actor_get_layout_manager (ClutterActor *self)
16055 {
16056   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16057
16058   return self->priv->layout_manager;
16059 }
16060
16061 static const ClutterLayoutInfo default_layout_info = {
16062   0.f,                          /* fixed-x */
16063   0.f,                          /* fixed-y */
16064   { 0, 0, 0, 0 },               /* margin */
16065   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16066   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16067   0.f, 0.f,                     /* min_width, natural_width */
16068   0.f, 0.f,                     /* natual_width, natural_height */
16069 };
16070
16071 static void
16072 layout_info_free (gpointer data)
16073 {
16074   if (G_LIKELY (data != NULL))
16075     g_slice_free (ClutterLayoutInfo, data);
16076 }
16077
16078 /*< private >
16079  * _clutter_actor_get_layout_info:
16080  * @self: a #ClutterActor
16081  *
16082  * Retrieves a pointer to the ClutterLayoutInfo structure.
16083  *
16084  * If the actor does not have a ClutterLayoutInfo associated to it, one
16085  * will be created and initialized to the default values.
16086  *
16087  * This function should be used for setters.
16088  *
16089  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16090  * instead.
16091  *
16092  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16093  */
16094 ClutterLayoutInfo *
16095 _clutter_actor_get_layout_info (ClutterActor *self)
16096 {
16097   ClutterLayoutInfo *retval;
16098
16099   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16100   if (retval == NULL)
16101     {
16102       retval = g_slice_new (ClutterLayoutInfo);
16103
16104       *retval = default_layout_info;
16105
16106       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16107                                retval,
16108                                layout_info_free);
16109     }
16110
16111   return retval;
16112 }
16113
16114 /*< private >
16115  * _clutter_actor_get_layout_info_or_defaults:
16116  * @self: a #ClutterActor
16117  *
16118  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16119  *
16120  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16121  * then the default structure will be returned.
16122  *
16123  * This function should only be used for getters.
16124  *
16125  * Return value: a const pointer to the ClutterLayoutInfo structure
16126  */
16127 const ClutterLayoutInfo *
16128 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16129 {
16130   const ClutterLayoutInfo *info;
16131
16132   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16133   if (info == NULL)
16134     return &default_layout_info;
16135
16136   return info;
16137 }
16138
16139 /**
16140  * clutter_actor_set_x_align:
16141  * @self: a #ClutterActor
16142  * @x_align: the horizontal alignment policy
16143  *
16144  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16145  * actor received extra horizontal space.
16146  *
16147  * See also the #ClutterActor:x-align property.
16148  *
16149  * Since: 1.10
16150  */
16151 void
16152 clutter_actor_set_x_align (ClutterActor      *self,
16153                            ClutterActorAlign  x_align)
16154 {
16155   ClutterLayoutInfo *info;
16156
16157   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16158
16159   info = _clutter_actor_get_layout_info (self);
16160
16161   if (info->x_align != x_align)
16162     {
16163       info->x_align = x_align;
16164
16165       clutter_actor_queue_relayout (self);
16166
16167       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16168     }
16169 }
16170
16171 /**
16172  * clutter_actor_get_x_align:
16173  * @self: a #ClutterActor
16174  *
16175  * Retrieves the horizontal alignment policy set using
16176  * clutter_actor_set_x_align().
16177  *
16178  * Return value: the horizontal alignment policy.
16179  *
16180  * Since: 1.10
16181  */
16182 ClutterActorAlign
16183 clutter_actor_get_x_align (ClutterActor *self)
16184 {
16185   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16186
16187   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16188 }
16189
16190 /**
16191  * clutter_actor_set_y_align:
16192  * @self: a #ClutterActor
16193  * @y_align: the vertical alignment policy
16194  *
16195  * Sets the vertical alignment policy of a #ClutterActor, in case the
16196  * actor received extra vertical space.
16197  *
16198  * See also the #ClutterActor:y-align property.
16199  *
16200  * Since: 1.10
16201  */
16202 void
16203 clutter_actor_set_y_align (ClutterActor      *self,
16204                            ClutterActorAlign  y_align)
16205 {
16206   ClutterLayoutInfo *info;
16207
16208   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16209
16210   info = _clutter_actor_get_layout_info (self);
16211
16212   if (info->y_align != y_align)
16213     {
16214       info->y_align = y_align;
16215
16216       clutter_actor_queue_relayout (self);
16217
16218       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16219     }
16220 }
16221
16222 /**
16223  * clutter_actor_get_y_align:
16224  * @self: a #ClutterActor
16225  *
16226  * Retrieves the vertical alignment policy set using
16227  * clutter_actor_set_y_align().
16228  *
16229  * Return value: the vertical alignment policy.
16230  *
16231  * Since: 1.10
16232  */
16233 ClutterActorAlign
16234 clutter_actor_get_y_align (ClutterActor *self)
16235 {
16236   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16237
16238   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16239 }
16240
16241
16242 /**
16243  * clutter_margin_new:
16244  *
16245  * Creates a new #ClutterMargin.
16246  *
16247  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16248  *   clutter_margin_free() to free the resources associated with it when
16249  *   done.
16250  *
16251  * Since: 1.10
16252  */
16253 ClutterMargin *
16254 clutter_margin_new (void)
16255 {
16256   return g_slice_new0 (ClutterMargin);
16257 }
16258
16259 /**
16260  * clutter_margin_copy:
16261  * @margin_: a #ClutterMargin
16262  *
16263  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16264  * the newly created structure.
16265  *
16266  * Return value: (transfer full): a copy of the #ClutterMargin.
16267  *
16268  * Since: 1.10
16269  */
16270 ClutterMargin *
16271 clutter_margin_copy (const ClutterMargin *margin_)
16272 {
16273   if (G_LIKELY (margin_ != NULL))
16274     return g_slice_dup (ClutterMargin, margin_);
16275
16276   return NULL;
16277 }
16278
16279 /**
16280  * clutter_margin_free:
16281  * @margin_: a #ClutterMargin
16282  *
16283  * Frees the resources allocated by clutter_margin_new() and
16284  * clutter_margin_copy().
16285  *
16286  * Since: 1.10
16287  */
16288 void
16289 clutter_margin_free (ClutterMargin *margin_)
16290 {
16291   if (G_LIKELY (margin_ != NULL))
16292     g_slice_free (ClutterMargin, margin_);
16293 }
16294
16295 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16296                      clutter_margin_copy,
16297                      clutter_margin_free)
16298
16299 /**
16300  * clutter_actor_set_margin:
16301  * @self: a #ClutterActor
16302  * @margin: a #ClutterMargin
16303  *
16304  * Sets all the components of the margin of a #ClutterActor.
16305  *
16306  * Since: 1.10
16307  */
16308 void
16309 clutter_actor_set_margin (ClutterActor        *self,
16310                           const ClutterMargin *margin)
16311 {
16312   ClutterLayoutInfo *info;
16313   gboolean changed;
16314   GObject *obj;
16315
16316   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16317   g_return_if_fail (margin != NULL);
16318
16319   obj = G_OBJECT (self);
16320   changed = FALSE;
16321
16322   g_object_freeze_notify (obj);
16323
16324   info = _clutter_actor_get_layout_info (self);
16325
16326   if (info->margin.top != margin->top)
16327     {
16328       info->margin.top = margin->top;
16329       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16330       changed = TRUE;
16331     }
16332
16333   if (info->margin.right != margin->right)
16334     {
16335       info->margin.right = margin->right;
16336       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16337       changed = TRUE;
16338     }
16339
16340   if (info->margin.bottom != margin->bottom)
16341     {
16342       info->margin.bottom = margin->bottom;
16343       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16344       changed = TRUE;
16345     }
16346
16347   if (info->margin.left != margin->left)
16348     {
16349       info->margin.left = margin->left;
16350       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16351       changed = TRUE;
16352     }
16353
16354   if (changed)
16355     clutter_actor_queue_relayout (self);
16356
16357   g_object_thaw_notify (obj);
16358 }
16359
16360 /**
16361  * clutter_actor_get_margin:
16362  * @self: a #ClutterActor
16363  * @margin: (out caller-allocates): return location for a #ClutterMargin
16364  *
16365  * Retrieves all the components of the margin of a #ClutterActor.
16366  *
16367  * Since: 1.10
16368  */
16369 void
16370 clutter_actor_get_margin (ClutterActor  *self,
16371                           ClutterMargin *margin)
16372 {
16373   const ClutterLayoutInfo *info;
16374
16375   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16376   g_return_if_fail (margin != NULL);
16377
16378   info = _clutter_actor_get_layout_info_or_defaults (self);
16379
16380   *margin = info->margin;
16381 }
16382
16383 /**
16384  * clutter_actor_set_margin_top:
16385  * @self: a #ClutterActor
16386  * @margin: the top margin
16387  *
16388  * Sets the margin from the top of a #ClutterActor.
16389  *
16390  * Since: 1.10
16391  */
16392 void
16393 clutter_actor_set_margin_top (ClutterActor *self,
16394                               gfloat        margin)
16395 {
16396   ClutterLayoutInfo *info;
16397
16398   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16399   g_return_if_fail (margin >= 0.f);
16400
16401   info = _clutter_actor_get_layout_info (self);
16402
16403   if (info->margin.top == margin)
16404     return;
16405
16406   info->margin.top = margin;
16407
16408   clutter_actor_queue_relayout (self);
16409
16410   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16411 }
16412
16413 /**
16414  * clutter_actor_get_margin_top:
16415  * @self: a #ClutterActor
16416  *
16417  * Retrieves the top margin of a #ClutterActor.
16418  *
16419  * Return value: the top margin
16420  *
16421  * Since: 1.10
16422  */
16423 gfloat
16424 clutter_actor_get_margin_top (ClutterActor *self)
16425 {
16426   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16427
16428   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16429 }
16430
16431 /**
16432  * clutter_actor_set_margin_bottom:
16433  * @self: a #ClutterActor
16434  * @margin: the bottom margin
16435  *
16436  * Sets the margin from the bottom of a #ClutterActor.
16437  *
16438  * Since: 1.10
16439  */
16440 void
16441 clutter_actor_set_margin_bottom (ClutterActor *self,
16442                                  gfloat        margin)
16443 {
16444   ClutterLayoutInfo *info;
16445
16446   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16447   g_return_if_fail (margin >= 0.f);
16448
16449   info = _clutter_actor_get_layout_info (self);
16450
16451   if (info->margin.bottom == margin)
16452     return;
16453
16454   info->margin.bottom = margin;
16455
16456   clutter_actor_queue_relayout (self);
16457
16458   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16459 }
16460
16461 /**
16462  * clutter_actor_get_margin_bottom:
16463  * @self: a #ClutterActor
16464  *
16465  * Retrieves the bottom margin of a #ClutterActor.
16466  *
16467  * Return value: the bottom margin
16468  *
16469  * Since: 1.10
16470  */
16471 gfloat
16472 clutter_actor_get_margin_bottom (ClutterActor *self)
16473 {
16474   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16475
16476   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16477 }
16478
16479 /**
16480  * clutter_actor_set_margin_left:
16481  * @self: a #ClutterActor
16482  * @margin: the left margin
16483  *
16484  * Sets the margin from the left of a #ClutterActor.
16485  *
16486  * Since: 1.10
16487  */
16488 void
16489 clutter_actor_set_margin_left (ClutterActor *self,
16490                                gfloat        margin)
16491 {
16492   ClutterLayoutInfo *info;
16493
16494   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16495   g_return_if_fail (margin >= 0.f);
16496
16497   info = _clutter_actor_get_layout_info (self);
16498
16499   if (info->margin.left == margin)
16500     return;
16501
16502   info->margin.left = margin;
16503
16504   clutter_actor_queue_relayout (self);
16505
16506   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16507 }
16508
16509 /**
16510  * clutter_actor_get_margin_left:
16511  * @self: a #ClutterActor
16512  *
16513  * Retrieves the left margin of a #ClutterActor.
16514  *
16515  * Return value: the left margin
16516  *
16517  * Since: 1.10
16518  */
16519 gfloat
16520 clutter_actor_get_margin_left (ClutterActor *self)
16521 {
16522   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16523
16524   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16525 }
16526
16527 /**
16528  * clutter_actor_set_margin_right:
16529  * @self: a #ClutterActor
16530  * @margin: the right margin
16531  *
16532  * Sets the margin from the right of a #ClutterActor.
16533  *
16534  * Since: 1.10
16535  */
16536 void
16537 clutter_actor_set_margin_right (ClutterActor *self,
16538                                 gfloat        margin)
16539 {
16540   ClutterLayoutInfo *info;
16541
16542   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16543   g_return_if_fail (margin >= 0.f);
16544
16545   info = _clutter_actor_get_layout_info (self);
16546
16547   if (info->margin.right == margin)
16548     return;
16549
16550   info->margin.right = margin;
16551
16552   clutter_actor_queue_relayout (self);
16553
16554   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16555 }
16556
16557 /**
16558  * clutter_actor_get_margin_right:
16559  * @self: a #ClutterActor
16560  *
16561  * Retrieves the right margin of a #ClutterActor.
16562  *
16563  * Return value: the right margin
16564  *
16565  * Since: 1.10
16566  */
16567 gfloat
16568 clutter_actor_get_margin_right (ClutterActor *self)
16569 {
16570   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16571
16572   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16573 }
16574
16575 static inline void
16576 clutter_actor_set_background_color_internal (ClutterActor *self,
16577                                              const ClutterColor *color)
16578 {
16579   ClutterActorPrivate *priv = self->priv;
16580   GObject *obj;
16581
16582   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16583     return;
16584
16585   obj = G_OBJECT (self);
16586
16587   priv->bg_color = *color;
16588   priv->bg_color_set = TRUE;
16589
16590   clutter_actor_queue_redraw (self);
16591
16592   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16593   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16594 }
16595
16596 /**
16597  * clutter_actor_set_background_color:
16598  * @self: a #ClutterActor
16599  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16600  *  set color
16601  *
16602  * Sets the background color of a #ClutterActor.
16603  *
16604  * The background color will be used to cover the whole allocation of the
16605  * actor. The default background color of an actor is transparent.
16606  *
16607  * To check whether an actor has a background color, you can use the
16608  * #ClutterActor:background-color-set actor property.
16609  *
16610  * The #ClutterActor:background-color property is animatable.
16611  *
16612  * Since: 1.10
16613  */
16614 void
16615 clutter_actor_set_background_color (ClutterActor       *self,
16616                                     const ClutterColor *color)
16617 {
16618   ClutterActorPrivate *priv;
16619   GObject *obj;
16620   GParamSpec *bg_color_pspec;
16621
16622   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16623
16624   obj = G_OBJECT (self);
16625
16626   priv = self->priv;
16627
16628   if (color == NULL)
16629     {
16630       priv->bg_color_set = FALSE;
16631       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16632       clutter_actor_queue_redraw (self);
16633       return;
16634     }
16635
16636   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16637   if (clutter_actor_get_easing_duration (self) != 0)
16638     {
16639       ClutterTransition *transition;
16640
16641       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16642       if (transition == NULL)
16643         {
16644           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16645                                                          &priv->bg_color,
16646                                                          color);
16647         }
16648       else
16649         _clutter_actor_update_transition (self, bg_color_pspec, color);
16650
16651       clutter_actor_queue_redraw (self);
16652     }
16653   else
16654     clutter_actor_set_background_color_internal (self, color);
16655 }
16656
16657 /**
16658  * clutter_actor_get_background_color:
16659  * @self: a #ClutterActor
16660  * @color: (out caller-allocates): return location for a #ClutterColor
16661  *
16662  * Retrieves the color set using clutter_actor_set_background_color().
16663  *
16664  * Since: 1.10
16665  */
16666 void
16667 clutter_actor_get_background_color (ClutterActor *self,
16668                                     ClutterColor *color)
16669 {
16670   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16671   g_return_if_fail (color != NULL);
16672
16673   *color = self->priv->bg_color;
16674 }
16675
16676 /**
16677  * clutter_actor_get_previous_sibling:
16678  * @self: a #ClutterActor
16679  *
16680  * Retrieves the sibling of @self that comes before it in the list
16681  * of children of @self's parent.
16682  *
16683  * The returned pointer is only valid until the scene graph changes; it
16684  * is not safe to modify the list of children of @self while iterating
16685  * it.
16686  *
16687  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16688  *
16689  * Since: 1.10
16690  */
16691 ClutterActor *
16692 clutter_actor_get_previous_sibling (ClutterActor *self)
16693 {
16694   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16695
16696   return self->priv->prev_sibling;
16697 }
16698
16699 /**
16700  * clutter_actor_get_next_sibling:
16701  * @self: a #ClutterActor
16702  *
16703  * Retrieves the sibling of @self that comes after it in the list
16704  * of children of @self's parent.
16705  *
16706  * The returned pointer is only valid until the scene graph changes; it
16707  * is not safe to modify the list of children of @self while iterating
16708  * it.
16709  *
16710  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16711  *
16712  * Since: 1.10
16713  */
16714 ClutterActor *
16715 clutter_actor_get_next_sibling (ClutterActor *self)
16716 {
16717   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16718
16719   return self->priv->next_sibling;
16720 }
16721
16722 /**
16723  * clutter_actor_get_first_child:
16724  * @self: a #ClutterActor
16725  *
16726  * Retrieves the first child of @self.
16727  *
16728  * The returned pointer is only valid until the scene graph changes; it
16729  * is not safe to modify the list of children of @self while iterating
16730  * it.
16731  *
16732  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16733  *
16734  * Since: 1.10
16735  */
16736 ClutterActor *
16737 clutter_actor_get_first_child (ClutterActor *self)
16738 {
16739   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16740
16741   return self->priv->first_child;
16742 }
16743
16744 /**
16745  * clutter_actor_get_last_child:
16746  * @self: a #ClutterActor
16747  *
16748  * Retrieves the last child of @self.
16749  *
16750  * The returned pointer is only valid until the scene graph changes; it
16751  * is not safe to modify the list of children of @self while iterating
16752  * it.
16753  *
16754  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16755  *
16756  * Since: 1.10
16757  */
16758 ClutterActor *
16759 clutter_actor_get_last_child (ClutterActor *self)
16760 {
16761   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16762
16763   return self->priv->last_child;
16764 }
16765
16766 /* easy way to have properly named fields instead of the dummy ones
16767  * we use in the public structure
16768  */
16769 typedef struct _RealActorIter
16770 {
16771   ClutterActor *root;           /* dummy1 */
16772   ClutterActor *current;        /* dummy2 */
16773   gpointer padding_1;           /* dummy3 */
16774   gint age;                     /* dummy4 */
16775   gpointer padding_2;           /* dummy5 */
16776 } RealActorIter;
16777
16778 /**
16779  * clutter_actor_iter_init:
16780  * @iter: a #ClutterActorIter
16781  * @root: a #ClutterActor
16782  *
16783  * Initializes a #ClutterActorIter, which can then be used to iterate
16784  * efficiently over a section of the scene graph, and associates it
16785  * with @root.
16786  *
16787  * Modifying the scene graph section that contains @root will invalidate
16788  * the iterator.
16789  *
16790  * |[
16791  *   ClutterActorIter iter;
16792  *   ClutterActor *child;
16793  *
16794  *   clutter_actor_iter_init (&iter, container);
16795  *   while (clutter_actor_iter_next (&iter, &child))
16796  *     {
16797  *       /&ast; do something with child &ast;/
16798  *     }
16799  * ]|
16800  *
16801  * Since: 1.10
16802  */
16803 void
16804 clutter_actor_iter_init (ClutterActorIter *iter,
16805                          ClutterActor     *root)
16806 {
16807   RealActorIter *ri = (RealActorIter *) iter;
16808
16809   g_return_if_fail (iter != NULL);
16810   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16811
16812   ri->root = root;
16813   ri->current = NULL;
16814   ri->age = root->priv->age;
16815 }
16816
16817 /**
16818  * clutter_actor_iter_next:
16819  * @iter: a #ClutterActorIter
16820  * @child: (out): return location for a #ClutterActor
16821  *
16822  * Advances the @iter and retrieves the next child of the root #ClutterActor
16823  * that was used to initialize the #ClutterActorIterator.
16824  *
16825  * If the iterator can advance, this function returns %TRUE and sets the
16826  * @child argument.
16827  *
16828  * If the iterator cannot advance, this function returns %FALSE, and
16829  * the contents of @child are undefined.
16830  *
16831  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16832  *
16833  * Since: 1.10
16834  */
16835 gboolean
16836 clutter_actor_iter_next (ClutterActorIter  *iter,
16837                          ClutterActor     **child)
16838 {
16839   RealActorIter *ri = (RealActorIter *) iter;
16840
16841   g_return_val_if_fail (iter != NULL, FALSE);
16842   g_return_val_if_fail (ri->root != NULL, FALSE);
16843 #ifndef G_DISABLE_ASSERT
16844   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16845 #endif
16846
16847   if (ri->current == NULL)
16848     ri->current = ri->root->priv->first_child;
16849   else
16850     ri->current = ri->current->priv->next_sibling;
16851
16852   if (child != NULL)
16853     *child = ri->current;
16854
16855   return ri->current != NULL;
16856 }
16857
16858 /**
16859  * clutter_actor_iter_prev:
16860  * @iter: a #ClutterActorIter
16861  * @child: (out): return location for a #ClutterActor
16862  *
16863  * Advances the @iter and retrieves the previous child of the root
16864  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16865  *
16866  * If the iterator can advance, this function returns %TRUE and sets the
16867  * @child argument.
16868  *
16869  * If the iterator cannot advance, this function returns %FALSE, and
16870  * the contents of @child are undefined.
16871  *
16872  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16873  *
16874  * Since: 1.10
16875  */
16876 gboolean
16877 clutter_actor_iter_prev (ClutterActorIter  *iter,
16878                          ClutterActor     **child)
16879 {
16880   RealActorIter *ri = (RealActorIter *) iter;
16881
16882   g_return_val_if_fail (iter != NULL, FALSE);
16883   g_return_val_if_fail (ri->root != NULL, FALSE);
16884 #ifndef G_DISABLE_ASSERT
16885   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16886 #endif
16887
16888   if (ri->current == NULL)
16889     ri->current = ri->root->priv->last_child;
16890   else
16891     ri->current = ri->current->priv->prev_sibling;
16892
16893   if (child != NULL)
16894     *child = ri->current;
16895
16896   return ri->current != NULL;
16897 }
16898
16899 /**
16900  * clutter_actor_iter_remove:
16901  * @iter: a #ClutterActorIter
16902  *
16903  * Safely removes the #ClutterActor currently pointer to by the iterator
16904  * from its parent.
16905  *
16906  * This function can only be called after clutter_actor_iter_next() or
16907  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16908  * than once for the same actor.
16909  *
16910  * This function will call clutter_actor_remove_child() internally.
16911  *
16912  * Since: 1.10
16913  */
16914 void
16915 clutter_actor_iter_remove (ClutterActorIter *iter)
16916 {
16917   RealActorIter *ri = (RealActorIter *) iter;
16918   ClutterActor *cur;
16919
16920   g_return_if_fail (iter != NULL);
16921   g_return_if_fail (ri->root != NULL);
16922 #ifndef G_DISABLE_ASSERT
16923   g_return_if_fail (ri->age == ri->root->priv->age);
16924 #endif
16925   g_return_if_fail (ri->current != NULL);
16926
16927   cur = ri->current;
16928
16929   if (cur != NULL)
16930     {
16931       ri->current = cur->priv->prev_sibling;
16932
16933       clutter_actor_remove_child_internal (ri->root, cur,
16934                                            REMOVE_CHILD_DEFAULT_FLAGS);
16935
16936       ri->age += 1;
16937     }
16938 }
16939
16940 /**
16941  * clutter_actor_iter_destroy:
16942  * @iter: a #ClutterActorIter
16943  *
16944  * Safely destroys the #ClutterActor currently pointer to by the iterator
16945  * from its parent.
16946  *
16947  * This function can only be called after clutter_actor_iter_next() or
16948  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16949  * than once for the same actor.
16950  *
16951  * This function will call clutter_actor_destroy() internally.
16952  *
16953  * Since: 1.10
16954  */
16955 void
16956 clutter_actor_iter_destroy (ClutterActorIter *iter)
16957 {
16958   RealActorIter *ri = (RealActorIter *) iter;
16959   ClutterActor *cur;
16960
16961   g_return_if_fail (iter != NULL);
16962   g_return_if_fail (ri->root != NULL);
16963 #ifndef G_DISABLE_ASSERT
16964   g_return_if_fail (ri->age == ri->root->priv->age);
16965 #endif
16966   g_return_if_fail (ri->current != NULL);
16967
16968   cur = ri->current;
16969
16970   if (cur != NULL)
16971     {
16972       ri->current = cur->priv->prev_sibling;
16973
16974       clutter_actor_destroy (cur);
16975
16976       ri->age += 1;
16977     }
16978 }
16979
16980 static const ClutterAnimationInfo default_animation_info = {
16981   NULL,         /* transitions */
16982   NULL,         /* states */
16983   NULL,         /* cur_state */
16984 };
16985
16986 static void
16987 clutter_animation_info_free (gpointer data)
16988 {
16989   if (data != NULL)
16990     {
16991       ClutterAnimationInfo *info = data;
16992
16993       if (info->transitions != NULL)
16994         g_hash_table_unref (info->transitions);
16995
16996       if (info->states != NULL)
16997         g_array_unref (info->states);
16998
16999       g_slice_free (ClutterAnimationInfo, info);
17000     }
17001 }
17002
17003 const ClutterAnimationInfo *
17004 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17005 {
17006   const ClutterAnimationInfo *res;
17007   GObject *obj = G_OBJECT (self);
17008
17009   res = g_object_get_qdata (obj, quark_actor_animation_info);
17010   if (res != NULL)
17011     return res;
17012
17013   return &default_animation_info;
17014 }
17015
17016 ClutterAnimationInfo *
17017 _clutter_actor_get_animation_info (ClutterActor *self)
17018 {
17019   GObject *obj = G_OBJECT (self);
17020   ClutterAnimationInfo *res;
17021
17022   res = g_object_get_qdata (obj, quark_actor_animation_info);
17023   if (res == NULL)
17024     {
17025       res = g_slice_new (ClutterAnimationInfo);
17026
17027       *res = default_animation_info;
17028
17029       g_object_set_qdata_full (obj, quark_actor_animation_info,
17030                                res,
17031                                clutter_animation_info_free);
17032     }
17033
17034   return res;
17035 }
17036
17037 ClutterTransition *
17038 _clutter_actor_get_transition (ClutterActor *actor,
17039                                GParamSpec   *pspec)
17040 {
17041   const ClutterAnimationInfo *info;
17042
17043   info = _clutter_actor_get_animation_info_or_defaults (actor);
17044
17045   if (info->transitions == NULL)
17046     return NULL;
17047
17048   return g_hash_table_lookup (info->transitions, pspec->name);
17049 }
17050
17051 typedef struct _TransitionClosure
17052 {
17053   ClutterActor *actor;
17054   ClutterTransition *transition;
17055   gchar *name;
17056   gulong completed_id;
17057 } TransitionClosure;
17058
17059 static void
17060 transition_closure_free (gpointer data)
17061 {
17062   if (G_LIKELY (data != NULL))
17063     {
17064       TransitionClosure *clos = data;
17065
17066       if (clutter_timeline_is_playing (CLUTTER_TIMELINE (clos->transition)))
17067         clutter_timeline_stop (CLUTTER_TIMELINE (clos->transition));
17068
17069       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17070
17071       g_object_unref (clos->transition);
17072       g_free (clos->name);
17073
17074       g_slice_free (TransitionClosure, clos);
17075     }
17076 }
17077
17078 static void
17079 on_transition_completed (ClutterTransition *transition,
17080                          TransitionClosure *clos)
17081 {
17082   ClutterActor *actor = clos->actor;
17083   ClutterAnimationInfo *info;
17084
17085   info = _clutter_actor_get_animation_info (actor);
17086
17087   /* this will take care of cleaning clos for us */
17088   if (clutter_transition_get_remove_on_complete (transition))
17089     {
17090       /* we take a reference here because removing the closure
17091        * will release the reference on the transition, and we
17092        * want the transition to survive the signal emission;
17093        * the master clock will release the laste reference at
17094        * the end of the frame processing.
17095        */
17096       g_object_ref (transition);
17097       g_hash_table_remove (info->transitions, clos->name);
17098     }
17099
17100   /* if it's the last transition then we clean up */
17101   if (g_hash_table_size (info->transitions) == 0)
17102     {
17103       g_hash_table_unref (info->transitions);
17104       info->transitions = NULL;
17105
17106       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17107                     _clutter_actor_get_debug_name (actor));
17108
17109       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17110     }
17111 }
17112
17113 void
17114 _clutter_actor_update_transition (ClutterActor *actor,
17115                                   GParamSpec   *pspec,
17116                                   ...)
17117 {
17118   TransitionClosure *clos;
17119   ClutterInterval *interval;
17120   const ClutterAnimationInfo *info;
17121   va_list var_args;
17122   GType ptype;
17123   GValue initial = G_VALUE_INIT;
17124   GValue final = G_VALUE_INIT;
17125   char *error = NULL;
17126
17127   info = _clutter_actor_get_animation_info_or_defaults (actor);
17128
17129   if (info->transitions == NULL)
17130     return;
17131
17132   clos = g_hash_table_lookup (info->transitions, pspec->name);
17133   if (clos == NULL)
17134     return;
17135
17136   va_start (var_args, pspec);
17137
17138   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17139
17140   g_value_init (&initial, ptype);
17141   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17142                                         pspec->name,
17143                                         &initial);
17144
17145   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17146   if (error != NULL)
17147     {
17148       g_critical ("%s: %s", G_STRLOC, error);
17149       g_free (error);
17150       goto out;
17151     }
17152
17153   interval = clutter_transition_get_interval (clos->transition);
17154   clutter_interval_set_initial_value (interval, &initial);
17155   clutter_interval_set_final_value (interval, &final);
17156
17157   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
17158
17159 out:
17160   g_value_unset (&initial);
17161   g_value_unset (&final);
17162
17163   va_end (var_args);
17164 }
17165
17166 /*< private >*
17167  * _clutter_actor_create_transition:
17168  * @actor: a #ClutterActor
17169  * @pspec: the property used for the transition
17170  * @...: initial and final state
17171  *
17172  * Creates a #ClutterTransition for the property represented by @pspec.
17173  *
17174  * Return value: a #ClutterTransition
17175  */
17176 ClutterTransition *
17177 _clutter_actor_create_transition (ClutterActor *actor,
17178                                   GParamSpec   *pspec,
17179                                   ...)
17180 {
17181   ClutterAnimationInfo *info;
17182   ClutterTransition *res = NULL;
17183   gboolean call_restore = FALSE;
17184   TransitionClosure *clos;
17185   va_list var_args;
17186
17187   info = _clutter_actor_get_animation_info (actor);
17188
17189   if (info->states == NULL)
17190     {
17191       clutter_actor_save_easing_state (actor);
17192       call_restore = TRUE;
17193     }
17194
17195   if (info->transitions == NULL)
17196     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17197                                                NULL,
17198                                                transition_closure_free);
17199
17200   va_start (var_args, pspec);
17201
17202   clos = g_hash_table_lookup (info->transitions, pspec->name);
17203   if (clos == NULL)
17204     {
17205       ClutterInterval *interval;
17206       GValue initial = G_VALUE_INIT;
17207       GValue final = G_VALUE_INIT;
17208       GType ptype;
17209       char *error;
17210
17211       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17212
17213       G_VALUE_COLLECT_INIT (&initial, ptype,
17214                             var_args, 0,
17215                             &error);
17216       if (error != NULL)
17217         {
17218           g_critical ("%s: %s", G_STRLOC, error);
17219           g_free (error);
17220           goto out;
17221         }
17222
17223       G_VALUE_COLLECT_INIT (&final, ptype,
17224                             var_args, 0,
17225                             &error);
17226
17227       if (error != NULL)
17228         {
17229           g_critical ("%s: %s", G_STRLOC, error);
17230           g_value_unset (&initial);
17231           g_free (error);
17232           goto out;
17233         }
17234
17235       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17236
17237       g_value_unset (&initial);
17238       g_value_unset (&final);
17239
17240       res = clutter_property_transition_new (pspec->name);
17241
17242       clutter_transition_set_interval (res, interval);
17243       clutter_transition_set_remove_on_complete (res, TRUE);
17244
17245       /* this will start the transition as well */
17246       clutter_actor_add_transition (actor, pspec->name, res);
17247
17248       /* the actor now owns the transition */
17249       g_object_unref (res);
17250     }
17251   else
17252     res = clos->transition;
17253
17254 out:
17255   if (call_restore)
17256     clutter_actor_restore_easing_state (actor);
17257
17258   va_end (var_args);
17259
17260   return res;
17261 }
17262
17263 /**
17264  * clutter_actor_add_transition:
17265  * @self: a #ClutterActor
17266  * @name: the name of the transition to add
17267  * @transition: the #ClutterTransition to add
17268  *
17269  * Adds a @transition to the #ClutterActor's list of animations.
17270  *
17271  * The @name string is a per-actor unique identifier of the @transition: only
17272  * one #ClutterTransition can be associated to the specified @name.
17273  *
17274  * The @transition will be given the easing duration, mode, and delay
17275  * associated to the actor's current easing state; it is possible to modify
17276  * these values after calling clutter_actor_add_transition().
17277  *
17278  * The @transition will be started once added.
17279  *
17280  * This function will take a reference on the @transition.
17281  *
17282  * This function is usually called implicitly when modifying an animatable
17283  * property.
17284  *
17285  * Since: 1.10
17286  */
17287 void
17288 clutter_actor_add_transition (ClutterActor      *self,
17289                               const char        *name,
17290                               ClutterTransition *transition)
17291 {
17292   ClutterTimeline *timeline;
17293   TransitionClosure *clos;
17294   ClutterAnimationInfo *info;
17295
17296   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17297   g_return_if_fail (name != NULL);
17298   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17299
17300   info = _clutter_actor_get_animation_info (self);
17301
17302   if (info->cur_state == NULL)
17303     {
17304       g_warning ("No easing state is defined for the actor '%s'; you "
17305                  "must call clutter_actor_save_easing_state() before "
17306                  "calling clutter_actor_add_transition().",
17307                  _clutter_actor_get_debug_name (self));
17308       return;
17309     }
17310
17311   if (info->transitions == NULL)
17312     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17313                                                NULL,
17314                                                transition_closure_free);
17315
17316   if (g_hash_table_lookup (info->transitions, name) != NULL)
17317     {
17318       g_warning ("A transition with name '%s' already exists for "
17319                  "the actor '%s'",
17320                  name,
17321                  _clutter_actor_get_debug_name (self));
17322       return;
17323     }
17324
17325   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17326
17327   timeline = CLUTTER_TIMELINE (transition);
17328
17329   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17330   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17331   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17332
17333   clos = g_slice_new (TransitionClosure);
17334   clos->actor = self;
17335   clos->transition = g_object_ref (transition);
17336   clos->name = g_strdup (name);
17337   clos->completed_id = g_signal_connect (timeline, "completed",
17338                                          G_CALLBACK (on_transition_completed),
17339                                          clos);
17340
17341   g_hash_table_insert (info->transitions, clos->name, clos);
17342   clutter_timeline_start (timeline);
17343 }
17344
17345 /**
17346  * clutter_actor_remove_transition:
17347  * @self: a #ClutterActor
17348  * @name: the name of the transition to remove
17349  *
17350  * Removes the transition stored inside a #ClutterActor using @name
17351  * identifier.
17352  *
17353  * If the transition is currently in progress, it will be stopped.
17354  *
17355  * This function releases the reference acquired when the transition
17356  * was added to the #ClutterActor.
17357  *
17358  * Since: 1.10
17359  */
17360 void
17361 clutter_actor_remove_transition (ClutterActor *self,
17362                                  const char   *name)
17363 {
17364   const ClutterAnimationInfo *info;
17365
17366   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17367   g_return_if_fail (name != NULL);
17368
17369   info = _clutter_actor_get_animation_info_or_defaults (self);
17370
17371   if (info->transitions == NULL)
17372     return;
17373
17374   g_hash_table_remove (info->transitions, name);
17375 }
17376
17377 /**
17378  * clutter_actor_remove_all_transitions:
17379  * @self: a #ClutterActor
17380  *
17381  * Removes all transitions associated to @self.
17382  *
17383  * Since: 1.10
17384  */
17385 void
17386 clutter_actor_remove_all_transitions (ClutterActor *self)
17387 {
17388   const ClutterAnimationInfo *info;
17389
17390   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17391
17392   info = _clutter_actor_get_animation_info_or_defaults (self);
17393   if (info->transitions == NULL)
17394     return;
17395
17396   g_hash_table_remove_all (info->transitions);
17397 }
17398
17399 /**
17400  * clutter_actor_set_easing_duration:
17401  * @self: a #ClutterActor
17402  * @msecs: the duration of the easing, or %NULL
17403  *
17404  * Sets the duration of the tweening for animatable properties
17405  * of @self for the current easing state.
17406  *
17407  * Since: 1.10
17408  */
17409 void
17410 clutter_actor_set_easing_duration (ClutterActor *self,
17411                                    guint         msecs)
17412 {
17413   ClutterAnimationInfo *info;
17414
17415   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17416
17417   info = _clutter_actor_get_animation_info (self);
17418
17419   if (info->cur_state == NULL)
17420     {
17421       g_warning ("You must call clutter_actor_save_easing_state() prior "
17422                  "to calling clutter_actor_set_easing_duration().");
17423       return;
17424     }
17425
17426   if (info->cur_state->easing_duration != msecs)
17427     info->cur_state->easing_duration = msecs;
17428 }
17429
17430 /**
17431  * clutter_actor_get_easing_duration:
17432  * @self: a #ClutterActor
17433  *
17434  * Retrieves the duration of the tweening for animatable
17435  * properties of @self for the current easing state.
17436  *
17437  * Return value: the duration of the tweening, in milliseconds
17438  *
17439  * Since: 1.10
17440  */
17441 guint
17442 clutter_actor_get_easing_duration (ClutterActor *self)
17443 {
17444   const ClutterAnimationInfo *info;
17445
17446   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17447
17448   info = _clutter_actor_get_animation_info_or_defaults (self);
17449
17450   if (info->cur_state != NULL)
17451     return info->cur_state->easing_duration;
17452
17453   return 0;
17454 }
17455
17456 /**
17457  * clutter_actor_set_easing_mode:
17458  * @self: a #ClutterActor
17459  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17460  *
17461  * Sets the easing mode for the tweening of animatable properties
17462  * of @self.
17463  *
17464  * Since: 1.10
17465  */
17466 void
17467 clutter_actor_set_easing_mode (ClutterActor         *self,
17468                                ClutterAnimationMode  mode)
17469 {
17470   ClutterAnimationInfo *info;
17471
17472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17473   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17474   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17475
17476   info = _clutter_actor_get_animation_info (self);
17477
17478   if (info->cur_state == NULL)
17479     {
17480       g_warning ("You must call clutter_actor_save_easing_state() prior "
17481                  "to calling clutter_actor_set_easing_mode().");
17482       return;
17483     }
17484
17485   if (info->cur_state->easing_mode != mode)
17486     info->cur_state->easing_mode = mode;
17487 }
17488
17489 /**
17490  * clutter_actor_get_easing_mode:
17491  * @self: a #ClutterActor
17492  *
17493  * Retrieves the easing mode for the tweening of animatable properties
17494  * of @self for the current easing state.
17495  *
17496  * Return value: an easing mode
17497  *
17498  * Since: 1.10
17499  */
17500 ClutterAnimationMode
17501 clutter_actor_get_easing_mode (ClutterActor *self)
17502 {
17503   const ClutterAnimationInfo *info;
17504
17505   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17506
17507   info = _clutter_actor_get_animation_info_or_defaults (self);
17508
17509   if (info->cur_state != NULL)
17510     return info->cur_state->easing_mode;
17511
17512   return CLUTTER_EASE_OUT_CUBIC;
17513 }
17514
17515 /**
17516  * clutter_actor_set_easing_delay:
17517  * @self: a #ClutterActor
17518  * @msecs: the delay before the start of the tweening, in milliseconds
17519  *
17520  * Sets the delay that should be applied before tweening animatable
17521  * properties.
17522  *
17523  * Since: 1.10
17524  */
17525 void
17526 clutter_actor_set_easing_delay (ClutterActor *self,
17527                                 guint         msecs)
17528 {
17529   ClutterAnimationInfo *info;
17530
17531   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17532
17533   info = _clutter_actor_get_animation_info (self);
17534
17535   if (info->cur_state == NULL)
17536     {
17537       g_warning ("You must call clutter_actor_save_easing_state() prior "
17538                  "to calling clutter_actor_set_easing_delay().");
17539       return;
17540     }
17541
17542   if (info->cur_state->easing_delay != msecs)
17543     info->cur_state->easing_delay = msecs;
17544 }
17545
17546 /**
17547  * clutter_actor_get_easing_delay:
17548  * @self: a #ClutterActor
17549  *
17550  * Retrieves the delay that should be applied when tweening animatable
17551  * properties.
17552  *
17553  * Return value: a delay, in milliseconds
17554  *
17555  * Since: 1.10
17556  */
17557 guint
17558 clutter_actor_get_easing_delay (ClutterActor *self)
17559 {
17560   const ClutterAnimationInfo *info;
17561
17562   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17563
17564   info = _clutter_actor_get_animation_info_or_defaults (self);
17565
17566   if (info->cur_state != NULL)
17567     return info->cur_state->easing_delay;
17568
17569   return 0;
17570 }
17571
17572 /**
17573  * clutter_actor_get_transition:
17574  * @self: a #ClutterActor
17575  * @name: the name of the transition
17576  *
17577  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17578  * transition @name.
17579  *
17580  * Transitions created for animatable properties use the name of the
17581  * property itself, for instance the code below:
17582  *
17583  * |[
17584  *   clutter_actor_set_easing_duration (actor, 1000);
17585  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17586  *
17587  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17588  *   g_signal_connect (transition, "completed",
17589  *                     G_CALLBACK (on_transition_complete),
17590  *                     actor);
17591  * ]|
17592  *
17593  * will call the <function>on_transition_complete</function> callback when
17594  * the transition is complete.
17595  *
17596  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17597  *   was found to match the passed name; the returned instance is owned
17598  *   by Clutter and it should not be freed
17599  *
17600  * Since: 1.10
17601  */
17602 ClutterTransition *
17603 clutter_actor_get_transition (ClutterActor *self,
17604                               const char   *name)
17605 {
17606   TransitionClosure *clos;
17607   const ClutterAnimationInfo *info;
17608
17609   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17610   g_return_val_if_fail (name != NULL, NULL);
17611
17612   info = _clutter_actor_get_animation_info_or_defaults (self);
17613
17614   if (info->transitions == NULL)
17615     return NULL;
17616
17617   clos = g_hash_table_lookup (info->transitions, name);
17618   if (clos == NULL)
17619     return NULL;
17620
17621   return clos->transition;
17622 }
17623
17624 /**
17625  * clutter_actor_save_easing_state:
17626  * @self: a #ClutterActor
17627  *
17628  * Saves the current easing state for animatable properties, and creates
17629  * a new state with the default values for easing mode and duration.
17630  *
17631  * Since: 1.10
17632  */
17633 void
17634 clutter_actor_save_easing_state (ClutterActor *self)
17635 {
17636   ClutterAnimationInfo *info;
17637   AState new_state;
17638
17639   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17640
17641   info = _clutter_actor_get_animation_info (self);
17642
17643   if (info->states == NULL)
17644     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17645
17646   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17647   new_state.easing_duration = 250;
17648   new_state.easing_delay = 0;
17649
17650   g_array_append_val (info->states, new_state);
17651
17652   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17653 }
17654
17655 /**
17656  * clutter_actor_restore_easing_state:
17657  * @self: a #ClutterActor
17658  *
17659  * Restores the easing state as it was prior to a call to
17660  * clutter_actor_save_easing_state().
17661  *
17662  * Since: 1.10
17663  */
17664 void
17665 clutter_actor_restore_easing_state (ClutterActor *self)
17666 {
17667   ClutterAnimationInfo *info;
17668
17669   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17670
17671   info = _clutter_actor_get_animation_info (self);
17672
17673   if (info->states == NULL)
17674     {
17675       g_critical ("The function clutter_actor_restore_easing_state() has "
17676                   "called without a previous call to "
17677                   "clutter_actor_save_easing_state().");
17678       return;
17679     }
17680
17681   g_array_remove_index (info->states, info->states->len - 1);
17682
17683   if (info->states->len > 0)
17684     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17685   else
17686     {
17687       g_array_unref (info->states);
17688       info->states = NULL;
17689     }
17690 }
17691
17692 /**
17693  * clutter_actor_set_content:
17694  * @self: a #ClutterActor
17695  * @content: (allow-none): a #ClutterContent, or %NULL
17696  *
17697  * Sets the contents of a #ClutterActor.
17698  *
17699  * Since: 1.10
17700  */
17701 void
17702 clutter_actor_set_content (ClutterActor   *self,
17703                            ClutterContent *content)
17704 {
17705   ClutterActorPrivate *priv;
17706
17707   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17708   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17709
17710   priv = self->priv;
17711
17712   if (priv->content != NULL)
17713     {
17714       _clutter_content_detached (priv->content, self);
17715       g_clear_object (&priv->content);
17716     }
17717
17718   priv->content = content;
17719
17720   if (priv->content != NULL)
17721     {
17722       g_object_ref (priv->content);
17723       _clutter_content_attached (priv->content, self);
17724     }
17725
17726   /* given that the content is always painted within the allocation,
17727    * we only need to queue a redraw here
17728    */
17729   clutter_actor_queue_redraw (self);
17730
17731   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17732
17733   /* if the content gravity is not resize-fill, and the new content has a
17734    * different preferred size than the previous one, then the content box
17735    * may have been changed. since we compute that lazily, we just notify
17736    * here, and let whomever watches :content-box do whatever they need to
17737    * do.
17738    */
17739   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17740     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17741 }
17742
17743 /**
17744  * clutter_actor_get_content:
17745  * @self: a #ClutterActor
17746  *
17747  * Retrieves the contents of @self.
17748  *
17749  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17750  *   or %NULL if none was set
17751  *
17752  * Since: 1.10
17753  */
17754 ClutterContent *
17755 clutter_actor_get_content (ClutterActor *self)
17756 {
17757   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17758
17759   return self->priv->content;
17760 }
17761
17762 /**
17763  * clutter_actor_set_content_gravity:
17764  * @self: a #ClutterActor
17765  * @gravity: the #ClutterContentGravity
17766  *
17767  * Sets the gravity of the #ClutterContent used by @self.
17768  *
17769  * See the description of the #ClutterActor:content-gravity property for
17770  * more information.
17771  *
17772  * Since: 1.10
17773  */
17774 void
17775 clutter_actor_set_content_gravity (ClutterActor *self,
17776                                    ClutterContentGravity  gravity)
17777 {
17778   ClutterActorPrivate *priv;
17779
17780   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17781
17782   priv = self->priv;
17783
17784   if (priv->content_gravity == gravity)
17785     return;
17786
17787   priv->content_gravity = gravity;
17788
17789   clutter_actor_queue_redraw (self);
17790
17791   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17792   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17793 }
17794
17795 /**
17796  * clutter_actor_get_content_gravity:
17797  * @self: a #ClutterActor
17798  *
17799  * Retrieves the content gravity as set using
17800  * clutter_actor_get_content_gravity().
17801  *
17802  * Return value: the content gravity
17803  *
17804  * Since: 1.10
17805  */
17806 ClutterContentGravity
17807 clutter_actor_get_content_gravity (ClutterActor *self)
17808 {
17809   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17810                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17811
17812   return self->priv->content_gravity;
17813 }
17814
17815 /**
17816  * clutter_actor_get_content_box:
17817  * @self: a #ClutterActor
17818  * @box: (out caller-allocates): the return location for the bounding
17819  *   box for the #ClutterContent
17820  *
17821  * Retrieves the bounding box for the #ClutterContent of @self.
17822  *
17823  * The bounding box is relative to the actor's allocation.
17824  *
17825  * If no #ClutterContent is set for @self, or if @self has not been
17826  * allocated yet, then the result is undefined.
17827  *
17828  * The content box is guaranteed to be, at most, as big as the allocation
17829  * of the #ClutterActor.
17830  *
17831  * If the #ClutterContent used by the actor has a preferred size, then
17832  * it is possible to modify the content box by using the
17833  * #ClutterActor:content-gravity property.
17834  *
17835  * Since: 1.10
17836  */
17837 void
17838 clutter_actor_get_content_box (ClutterActor    *self,
17839                                ClutterActorBox *box)
17840 {
17841   ClutterActorPrivate *priv;
17842   gfloat content_w, content_h;
17843   gfloat alloc_w, alloc_h;
17844
17845   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17846   g_return_if_fail (box != NULL);
17847
17848   priv = self->priv;
17849
17850   box->x1 = 0.f;
17851   box->y1 = 0.f;
17852   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17853   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17854
17855   if (priv->content == NULL)
17856     return;
17857
17858   /* no need to do any more work */
17859   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17860     return;
17861
17862   /* if the content does not have a preferred size then there is
17863    * no point in computing the content box
17864    */
17865   if (!clutter_content_get_preferred_size (priv->content,
17866                                            &content_w,
17867                                            &content_h))
17868     return;
17869
17870   alloc_w = box->x2;
17871   alloc_h = box->y2;
17872
17873   switch (priv->content_gravity)
17874     {
17875     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17876       box->x2 = box->x1 + MIN (content_w, alloc_w);
17877       box->y2 = box->y1 + MIN (content_h, alloc_h);
17878       break;
17879
17880     case CLUTTER_CONTENT_GRAVITY_TOP:
17881       if (alloc_w > content_w)
17882         {
17883           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17884           box->x2 = box->x1 + content_w;
17885         }
17886       box->y2 = box->y1 + MIN (content_h, alloc_h);
17887       break;
17888
17889     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17890       if (alloc_w > content_w)
17891         {
17892           box->x1 += (alloc_w - content_w);
17893           box->x2 = box->x1 + content_w;
17894         }
17895       box->y2 = box->y1 + MIN (content_h, alloc_h);
17896       break;
17897
17898     case CLUTTER_CONTENT_GRAVITY_LEFT:
17899       box->x2 = box->x1 + MIN (content_w, alloc_w);
17900       if (alloc_h > content_h)
17901         {
17902           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17903           box->y2 = box->y1 + content_h;
17904         }
17905       break;
17906
17907     case CLUTTER_CONTENT_GRAVITY_CENTER:
17908       if (alloc_w > content_w)
17909         {
17910           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17911           box->x2 = box->x1 + content_w;
17912         }
17913       if (alloc_h > content_h)
17914         {
17915           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17916           box->y2 = box->y1 + content_h;
17917         }
17918       break;
17919
17920     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17921       if (alloc_w > content_w)
17922         {
17923           box->x1 += (alloc_w - content_w);
17924           box->x2 = box->x1 + content_w;
17925         }
17926       if (alloc_h > content_h)
17927         {
17928           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17929           box->y2 = box->y1 + content_h;
17930         }
17931       break;
17932
17933     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17934       box->x2 = box->x1 + MIN (content_w, alloc_w);
17935       if (alloc_h > content_h)
17936         {
17937           box->y1 += (alloc_h - content_h);
17938           box->y2 = box->y1 + content_h;
17939         }
17940       break;
17941
17942     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17943       if (alloc_w > content_w)
17944         {
17945           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17946           box->x2 = box->x1 + content_w;
17947         }
17948       if (alloc_h > content_h)
17949         {
17950           box->y1 += (alloc_h - content_h);
17951           box->y2 = box->y1 + content_h;
17952         }
17953       break;
17954
17955     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17956       if (alloc_w > content_w)
17957         {
17958           box->x1 += (alloc_w - content_w);
17959           box->x2 = box->x1 + content_w;
17960         }
17961       if (alloc_h > content_h)
17962         {
17963           box->y1 += (alloc_h - content_h);
17964           box->y2 = box->y1 + content_h;
17965         }
17966       break;
17967
17968     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17969       g_assert_not_reached ();
17970       break;
17971
17972     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17973       {
17974         double r_c = content_w / content_h;
17975         double r_a = alloc_w / alloc_h;
17976
17977         if (r_c >= 1.0)
17978           {
17979             if (r_a >= 1.0)
17980               {
17981                 box->x1 = 0.f;
17982                 box->x2 = alloc_w;
17983
17984                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17985                 box->y2 = box->y1 + (alloc_w * r_c);
17986               }
17987             else
17988               {
17989                 box->y1 = 0.f;
17990                 box->y2 = alloc_h;
17991
17992                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17993                 box->x2 = box->x1 + (alloc_h * r_c);
17994               }
17995           }
17996         else
17997           {
17998             if (r_a >= 1.0)
17999               {
18000                 box->y1 = 0.f;
18001                 box->y2 = alloc_h;
18002
18003                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18004                 box->x2 = box->x1 + (alloc_h * r_c);
18005               }
18006             else
18007               {
18008                 box->x1 = 0.f;
18009                 box->x2 = alloc_w;
18010
18011                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18012                 box->y2 = box->y1 + (alloc_w * r_c);
18013               }
18014           }
18015       }
18016       break;
18017     }
18018 }
18019
18020 /**
18021  * clutter_actor_set_content_scaling_filters:
18022  * @self: a #ClutterActor
18023  * @min_filter: the minification filter for the content
18024  * @mag_filter: the magnification filter for the content
18025  *
18026  * Sets the minification and magnification filter to be applied when
18027  * scaling the #ClutterActor:content of a #ClutterActor.
18028  *
18029  * The #ClutterActor:minification-filter will be used when reducing
18030  * the size of the content; the #ClutterActor:magnification-filter
18031  * will be used when increasing the size of the content.
18032  *
18033  * Since: 1.10
18034  */
18035 void
18036 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18037                                            ClutterScalingFilter  min_filter,
18038                                            ClutterScalingFilter  mag_filter)
18039 {
18040   ClutterActorPrivate *priv;
18041   gboolean changed;
18042   GObject *obj;
18043
18044   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18045
18046   priv = self->priv;
18047   obj = G_OBJECT (self);
18048
18049   g_object_freeze_notify (obj);
18050
18051   changed = FALSE;
18052
18053   if (priv->min_filter != min_filter)
18054     {
18055       priv->min_filter = min_filter;
18056       changed = TRUE;
18057
18058       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18059     }
18060
18061   if (priv->mag_filter != mag_filter)
18062     {
18063       priv->mag_filter = mag_filter;
18064       changed = TRUE;
18065
18066       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18067     }
18068
18069   if (changed)
18070     clutter_actor_queue_redraw (self);
18071
18072   g_object_thaw_notify (obj);
18073 }
18074
18075 /**
18076  * clutter_actor_get_content_scaling_filters:
18077  * @self: a #ClutterActor
18078  * @min_filter: (out) (allow-none): return location for the minification
18079  *   filter, or %NULL
18080  * @mag_filter: (out) (allow-none): return location for the magnification
18081  *   filter, or %NULL
18082  *
18083  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18084  *
18085  * Since: 1.10
18086  */
18087 void
18088 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18089                                            ClutterScalingFilter *min_filter,
18090                                            ClutterScalingFilter *mag_filter)
18091 {
18092   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18093
18094   if (min_filter != NULL)
18095     *min_filter = self->priv->min_filter;
18096
18097   if (mag_filter != NULL)
18098     *mag_filter = self->priv->mag_filter;
18099 }