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