content: Make get_preferred_size() public
[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: Base abstract class for all visual stage actors.
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  *
171  *   /&ast; paint the content of the node using the allocation &ast;/
172  *   clutter_paint_node_add_rectangle (node, &box);
173  *
174  *   /&ast; add the node, and transfer ownership &ast;/
175  *   clutter_paint_node_add_child (root, node);
176  *   clutter_paint_node_unref (node);
177  * }
178  *     </programlisting></informalexample>
179  *   </formalpara>
180  *   <formalpara>
181  *     <title>Overriding the paint virtual function</title>
182  *     <para>The #ClutterActorClass.paint() virtual function is invoked
183  *     when the #ClutterActor::paint signal is emitted, and after the other
184  *     signal handlers have been invoked. Overriding the paint virtual
185  *     function gives total control to the paint sequence of the actor
186  *     itself, including the children of the actor, if any.</para>
187  *     <warning><para>It is strongly discouraged to override the
188  *     #ClutterActorClass.paint() virtual function, as well as connecting
189  *     to the #ClutterActor::paint signal. These hooks into the paint
190  *     sequence are considered legacy, and will be removed when the Clutter
191  *     API changes.</para></warning>
192  *   </formalpara>
193  * </refsect2>
194  *
195  * <refsect2 id="ClutterActor-events">
196  *   <title>Handling events on an actor</title>
197  *   <para>A #ClutterActor can receive and handle input device events, for
198  *   instance pointer events and key events, as long as its
199  *   #ClutterActor:reactive property is set to %TRUE.</para>
200  *   <para>Once an actor has been determined to be the source of an event,
201  *   Clutter will traverse the scene graph from the top-level actor towards the
202  *   event source, emitting the #ClutterActor::captured-event signal on each
203  *   ancestor until it reaches the source; this phase is also called
204  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
205  *   stopped, the graph is walked backwards, from the source actor to the
206  *   top-level, and the #ClutterActor::event signal, along with other event
207  *   signals if needed, is emitted; this phase is also called <emphasis>the
208  *   bubble phase</emphasis>. At any point of the signal emission, signal
209  *   handlers can stop the propagation through the scene graph by returning
210  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
211  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
212  * </refsect2>
213  *
214  * <refsect2 id="ClutterActor-subclassing">
215  *   <title>Implementing an actor</title>
216  *   <para>Careful consideration should be given when deciding to implement
217  *   a #ClutterActor sub-class. It is generally recommended to implement a
218  *   sub-class of #ClutterActor only for actors that should be used as leaf
219  *   nodes of a scene graph.</para>
220  *   <para>If your actor should be painted in a custom way, you should
221  *   override the #ClutterActor::paint signal class handler. You can either
222  *   opt to chain up to the parent class implementation or decide to fully
223  *   override the default paint implementation; Clutter will set up the
224  *   transformations and clip regions prior to emitting the #ClutterActor::paint
225  *   signal.</para>
226  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
227  *   #ClutterActorClass.get_preferred_height() virtual functions it is
228  *   possible to change or provide the preferred size of an actor; similarly,
229  *   by overriding the #ClutterActorClass.allocate() virtual function it is
230  *   possible to control the layout of the children of an actor. Make sure to
231  *   always chain up to the parent implementation of the
232  *   #ClutterActorClass.allocate() virtual function.</para>
233  *   <para>In general, it is strongly encouraged to use delegation and
234  *   composition instead of direct subclassing.</para>
235  * </refsect2>
236  *
237  * <refsect2 id="ClutterActor-script">
238  *   <title>ClutterActor custom properties for #ClutterScript</title>
239  *   <para>#ClutterActor defines a custom "rotation" property which
240  *   allows a short-hand description of the rotations to be applied
241  *   to an actor.</para>
242  *   <para>The syntax of the "rotation" property is the following:</para>
243  *   <informalexample>
244  *     <programlisting>
245  * "rotation" : [
246  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
247  * ]
248  *     </programlisting>
249  *   </informalexample>
250  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
251  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
252  *   floating point value representing the rotation angle on the given axis,
253  *   in degrees.</para>
254  *   <para>The <emphasis>center</emphasis> array is optional, and if present
255  *   it must contain the center of rotation as described by two coordinates:
256  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
257  *   "z-axis".</para>
258  *   <para>#ClutterActor will also parse every positional and dimensional
259  *   property defined as a string through clutter_units_from_string(); you
260  *   should read the documentation for the #ClutterUnits parser format for
261  *   the valid units and syntax.</para>
262  * </refsect2>
263  *
264  * <refsect2 id="ClutterActor-animating">
265  *   <title>Custom animatable properties</title>
266  *   <para>#ClutterActor allows accessing properties of #ClutterAction
267  *   and #ClutterConstraint instances associated to an actor instance
268  *   for animation purposes.</para>
269  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
270  *   property it is necessary to set the #ClutterActorMeta:name property on the
271  *   given action or constraint.</para>
272  *   <para>The property can be accessed using the following syntax:</para>
273  *   <informalexample>
274  *     <programlisting>
275  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
276  *     </programlisting>
277  *   </informalexample>
278  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
279  *   <para>The <emphasis>section</emphasis> fragment can be one between
280  *   "actions", "constraints" and "effects".</para>
281  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
282  *   action or constraint, as specified by the #ClutterActorMeta:name
283  *   property.</para>
284  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
285  *   action or constraint property to be animated.</para>
286  *   <para>The example below animates a #ClutterBindConstraint applied to an
287  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
288  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
289  *   its initial state is fully transparent and overlapping the actor to
290  *   which is bound to. </para>
291  *   <informalexample><programlisting>
292  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
293  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
294  * clutter_actor_add_constraint (rect, constraint);
295  *
296  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
297  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
298  * clutter_actor_add_constraint (rect, constraint);
299  *
300  * clutter_actor_set_reactive (rect, TRUE);
301  * clutter_actor_set_opacity (rect, 0);
302  *
303  * g_signal_connect (rect, "button-press-event",
304  *                   G_CALLBACK (on_button_press),
305  *                   NULL);
306  *   </programlisting></informalexample>
307  *   <para>On button press, the rectangle "slides" from behind the actor to
308  *   which is bound to, using the #ClutterBindConstraint:offset property and
309  *   the #ClutterActor:opacity property.</para>
310  *   <informalexample><programlisting>
311  * float new_offset = clutter_actor_get_width (origin) + h_padding;
312  *
313  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
314  *                        "opacity", 255,
315  *                        "@constraints.bind-x.offset", new_offset,
316  *                        NULL);
317  *   </programlisting></informalexample>
318  * </refsect2>
319  *
320  * <refsect2 id="ClutterActor-animatable-properties">
321  *   <title>Animatable properties</title>
322  *   <para>Certain properties on #ClutterActor are marked as "animatable";
323  *   these properties will be automatically tweened between the current
324  *   value and the new value when one is set.</para>
325  *   <para>For backward compatibility, animatable properties will only be
326  *   tweened if the easing duration is greater than 0, or if a new easing
327  *   state is set, for instance the following example:</para>
328  *   <informalexample><programlisting>
329  * clutter_actor_save_easing_state (actor);
330  * clutter_actor_set_position (actor, 200, 200);
331  * clutter_actor_restore_easing_state (actor);
332  *   </programlisting></informalexample>
333  *   <para>will tween the actor to the (200, 200) coordinates using the default
334  *   easing mode and duration of a new easing state. The example above is
335  *   equivalent to the following code:</para>
336  *   <informalexample><programlisting>
337  * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
338  * clutter_actor_set_easing_duration (actor, 250);
339  * clutter_actor_set_position (actor, 200, 200);
340  * clutter_actor_restore_easing_state (actor);
341  *   </programlisting></informalexample>
342  *   <para>It is possible to nest easing states to tween animatable
343  *   properties using different modes and durations, for instance:</para>
344  *   <informalexample><programlisting>
345  * clutter_actor_save_easing_state (actor); /&ast; outer state &ast;/
346  *
347  * /&ast; set the duration of the animation to 2 seconds and change position &ast;/
348  * clutter_actor_set_easing_duration (actor, 2000);
349  * clutter_actor_set_position (actor, 0, 0);
350  *
351  * clutter_actor_save_easing_state (actor); /&ast; inner state &ast;/
352  *
353  * /&ast; set the duration of the animation to 5 seconds and change depth and opacity &ast;/
354  * clutter_actor_set_easing_duration (actor, 5000);
355  * clutter_actor_set_depth (actor, 200);
356  * clutter_actor_set_opacity (actor, 0);
357  *
358  * clutter_actor_restore_easing_state (actor);
359  *
360  * clutter_actor_restore_easing_state (actor);
361  *   </programlisting></informalexample>
362  * </refsect2>
363  */
364
365 /**
366  * CLUTTER_ACTOR_IS_MAPPED:
367  * @a: a #ClutterActor
368  *
369  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
370  *
371  * The mapped state is set when the actor is visible and all its parents up
372  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
373  *
374  * This check can be used to see if an actor is going to be painted, as only
375  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
376  *
377  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
378  * not be checked directly; instead, the recommended usage is to connect a
379  * handler on the #GObject::notify signal for the #ClutterActor:mapped
380  * property of #ClutterActor, and check the presence of
381  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
382  *
383  * It is also important to note that Clutter may delay the changes of
384  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
385  * limitations, or during the reparenting of an actor, to optimize
386  * unnecessary (and potentially expensive) state changes.
387  *
388  * Since: 0.2
389  */
390
391 /**
392  * CLUTTER_ACTOR_IS_REALIZED:
393  * @a: a #ClutterActor
394  *
395  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
396  *
397  * The realized state has an actor-dependant interpretation. If an
398  * actor wants to delay allocating resources until it is attached to a
399  * stage, it may use the realize state to do so. However it is
400  * perfectly acceptable for an actor to allocate Cogl resources before
401  * being realized because there is only one drawing context used by Clutter
402  * so any resources will work on any stage.  If an actor is mapped it
403  * must also be realized, but an actor can be realized and unmapped
404  * (this is so hiding an actor temporarily doesn't do an expensive
405  * unrealize/realize).
406  *
407  * To be realized an actor must be inside a stage, and all its parents
408  * must be realized.
409  *
410  * Since: 0.2
411  */
412
413 /**
414  * CLUTTER_ACTOR_IS_VISIBLE:
415  * @a: a #ClutterActor
416  *
417  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
418  * Equivalent to the ClutterActor::visible object property.
419  *
420  * Note that an actor is only painted onscreen if it's mapped, which
421  * means it's visible, and all its parents are visible, and one of the
422  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
423  *
424  * Since: 0.2
425  */
426
427 /**
428  * CLUTTER_ACTOR_IS_REACTIVE:
429  * @a: a #ClutterActor
430  *
431  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
432  *
433  * Only reactive actors will receive event-related signals.
434  *
435  * Since: 0.6
436  */
437
438 #ifdef HAVE_CONFIG_H
439 #include "config.h"
440 #endif
441
442 #include <math.h>
443
444 #include <gobject/gvaluecollector.h>
445
446 #include <cogl/cogl.h>
447
448 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
449 #define CLUTTER_ENABLE_EXPERIMENTAL_API
450
451 #include "clutter-actor-private.h"
452
453 #include "clutter-action.h"
454 #include "clutter-actor-meta-private.h"
455 #include "clutter-animatable.h"
456 #include "clutter-color-static.h"
457 #include "clutter-color.h"
458 #include "clutter-constraint.h"
459 #include "clutter-container.h"
460 #include "clutter-content-private.h"
461 #include "clutter-debug.h"
462 #include "clutter-effect-private.h"
463 #include "clutter-enum-types.h"
464 #include "clutter-fixed-layout.h"
465 #include "clutter-flatten-effect.h"
466 #include "clutter-interval.h"
467 #include "clutter-main.h"
468 #include "clutter-marshal.h"
469 #include "clutter-paint-nodes.h"
470 #include "clutter-paint-node-private.h"
471 #include "clutter-paint-volume-private.h"
472 #include "clutter-private.h"
473 #include "clutter-profile.h"
474 #include "clutter-property-transition.h"
475 #include "clutter-scriptable.h"
476 #include "clutter-script-private.h"
477 #include "clutter-stage-private.h"
478 #include "clutter-timeline.h"
479 #include "clutter-transition.h"
480 #include "clutter-units.h"
481
482 #include "deprecated/clutter-actor.h"
483 #include "deprecated/clutter-behaviour.h"
484 #include "deprecated/clutter-container.h"
485
486 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
487 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
488
489 /* Internal enum used to control mapped state update.  This is a hint
490  * which indicates when to do something other than just enforce
491  * invariants.
492  */
493 typedef enum {
494   MAP_STATE_CHECK,           /* just enforce invariants. */
495   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
496                               * used when about to unparent.
497                               */
498   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
499                               * used to set mapped on toplevels.
500                               */
501   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
502                               * used just before unmapping parent.
503                               */
504 } MapStateChange;
505
506 /* 3 entries should be a good compromise, few layout managers
507  * will ask for 3 different preferred size in each allocation cycle */
508 #define N_CACHED_SIZE_REQUESTS 3
509
510 struct _ClutterActorPrivate
511 {
512   /* request mode */
513   ClutterRequestMode request_mode;
514
515   /* our cached size requests for different width / height */
516   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
517   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
518
519   /* An age of 0 means the entry is not set */
520   guint cached_height_age;
521   guint cached_width_age;
522
523   /* the bounding box of the actor, relative to the parent's
524    * allocation
525    */
526   ClutterActorBox allocation;
527   ClutterAllocationFlags allocation_flags;
528
529   /* clip, in actor coordinates */
530   cairo_rectangle_t clip;
531
532   /* the cached transformation matrix; see apply_transform() */
533   CoglMatrix transform;
534
535   guint8 opacity;
536   gint opacity_override;
537
538   ClutterOffscreenRedirect offscreen_redirect;
539
540   /* This is an internal effect used to implement the
541      offscreen-redirect property */
542   ClutterEffect *flatten_effect;
543
544   /* scene graph */
545   ClutterActor *parent;
546   ClutterActor *prev_sibling;
547   ClutterActor *next_sibling;
548   ClutterActor *first_child;
549   ClutterActor *last_child;
550
551   gint n_children;
552
553   /* tracks whenever the children of an actor are changed; the
554    * age is incremented by 1 whenever an actor is added or
555    * removed. the age is not incremented when the first or the
556    * last child pointers are changed, or when grandchildren of
557    * an actor are changed.
558    */
559   gint age;
560
561   gchar *name; /* a non-unique name, used for debugging */
562   guint32 id; /* unique id, used for backward compatibility */
563
564   gint32 pick_id; /* per-stage unique id, used for picking */
565
566   /* a back-pointer to the Pango context that we can use
567    * to create pre-configured PangoLayout
568    */
569   PangoContext *pango_context;
570
571   /* the text direction configured for this child - either by
572    * application code, or by the actor's parent
573    */
574   ClutterTextDirection text_direction;
575
576   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
577   gint internal_child;
578
579   /* meta classes */
580   ClutterMetaGroup *actions;
581   ClutterMetaGroup *constraints;
582   ClutterMetaGroup *effects;
583
584   /* delegate object used to allocate the children of this actor */
585   ClutterLayoutManager *layout_manager;
586
587   /* delegate object used to paint the contents of this actor */
588   ClutterContent *content;
589
590   ClutterContentGravity content_gravity;
591
592   /* used when painting, to update the paint volume */
593   ClutterEffect *current_effect;
594
595   /* This is used to store an effect which needs to be redrawn. A
596      redraw can be queued to start from a particular effect. This is
597      used by parametrised effects that can cache an image of the
598      actor. If a parameter of the effect changes then it only needs to
599      redraw the cached image, not the actual actor. The pointer is
600      only valid if is_dirty == TRUE. If the pointer is NULL then the
601      whole actor is dirty. */
602   ClutterEffect *effect_to_redraw;
603
604   /* This is used when painting effects to implement the
605      clutter_actor_continue_paint() function. It points to the node in
606      the list of effects that is next in the chain */
607   const GList *next_effect_to_paint;
608
609   ClutterPaintVolume paint_volume;
610
611   /* NB: This volume isn't relative to this actor, it is in eye
612    * coordinates so that it can remain valid after the actor changes.
613    */
614   ClutterPaintVolume last_paint_volume;
615
616   ClutterStageQueueRedrawEntry *queue_redraw_entry;
617
618   ClutterColor bg_color;
619
620   /* bitfields */
621
622   /* fixed position and sizes */
623   guint position_set                : 1;
624   guint min_width_set               : 1;
625   guint min_height_set              : 1;
626   guint natural_width_set           : 1;
627   guint natural_height_set          : 1;
628   /* cached request is invalid (implies allocation is too) */
629   guint needs_width_request         : 1;
630   /* cached request is invalid (implies allocation is too) */
631   guint needs_height_request        : 1;
632   /* cached allocation is invalid (request has changed, probably) */
633   guint needs_allocation            : 1;
634   guint show_on_set_parent          : 1;
635   guint has_clip                    : 1;
636   guint clip_to_allocation          : 1;
637   guint enable_model_view_transform : 1;
638   guint enable_paint_unmapped       : 1;
639   guint has_pointer                 : 1;
640   guint propagated_one_redraw       : 1;
641   guint paint_volume_valid          : 1;
642   guint last_paint_volume_valid     : 1;
643   guint in_clone_paint              : 1;
644   guint transform_valid             : 1;
645   /* This is TRUE if anything has queued a redraw since we were last
646      painted. In this case effect_to_redraw will point to an effect
647      the redraw was queued from or it will be NULL if the redraw was
648      queued without an effect. */
649   guint is_dirty                    : 1;
650   guint bg_color_set                : 1;
651 };
652
653 enum
654 {
655   PROP_0,
656
657   PROP_NAME,
658
659   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
660    * when set they force a size request, when gotten they
661    * get the allocation if the allocation is valid, and the
662    * request otherwise
663    */
664   PROP_X,
665   PROP_Y,
666   PROP_WIDTH,
667   PROP_HEIGHT,
668
669   /* Then the rest of these size-related properties are the "actual"
670    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
671    */
672   PROP_FIXED_X,
673   PROP_FIXED_Y,
674
675   PROP_FIXED_POSITION_SET,
676
677   PROP_MIN_WIDTH,
678   PROP_MIN_WIDTH_SET,
679
680   PROP_MIN_HEIGHT,
681   PROP_MIN_HEIGHT_SET,
682
683   PROP_NATURAL_WIDTH,
684   PROP_NATURAL_WIDTH_SET,
685
686   PROP_NATURAL_HEIGHT,
687   PROP_NATURAL_HEIGHT_SET,
688
689   PROP_REQUEST_MODE,
690
691   /* Allocation properties are read-only */
692   PROP_ALLOCATION,
693
694   PROP_DEPTH,
695
696   PROP_CLIP,
697   PROP_HAS_CLIP,
698   PROP_CLIP_TO_ALLOCATION,
699
700   PROP_OPACITY,
701
702   PROP_OFFSCREEN_REDIRECT,
703
704   PROP_VISIBLE,
705   PROP_MAPPED,
706   PROP_REALIZED,
707   PROP_REACTIVE,
708
709   PROP_SCALE_X,
710   PROP_SCALE_Y,
711   PROP_SCALE_CENTER_X,
712   PROP_SCALE_CENTER_Y,
713   PROP_SCALE_GRAVITY,
714
715   PROP_ROTATION_ANGLE_X,
716   PROP_ROTATION_ANGLE_Y,
717   PROP_ROTATION_ANGLE_Z,
718   PROP_ROTATION_CENTER_X,
719   PROP_ROTATION_CENTER_Y,
720   PROP_ROTATION_CENTER_Z,
721   /* This property only makes sense for the z rotation because the
722      others would depend on the actor having a size along the
723      z-axis */
724   PROP_ROTATION_CENTER_Z_GRAVITY,
725
726   PROP_ANCHOR_X,
727   PROP_ANCHOR_Y,
728   PROP_ANCHOR_GRAVITY,
729
730   PROP_SHOW_ON_SET_PARENT,
731
732   PROP_TEXT_DIRECTION,
733   PROP_HAS_POINTER,
734
735   PROP_ACTIONS,
736   PROP_CONSTRAINTS,
737   PROP_EFFECT,
738
739   PROP_LAYOUT_MANAGER,
740
741   PROP_X_ALIGN,
742   PROP_Y_ALIGN,
743   PROP_MARGIN_TOP,
744   PROP_MARGIN_BOTTOM,
745   PROP_MARGIN_LEFT,
746   PROP_MARGIN_RIGHT,
747
748   PROP_BACKGROUND_COLOR,
749   PROP_BACKGROUND_COLOR_SET,
750
751   PROP_FIRST_CHILD,
752   PROP_LAST_CHILD,
753
754   PROP_CONTENT,
755   PROP_CONTENT_GRAVITY,
756   PROP_CONTENT_BOX,
757
758   PROP_LAST
759 };
760
761 static GParamSpec *obj_props[PROP_LAST];
762
763 enum
764 {
765   SHOW,
766   HIDE,
767   DESTROY,
768   PARENT_SET,
769   KEY_FOCUS_IN,
770   KEY_FOCUS_OUT,
771   PAINT,
772   PICK,
773   REALIZE,
774   UNREALIZE,
775   QUEUE_REDRAW,
776   QUEUE_RELAYOUT,
777   EVENT,
778   CAPTURED_EVENT,
779   BUTTON_PRESS_EVENT,
780   BUTTON_RELEASE_EVENT,
781   SCROLL_EVENT,
782   KEY_PRESS_EVENT,
783   KEY_RELEASE_EVENT,
784   MOTION_EVENT,
785   ENTER_EVENT,
786   LEAVE_EVENT,
787   ALLOCATION_CHANGED,
788
789   LAST_SIGNAL
790 };
791
792 static guint actor_signals[LAST_SIGNAL] = { 0, };
793
794 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
795 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
796 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
797 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
798
799 /* These setters are all static for now, maybe they should be in the
800  * public API, but they are perhaps obscure enough to leave only as
801  * properties
802  */
803 static void clutter_actor_set_min_width          (ClutterActor *self,
804                                                   gfloat        min_width);
805 static void clutter_actor_set_min_height         (ClutterActor *self,
806                                                   gfloat        min_height);
807 static void clutter_actor_set_natural_width      (ClutterActor *self,
808                                                   gfloat        natural_width);
809 static void clutter_actor_set_natural_height     (ClutterActor *self,
810                                                   gfloat        natural_height);
811 static void clutter_actor_set_min_width_set      (ClutterActor *self,
812                                                   gboolean      use_min_width);
813 static void clutter_actor_set_min_height_set     (ClutterActor *self,
814                                                   gboolean      use_min_height);
815 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
816                                                   gboolean  use_natural_width);
817 static void clutter_actor_set_natural_height_set (ClutterActor *self,
818                                                   gboolean  use_natural_height);
819 static void clutter_actor_update_map_state       (ClutterActor  *self,
820                                                   MapStateChange change);
821 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
822
823 /* Helper routines for managing anchor coords */
824 static void clutter_anchor_coord_get_units (ClutterActor      *self,
825                                             const AnchorCoord *coord,
826                                             gfloat            *x,
827                                             gfloat            *y,
828                                             gfloat            *z);
829 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
830                                             gfloat             x,
831                                             gfloat             y,
832                                             gfloat             z);
833
834 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
835 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
836                                                         ClutterGravity     gravity);
837
838 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
839
840 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
841
842 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
843                                                                ClutterActor *ancestor,
844                                                                CoglMatrix *matrix);
845
846 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
847
848 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
849
850 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
851                                                                 const ClutterColor *color);
852
853 static void on_layout_manager_changed (ClutterLayoutManager *manager,
854                                        ClutterActor         *self);
855
856 /* Helper macro which translates by the anchor coord, applies the
857    given transformation and then translates back */
858 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
859   gfloat _tx, _ty, _tz;                                                \
860   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
861   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
862   { _transform; }                                                      \
863   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
864
865 static GQuark quark_shader_data = 0;
866 static GQuark quark_actor_layout_info = 0;
867 static GQuark quark_actor_transform_info = 0;
868 static GQuark quark_actor_animation_info = 0;
869
870 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
871                          clutter_actor,
872                          G_TYPE_INITIALLY_UNOWNED,
873                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
874                                                 clutter_container_iface_init)
875                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
876                                                 clutter_scriptable_iface_init)
877                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
878                                                 clutter_animatable_iface_init)
879                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
880                                                 atk_implementor_iface_init));
881
882 /*< private >
883  * clutter_actor_get_debug_name:
884  * @actor: a #ClutterActor
885  *
886  * Retrieves a printable name of @actor for debugging messages
887  *
888  * Return value: a string with a printable name
889  */
890 const gchar *
891 _clutter_actor_get_debug_name (ClutterActor *actor)
892 {
893   return actor->priv->name != NULL ? actor->priv->name
894                                    : G_OBJECT_TYPE_NAME (actor);
895 }
896
897 #ifdef CLUTTER_ENABLE_DEBUG
898 /* XXX - this is for debugging only, remove once working (or leave
899  * in only in some debug mode). Should leave it for a little while
900  * until we're confident in the new map/realize/visible handling.
901  */
902 static inline void
903 clutter_actor_verify_map_state (ClutterActor *self)
904 {
905   ClutterActorPrivate *priv = self->priv;
906
907   if (CLUTTER_ACTOR_IS_REALIZED (self))
908     {
909       /* all bets are off during reparent when we're potentially realized,
910        * but should not be according to invariants
911        */
912       if (!CLUTTER_ACTOR_IN_REPARENT (self))
913         {
914           if (priv->parent == NULL)
915             {
916               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
917                 {
918                 }
919               else
920                 g_warning ("Realized non-toplevel actor '%s' should "
921                            "have a parent",
922                            _clutter_actor_get_debug_name (self));
923             }
924           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
925             {
926               g_warning ("Realized actor %s has an unrealized parent %s",
927                          _clutter_actor_get_debug_name (self),
928                          _clutter_actor_get_debug_name (priv->parent));
929             }
930         }
931     }
932
933   if (CLUTTER_ACTOR_IS_MAPPED (self))
934     {
935       if (!CLUTTER_ACTOR_IS_REALIZED (self))
936         g_warning ("Actor '%s' is mapped but not realized",
937                    _clutter_actor_get_debug_name (self));
938
939       /* remaining bets are off during reparent when we're potentially
940        * mapped, but should not be according to invariants
941        */
942       if (!CLUTTER_ACTOR_IN_REPARENT (self))
943         {
944           if (priv->parent == NULL)
945             {
946               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
947                 {
948                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
949                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
950                     {
951                       g_warning ("Toplevel actor '%s' is mapped "
952                                  "but not visible",
953                                  _clutter_actor_get_debug_name (self));
954                     }
955                 }
956               else
957                 {
958                   g_warning ("Mapped actor '%s' should have a parent",
959                              _clutter_actor_get_debug_name (self));
960                 }
961             }
962           else
963             {
964               ClutterActor *iter = self;
965
966               /* check for the enable_paint_unmapped flag on the actor
967                * and parents; if the flag is enabled at any point of this
968                * branch of the scene graph then all the later checks
969                * become pointless
970                */
971               while (iter != NULL)
972                 {
973                   if (iter->priv->enable_paint_unmapped)
974                     return;
975
976                   iter = iter->priv->parent;
977                 }
978
979               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
980                 {
981                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
982                              "is not visible",
983                              _clutter_actor_get_debug_name (self),
984                              _clutter_actor_get_debug_name (priv->parent));
985                 }
986
987               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
988                 {
989                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
990                              "is not realized",
991                              _clutter_actor_get_debug_name (self),
992                              _clutter_actor_get_debug_name (priv->parent));
993                 }
994
995               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
996                 {
997                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
998                     g_warning ("Actor '%s' is mapped but its non-toplevel "
999                                "parent '%s' is not mapped",
1000                                _clutter_actor_get_debug_name (self),
1001                                _clutter_actor_get_debug_name (priv->parent));
1002                 }
1003             }
1004         }
1005     }
1006 }
1007
1008 #endif /* CLUTTER_ENABLE_DEBUG */
1009
1010 static void
1011 clutter_actor_set_mapped (ClutterActor *self,
1012                           gboolean      mapped)
1013 {
1014   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1015     return;
1016
1017   if (mapped)
1018     {
1019       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1020       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1021     }
1022   else
1023     {
1024       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1025       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1026     }
1027 }
1028
1029 /* this function updates the mapped and realized states according to
1030  * invariants, in the appropriate order.
1031  */
1032 static void
1033 clutter_actor_update_map_state (ClutterActor  *self,
1034                                 MapStateChange change)
1035 {
1036   gboolean was_mapped;
1037
1038   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1039
1040   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1041     {
1042       /* the mapped flag on top-level actors must be set by the
1043        * per-backend implementation because it might be asynchronous.
1044        *
1045        * That is, the MAPPED flag on toplevels currently tracks the X
1046        * server mapped-ness of the window, while the expected behavior
1047        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1048        * This creates some weird complexity by breaking the invariant
1049        * that if we're visible and all ancestors shown then we are
1050        * also mapped - instead, we are mapped if all ancestors
1051        * _possibly excepting_ the stage are mapped. The stage
1052        * will map/unmap for example when it is minimized or
1053        * moved to another workspace.
1054        *
1055        * So, the only invariant on the stage is that if visible it
1056        * should be realized, and that it has to be visible to be
1057        * mapped.
1058        */
1059       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1060         clutter_actor_realize (self);
1061
1062       switch (change)
1063         {
1064         case MAP_STATE_CHECK:
1065           break;
1066
1067         case MAP_STATE_MAKE_MAPPED:
1068           g_assert (!was_mapped);
1069           clutter_actor_set_mapped (self, TRUE);
1070           break;
1071
1072         case MAP_STATE_MAKE_UNMAPPED:
1073           g_assert (was_mapped);
1074           clutter_actor_set_mapped (self, FALSE);
1075           break;
1076
1077         case MAP_STATE_MAKE_UNREALIZED:
1078           /* we only use MAKE_UNREALIZED in unparent,
1079            * and unparenting a stage isn't possible.
1080            * If someone wants to just unrealize a stage
1081            * then clutter_actor_unrealize() doesn't
1082            * go through this codepath.
1083            */
1084           g_warning ("Trying to force unrealize stage is not allowed");
1085           break;
1086         }
1087
1088       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1089           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1090           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1091         {
1092           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1093                      "it is somehow still mapped",
1094                      _clutter_actor_get_debug_name (self));
1095         }
1096     }
1097   else
1098     {
1099       ClutterActorPrivate *priv = self->priv;
1100       ClutterActor *parent = priv->parent;
1101       gboolean should_be_mapped;
1102       gboolean may_be_realized;
1103       gboolean must_be_realized;
1104
1105       should_be_mapped = FALSE;
1106       may_be_realized = TRUE;
1107       must_be_realized = FALSE;
1108
1109       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1110         {
1111           may_be_realized = FALSE;
1112         }
1113       else
1114         {
1115           /* Maintain invariant that if parent is mapped, and we are
1116            * visible, then we are mapped ...  unless parent is a
1117            * stage, in which case we map regardless of parent's map
1118            * state but do require stage to be visible and realized.
1119            *
1120            * If parent is realized, that does not force us to be
1121            * realized; but if parent is unrealized, that does force
1122            * us to be unrealized.
1123            *
1124            * The reason we don't force children to realize with
1125            * parents is _clutter_actor_rerealize(); if we require that
1126            * a realized parent means children are realized, then to
1127            * unrealize an actor we would have to unrealize its
1128            * parents, which would end up meaning unrealizing and
1129            * hiding the entire stage. So we allow unrealizing a
1130            * child (as long as that child is not mapped) while that
1131            * child still has a realized parent.
1132            *
1133            * Also, if we unrealize from leaf nodes to root, and
1134            * realize from root to leaf, the invariants are never
1135            * violated if we allow children to be unrealized
1136            * while parents are realized.
1137            *
1138            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1139            * to force us to unmap, even though parent is still
1140            * mapped. This is because we're unmapping from leaf nodes
1141            * up to root nodes.
1142            */
1143           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1144               change != MAP_STATE_MAKE_UNMAPPED)
1145             {
1146               gboolean parent_is_visible_realized_toplevel;
1147
1148               parent_is_visible_realized_toplevel =
1149                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1150                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1151                  CLUTTER_ACTOR_IS_REALIZED (parent));
1152
1153               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1154                   parent_is_visible_realized_toplevel)
1155                 {
1156                   must_be_realized = TRUE;
1157                   should_be_mapped = TRUE;
1158                 }
1159             }
1160
1161           /* if the actor has been set to be painted even if unmapped
1162            * then we should map it and check for realization as well;
1163            * this is an override for the branch of the scene graph
1164            * which begins with this node
1165            */
1166           if (priv->enable_paint_unmapped)
1167             {
1168               if (priv->parent == NULL)
1169                 g_warning ("Attempting to map an unparented actor '%s'",
1170                            _clutter_actor_get_debug_name (self));
1171
1172               should_be_mapped = TRUE;
1173               must_be_realized = TRUE;
1174             }
1175
1176           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1177             may_be_realized = FALSE;
1178         }
1179
1180       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1181         {
1182           if (parent == NULL)
1183             g_warning ("Attempting to map a child that does not "
1184                        "meet the necessary invariants: the actor '%s' "
1185                        "has no parent",
1186                        _clutter_actor_get_debug_name (self));
1187           else
1188             g_warning ("Attempting to map a child that does not "
1189                        "meet the necessary invariants: the actor '%s' "
1190                        "is parented to an unmapped actor '%s'",
1191                        _clutter_actor_get_debug_name (self),
1192                        _clutter_actor_get_debug_name (priv->parent));
1193         }
1194
1195       /* If in reparent, we temporarily suspend unmap and unrealize.
1196        *
1197        * We want to go in the order "realize, map" and "unmap, unrealize"
1198        */
1199
1200       /* Unmap */
1201       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1202         clutter_actor_set_mapped (self, FALSE);
1203
1204       /* Realize */
1205       if (must_be_realized)
1206         clutter_actor_realize (self);
1207
1208       /* if we must be realized then we may be, presumably */
1209       g_assert (!(must_be_realized && !may_be_realized));
1210
1211       /* Unrealize */
1212       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1213         clutter_actor_unrealize_not_hiding (self);
1214
1215       /* Map */
1216       if (should_be_mapped)
1217         {
1218           if (!must_be_realized)
1219             g_warning ("Somehow we think actor '%s' should be mapped but "
1220                        "not realized, which isn't allowed",
1221                        _clutter_actor_get_debug_name (self));
1222
1223           /* realization is allowed to fail (though I don't know what
1224            * an app is supposed to do about that - shouldn't it just
1225            * be a g_error? anyway, we have to avoid mapping if this
1226            * happens)
1227            */
1228           if (CLUTTER_ACTOR_IS_REALIZED (self))
1229             clutter_actor_set_mapped (self, TRUE);
1230         }
1231     }
1232
1233 #ifdef CLUTTER_ENABLE_DEBUG
1234   /* check all invariants were kept */
1235   clutter_actor_verify_map_state (self);
1236 #endif
1237 }
1238
1239 static void
1240 clutter_actor_real_map (ClutterActor *self)
1241 {
1242   ClutterActorPrivate *priv = self->priv;
1243   ClutterActor *stage, *iter;
1244
1245   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1246
1247   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1248                 _clutter_actor_get_debug_name (self));
1249
1250   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1251
1252   stage = _clutter_actor_get_stage_internal (self);
1253   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1254
1255   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1256                 priv->pick_id,
1257                 _clutter_actor_get_debug_name (self));
1258
1259   /* notify on parent mapped before potentially mapping
1260    * children, so apps see a top-down notification.
1261    */
1262   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1263
1264   for (iter = self->priv->first_child;
1265        iter != NULL;
1266        iter = iter->priv->next_sibling)
1267     {
1268       clutter_actor_map (iter);
1269     }
1270 }
1271
1272 /**
1273  * clutter_actor_map:
1274  * @self: A #ClutterActor
1275  *
1276  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1277  * and realizes its children if they are visible. Does nothing if the
1278  * actor is not visible.
1279  *
1280  * Calling this function is strongly disencouraged: the default
1281  * implementation of #ClutterActorClass.map() will map all the children
1282  * of an actor when mapping its parent.
1283  *
1284  * When overriding map, it is mandatory to chain up to the parent
1285  * implementation.
1286  *
1287  * Since: 1.0
1288  */
1289 void
1290 clutter_actor_map (ClutterActor *self)
1291 {
1292   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1293
1294   if (CLUTTER_ACTOR_IS_MAPPED (self))
1295     return;
1296
1297   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1298     return;
1299
1300   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1301 }
1302
1303 static void
1304 clutter_actor_real_unmap (ClutterActor *self)
1305 {
1306   ClutterActorPrivate *priv = self->priv;
1307   ClutterActor *iter;
1308
1309   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1310
1311   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1312                 _clutter_actor_get_debug_name (self));
1313
1314   for (iter = self->priv->first_child;
1315        iter != NULL;
1316        iter = iter->priv->next_sibling)
1317     {
1318       clutter_actor_unmap (iter);
1319     }
1320
1321   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1322
1323   /* clear the contents of the last paint volume, so that hiding + moving +
1324    * showing will not result in the wrong area being repainted
1325    */
1326   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1327   priv->last_paint_volume_valid = TRUE;
1328
1329   /* notify on parent mapped after potentially unmapping
1330    * children, so apps see a bottom-up notification.
1331    */
1332   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1333
1334   /* relinquish keyboard focus if we were unmapped while owning it */
1335   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1336     {
1337       ClutterStage *stage;
1338
1339       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1340
1341       if (stage != NULL)
1342         _clutter_stage_release_pick_id (stage, priv->pick_id);
1343
1344       priv->pick_id = -1;
1345
1346       if (stage != NULL &&
1347           clutter_stage_get_key_focus (stage) == self)
1348         {
1349           clutter_stage_set_key_focus (stage, NULL);
1350         }
1351     }
1352 }
1353
1354 /**
1355  * clutter_actor_unmap:
1356  * @self: A #ClutterActor
1357  *
1358  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1359  * unmaps its children if they were mapped.
1360  *
1361  * Calling this function is not encouraged: the default #ClutterActor
1362  * implementation of #ClutterActorClass.unmap() will also unmap any
1363  * eventual children by default when their parent is unmapped.
1364  *
1365  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1366  * chain up to the parent implementation.
1367  *
1368  * <note>It is important to note that the implementation of the
1369  * #ClutterActorClass.unmap() virtual function may be called after
1370  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1371  * implementation, but it is guaranteed to be called before the
1372  * #GObjectClass.finalize() implementation.</note>
1373  *
1374  * Since: 1.0
1375  */
1376 void
1377 clutter_actor_unmap (ClutterActor *self)
1378 {
1379   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1380
1381   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1382     return;
1383
1384   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1385 }
1386
1387 static void
1388 clutter_actor_real_show (ClutterActor *self)
1389 {
1390   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1391     {
1392       ClutterActorPrivate *priv = self->priv;
1393
1394       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1395
1396       /* we notify on the "visible" flag in the clutter_actor_show()
1397        * wrapper so the entire show signal emission completes first
1398        * (?)
1399        */
1400       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1401
1402       /* we queue a relayout unless the actor is inside a
1403        * container that explicitly told us not to
1404        */
1405       if (priv->parent != NULL &&
1406           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1407         {
1408           /* While an actor is hidden the parent may not have
1409            * allocated/requested so we need to start from scratch
1410            * and avoid the short-circuiting in
1411            * clutter_actor_queue_relayout().
1412            */
1413           priv->needs_width_request  = FALSE;
1414           priv->needs_height_request = FALSE;
1415           priv->needs_allocation     = FALSE;
1416           clutter_actor_queue_relayout (self);
1417         }
1418     }
1419 }
1420
1421 static inline void
1422 set_show_on_set_parent (ClutterActor *self,
1423                         gboolean      set_show)
1424 {
1425   ClutterActorPrivate *priv = self->priv;
1426
1427   set_show = !!set_show;
1428
1429   if (priv->show_on_set_parent == set_show)
1430     return;
1431
1432   if (priv->parent == NULL)
1433     {
1434       priv->show_on_set_parent = set_show;
1435       g_object_notify_by_pspec (G_OBJECT (self),
1436                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1437     }
1438 }
1439
1440 /**
1441  * clutter_actor_show:
1442  * @self: A #ClutterActor
1443  *
1444  * Flags an actor to be displayed. An actor that isn't shown will not
1445  * be rendered on the stage.
1446  *
1447  * Actors are visible by default.
1448  *
1449  * If this function is called on an actor without a parent, the
1450  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1451  * effect.
1452  */
1453 void
1454 clutter_actor_show (ClutterActor *self)
1455 {
1456   ClutterActorPrivate *priv;
1457
1458   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1459
1460   /* simple optimization */
1461   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1462     {
1463       /* we still need to set the :show-on-set-parent property, in
1464        * case show() is called on an unparented actor
1465        */
1466       set_show_on_set_parent (self, TRUE);
1467       return;
1468     }
1469
1470 #ifdef CLUTTER_ENABLE_DEBUG
1471   clutter_actor_verify_map_state (self);
1472 #endif
1473
1474   priv = self->priv;
1475
1476   g_object_freeze_notify (G_OBJECT (self));
1477
1478   set_show_on_set_parent (self, TRUE);
1479
1480   g_signal_emit (self, actor_signals[SHOW], 0);
1481   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1482
1483   if (priv->parent != NULL)
1484     clutter_actor_queue_redraw (priv->parent);
1485
1486   g_object_thaw_notify (G_OBJECT (self));
1487 }
1488
1489 /**
1490  * clutter_actor_show_all:
1491  * @self: a #ClutterActor
1492  *
1493  * Calls clutter_actor_show() on all children of an actor (if any).
1494  *
1495  * Since: 0.2
1496  *
1497  * Deprecated: 1.10: Actors are visible by default
1498  */
1499 void
1500 clutter_actor_show_all (ClutterActor *self)
1501 {
1502   ClutterActorClass *klass;
1503
1504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1505
1506   klass = CLUTTER_ACTOR_GET_CLASS (self);
1507   if (klass->show_all)
1508     klass->show_all (self);
1509 }
1510
1511 static void
1512 clutter_actor_real_hide (ClutterActor *self)
1513 {
1514   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1515     {
1516       ClutterActorPrivate *priv = self->priv;
1517
1518       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1519
1520       /* we notify on the "visible" flag in the clutter_actor_hide()
1521        * wrapper so the entire hide signal emission completes first
1522        * (?)
1523        */
1524       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1525
1526       /* we queue a relayout unless the actor is inside a
1527        * container that explicitly told us not to
1528        */
1529       if (priv->parent != NULL &&
1530           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1531         clutter_actor_queue_relayout (priv->parent);
1532     }
1533 }
1534
1535 /**
1536  * clutter_actor_hide:
1537  * @self: A #ClutterActor
1538  *
1539  * Flags an actor to be hidden. A hidden actor will not be
1540  * rendered on the stage.
1541  *
1542  * Actors are visible by default.
1543  *
1544  * If this function is called on an actor without a parent, the
1545  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1546  * as a side-effect.
1547  */
1548 void
1549 clutter_actor_hide (ClutterActor *self)
1550 {
1551   ClutterActorPrivate *priv;
1552
1553   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1554
1555   /* simple optimization */
1556   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1557     {
1558       /* we still need to set the :show-on-set-parent property, in
1559        * case hide() is called on an unparented actor
1560        */
1561       set_show_on_set_parent (self, FALSE);
1562       return;
1563     }
1564
1565 #ifdef CLUTTER_ENABLE_DEBUG
1566   clutter_actor_verify_map_state (self);
1567 #endif
1568
1569   priv = self->priv;
1570
1571   g_object_freeze_notify (G_OBJECT (self));
1572
1573   set_show_on_set_parent (self, FALSE);
1574
1575   g_signal_emit (self, actor_signals[HIDE], 0);
1576   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1577
1578   if (priv->parent != NULL)
1579     clutter_actor_queue_redraw (priv->parent);
1580
1581   g_object_thaw_notify (G_OBJECT (self));
1582 }
1583
1584 /**
1585  * clutter_actor_hide_all:
1586  * @self: a #ClutterActor
1587  *
1588  * Calls clutter_actor_hide() on all child actors (if any).
1589  *
1590  * Since: 0.2
1591  *
1592  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1593  *   prevent its children from being painted as well.
1594  */
1595 void
1596 clutter_actor_hide_all (ClutterActor *self)
1597 {
1598   ClutterActorClass *klass;
1599
1600   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1601
1602   klass = CLUTTER_ACTOR_GET_CLASS (self);
1603   if (klass->hide_all)
1604     klass->hide_all (self);
1605 }
1606
1607 /**
1608  * clutter_actor_realize:
1609  * @self: A #ClutterActor
1610  *
1611  * Realization informs the actor that it is attached to a stage. It
1612  * can use this to allocate resources if it wanted to delay allocation
1613  * until it would be rendered. However it is perfectly acceptable for
1614  * an actor to create resources before being realized because Clutter
1615  * only ever has a single rendering context so that actor is free to
1616  * be moved from one stage to another.
1617  *
1618  * This function does nothing if the actor is already realized.
1619  *
1620  * Because a realized actor must have realized parent actors, calling
1621  * clutter_actor_realize() will also realize all parents of the actor.
1622  *
1623  * This function does not realize child actors, except in the special
1624  * case that realizing the stage, when the stage is visible, will
1625  * suddenly map (and thus realize) the children of the stage.
1626  **/
1627 void
1628 clutter_actor_realize (ClutterActor *self)
1629 {
1630   ClutterActorPrivate *priv;
1631
1632   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1633
1634   priv = self->priv;
1635
1636 #ifdef CLUTTER_ENABLE_DEBUG
1637   clutter_actor_verify_map_state (self);
1638 #endif
1639
1640   if (CLUTTER_ACTOR_IS_REALIZED (self))
1641     return;
1642
1643   /* To be realized, our parent actors must be realized first.
1644    * This will only succeed if we're inside a toplevel.
1645    */
1646   if (priv->parent != NULL)
1647     clutter_actor_realize (priv->parent);
1648
1649   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1650     {
1651       /* toplevels can be realized at any time */
1652     }
1653   else
1654     {
1655       /* "Fail" the realization if parent is missing or unrealized;
1656        * this should really be a g_warning() not some kind of runtime
1657        * failure; how can an app possibly recover? Instead it's a bug
1658        * in the app and the app should get an explanatory warning so
1659        * someone can fix it. But for now it's too hard to fix this
1660        * because e.g. ClutterTexture needs reworking.
1661        */
1662       if (priv->parent == NULL ||
1663           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1664         return;
1665     }
1666
1667   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1668
1669   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1670   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1671
1672   g_signal_emit (self, actor_signals[REALIZE], 0);
1673
1674   /* Stage actor is allowed to unset the realized flag again in its
1675    * default signal handler, though that is a pathological situation.
1676    */
1677
1678   /* If realization "failed" we'll have to update child state. */
1679   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1680 }
1681
1682 static void
1683 clutter_actor_real_unrealize (ClutterActor *self)
1684 {
1685   /* we must be unmapped (implying our children are also unmapped) */
1686   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1687 }
1688
1689 /**
1690  * clutter_actor_unrealize:
1691  * @self: A #ClutterActor
1692  *
1693  * Unrealization informs the actor that it may be being destroyed or
1694  * moved to another stage. The actor may want to destroy any
1695  * underlying graphics resources at this point. However it is
1696  * perfectly acceptable for it to retain the resources until the actor
1697  * is destroyed because Clutter only ever uses a single rendering
1698  * context and all of the graphics resources are valid on any stage.
1699  *
1700  * Because mapped actors must be realized, actors may not be
1701  * unrealized if they are mapped. This function hides the actor to be
1702  * sure it isn't mapped, an application-visible side effect that you
1703  * may not be expecting.
1704  *
1705  * This function should not be called by application code.
1706  */
1707 void
1708 clutter_actor_unrealize (ClutterActor *self)
1709 {
1710   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1711   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1712
1713 /* This function should not really be in the public API, because
1714  * there isn't a good reason to call it. ClutterActor will already
1715  * unrealize things for you when it's important to do so.
1716  *
1717  * If you were using clutter_actor_unrealize() in a dispose
1718  * implementation, then don't, just chain up to ClutterActor's
1719  * dispose.
1720  *
1721  * If you were using clutter_actor_unrealize() to implement
1722  * unrealizing children of your container, then don't, ClutterActor
1723  * will already take care of that.
1724  *
1725  * If you were using clutter_actor_unrealize() to re-realize to
1726  * create your resources in a different way, then use
1727  * _clutter_actor_rerealize() (inside Clutter) or just call your
1728  * code that recreates your resources directly (outside Clutter).
1729  */
1730
1731 #ifdef CLUTTER_ENABLE_DEBUG
1732   clutter_actor_verify_map_state (self);
1733 #endif
1734
1735   clutter_actor_hide (self);
1736
1737   clutter_actor_unrealize_not_hiding (self);
1738 }
1739
1740 static ClutterActorTraverseVisitFlags
1741 unrealize_actor_before_children_cb (ClutterActor *self,
1742                                     int depth,
1743                                     void *user_data)
1744 {
1745   /* If an actor is already unrealized we know its children have also
1746    * already been unrealized... */
1747   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1748     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1749
1750   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1751
1752   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1753 }
1754
1755 static ClutterActorTraverseVisitFlags
1756 unrealize_actor_after_children_cb (ClutterActor *self,
1757                                    int depth,
1758                                    void *user_data)
1759 {
1760   /* We want to unset the realized flag only _after_
1761    * child actors are unrealized, to maintain invariants.
1762    */
1763   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1764   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1765   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1766 }
1767
1768 /*
1769  * clutter_actor_unrealize_not_hiding:
1770  * @self: A #ClutterActor
1771  *
1772  * Unrealization informs the actor that it may be being destroyed or
1773  * moved to another stage. The actor may want to destroy any
1774  * underlying graphics resources at this point. However it is
1775  * perfectly acceptable for it to retain the resources until the actor
1776  * is destroyed because Clutter only ever uses a single rendering
1777  * context and all of the graphics resources are valid on any stage.
1778  *
1779  * Because mapped actors must be realized, actors may not be
1780  * unrealized if they are mapped. You must hide the actor or one of
1781  * its parents before attempting to unrealize.
1782  *
1783  * This function is separate from clutter_actor_unrealize() because it
1784  * does not automatically hide the actor.
1785  * Actors need not be hidden to be unrealized, they just need to
1786  * be unmapped. In fact we don't want to mess up the application's
1787  * setting of the "visible" flag, so hiding is very undesirable.
1788  *
1789  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1790  * backward compatibility.
1791  */
1792 static void
1793 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1794 {
1795   _clutter_actor_traverse (self,
1796                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1797                            unrealize_actor_before_children_cb,
1798                            unrealize_actor_after_children_cb,
1799                            NULL);
1800 }
1801
1802 /*
1803  * _clutter_actor_rerealize:
1804  * @self: A #ClutterActor
1805  * @callback: Function to call while unrealized
1806  * @data: data for callback
1807  *
1808  * If an actor is already unrealized, this just calls the callback.
1809  *
1810  * If it is realized, it unrealizes temporarily, calls the callback,
1811  * and then re-realizes the actor.
1812  *
1813  * As a side effect, leaves all children of the actor unrealized if
1814  * the actor was realized but not showing.  This is because when we
1815  * unrealize the actor temporarily we must unrealize its children
1816  * (e.g. children of a stage can't be realized if stage window is
1817  * gone). And we aren't clever enough to save the realization state of
1818  * all children. In most cases this should not matter, because
1819  * the children will automatically realize when they next become mapped.
1820  */
1821 void
1822 _clutter_actor_rerealize (ClutterActor    *self,
1823                           ClutterCallback  callback,
1824                           void            *data)
1825 {
1826   gboolean was_mapped;
1827   gboolean was_showing;
1828   gboolean was_realized;
1829
1830   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1831
1832 #ifdef CLUTTER_ENABLE_DEBUG
1833   clutter_actor_verify_map_state (self);
1834 #endif
1835
1836   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1837   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1838   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1839
1840   /* Must be unmapped to unrealize. Note we only have to hide this
1841    * actor if it was mapped (if all parents were showing).  If actor
1842    * is merely visible (but not mapped), then that's fine, we can
1843    * leave it visible.
1844    */
1845   if (was_mapped)
1846     clutter_actor_hide (self);
1847
1848   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1849
1850   /* unrealize self and all children */
1851   clutter_actor_unrealize_not_hiding (self);
1852
1853   if (callback != NULL)
1854     {
1855       (* callback) (self, data);
1856     }
1857
1858   if (was_showing)
1859     clutter_actor_show (self); /* will realize only if mapping implies it */
1860   else if (was_realized)
1861     clutter_actor_realize (self); /* realize self and all parents */
1862 }
1863
1864 static void
1865 clutter_actor_real_pick (ClutterActor       *self,
1866                          const ClutterColor *color)
1867 {
1868   /* the default implementation is just to paint a rectangle
1869    * with the same size of the actor using the passed color
1870    */
1871   if (clutter_actor_should_pick_paint (self))
1872     {
1873       ClutterActorBox box = { 0, };
1874       float width, height;
1875
1876       clutter_actor_get_allocation_box (self, &box);
1877
1878       width = box.x2 - box.x1;
1879       height = box.y2 - box.y1;
1880
1881       cogl_set_source_color4ub (color->red,
1882                                 color->green,
1883                                 color->blue,
1884                                 color->alpha);
1885
1886       cogl_rectangle (0, 0, width, height);
1887     }
1888
1889   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1890    * with existing container classes that override the pick() virtual
1891    * and chain up to the default implementation - otherwise we'll end up
1892    * painting our children twice.
1893    *
1894    * this has to go away for 2.0; hopefully along the pick() itself.
1895    */
1896   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1897     {
1898       ClutterActor *iter;
1899
1900       for (iter = self->priv->first_child;
1901            iter != NULL;
1902            iter = iter->priv->next_sibling)
1903         clutter_actor_paint (iter);
1904     }
1905 }
1906
1907 /**
1908  * clutter_actor_should_pick_paint:
1909  * @self: A #ClutterActor
1910  *
1911  * Should be called inside the implementation of the
1912  * #ClutterActor::pick virtual function in order to check whether
1913  * the actor should paint itself in pick mode or not.
1914  *
1915  * This function should never be called directly by applications.
1916  *
1917  * Return value: %TRUE if the actor should paint its silhouette,
1918  *   %FALSE otherwise
1919  */
1920 gboolean
1921 clutter_actor_should_pick_paint (ClutterActor *self)
1922 {
1923   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1924
1925   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1926       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1927        CLUTTER_ACTOR_IS_REACTIVE (self)))
1928     return TRUE;
1929
1930   return FALSE;
1931 }
1932
1933 static void
1934 clutter_actor_real_get_preferred_width (ClutterActor *self,
1935                                         gfloat        for_height,
1936                                         gfloat       *min_width_p,
1937                                         gfloat       *natural_width_p)
1938 {
1939   ClutterActorPrivate *priv = self->priv;
1940
1941   if (priv->n_children != 0 &&
1942       priv->layout_manager != NULL)
1943     {
1944       ClutterContainer *container = CLUTTER_CONTAINER (self);
1945
1946       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1947                     "for the preferred width",
1948                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1949                     priv->layout_manager);
1950
1951       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1952                                                   container,
1953                                                   for_height,
1954                                                   min_width_p,
1955                                                   natural_width_p);
1956
1957       return;
1958     }
1959
1960   /* Default implementation is always 0x0, usually an actor
1961    * using this default is relying on someone to set the
1962    * request manually
1963    */
1964   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1965
1966   if (min_width_p)
1967     *min_width_p = 0;
1968
1969   if (natural_width_p)
1970     *natural_width_p = 0;
1971 }
1972
1973 static void
1974 clutter_actor_real_get_preferred_height (ClutterActor *self,
1975                                          gfloat        for_width,
1976                                          gfloat       *min_height_p,
1977                                          gfloat       *natural_height_p)
1978 {
1979   ClutterActorPrivate *priv = self->priv;
1980
1981   if (priv->n_children != 0 &&
1982       priv->layout_manager != NULL)
1983     {
1984       ClutterContainer *container = CLUTTER_CONTAINER (self);
1985
1986       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1987                     "for the preferred height",
1988                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1989                     priv->layout_manager);
1990
1991       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1992                                                    container,
1993                                                    for_width,
1994                                                    min_height_p,
1995                                                    natural_height_p);
1996
1997       return;
1998     }
1999   /* Default implementation is always 0x0, usually an actor
2000    * using this default is relying on someone to set the
2001    * request manually
2002    */
2003   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2004
2005   if (min_height_p)
2006     *min_height_p = 0;
2007
2008   if (natural_height_p)
2009     *natural_height_p = 0;
2010 }
2011
2012 static void
2013 clutter_actor_store_old_geometry (ClutterActor    *self,
2014                                   ClutterActorBox *box)
2015 {
2016   *box = self->priv->allocation;
2017 }
2018
2019 static inline void
2020 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2021                                           const ClutterActorBox *old)
2022 {
2023   ClutterActorPrivate *priv = self->priv;
2024   GObject *obj = G_OBJECT (self);
2025
2026   g_object_freeze_notify (obj);
2027
2028   /* to avoid excessive requisition or allocation cycles we
2029    * use the cached values.
2030    *
2031    * - if we don't have an allocation we assume that we need
2032    *   to notify anyway
2033    * - if we don't have a width or a height request we notify
2034    *   width and height
2035    * - if we have a valid allocation then we check the old
2036    *   bounding box with the current allocation and we notify
2037    *   the changes
2038    */
2039   if (priv->needs_allocation)
2040     {
2041       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2042       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2043       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2044       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2045     }
2046   else if (priv->needs_width_request || priv->needs_height_request)
2047     {
2048       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2049       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2050     }
2051   else
2052     {
2053       gfloat xu, yu;
2054       gfloat widthu, heightu;
2055
2056       xu = priv->allocation.x1;
2057       yu = priv->allocation.y1;
2058       widthu = priv->allocation.x2 - priv->allocation.x1;
2059       heightu = priv->allocation.y2 - priv->allocation.y1;
2060
2061       if (xu != old->x1)
2062         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2063
2064       if (yu != old->y1)
2065         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2066
2067       if (widthu != (old->x2 - old->x1))
2068         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2069
2070       if (heightu != (old->y2 - old->y1))
2071         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2072     }
2073
2074   g_object_thaw_notify (obj);
2075 }
2076
2077 /*< private >
2078  * clutter_actor_set_allocation_internal:
2079  * @self: a #ClutterActor
2080  * @box: a #ClutterActorBox
2081  * @flags: allocation flags
2082  *
2083  * Stores the allocation of @self.
2084  *
2085  * This function only performs basic storage and property notification.
2086  *
2087  * This function should be called by clutter_actor_set_allocation()
2088  * and by the default implementation of #ClutterActorClass.allocate().
2089  *
2090  * Return value: %TRUE if the allocation of the #ClutterActor has been
2091  *   changed, and %FALSE otherwise
2092  */
2093 static inline gboolean
2094 clutter_actor_set_allocation_internal (ClutterActor           *self,
2095                                        const ClutterActorBox  *box,
2096                                        ClutterAllocationFlags  flags)
2097 {
2098   ClutterActorPrivate *priv = self->priv;
2099   GObject *obj;
2100   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2101   gboolean flags_changed;
2102   gboolean retval;
2103   ClutterActorBox old_alloc = { 0, };
2104
2105   obj = G_OBJECT (self);
2106
2107   g_object_freeze_notify (obj);
2108
2109   clutter_actor_store_old_geometry (self, &old_alloc);
2110
2111   x1_changed = priv->allocation.x1 != box->x1;
2112   y1_changed = priv->allocation.y1 != box->y1;
2113   x2_changed = priv->allocation.x2 != box->x2;
2114   y2_changed = priv->allocation.y2 != box->y2;
2115
2116   flags_changed = priv->allocation_flags != flags;
2117
2118   priv->allocation = *box;
2119   priv->allocation_flags = flags;
2120
2121   /* allocation is authoritative */
2122   priv->needs_width_request = FALSE;
2123   priv->needs_height_request = FALSE;
2124   priv->needs_allocation = FALSE;
2125
2126   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2127     {
2128       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2129                     _clutter_actor_get_debug_name (self));
2130
2131       priv->transform_valid = FALSE;
2132
2133       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2134
2135       /* if the allocation changes, so does the content box */
2136       if (priv->content != NULL)
2137         g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2138
2139       retval = TRUE;
2140     }
2141   else
2142     retval = FALSE;
2143
2144   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2145
2146   g_object_thaw_notify (obj);
2147
2148   return retval;
2149 }
2150
2151 static void clutter_actor_real_allocate (ClutterActor           *self,
2152                                          const ClutterActorBox  *box,
2153                                          ClutterAllocationFlags  flags);
2154
2155 static inline void
2156 clutter_actor_maybe_layout_children (ClutterActor           *self,
2157                                      const ClutterActorBox  *allocation,
2158                                      ClutterAllocationFlags  flags)
2159 {
2160   ClutterActorPrivate *priv = self->priv;
2161
2162   /* this is going to be a bit hard to follow, so let's put an explanation
2163    * here.
2164    *
2165    * we want ClutterActor to have a default layout manager if the actor was
2166    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2167    *
2168    * we also want any subclass of ClutterActor that does not override the
2169    * ::allocate() virtual function to delegate to a layout manager.
2170    *
2171    * finally, we want to allow people subclassing ClutterActor and overriding
2172    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2173    *
2174    * on the other hand, we want existing actor subclasses overriding the
2175    * ::allocate() virtual function and chaining up to the parent's
2176    * implementation to continue working without allocating their children
2177    * twice, or without entering an allocation loop.
2178    *
2179    * for the first two points, we check if the class of the actor is
2180    * overridding the ::allocate() virtual function; if it isn't, then we
2181    * follow through with checking whether we have children and a layout
2182    * manager, and eventually calling clutter_layout_manager_allocate().
2183    *
2184    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2185    * allocation flags that we got passed, and if it is present, we continue
2186    * with the check above.
2187    *
2188    * if neither of these two checks yields a positive result, we just
2189    * assume that the ::allocate() virtual function that resulted in this
2190    * function being called will also allocate the children of the actor.
2191    */
2192
2193   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2194     goto check_layout;
2195
2196   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2197     goto check_layout;
2198
2199   return;
2200
2201 check_layout:
2202   if (priv->n_children != 0 &&
2203       priv->layout_manager != NULL)
2204     {
2205       ClutterContainer *container = CLUTTER_CONTAINER (self);
2206       ClutterAllocationFlags children_flags;
2207       ClutterActorBox children_box;
2208
2209       /* normalize the box passed to the layout manager */
2210       children_box.x1 = children_box.y1 = 0.f;
2211       children_box.x2 = (allocation->x2 - allocation->x1);
2212       children_box.y2 = (allocation->y2 - allocation->y1);
2213
2214       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2215        * the actor's children, since it refers only to the current
2216        * actor's allocation.
2217        */
2218       children_flags = flags;
2219       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2220
2221       CLUTTER_NOTE (LAYOUT,
2222                     "Allocating %d children of %s "
2223                     "at { %.2f, %.2f - %.2f x %.2f } "
2224                     "using %s",
2225                     priv->n_children,
2226                     _clutter_actor_get_debug_name (self),
2227                     allocation->x1,
2228                     allocation->y1,
2229                     (allocation->x2 - allocation->x1),
2230                     (allocation->y2 - allocation->y1),
2231                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2232
2233       clutter_layout_manager_allocate (priv->layout_manager,
2234                                        container,
2235                                        &children_box,
2236                                        children_flags);
2237     }
2238 }
2239
2240 static void
2241 clutter_actor_real_allocate (ClutterActor           *self,
2242                              const ClutterActorBox  *box,
2243                              ClutterAllocationFlags  flags)
2244 {
2245   ClutterActorPrivate *priv = self->priv;
2246   gboolean changed;
2247
2248   g_object_freeze_notify (G_OBJECT (self));
2249
2250   changed = clutter_actor_set_allocation_internal (self, box, flags);
2251
2252   /* we allocate our children before we notify changes in our geometry,
2253    * so that people connecting to properties will be able to get valid
2254    * data out of the sub-tree of the scene graph that has this actor at
2255    * the root.
2256    */
2257   clutter_actor_maybe_layout_children (self, box, flags);
2258
2259   if (changed)
2260     {
2261       ClutterActorBox signal_box = priv->allocation;
2262       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2263
2264       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2265                      &signal_box,
2266                      signal_flags);
2267     }
2268
2269   g_object_thaw_notify (G_OBJECT (self));
2270 }
2271
2272 static void
2273 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2274                                     ClutterActor *origin)
2275 {
2276   /* no point in queuing a redraw on a destroyed actor */
2277   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2278     return;
2279
2280   /* NB: We can't bail out early here if the actor is hidden in case
2281    * the actor bas been cloned. In this case the clone will need to
2282    * receive the signal so it can queue its own redraw.
2283    */
2284
2285   /* calls klass->queue_redraw in default handler */
2286   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2287 }
2288
2289 static void
2290 clutter_actor_real_queue_redraw (ClutterActor *self,
2291                                  ClutterActor *origin)
2292 {
2293   ClutterActor *parent;
2294
2295   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2296                 _clutter_actor_get_debug_name (self),
2297                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2298                                : "same actor");
2299
2300   /* no point in queuing a redraw on a destroyed actor */
2301   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2302     return;
2303
2304   /* If the queue redraw is coming from a child then the actor has
2305      become dirty and any queued effect is no longer valid */
2306   if (self != origin)
2307     {
2308       self->priv->is_dirty = TRUE;
2309       self->priv->effect_to_redraw = NULL;
2310     }
2311
2312   /* If the actor isn't visible, we still had to emit the signal
2313    * to allow for a ClutterClone, but the appearance of the parent
2314    * won't change so we don't have to propagate up the hierarchy.
2315    */
2316   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2317     return;
2318
2319   /* Although we could determine here that a full stage redraw
2320    * has already been queued and immediately bail out, we actually
2321    * guarantee that we will propagate a queue-redraw signal to our
2322    * parent at least once so that it's possible to implement a
2323    * container that tracks which of its children have queued a
2324    * redraw.
2325    */
2326   if (self->priv->propagated_one_redraw)
2327     {
2328       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2329       if (stage != NULL &&
2330           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2331         return;
2332     }
2333
2334   self->priv->propagated_one_redraw = TRUE;
2335
2336   /* notify parents, if they are all visible eventually we'll
2337    * queue redraw on the stage, which queues the redraw idle.
2338    */
2339   parent = clutter_actor_get_parent (self);
2340   if (parent != NULL)
2341     {
2342       /* this will go up recursively */
2343       _clutter_actor_signal_queue_redraw (parent, origin);
2344     }
2345 }
2346
2347 static void
2348 clutter_actor_real_queue_relayout (ClutterActor *self)
2349 {
2350   ClutterActorPrivate *priv = self->priv;
2351
2352   /* no point in queueing a redraw on a destroyed actor */
2353   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2354     return;
2355
2356   priv->needs_width_request  = TRUE;
2357   priv->needs_height_request = TRUE;
2358   priv->needs_allocation     = TRUE;
2359
2360   /* reset the cached size requests */
2361   memset (priv->width_requests, 0,
2362           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2363   memset (priv->height_requests, 0,
2364           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2365
2366   /* We need to go all the way up the hierarchy */
2367   if (priv->parent != NULL)
2368     _clutter_actor_queue_only_relayout (priv->parent);
2369 }
2370
2371 /**
2372  * clutter_actor_apply_relative_transform_to_point:
2373  * @self: A #ClutterActor
2374  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2375  *   default #ClutterStage
2376  * @point: A point as #ClutterVertex
2377  * @vertex: (out caller-allocates): The translated #ClutterVertex
2378  *
2379  * Transforms @point in coordinates relative to the actor into
2380  * ancestor-relative coordinates using the relevant transform
2381  * stack (i.e. scale, rotation, etc).
2382  *
2383  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2384  * this case, the coordinates returned will be the coordinates on
2385  * the stage before the projection is applied. This is different from
2386  * the behaviour of clutter_actor_apply_transform_to_point().
2387  *
2388  * Since: 0.6
2389  */
2390 void
2391 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2392                                                  ClutterActor        *ancestor,
2393                                                  const ClutterVertex *point,
2394                                                  ClutterVertex       *vertex)
2395 {
2396   gfloat w;
2397   CoglMatrix matrix;
2398
2399   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2400   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2401   g_return_if_fail (point != NULL);
2402   g_return_if_fail (vertex != NULL);
2403
2404   *vertex = *point;
2405   w = 1.0;
2406
2407   if (ancestor == NULL)
2408     ancestor = _clutter_actor_get_stage_internal (self);
2409
2410   if (ancestor == NULL)
2411     {
2412       *vertex = *point;
2413       return;
2414     }
2415
2416   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2417   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2418 }
2419
2420 static gboolean
2421 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2422                                          const ClutterVertex *vertices_in,
2423                                          ClutterVertex *vertices_out,
2424                                          int n_vertices)
2425 {
2426   ClutterActor *stage;
2427   CoglMatrix modelview;
2428   CoglMatrix projection;
2429   float viewport[4];
2430
2431   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2432
2433   stage = _clutter_actor_get_stage_internal (self);
2434
2435   /* We really can't do anything meaningful in this case so don't try
2436    * to do any transform */
2437   if (stage == NULL)
2438     return FALSE;
2439
2440   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2441    * that gets us to stage coordinates, we want to go all the way to eye
2442    * coordinates */
2443   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2444
2445   /* Fetch the projection and viewport */
2446   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2447   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2448                                &viewport[0],
2449                                &viewport[1],
2450                                &viewport[2],
2451                                &viewport[3]);
2452
2453   _clutter_util_fully_transform_vertices (&modelview,
2454                                           &projection,
2455                                           viewport,
2456                                           vertices_in,
2457                                           vertices_out,
2458                                           n_vertices);
2459
2460   return TRUE;
2461 }
2462
2463 /**
2464  * clutter_actor_apply_transform_to_point:
2465  * @self: A #ClutterActor
2466  * @point: A point as #ClutterVertex
2467  * @vertex: (out caller-allocates): The translated #ClutterVertex
2468  *
2469  * Transforms @point in coordinates relative to the actor
2470  * into screen-relative coordinates with the current actor
2471  * transformation (i.e. scale, rotation, etc)
2472  *
2473  * Since: 0.4
2474  **/
2475 void
2476 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2477                                         const ClutterVertex *point,
2478                                         ClutterVertex       *vertex)
2479 {
2480   g_return_if_fail (point != NULL);
2481   g_return_if_fail (vertex != NULL);
2482   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2483 }
2484
2485 /*
2486  * _clutter_actor_get_relative_transformation_matrix:
2487  * @self: The actor whose coordinate space you want to transform from.
2488  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2489  *            or %NULL if you want to transform all the way to eye coordinates.
2490  * @matrix: A #CoglMatrix to store the transformation
2491  *
2492  * This gets a transformation @matrix that will transform coordinates from the
2493  * coordinate space of @self into the coordinate space of @ancestor.
2494  *
2495  * For example if you need a matrix that can transform the local actor
2496  * coordinates of @self into stage coordinates you would pass the actor's stage
2497  * pointer as the @ancestor.
2498  *
2499  * If you pass %NULL then the transformation will take you all the way through
2500  * to eye coordinates. This can be useful if you want to extract the entire
2501  * modelview transform that Clutter applies before applying the projection
2502  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2503  * using cogl_set_modelview_matrix() for example then you would want a matrix
2504  * that transforms into eye coordinates.
2505  *
2506  * <note><para>This function explicitly initializes the given @matrix. If you just
2507  * want clutter to multiply a relative transformation with an existing matrix
2508  * you can use clutter_actor_apply_relative_transformation_matrix()
2509  * instead.</para></note>
2510  *
2511  */
2512 /* XXX: We should consider caching the stage relative modelview along with
2513  * the actor itself */
2514 static void
2515 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2516                                                    ClutterActor *ancestor,
2517                                                    CoglMatrix *matrix)
2518 {
2519   cogl_matrix_init_identity (matrix);
2520
2521   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2522 }
2523
2524 /* Project the given @box into stage window coordinates, writing the
2525  * transformed vertices to @verts[]. */
2526 static gboolean
2527 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2528                                           const ClutterActorBox *box,
2529                                           ClutterVertex          verts[])
2530 {
2531   ClutterVertex box_vertices[4];
2532
2533   box_vertices[0].x = box->x1;
2534   box_vertices[0].y = box->y1;
2535   box_vertices[0].z = 0;
2536   box_vertices[1].x = box->x2;
2537   box_vertices[1].y = box->y1;
2538   box_vertices[1].z = 0;
2539   box_vertices[2].x = box->x1;
2540   box_vertices[2].y = box->y2;
2541   box_vertices[2].z = 0;
2542   box_vertices[3].x = box->x2;
2543   box_vertices[3].y = box->y2;
2544   box_vertices[3].z = 0;
2545
2546   return
2547     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2548 }
2549
2550 /**
2551  * clutter_actor_get_allocation_vertices:
2552  * @self: A #ClutterActor
2553  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2554  *   against, or %NULL to use the #ClutterStage
2555  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2556  *   location for an array of 4 #ClutterVertex in which to store the result
2557  *
2558  * Calculates the transformed coordinates of the four corners of the
2559  * actor in the plane of @ancestor. The returned vertices relate to
2560  * the #ClutterActorBox coordinates as follows:
2561  * <itemizedlist>
2562  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2563  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2564  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2565  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2566  * </itemizedlist>
2567  *
2568  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2569  * this case, the coordinates returned will be the coordinates on
2570  * the stage before the projection is applied. This is different from
2571  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2572  *
2573  * Since: 0.6
2574  */
2575 void
2576 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2577                                        ClutterActor  *ancestor,
2578                                        ClutterVertex  verts[])
2579 {
2580   ClutterActorPrivate *priv;
2581   ClutterActorBox box;
2582   ClutterVertex vertices[4];
2583   CoglMatrix modelview;
2584
2585   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2586   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2587
2588   if (ancestor == NULL)
2589     ancestor = _clutter_actor_get_stage_internal (self);
2590
2591   /* Fallback to a NOP transform if the actor isn't parented under a
2592    * stage. */
2593   if (ancestor == NULL)
2594     ancestor = self;
2595
2596   priv = self->priv;
2597
2598   /* if the actor needs to be allocated we force a relayout, so that
2599    * we will have valid values to use in the transformations */
2600   if (priv->needs_allocation)
2601     {
2602       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2603       if (stage)
2604         _clutter_stage_maybe_relayout (stage);
2605       else
2606         {
2607           box.x1 = box.y1 = 0;
2608           /* The result isn't really meaningful in this case but at
2609            * least try to do something *vaguely* reasonable... */
2610           clutter_actor_get_size (self, &box.x2, &box.y2);
2611         }
2612     }
2613
2614   clutter_actor_get_allocation_box (self, &box);
2615
2616   vertices[0].x = box.x1;
2617   vertices[0].y = box.y1;
2618   vertices[0].z = 0;
2619   vertices[1].x = box.x2;
2620   vertices[1].y = box.y1;
2621   vertices[1].z = 0;
2622   vertices[2].x = box.x1;
2623   vertices[2].y = box.y2;
2624   vertices[2].z = 0;
2625   vertices[3].x = box.x2;
2626   vertices[3].y = box.y2;
2627   vertices[3].z = 0;
2628
2629   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2630                                                      &modelview);
2631
2632   cogl_matrix_transform_points (&modelview,
2633                                 3,
2634                                 sizeof (ClutterVertex),
2635                                 vertices,
2636                                 sizeof (ClutterVertex),
2637                                 vertices,
2638                                 4);
2639 }
2640
2641 /**
2642  * clutter_actor_get_abs_allocation_vertices:
2643  * @self: A #ClutterActor
2644  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2645  *   of 4 #ClutterVertex where to store the result.
2646  *
2647  * Calculates the transformed screen coordinates of the four corners of
2648  * the actor; the returned vertices relate to the #ClutterActorBox
2649  * coordinates  as follows:
2650  * <itemizedlist>
2651  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2652  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2653  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2654  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2655  * </itemizedlist>
2656  *
2657  * Since: 0.4
2658  */
2659 void
2660 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2661                                            ClutterVertex  verts[])
2662 {
2663   ClutterActorPrivate *priv;
2664   ClutterActorBox actor_space_allocation;
2665
2666   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2667
2668   priv = self->priv;
2669
2670   /* if the actor needs to be allocated we force a relayout, so that
2671    * the actor allocation box will be valid for
2672    * _clutter_actor_transform_and_project_box()
2673    */
2674   if (priv->needs_allocation)
2675     {
2676       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2677       /* There's nothing meaningful we can do now */
2678       if (!stage)
2679         return;
2680
2681       _clutter_stage_maybe_relayout (stage);
2682     }
2683
2684   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2685    * own coordinate space... */
2686   actor_space_allocation.x1 = 0;
2687   actor_space_allocation.y1 = 0;
2688   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2689   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2690   _clutter_actor_transform_and_project_box (self,
2691                                             &actor_space_allocation,
2692                                             verts);
2693 }
2694
2695 static void
2696 clutter_actor_real_apply_transform (ClutterActor *self,
2697                                     CoglMatrix   *matrix)
2698 {
2699   ClutterActorPrivate *priv = self->priv;
2700
2701   if (!priv->transform_valid)
2702     {
2703       CoglMatrix *transform = &priv->transform;
2704       const ClutterTransformInfo *info;
2705
2706       info = _clutter_actor_get_transform_info_or_defaults (self);
2707
2708       cogl_matrix_init_identity (transform);
2709
2710       cogl_matrix_translate (transform,
2711                              priv->allocation.x1,
2712                              priv->allocation.y1,
2713                              0.0);
2714
2715       if (info->depth)
2716         cogl_matrix_translate (transform, 0, 0, info->depth);
2717
2718       /*
2719        * because the rotation involves translations, we must scale
2720        * before applying the rotations (if we apply the scale after
2721        * the rotations, the translations included in the rotation are
2722        * not scaled and so the entire object will move on the screen
2723        * as a result of rotating it).
2724        */
2725       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2726         {
2727           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2728                                         &info->scale_center,
2729                                         cogl_matrix_scale (transform,
2730                                                            info->scale_x,
2731                                                            info->scale_y,
2732                                                            1.0));
2733         }
2734
2735       if (info->rz_angle)
2736         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2737                                       &info->rz_center,
2738                                       cogl_matrix_rotate (transform,
2739                                                           info->rz_angle,
2740                                                           0, 0, 1.0));
2741
2742       if (info->ry_angle)
2743         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2744                                       &info->ry_center,
2745                                       cogl_matrix_rotate (transform,
2746                                                           info->ry_angle,
2747                                                           0, 1.0, 0));
2748
2749       if (info->rx_angle)
2750         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2751                                       &info->rx_center,
2752                                       cogl_matrix_rotate (transform,
2753                                                           info->rx_angle,
2754                                                           1.0, 0, 0));
2755
2756       if (!clutter_anchor_coord_is_zero (&info->anchor))
2757         {
2758           gfloat x, y, z;
2759
2760           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2761           cogl_matrix_translate (transform, -x, -y, -z);
2762         }
2763
2764       priv->transform_valid = TRUE;
2765     }
2766
2767   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2768 }
2769
2770 /* Applies the transforms associated with this actor to the given
2771  * matrix. */
2772 void
2773 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2774                                           CoglMatrix *matrix)
2775 {
2776   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2777 }
2778
2779 /*
2780  * clutter_actor_apply_relative_transformation_matrix:
2781  * @self: The actor whose coordinate space you want to transform from.
2782  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2783  *            or %NULL if you want to transform all the way to eye coordinates.
2784  * @matrix: A #CoglMatrix to apply the transformation too.
2785  *
2786  * This multiplies a transform with @matrix that will transform coordinates
2787  * from the coordinate space of @self into the coordinate space of @ancestor.
2788  *
2789  * For example if you need a matrix that can transform the local actor
2790  * coordinates of @self into stage coordinates you would pass the actor's stage
2791  * pointer as the @ancestor.
2792  *
2793  * If you pass %NULL then the transformation will take you all the way through
2794  * to eye coordinates. This can be useful if you want to extract the entire
2795  * modelview transform that Clutter applies before applying the projection
2796  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2797  * using cogl_set_modelview_matrix() for example then you would want a matrix
2798  * that transforms into eye coordinates.
2799  *
2800  * <note>This function doesn't initialize the given @matrix, it simply
2801  * multiplies the requested transformation matrix with the existing contents of
2802  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2803  * before calling this function, or you can use
2804  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2805  */
2806 void
2807 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2808                                                      ClutterActor *ancestor,
2809                                                      CoglMatrix *matrix)
2810 {
2811   ClutterActor *parent;
2812
2813   /* Note we terminate before ever calling stage->apply_transform()
2814    * since that would conceptually be relative to the underlying
2815    * window OpenGL coordinates so we'd need a special @ancestor
2816    * value to represent the fake parent of the stage. */
2817   if (self == ancestor)
2818     return;
2819
2820   parent = clutter_actor_get_parent (self);
2821
2822   if (parent != NULL)
2823     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2824                                                          matrix);
2825
2826   _clutter_actor_apply_modelview_transform (self, matrix);
2827 }
2828
2829 static void
2830 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2831                                        ClutterPaintVolume *pv,
2832                                        const char *label,
2833                                        const CoglColor *color)
2834 {
2835   static CoglPipeline *outline = NULL;
2836   CoglPrimitive *prim;
2837   ClutterVertex line_ends[12 * 2];
2838   int n_vertices;
2839   CoglContext *ctx =
2840     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2841   /* XXX: at some point we'll query this from the stage but we can't
2842    * do that until the osx backend uses Cogl natively. */
2843   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2844
2845   if (outline == NULL)
2846     outline = cogl_pipeline_new (ctx);
2847
2848   _clutter_paint_volume_complete (pv);
2849
2850   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2851
2852   /* Front face */
2853   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2854   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2855   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2856   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2857
2858   if (!pv->is_2d)
2859     {
2860       /* Back face */
2861       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2862       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2863       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2864       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2865
2866       /* Lines connecting front face to back face */
2867       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2868       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2869       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2870       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2871     }
2872
2873   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2874                                 n_vertices,
2875                                 (CoglVertexP3 *)line_ends);
2876
2877   cogl_pipeline_set_color (outline, color);
2878   cogl_framebuffer_draw_primitive (fb, outline, prim);
2879   cogl_object_unref (prim);
2880
2881   if (label)
2882     {
2883       PangoLayout *layout;
2884       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2885       pango_layout_set_text (layout, label, -1);
2886       cogl_pango_render_layout (layout,
2887                                 pv->vertices[0].x,
2888                                 pv->vertices[0].y,
2889                                 color,
2890                                 0);
2891       g_object_unref (layout);
2892     }
2893 }
2894
2895 static void
2896 _clutter_actor_draw_paint_volume (ClutterActor *self)
2897 {
2898   ClutterPaintVolume *pv;
2899   CoglColor color;
2900
2901   pv = _clutter_actor_get_paint_volume_mutable (self);
2902   if (!pv)
2903     {
2904       gfloat width, height;
2905       ClutterPaintVolume fake_pv;
2906
2907       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2908       _clutter_paint_volume_init_static (&fake_pv, stage);
2909
2910       clutter_actor_get_size (self, &width, &height);
2911       clutter_paint_volume_set_width (&fake_pv, width);
2912       clutter_paint_volume_set_height (&fake_pv, height);
2913
2914       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2915       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2916                                              _clutter_actor_get_debug_name (self),
2917                                              &color);
2918
2919       clutter_paint_volume_free (&fake_pv);
2920     }
2921   else
2922     {
2923       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2924       _clutter_actor_draw_paint_volume_full (self, pv,
2925                                              _clutter_actor_get_debug_name (self),
2926                                              &color);
2927     }
2928 }
2929
2930 static void
2931 _clutter_actor_paint_cull_result (ClutterActor *self,
2932                                   gboolean success,
2933                                   ClutterCullResult result)
2934 {
2935   ClutterPaintVolume *pv;
2936   CoglColor color;
2937
2938   if (success)
2939     {
2940       if (result == CLUTTER_CULL_RESULT_IN)
2941         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2942       else if (result == CLUTTER_CULL_RESULT_OUT)
2943         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2944       else
2945         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2946     }
2947   else
2948     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2949
2950   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2951     _clutter_actor_draw_paint_volume_full (self, pv,
2952                                            _clutter_actor_get_debug_name (self),
2953                                            &color);
2954   else
2955     {
2956       PangoLayout *layout;
2957       char *label =
2958         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2959       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2960       cogl_set_source_color (&color);
2961
2962       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2963       pango_layout_set_text (layout, label, -1);
2964       cogl_pango_render_layout (layout,
2965                                 0,
2966                                 0,
2967                                 &color,
2968                                 0);
2969       g_free (label);
2970       g_object_unref (layout);
2971     }
2972 }
2973
2974 static int clone_paint_level = 0;
2975
2976 void
2977 _clutter_actor_push_clone_paint (void)
2978 {
2979   clone_paint_level++;
2980 }
2981
2982 void
2983 _clutter_actor_pop_clone_paint (void)
2984 {
2985   clone_paint_level--;
2986 }
2987
2988 static gboolean
2989 in_clone_paint (void)
2990 {
2991   return clone_paint_level > 0;
2992 }
2993
2994 /* Returns TRUE if the actor can be ignored */
2995 /* FIXME: we should return a ClutterCullResult, and
2996  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2997  * means there's no point in trying to cull descendants of the current
2998  * node. */
2999 static gboolean
3000 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3001 {
3002   ClutterActorPrivate *priv = self->priv;
3003   ClutterActor *stage;
3004   const ClutterPlane *stage_clip;
3005
3006   if (!priv->last_paint_volume_valid)
3007     {
3008       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3009                     "->last_paint_volume_valid == FALSE",
3010                     _clutter_actor_get_debug_name (self));
3011       return FALSE;
3012     }
3013
3014   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3015     return FALSE;
3016
3017   stage = _clutter_actor_get_stage_internal (self);
3018   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3019   if (G_UNLIKELY (!stage_clip))
3020     {
3021       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3022                     "No stage clip set",
3023                     _clutter_actor_get_debug_name (self));
3024       return FALSE;
3025     }
3026
3027   if (cogl_get_draw_framebuffer () !=
3028       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3029     {
3030       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3031                     "Current framebuffer doesn't correspond to stage",
3032                     _clutter_actor_get_debug_name (self));
3033       return FALSE;
3034     }
3035
3036   *result_out =
3037     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3038   return TRUE;
3039 }
3040
3041 static void
3042 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3043 {
3044   ClutterActorPrivate *priv = self->priv;
3045   const ClutterPaintVolume *pv;
3046
3047   if (priv->last_paint_volume_valid)
3048     {
3049       clutter_paint_volume_free (&priv->last_paint_volume);
3050       priv->last_paint_volume_valid = FALSE;
3051     }
3052
3053   pv = clutter_actor_get_paint_volume (self);
3054   if (!pv)
3055     {
3056       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3057                     "Actor failed to report a paint volume",
3058                     _clutter_actor_get_debug_name (self));
3059       return;
3060     }
3061
3062   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3063
3064   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3065                                             NULL); /* eye coordinates */
3066
3067   priv->last_paint_volume_valid = TRUE;
3068 }
3069
3070 static inline gboolean
3071 actor_has_shader_data (ClutterActor *self)
3072 {
3073   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3074 }
3075
3076 guint32
3077 _clutter_actor_get_pick_id (ClutterActor *self)
3078 {
3079   if (self->priv->pick_id < 0)
3080     return 0;
3081
3082   return self->priv->pick_id;
3083 }
3084
3085 /* This is the same as clutter_actor_add_effect except that it doesn't
3086    queue a redraw and it doesn't notify on the effect property */
3087 static void
3088 _clutter_actor_add_effect_internal (ClutterActor  *self,
3089                                     ClutterEffect *effect)
3090 {
3091   ClutterActorPrivate *priv = self->priv;
3092
3093   if (priv->effects == NULL)
3094     {
3095       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3096       priv->effects->actor = self;
3097     }
3098
3099   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3100 }
3101
3102 /* This is the same as clutter_actor_remove_effect except that it doesn't
3103    queue a redraw and it doesn't notify on the effect property */
3104 static void
3105 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3106                                        ClutterEffect *effect)
3107 {
3108   ClutterActorPrivate *priv = self->priv;
3109
3110   if (priv->effects == NULL)
3111     return;
3112
3113   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3114 }
3115
3116 static gboolean
3117 needs_flatten_effect (ClutterActor *self)
3118 {
3119   ClutterActorPrivate *priv = self->priv;
3120
3121   if (G_UNLIKELY (clutter_paint_debug_flags &
3122                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3123     return FALSE;
3124
3125   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3126     return TRUE;
3127   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3128     {
3129       if (clutter_actor_get_paint_opacity (self) < 255 &&
3130           clutter_actor_has_overlaps (self))
3131         return TRUE;
3132     }
3133
3134   return FALSE;
3135 }
3136
3137 static void
3138 add_or_remove_flatten_effect (ClutterActor *self)
3139 {
3140   ClutterActorPrivate *priv = self->priv;
3141
3142   /* Add or remove the flatten effect depending on the
3143      offscreen-redirect property. */
3144   if (needs_flatten_effect (self))
3145     {
3146       if (priv->flatten_effect == NULL)
3147         {
3148           ClutterActorMeta *actor_meta;
3149           gint priority;
3150
3151           priv->flatten_effect = _clutter_flatten_effect_new ();
3152           /* Keep a reference to the effect so that we can queue
3153              redraws from it */
3154           g_object_ref_sink (priv->flatten_effect);
3155
3156           /* Set the priority of the effect to high so that it will
3157              always be applied to the actor first. It uses an internal
3158              priority so that it won't be visible to applications */
3159           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3160           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3161           _clutter_actor_meta_set_priority (actor_meta, priority);
3162
3163           /* This will add the effect without queueing a redraw */
3164           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3165         }
3166     }
3167   else
3168     {
3169       if (priv->flatten_effect != NULL)
3170         {
3171           /* Destroy the effect so that it will lose its fbo cache of
3172              the actor */
3173           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3174           g_object_unref (priv->flatten_effect);
3175           priv->flatten_effect = NULL;
3176         }
3177     }
3178 }
3179
3180 static void
3181 clutter_actor_real_paint (ClutterActor *actor)
3182 {
3183   ClutterActorPrivate *priv = actor->priv;
3184   ClutterActor *iter;
3185
3186   for (iter = priv->first_child;
3187        iter != NULL;
3188        iter = iter->priv->next_sibling)
3189     {
3190       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3191                     _clutter_actor_get_debug_name (iter),
3192                     _clutter_actor_get_debug_name (actor),
3193                     iter->priv->allocation.x1,
3194                     iter->priv->allocation.y1,
3195                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3196                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3197
3198       clutter_actor_paint (iter);
3199     }
3200 }
3201
3202 static gboolean
3203 clutter_actor_paint_node (ClutterActor     *actor,
3204                           ClutterPaintNode *root)
3205 {
3206   ClutterActorPrivate *priv = actor->priv;
3207
3208   if (root == NULL)
3209     return FALSE;
3210
3211   if (priv->bg_color_set &&
3212       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3213     {
3214       ClutterPaintNode *node;
3215       ClutterColor bg_color;
3216       ClutterActorBox box;
3217
3218       box.x1 = 0.f;
3219       box.y1 = 0.f;
3220       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3221       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3222
3223       bg_color = priv->bg_color;
3224       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3225                      * priv->bg_color.alpha
3226                      / 255;
3227
3228       node = clutter_color_node_new (&bg_color);
3229       clutter_paint_node_set_name (node, "backgroundColor");
3230       clutter_paint_node_add_rectangle (node, &box);
3231       clutter_paint_node_add_child (root, node);
3232       clutter_paint_node_unref (node);
3233     }
3234
3235   if (priv->content != NULL)
3236     _clutter_content_paint_content (priv->content, actor, root);
3237
3238   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3239     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3240
3241   if (clutter_paint_node_get_n_children (root) == 0)
3242     return FALSE;
3243
3244 #ifdef CLUTTER_ENABLE_DEBUG
3245   if (CLUTTER_HAS_DEBUG (PAINT))
3246     {
3247       /* dump the tree only if we have one */
3248       _clutter_paint_node_dump_tree (root);
3249     }
3250 #endif /* CLUTTER_ENABLE_DEBUG */
3251
3252   _clutter_paint_node_paint (root);
3253
3254   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3255
3256   return TRUE;
3257 }
3258
3259 /**
3260  * clutter_actor_paint:
3261  * @self: A #ClutterActor
3262  *
3263  * Renders the actor to display.
3264  *
3265  * This function should not be called directly by applications.
3266  * Call clutter_actor_queue_redraw() to queue paints, instead.
3267  *
3268  * This function is context-aware, and will either cause a
3269  * regular paint or a pick paint.
3270  *
3271  * This function will emit the #ClutterActor::paint signal or
3272  * the #ClutterActor::pick signal, depending on the context.
3273  *
3274  * This function does not paint the actor if the actor is set to 0,
3275  * unless it is performing a pick paint.
3276  */
3277 void
3278 clutter_actor_paint (ClutterActor *self)
3279 {
3280   ClutterActorPrivate *priv;
3281   ClutterPickMode pick_mode;
3282   gboolean clip_set = FALSE;
3283   gboolean shader_applied = FALSE;
3284
3285   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3286                           "Actor real-paint counter",
3287                           "Increments each time any actor is painted",
3288                           0 /* no application private data */);
3289   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3290                           "Actor pick-paint counter",
3291                           "Increments each time any actor is painted "
3292                           "for picking",
3293                           0 /* no application private data */);
3294
3295   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3296
3297   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3298     return;
3299
3300   priv = self->priv;
3301
3302   pick_mode = _clutter_context_get_pick_mode ();
3303
3304   if (pick_mode == CLUTTER_PICK_NONE)
3305     priv->propagated_one_redraw = FALSE;
3306
3307   /* It's an important optimization that we consider painting of
3308    * actors with 0 opacity to be a NOP... */
3309   if (pick_mode == CLUTTER_PICK_NONE &&
3310       /* ignore top-levels, since they might be transparent */
3311       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3312       /* Use the override opacity if its been set */
3313       ((priv->opacity_override >= 0) ?
3314        priv->opacity_override : priv->opacity) == 0)
3315     return;
3316
3317   /* if we aren't paintable (not in a toplevel with all
3318    * parents paintable) then do nothing.
3319    */
3320   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3321     return;
3322
3323   /* mark that we are in the paint process */
3324   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3325
3326   cogl_push_matrix();
3327
3328   if (priv->enable_model_view_transform)
3329     {
3330       CoglMatrix matrix;
3331
3332       /* XXX: It could be better to cache the modelview with the actor
3333        * instead of progressively building up the transformations on
3334        * the matrix stack every time we paint. */
3335       cogl_get_modelview_matrix (&matrix);
3336       _clutter_actor_apply_modelview_transform (self, &matrix);
3337
3338 #ifdef CLUTTER_ENABLE_DEBUG
3339       /* Catch when out-of-band transforms have been made by actors not as part
3340        * of an apply_transform vfunc... */
3341       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3342         {
3343           CoglMatrix expected_matrix;
3344
3345           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3346                                                              &expected_matrix);
3347
3348           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3349             {
3350               GString *buf = g_string_sized_new (1024);
3351               ClutterActor *parent;
3352
3353               parent = self;
3354               while (parent != NULL)
3355                 {
3356                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3357
3358                   if (parent->priv->parent != NULL)
3359                     g_string_append (buf, "->");
3360
3361                   parent = parent->priv->parent;
3362                 }
3363
3364               g_warning ("Unexpected transform found when painting actor "
3365                          "\"%s\". This will be caused by one of the actor's "
3366                          "ancestors (%s) using the Cogl API directly to transform "
3367                          "children instead of using ::apply_transform().",
3368                          _clutter_actor_get_debug_name (self),
3369                          buf->str);
3370
3371               g_string_free (buf, TRUE);
3372             }
3373         }
3374 #endif /* CLUTTER_ENABLE_DEBUG */
3375
3376       cogl_set_modelview_matrix (&matrix);
3377     }
3378
3379   if (priv->has_clip)
3380     {
3381       cogl_clip_push_rectangle (priv->clip.x,
3382                                 priv->clip.y,
3383                                 priv->clip.x + priv->clip.width,
3384                                 priv->clip.y + priv->clip.height);
3385       clip_set = TRUE;
3386     }
3387   else if (priv->clip_to_allocation)
3388     {
3389       gfloat width, height;
3390
3391       width  = priv->allocation.x2 - priv->allocation.x1;
3392       height = priv->allocation.y2 - priv->allocation.y1;
3393
3394       cogl_clip_push_rectangle (0, 0, width, height);
3395       clip_set = TRUE;
3396     }
3397
3398   if (pick_mode == CLUTTER_PICK_NONE)
3399     {
3400       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3401
3402       /* We check whether we need to add the flatten effect before
3403          each paint so that we can avoid having a mechanism for
3404          applications to notify when the value of the
3405          has_overlaps virtual changes. */
3406       add_or_remove_flatten_effect (self);
3407     }
3408   else
3409     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3410
3411   /* We save the current paint volume so that the next time the
3412    * actor queues a redraw we can constrain the redraw to just
3413    * cover the union of the new bounding box and the old.
3414    *
3415    * We also fetch the current paint volume to perform culling so
3416    * we can avoid painting actors outside the current clip region.
3417    *
3418    * If we are painting inside a clone, we should neither update
3419    * the paint volume or use it to cull painting, since the paint
3420    * box represents the location of the source actor on the
3421    * screen.
3422    *
3423    * XXX: We are starting to do a lot of vertex transforms on
3424    * the CPU in a typical paint, so at some point we should
3425    * audit these and consider caching some things.
3426    *
3427    * NB: We don't perform culling while picking at this point because
3428    * clutter-stage.c doesn't setup the clipping planes appropriately.
3429    *
3430    * NB: We don't want to update the last-paint-volume during picking
3431    * because the last-paint-volume is used to determine the old screen
3432    * space location of an actor that has moved so we can know the
3433    * minimal region to redraw to clear an old view of the actor. If we
3434    * update this during picking then by the time we come around to
3435    * paint then the last-paint-volume would likely represent the new
3436    * actor position not the old.
3437    */
3438   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3439     {
3440       gboolean success;
3441       /* annoyingly gcc warns if uninitialized even though
3442        * the initialization is redundant :-( */
3443       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3444
3445       if (G_LIKELY ((clutter_paint_debug_flags &
3446                      (CLUTTER_DEBUG_DISABLE_CULLING |
3447                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3448                     (CLUTTER_DEBUG_DISABLE_CULLING |
3449                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3450         _clutter_actor_update_last_paint_volume (self);
3451
3452       success = cull_actor (self, &result);
3453
3454       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3455         _clutter_actor_paint_cull_result (self, success, result);
3456       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3457         goto done;
3458     }
3459
3460   if (priv->effects == NULL)
3461     {
3462       if (pick_mode == CLUTTER_PICK_NONE &&
3463           actor_has_shader_data (self))
3464         {
3465           _clutter_actor_shader_pre_paint (self, FALSE);
3466           shader_applied = TRUE;
3467         }
3468
3469       priv->next_effect_to_paint = NULL;
3470     }
3471   else
3472     priv->next_effect_to_paint =
3473       _clutter_meta_group_peek_metas (priv->effects);
3474
3475   clutter_actor_continue_paint (self);
3476
3477   if (shader_applied)
3478     _clutter_actor_shader_post_paint (self);
3479
3480   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3481                   pick_mode == CLUTTER_PICK_NONE))
3482     _clutter_actor_draw_paint_volume (self);
3483
3484 done:
3485   /* If we make it here then the actor has run through a complete
3486      paint run including all the effects so it's no longer dirty */
3487   if (pick_mode == CLUTTER_PICK_NONE)
3488     priv->is_dirty = FALSE;
3489
3490   if (clip_set)
3491     cogl_clip_pop();
3492
3493   cogl_pop_matrix();
3494
3495   /* paint sequence complete */
3496   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3497 }
3498
3499 /**
3500  * clutter_actor_continue_paint:
3501  * @self: A #ClutterActor
3502  *
3503  * Run the next stage of the paint sequence. This function should only
3504  * be called within the implementation of the ‘run’ virtual of a
3505  * #ClutterEffect. It will cause the run method of the next effect to
3506  * be applied, or it will paint the actual actor if the current effect
3507  * is the last effect in the chain.
3508  *
3509  * Since: 1.8
3510  */
3511 void
3512 clutter_actor_continue_paint (ClutterActor *self)
3513 {
3514   ClutterActorPrivate *priv;
3515
3516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3517   /* This should only be called from with in the ‘run’ implementation
3518      of a ClutterEffect */
3519   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3520
3521   priv = self->priv;
3522
3523   /* Skip any effects that are disabled */
3524   while (priv->next_effect_to_paint &&
3525          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3526     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3527
3528   /* If this has come from the last effect then we'll just paint the
3529      actual actor */
3530   if (priv->next_effect_to_paint == NULL)
3531     {
3532       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3533         {
3534           ClutterPaintNode *dummy;
3535           gboolean emit_paint;
3536
3537           /* XXX - this will go away in 2.0, when we can get rid of this
3538            * stuff and switch to a pure retained render tree of PaintNodes
3539            * for the entire frame, starting from the Stage.
3540            */
3541           dummy = _clutter_dummy_node_new ();
3542           clutter_paint_node_set_name (dummy, "Root");
3543           emit_paint = !clutter_actor_paint_node (self, dummy);
3544           clutter_paint_node_unref (dummy);
3545
3546           if (emit_paint || CLUTTER_ACTOR_IS_TOPLEVEL (self))
3547             g_signal_emit (self, actor_signals[PAINT], 0);
3548           else
3549             {
3550               CLUTTER_NOTE (PAINT, "The actor '%s' painted using PaintNodes, "
3551                                    "skipping the emission of the paint signal.",
3552                                    _clutter_actor_get_debug_name (self));
3553             }
3554         }
3555       else
3556         {
3557           ClutterColor col = { 0, };
3558
3559           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3560
3561           /* Actor will then paint silhouette of itself in supplied
3562            * color.  See clutter_stage_get_actor_at_pos() for where
3563            * picking is enabled.
3564            */
3565           g_signal_emit (self, actor_signals[PICK], 0, &col);
3566         }
3567     }
3568   else
3569     {
3570       ClutterEffect *old_current_effect;
3571       ClutterEffectPaintFlags run_flags = 0;
3572
3573       /* Cache the current effect so that we can put it back before
3574          returning */
3575       old_current_effect = priv->current_effect;
3576
3577       priv->current_effect = priv->next_effect_to_paint->data;
3578       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3579
3580       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3581         {
3582           if (priv->is_dirty)
3583             {
3584               /* If there's an effect queued with this redraw then all
3585                  effects up to that one will be considered dirty. It
3586                  is expected the queued effect will paint the cached
3587                  image and not call clutter_actor_continue_paint again
3588                  (although it should work ok if it does) */
3589               if (priv->effect_to_redraw == NULL ||
3590                   priv->current_effect != priv->effect_to_redraw)
3591                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3592             }
3593
3594           _clutter_effect_paint (priv->current_effect, run_flags);
3595         }
3596       else
3597         {
3598           /* We can't determine when an actor has been modified since
3599              its last pick so lets just assume it has always been
3600              modified */
3601           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3602
3603           _clutter_effect_pick (priv->current_effect, run_flags);
3604         }
3605
3606       priv->current_effect = old_current_effect;
3607     }
3608 }
3609
3610 static ClutterActorTraverseVisitFlags
3611 invalidate_queue_redraw_entry (ClutterActor *self,
3612                                int           depth,
3613                                gpointer      user_data)
3614 {
3615   ClutterActorPrivate *priv = self->priv;
3616
3617   if (priv->queue_redraw_entry != NULL)
3618     {
3619       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3620       priv->queue_redraw_entry = NULL;
3621     }
3622
3623   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3624 }
3625
3626 static inline void
3627 remove_child (ClutterActor *self,
3628               ClutterActor *child)
3629 {
3630   ClutterActor *prev_sibling, *next_sibling;
3631
3632   prev_sibling = child->priv->prev_sibling;
3633   next_sibling = child->priv->next_sibling;
3634
3635   if (prev_sibling != NULL)
3636     prev_sibling->priv->next_sibling = next_sibling;
3637
3638   if (next_sibling != NULL)
3639     next_sibling->priv->prev_sibling = prev_sibling;
3640
3641   if (self->priv->first_child == child)
3642     self->priv->first_child = next_sibling;
3643
3644   if (self->priv->last_child == child)
3645     self->priv->last_child = prev_sibling;
3646
3647   child->priv->parent = NULL;
3648   child->priv->prev_sibling = NULL;
3649   child->priv->next_sibling = NULL;
3650 }
3651
3652 typedef enum {
3653   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3654   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3655   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3656   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3657   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3658   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3659
3660   /* default flags for public API */
3661   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3662                                     REMOVE_CHILD_EMIT_PARENT_SET |
3663                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3664                                     REMOVE_CHILD_CHECK_STATE |
3665                                     REMOVE_CHILD_FLUSH_QUEUE |
3666                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3667
3668   /* flags for legacy/deprecated API */
3669   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3670                                     REMOVE_CHILD_FLUSH_QUEUE |
3671                                     REMOVE_CHILD_EMIT_PARENT_SET |
3672                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3673 } ClutterActorRemoveChildFlags;
3674
3675 /*< private >
3676  * clutter_actor_remove_child_internal:
3677  * @self: a #ClutterActor
3678  * @child: the child of @self that has to be removed
3679  * @flags: control the removal operations
3680  *
3681  * Removes @child from the list of children of @self.
3682  */
3683 static void
3684 clutter_actor_remove_child_internal (ClutterActor                 *self,
3685                                      ClutterActor                 *child,
3686                                      ClutterActorRemoveChildFlags  flags)
3687 {
3688   ClutterActor *old_first, *old_last;
3689   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3690   gboolean flush_queue;
3691   gboolean notify_first_last;
3692   gboolean was_mapped;
3693
3694   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3695   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3696   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3697   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3698   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3699   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3700
3701   g_object_freeze_notify (G_OBJECT (self));
3702
3703   if (destroy_meta)
3704     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3705
3706   if (check_state)
3707     {
3708       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3709
3710       /* we need to unrealize *before* we set parent_actor to NULL,
3711        * because in an unrealize method actors are dissociating from the
3712        * stage, which means they need to be able to
3713        * clutter_actor_get_stage().
3714        *
3715        * yhis should unmap and unrealize, unless we're reparenting.
3716        */
3717       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3718     }
3719   else
3720     was_mapped = FALSE;
3721
3722   if (flush_queue)
3723     {
3724       /* We take this opportunity to invalidate any queue redraw entry
3725        * associated with the actor and descendants since we won't be able to
3726        * determine the appropriate stage after this.
3727        *
3728        * we do this after we updated the mapped state because actors might
3729        * end up queueing redraws inside their mapped/unmapped virtual
3730        * functions, and if we invalidate the redraw entry we could end up
3731        * with an inconsistent state and weird memory corruption. see
3732        * bugs:
3733        *
3734        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3735        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3736        */
3737       _clutter_actor_traverse (child,
3738                                0,
3739                                invalidate_queue_redraw_entry,
3740                                NULL,
3741                                NULL);
3742     }
3743
3744   old_first = self->priv->first_child;
3745   old_last = self->priv->last_child;
3746
3747   remove_child (self, child);
3748
3749   self->priv->n_children -= 1;
3750
3751   self->priv->age += 1;
3752
3753   /* clutter_actor_reparent() will emit ::parent-set for us */
3754   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3755     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3756
3757   /* if the child was mapped then we need to relayout ourselves to account
3758    * for the removed child
3759    */
3760   if (was_mapped)
3761     clutter_actor_queue_relayout (self);
3762
3763   /* we need to emit the signal before dropping the reference */
3764   if (emit_actor_removed)
3765     g_signal_emit_by_name (self, "actor-removed", child);
3766
3767   if (notify_first_last)
3768     {
3769       if (old_first != self->priv->first_child)
3770         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3771
3772       if (old_last != self->priv->last_child)
3773         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3774     }
3775
3776   g_object_thaw_notify (G_OBJECT (self));
3777
3778   /* remove the reference we acquired in clutter_actor_add_child() */
3779   g_object_unref (child);
3780 }
3781
3782 static const ClutterTransformInfo default_transform_info = {
3783   0.0, { 0, },          /* rotation-x */
3784   0.0, { 0, },          /* rotation-y */
3785   0.0, { 0, },          /* rotation-z */
3786
3787   1.0, 1.0, { 0, },     /* scale */
3788
3789   { 0, },               /* anchor */
3790
3791   0.0,                  /* depth */
3792 };
3793
3794 /*< private >
3795  * _clutter_actor_get_transform_info_or_defaults:
3796  * @self: a #ClutterActor
3797  *
3798  * Retrieves the ClutterTransformInfo structure associated to an actor.
3799  *
3800  * If the actor does not have a ClutterTransformInfo structure associated
3801  * to it, then the default structure will be returned.
3802  *
3803  * This function should only be used for getters.
3804  *
3805  * Return value: a const pointer to the ClutterTransformInfo structure
3806  */
3807 const ClutterTransformInfo *
3808 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3809 {
3810   ClutterTransformInfo *info;
3811
3812   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3813   if (info != NULL)
3814     return info;
3815
3816   return &default_transform_info;
3817 }
3818
3819 static void
3820 clutter_transform_info_free (gpointer data)
3821 {
3822   if (data != NULL)
3823     g_slice_free (ClutterTransformInfo, data);
3824 }
3825
3826 /*< private >
3827  * _clutter_actor_get_transform_info:
3828  * @self: a #ClutterActor
3829  *
3830  * Retrieves a pointer to the ClutterTransformInfo structure.
3831  *
3832  * If the actor does not have a ClutterTransformInfo associated to it, one
3833  * will be created and initialized to the default values.
3834  *
3835  * This function should be used for setters.
3836  *
3837  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3838  * instead.
3839  *
3840  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3841  *   structure
3842  */
3843 ClutterTransformInfo *
3844 _clutter_actor_get_transform_info (ClutterActor *self)
3845 {
3846   ClutterTransformInfo *info;
3847
3848   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3849   if (info == NULL)
3850     {
3851       info = g_slice_new (ClutterTransformInfo);
3852
3853       *info = default_transform_info;
3854
3855       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3856                                info,
3857                                clutter_transform_info_free);
3858     }
3859
3860   return info;
3861 }
3862
3863 /*< private >
3864  * clutter_actor_set_rotation_angle_internal:
3865  * @self: a #ClutterActor
3866  * @axis: the axis of the angle to change
3867  * @angle: the angle of rotation
3868  *
3869  * Sets the rotation angle on the given axis without affecting the
3870  * rotation center point.
3871  */
3872 static inline void
3873 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3874                                            ClutterRotateAxis  axis,
3875                                            gdouble            angle)
3876 {
3877   GObject *obj = G_OBJECT (self);
3878   ClutterTransformInfo *info;
3879
3880   info = _clutter_actor_get_transform_info (self);
3881
3882   g_object_freeze_notify (obj);
3883
3884   switch (axis)
3885     {
3886     case CLUTTER_X_AXIS:
3887       info->rx_angle = angle;
3888       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3889       break;
3890
3891     case CLUTTER_Y_AXIS:
3892       info->ry_angle = angle;
3893       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3894       break;
3895
3896     case CLUTTER_Z_AXIS:
3897       info->rz_angle = angle;
3898       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3899       break;
3900     }
3901
3902   self->priv->transform_valid = FALSE;
3903
3904   g_object_thaw_notify (obj);
3905
3906   clutter_actor_queue_redraw (self);
3907 }
3908
3909 static inline void
3910 clutter_actor_set_rotation_angle (ClutterActor      *self,
3911                                   ClutterRotateAxis  axis,
3912                                   gdouble            angle)
3913 {
3914   ClutterTransformInfo *info;
3915
3916   info = _clutter_actor_get_transform_info (self);
3917
3918   if (clutter_actor_get_easing_duration (self) != 0)
3919     {
3920       ClutterTransition *transition;
3921       GParamSpec *pspec = NULL;
3922       double *cur_angle_p = NULL;
3923
3924       switch (axis)
3925         {
3926         case CLUTTER_X_AXIS:
3927           cur_angle_p = &info->rx_angle;
3928           pspec = obj_props[PROP_ROTATION_ANGLE_X];
3929           break;
3930
3931         case CLUTTER_Y_AXIS:
3932           cur_angle_p = &info->ry_angle;
3933           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3934           break;
3935
3936         case CLUTTER_Z_AXIS:
3937           cur_angle_p = &info->rz_angle;
3938           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3939           break;
3940         }
3941
3942       g_assert (pspec != NULL);
3943       g_assert (cur_angle_p != NULL);
3944
3945       transition = _clutter_actor_get_transition (self, pspec);
3946       if (transition == NULL)
3947         {
3948           transition = _clutter_actor_create_transition (self, pspec,
3949                                                          *cur_angle_p,
3950                                                          angle);
3951           clutter_timeline_start (CLUTTER_TIMELINE (transition));
3952         }
3953       else
3954         _clutter_actor_update_transition (self, pspec, angle);
3955
3956       self->priv->transform_valid = FALSE;
3957       clutter_actor_queue_redraw (self);
3958     }
3959   else
3960     clutter_actor_set_rotation_angle_internal (self, axis, angle);
3961 }
3962
3963 /*< private >
3964  * clutter_actor_set_rotation_center_internal:
3965  * @self: a #ClutterActor
3966  * @axis: the axis of the center to change
3967  * @center: the coordinates of the rotation center
3968  *
3969  * Sets the rotation center on the given axis without affecting the
3970  * rotation angle.
3971  */
3972 static inline void
3973 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3974                                             ClutterRotateAxis    axis,
3975                                             const ClutterVertex *center)
3976 {
3977   GObject *obj = G_OBJECT (self);
3978   ClutterTransformInfo *info;
3979   ClutterVertex v = { 0, 0, 0 };
3980
3981   info = _clutter_actor_get_transform_info (self);
3982
3983   if (center != NULL)
3984     v = *center;
3985
3986   g_object_freeze_notify (obj);
3987
3988   switch (axis)
3989     {
3990     case CLUTTER_X_AXIS:
3991       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3992       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3993       break;
3994
3995     case CLUTTER_Y_AXIS:
3996       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3997       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3998       break;
3999
4000     case CLUTTER_Z_AXIS:
4001       /* if the previously set rotation center was fractional, then
4002        * setting explicit coordinates will have to notify the
4003        * :rotation-center-z-gravity property as well
4004        */
4005       if (info->rz_center.is_fractional)
4006         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4007
4008       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4009       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4010       break;
4011     }
4012
4013   self->priv->transform_valid = FALSE;
4014
4015   g_object_thaw_notify (obj);
4016
4017   clutter_actor_queue_redraw (self);
4018 }
4019
4020 static void
4021 clutter_actor_animate_scale_factor (ClutterActor *self,
4022                                     double        old_factor,
4023                                     double        new_factor,
4024                                     GParamSpec   *pspec)
4025 {
4026   ClutterTransition *transition;
4027
4028   transition = _clutter_actor_get_transition (self, pspec);
4029   if (transition == NULL)
4030     {
4031       transition = _clutter_actor_create_transition (self, pspec,
4032                                                      old_factor,
4033                                                      new_factor);
4034       clutter_timeline_start (CLUTTER_TIMELINE (transition));
4035     }
4036   else
4037     _clutter_actor_update_transition (self, pspec, new_factor);
4038
4039
4040   self->priv->transform_valid = FALSE;
4041   clutter_actor_queue_redraw (self);
4042 }
4043
4044 static void
4045 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4046                                          double factor,
4047                                          GParamSpec *pspec)
4048 {
4049   GObject *obj = G_OBJECT (self);
4050   ClutterTransformInfo *info;
4051
4052   info = _clutter_actor_get_transform_info (self);
4053
4054   if (pspec == obj_props[PROP_SCALE_X])
4055     info->scale_x = factor;
4056   else
4057     info->scale_y = factor;
4058
4059   self->priv->transform_valid = FALSE;
4060   clutter_actor_queue_redraw (self);
4061   g_object_notify_by_pspec (obj, pspec);
4062 }
4063
4064 static inline void
4065 clutter_actor_set_scale_factor (ClutterActor      *self,
4066                                 ClutterRotateAxis  axis,
4067                                 gdouble            factor)
4068 {
4069   GObject *obj = G_OBJECT (self);
4070   ClutterTransformInfo *info;
4071   GParamSpec *pspec;
4072
4073   info = _clutter_actor_get_transform_info (self);
4074
4075   g_object_freeze_notify (obj);
4076
4077   switch (axis)
4078     {
4079     case CLUTTER_X_AXIS:
4080       pspec = obj_props[PROP_SCALE_X];
4081
4082       if (clutter_actor_get_easing_duration (self) != 0)
4083         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4084       else
4085         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4086       break;
4087
4088     case CLUTTER_Y_AXIS:
4089       pspec = obj_props[PROP_SCALE_Y];
4090
4091       if (clutter_actor_get_easing_duration (self) != 0)
4092         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4093       else
4094         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4095       break;
4096
4097     default:
4098       g_assert_not_reached ();
4099     }
4100
4101   g_object_thaw_notify (obj);
4102 }
4103
4104 static inline void
4105 clutter_actor_set_scale_center (ClutterActor      *self,
4106                                 ClutterRotateAxis  axis,
4107                                 gfloat             coord)
4108 {
4109   GObject *obj = G_OBJECT (self);
4110   ClutterTransformInfo *info;
4111   gfloat center_x, center_y;
4112
4113   info = _clutter_actor_get_transform_info (self);
4114
4115   g_object_freeze_notify (obj);
4116
4117   /* get the current scale center coordinates */
4118   clutter_anchor_coord_get_units (self, &info->scale_center,
4119                                   &center_x,
4120                                   &center_y,
4121                                   NULL);
4122
4123   /* we need to notify this too, because setting explicit coordinates will
4124    * change the gravity as a side effect
4125    */
4126   if (info->scale_center.is_fractional)
4127     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4128
4129   switch (axis)
4130     {
4131     case CLUTTER_X_AXIS:
4132       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4133       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4134       break;
4135
4136     case CLUTTER_Y_AXIS:
4137       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4138       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4139       break;
4140
4141     default:
4142       g_assert_not_reached ();
4143     }
4144
4145   self->priv->transform_valid = FALSE;
4146
4147   clutter_actor_queue_redraw (self);
4148
4149   g_object_thaw_notify (obj);
4150 }
4151
4152 static inline void
4153 clutter_actor_set_anchor_coord (ClutterActor      *self,
4154                                 ClutterRotateAxis  axis,
4155                                 gfloat             coord)
4156 {
4157   GObject *obj = G_OBJECT (self);
4158   ClutterTransformInfo *info;
4159   gfloat anchor_x, anchor_y;
4160
4161   info = _clutter_actor_get_transform_info (self);
4162
4163   g_object_freeze_notify (obj);
4164
4165   clutter_anchor_coord_get_units (self, &info->anchor,
4166                                   &anchor_x,
4167                                   &anchor_y,
4168                                   NULL);
4169
4170   if (info->anchor.is_fractional)
4171     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4172
4173   switch (axis)
4174     {
4175     case CLUTTER_X_AXIS:
4176       clutter_anchor_coord_set_units (&info->anchor,
4177                                       coord,
4178                                       anchor_y,
4179                                       0.0);
4180       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4181       break;
4182
4183     case CLUTTER_Y_AXIS:
4184       clutter_anchor_coord_set_units (&info->anchor,
4185                                       anchor_x,
4186                                       coord,
4187                                       0.0);
4188       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4189       break;
4190
4191     default:
4192       g_assert_not_reached ();
4193     }
4194
4195   self->priv->transform_valid = FALSE;
4196
4197   clutter_actor_queue_redraw (self);
4198
4199   g_object_thaw_notify (obj);
4200 }
4201
4202 static void
4203 clutter_actor_set_property (GObject      *object,
4204                             guint         prop_id,
4205                             const GValue *value,
4206                             GParamSpec   *pspec)
4207 {
4208   ClutterActor *actor = CLUTTER_ACTOR (object);
4209   ClutterActorPrivate *priv = actor->priv;
4210
4211   switch (prop_id)
4212     {
4213     case PROP_X:
4214       clutter_actor_set_x (actor, g_value_get_float (value));
4215       break;
4216
4217     case PROP_Y:
4218       clutter_actor_set_y (actor, g_value_get_float (value));
4219       break;
4220
4221     case PROP_WIDTH:
4222       clutter_actor_set_width (actor, g_value_get_float (value));
4223       break;
4224
4225     case PROP_HEIGHT:
4226       clutter_actor_set_height (actor, g_value_get_float (value));
4227       break;
4228
4229     case PROP_FIXED_X:
4230       clutter_actor_set_x (actor, g_value_get_float (value));
4231       break;
4232
4233     case PROP_FIXED_Y:
4234       clutter_actor_set_y (actor, g_value_get_float (value));
4235       break;
4236
4237     case PROP_FIXED_POSITION_SET:
4238       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4239       break;
4240
4241     case PROP_MIN_WIDTH:
4242       clutter_actor_set_min_width (actor, g_value_get_float (value));
4243       break;
4244
4245     case PROP_MIN_HEIGHT:
4246       clutter_actor_set_min_height (actor, g_value_get_float (value));
4247       break;
4248
4249     case PROP_NATURAL_WIDTH:
4250       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4251       break;
4252
4253     case PROP_NATURAL_HEIGHT:
4254       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4255       break;
4256
4257     case PROP_MIN_WIDTH_SET:
4258       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4259       break;
4260
4261     case PROP_MIN_HEIGHT_SET:
4262       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4263       break;
4264
4265     case PROP_NATURAL_WIDTH_SET:
4266       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4267       break;
4268
4269     case PROP_NATURAL_HEIGHT_SET:
4270       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4271       break;
4272
4273     case PROP_REQUEST_MODE:
4274       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4275       break;
4276
4277     case PROP_DEPTH:
4278       clutter_actor_set_depth (actor, g_value_get_float (value));
4279       break;
4280
4281     case PROP_OPACITY:
4282       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4283       break;
4284
4285     case PROP_OFFSCREEN_REDIRECT:
4286       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4287       break;
4288
4289     case PROP_NAME:
4290       clutter_actor_set_name (actor, g_value_get_string (value));
4291       break;
4292
4293     case PROP_VISIBLE:
4294       if (g_value_get_boolean (value) == TRUE)
4295         clutter_actor_show (actor);
4296       else
4297         clutter_actor_hide (actor);
4298       break;
4299
4300     case PROP_SCALE_X:
4301       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4302                                       g_value_get_double (value));
4303       break;
4304
4305     case PROP_SCALE_Y:
4306       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4307                                       g_value_get_double (value));
4308       break;
4309
4310     case PROP_SCALE_CENTER_X:
4311       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4312                                       g_value_get_float (value));
4313       break;
4314
4315     case PROP_SCALE_CENTER_Y:
4316       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4317                                       g_value_get_float (value));
4318       break;
4319
4320     case PROP_SCALE_GRAVITY:
4321       {
4322         const ClutterTransformInfo *info;
4323         ClutterGravity gravity;
4324
4325         info = _clutter_actor_get_transform_info_or_defaults (actor);
4326         gravity = g_value_get_enum (value);
4327
4328         clutter_actor_set_scale_with_gravity (actor,
4329                                               info->scale_x,
4330                                               info->scale_y,
4331                                               gravity);
4332       }
4333       break;
4334
4335     case PROP_CLIP:
4336       {
4337         const ClutterGeometry *geom = g_value_get_boxed (value);
4338
4339         clutter_actor_set_clip (actor,
4340                                 geom->x, geom->y,
4341                                 geom->width, geom->height);
4342       }
4343       break;
4344
4345     case PROP_CLIP_TO_ALLOCATION:
4346       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4347       break;
4348
4349     case PROP_REACTIVE:
4350       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4351       break;
4352
4353     case PROP_ROTATION_ANGLE_X:
4354       clutter_actor_set_rotation_angle (actor,
4355                                         CLUTTER_X_AXIS,
4356                                         g_value_get_double (value));
4357       break;
4358
4359     case PROP_ROTATION_ANGLE_Y:
4360       clutter_actor_set_rotation_angle (actor,
4361                                         CLUTTER_Y_AXIS,
4362                                         g_value_get_double (value));
4363       break;
4364
4365     case PROP_ROTATION_ANGLE_Z:
4366       clutter_actor_set_rotation_angle (actor,
4367                                         CLUTTER_Z_AXIS,
4368                                         g_value_get_double (value));
4369       break;
4370
4371     case PROP_ROTATION_CENTER_X:
4372       clutter_actor_set_rotation_center_internal (actor,
4373                                                   CLUTTER_X_AXIS,
4374                                                   g_value_get_boxed (value));
4375       break;
4376
4377     case PROP_ROTATION_CENTER_Y:
4378       clutter_actor_set_rotation_center_internal (actor,
4379                                                   CLUTTER_Y_AXIS,
4380                                                   g_value_get_boxed (value));
4381       break;
4382
4383     case PROP_ROTATION_CENTER_Z:
4384       clutter_actor_set_rotation_center_internal (actor,
4385                                                   CLUTTER_Z_AXIS,
4386                                                   g_value_get_boxed (value));
4387       break;
4388
4389     case PROP_ROTATION_CENTER_Z_GRAVITY:
4390       {
4391         const ClutterTransformInfo *info;
4392
4393         info = _clutter_actor_get_transform_info_or_defaults (actor);
4394         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4395                                                    g_value_get_enum (value));
4396       }
4397       break;
4398
4399     case PROP_ANCHOR_X:
4400       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4401                                       g_value_get_float (value));
4402       break;
4403
4404     case PROP_ANCHOR_Y:
4405       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4406                                       g_value_get_float (value));
4407       break;
4408
4409     case PROP_ANCHOR_GRAVITY:
4410       clutter_actor_set_anchor_point_from_gravity (actor,
4411                                                    g_value_get_enum (value));
4412       break;
4413
4414     case PROP_SHOW_ON_SET_PARENT:
4415       priv->show_on_set_parent = g_value_get_boolean (value);
4416       break;
4417
4418     case PROP_TEXT_DIRECTION:
4419       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4420       break;
4421
4422     case PROP_ACTIONS:
4423       clutter_actor_add_action (actor, g_value_get_object (value));
4424       break;
4425
4426     case PROP_CONSTRAINTS:
4427       clutter_actor_add_constraint (actor, g_value_get_object (value));
4428       break;
4429
4430     case PROP_EFFECT:
4431       clutter_actor_add_effect (actor, g_value_get_object (value));
4432       break;
4433
4434     case PROP_LAYOUT_MANAGER:
4435       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4436       break;
4437
4438     case PROP_X_ALIGN:
4439       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4440       break;
4441
4442     case PROP_Y_ALIGN:
4443       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4444       break;
4445
4446     case PROP_MARGIN_TOP:
4447       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4448       break;
4449
4450     case PROP_MARGIN_BOTTOM:
4451       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4452       break;
4453
4454     case PROP_MARGIN_LEFT:
4455       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4456       break;
4457
4458     case PROP_MARGIN_RIGHT:
4459       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4460       break;
4461
4462     case PROP_BACKGROUND_COLOR:
4463       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4464       break;
4465
4466     case PROP_CONTENT:
4467       clutter_actor_set_content (actor, g_value_get_object (value));
4468       break;
4469
4470     case PROP_CONTENT_GRAVITY:
4471       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4472       break;
4473
4474     default:
4475       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4476       break;
4477     }
4478 }
4479
4480 static void
4481 clutter_actor_get_property (GObject    *object,
4482                             guint       prop_id,
4483                             GValue     *value,
4484                             GParamSpec *pspec)
4485 {
4486   ClutterActor *actor = CLUTTER_ACTOR (object);
4487   ClutterActorPrivate *priv = actor->priv;
4488
4489   switch (prop_id)
4490     {
4491     case PROP_X:
4492       g_value_set_float (value, clutter_actor_get_x (actor));
4493       break;
4494
4495     case PROP_Y:
4496       g_value_set_float (value, clutter_actor_get_y (actor));
4497       break;
4498
4499     case PROP_WIDTH:
4500       g_value_set_float (value, clutter_actor_get_width (actor));
4501       break;
4502
4503     case PROP_HEIGHT:
4504       g_value_set_float (value, clutter_actor_get_height (actor));
4505       break;
4506
4507     case PROP_FIXED_X:
4508       {
4509         const ClutterLayoutInfo *info;
4510
4511         info = _clutter_actor_get_layout_info_or_defaults (actor);
4512         g_value_set_float (value, info->fixed_x);
4513       }
4514       break;
4515
4516     case PROP_FIXED_Y:
4517       {
4518         const ClutterLayoutInfo *info;
4519
4520         info = _clutter_actor_get_layout_info_or_defaults (actor);
4521         g_value_set_float (value, info->fixed_y);
4522       }
4523       break;
4524
4525     case PROP_FIXED_POSITION_SET:
4526       g_value_set_boolean (value, priv->position_set);
4527       break;
4528
4529     case PROP_MIN_WIDTH:
4530       {
4531         const ClutterLayoutInfo *info;
4532
4533         info = _clutter_actor_get_layout_info_or_defaults (actor);
4534         g_value_set_float (value, info->min_width);
4535       }
4536       break;
4537
4538     case PROP_MIN_HEIGHT:
4539       {
4540         const ClutterLayoutInfo *info;
4541
4542         info = _clutter_actor_get_layout_info_or_defaults (actor);
4543         g_value_set_float (value, info->min_height);
4544       }
4545       break;
4546
4547     case PROP_NATURAL_WIDTH:
4548       {
4549         const ClutterLayoutInfo *info;
4550
4551         info = _clutter_actor_get_layout_info_or_defaults (actor);
4552         g_value_set_float (value, info->natural_width);
4553       }
4554       break;
4555
4556     case PROP_NATURAL_HEIGHT:
4557       {
4558         const ClutterLayoutInfo *info;
4559
4560         info = _clutter_actor_get_layout_info_or_defaults (actor);
4561         g_value_set_float (value, info->natural_height);
4562       }
4563       break;
4564
4565     case PROP_MIN_WIDTH_SET:
4566       g_value_set_boolean (value, priv->min_width_set);
4567       break;
4568
4569     case PROP_MIN_HEIGHT_SET:
4570       g_value_set_boolean (value, priv->min_height_set);
4571       break;
4572
4573     case PROP_NATURAL_WIDTH_SET:
4574       g_value_set_boolean (value, priv->natural_width_set);
4575       break;
4576
4577     case PROP_NATURAL_HEIGHT_SET:
4578       g_value_set_boolean (value, priv->natural_height_set);
4579       break;
4580
4581     case PROP_REQUEST_MODE:
4582       g_value_set_enum (value, priv->request_mode);
4583       break;
4584
4585     case PROP_ALLOCATION:
4586       g_value_set_boxed (value, &priv->allocation);
4587       break;
4588
4589     case PROP_DEPTH:
4590       g_value_set_float (value, clutter_actor_get_depth (actor));
4591       break;
4592
4593     case PROP_OPACITY:
4594       g_value_set_uint (value, priv->opacity);
4595       break;
4596
4597     case PROP_OFFSCREEN_REDIRECT:
4598       g_value_set_enum (value, priv->offscreen_redirect);
4599       break;
4600
4601     case PROP_NAME:
4602       g_value_set_string (value, priv->name);
4603       break;
4604
4605     case PROP_VISIBLE:
4606       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4607       break;
4608
4609     case PROP_MAPPED:
4610       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4611       break;
4612
4613     case PROP_REALIZED:
4614       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4615       break;
4616
4617     case PROP_HAS_CLIP:
4618       g_value_set_boolean (value, priv->has_clip);
4619       break;
4620
4621     case PROP_CLIP:
4622       {
4623         ClutterGeometry clip;
4624
4625         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4626         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4627         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4628         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4629
4630         g_value_set_boxed (value, &clip);
4631       }
4632       break;
4633
4634     case PROP_CLIP_TO_ALLOCATION:
4635       g_value_set_boolean (value, priv->clip_to_allocation);
4636       break;
4637
4638     case PROP_SCALE_X:
4639       {
4640         const ClutterTransformInfo *info;
4641
4642         info = _clutter_actor_get_transform_info_or_defaults (actor);
4643         g_value_set_double (value, info->scale_x);
4644       }
4645       break;
4646
4647     case PROP_SCALE_Y:
4648       {
4649         const ClutterTransformInfo *info;
4650
4651         info = _clutter_actor_get_transform_info_or_defaults (actor);
4652         g_value_set_double (value, info->scale_y);
4653       }
4654       break;
4655
4656     case PROP_SCALE_CENTER_X:
4657       {
4658         gfloat center;
4659
4660         clutter_actor_get_scale_center (actor, &center, NULL);
4661
4662         g_value_set_float (value, center);
4663       }
4664       break;
4665
4666     case PROP_SCALE_CENTER_Y:
4667       {
4668         gfloat center;
4669
4670         clutter_actor_get_scale_center (actor, NULL, &center);
4671
4672         g_value_set_float (value, center);
4673       }
4674       break;
4675
4676     case PROP_SCALE_GRAVITY:
4677       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4678       break;
4679
4680     case PROP_REACTIVE:
4681       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4682       break;
4683
4684     case PROP_ROTATION_ANGLE_X:
4685       {
4686         const ClutterTransformInfo *info;
4687
4688         info = _clutter_actor_get_transform_info_or_defaults (actor);
4689         g_value_set_double (value, info->rx_angle);
4690       }
4691       break;
4692
4693     case PROP_ROTATION_ANGLE_Y:
4694       {
4695         const ClutterTransformInfo *info;
4696
4697         info = _clutter_actor_get_transform_info_or_defaults (actor);
4698         g_value_set_double (value, info->ry_angle);
4699       }
4700       break;
4701
4702     case PROP_ROTATION_ANGLE_Z:
4703       {
4704         const ClutterTransformInfo *info;
4705
4706         info = _clutter_actor_get_transform_info_or_defaults (actor);
4707         g_value_set_double (value, info->rz_angle);
4708       }
4709       break;
4710
4711     case PROP_ROTATION_CENTER_X:
4712       {
4713         ClutterVertex center;
4714
4715         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4716                                     &center.x,
4717                                     &center.y,
4718                                     &center.z);
4719
4720         g_value_set_boxed (value, &center);
4721       }
4722       break;
4723
4724     case PROP_ROTATION_CENTER_Y:
4725       {
4726         ClutterVertex center;
4727
4728         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4729                                     &center.x,
4730                                     &center.y,
4731                                     &center.z);
4732
4733         g_value_set_boxed (value, &center);
4734       }
4735       break;
4736
4737     case PROP_ROTATION_CENTER_Z:
4738       {
4739         ClutterVertex center;
4740
4741         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4742                                     &center.x,
4743                                     &center.y,
4744                                     &center.z);
4745
4746         g_value_set_boxed (value, &center);
4747       }
4748       break;
4749
4750     case PROP_ROTATION_CENTER_Z_GRAVITY:
4751       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4752       break;
4753
4754     case PROP_ANCHOR_X:
4755       {
4756         const ClutterTransformInfo *info;
4757         gfloat anchor_x;
4758
4759         info = _clutter_actor_get_transform_info_or_defaults (actor);
4760         clutter_anchor_coord_get_units (actor, &info->anchor,
4761                                         &anchor_x,
4762                                         NULL,
4763                                         NULL);
4764         g_value_set_float (value, anchor_x);
4765       }
4766       break;
4767
4768     case PROP_ANCHOR_Y:
4769       {
4770         const ClutterTransformInfo *info;
4771         gfloat anchor_y;
4772
4773         info = _clutter_actor_get_transform_info_or_defaults (actor);
4774         clutter_anchor_coord_get_units (actor, &info->anchor,
4775                                         NULL,
4776                                         &anchor_y,
4777                                         NULL);
4778         g_value_set_float (value, anchor_y);
4779       }
4780       break;
4781
4782     case PROP_ANCHOR_GRAVITY:
4783       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4784       break;
4785
4786     case PROP_SHOW_ON_SET_PARENT:
4787       g_value_set_boolean (value, priv->show_on_set_parent);
4788       break;
4789
4790     case PROP_TEXT_DIRECTION:
4791       g_value_set_enum (value, priv->text_direction);
4792       break;
4793
4794     case PROP_HAS_POINTER:
4795       g_value_set_boolean (value, priv->has_pointer);
4796       break;
4797
4798     case PROP_LAYOUT_MANAGER:
4799       g_value_set_object (value, priv->layout_manager);
4800       break;
4801
4802     case PROP_X_ALIGN:
4803       {
4804         const ClutterLayoutInfo *info;
4805
4806         info = _clutter_actor_get_layout_info_or_defaults (actor);
4807         g_value_set_enum (value, info->x_align);
4808       }
4809       break;
4810
4811     case PROP_Y_ALIGN:
4812       {
4813         const ClutterLayoutInfo *info;
4814
4815         info = _clutter_actor_get_layout_info_or_defaults (actor);
4816         g_value_set_enum (value, info->y_align);
4817       }
4818       break;
4819
4820     case PROP_MARGIN_TOP:
4821       {
4822         const ClutterLayoutInfo *info;
4823
4824         info = _clutter_actor_get_layout_info_or_defaults (actor);
4825         g_value_set_float (value, info->margin.top);
4826       }
4827       break;
4828
4829     case PROP_MARGIN_BOTTOM:
4830       {
4831         const ClutterLayoutInfo *info;
4832
4833         info = _clutter_actor_get_layout_info_or_defaults (actor);
4834         g_value_set_float (value, info->margin.bottom);
4835       }
4836       break;
4837
4838     case PROP_MARGIN_LEFT:
4839       {
4840         const ClutterLayoutInfo *info;
4841
4842         info = _clutter_actor_get_layout_info_or_defaults (actor);
4843         g_value_set_float (value, info->margin.left);
4844       }
4845       break;
4846
4847     case PROP_MARGIN_RIGHT:
4848       {
4849         const ClutterLayoutInfo *info;
4850
4851         info = _clutter_actor_get_layout_info_or_defaults (actor);
4852         g_value_set_float (value, info->margin.right);
4853       }
4854       break;
4855
4856     case PROP_BACKGROUND_COLOR_SET:
4857       g_value_set_boolean (value, priv->bg_color_set);
4858       break;
4859
4860     case PROP_BACKGROUND_COLOR:
4861       g_value_set_boxed (value, &priv->bg_color);
4862       break;
4863
4864     case PROP_FIRST_CHILD:
4865       g_value_set_object (value, priv->first_child);
4866       break;
4867
4868     case PROP_LAST_CHILD:
4869       g_value_set_object (value, priv->last_child);
4870       break;
4871
4872     case PROP_CONTENT:
4873       g_value_set_object (value, priv->content);
4874       break;
4875
4876     case PROP_CONTENT_GRAVITY:
4877       g_value_set_enum (value, priv->content_gravity);
4878       break;
4879
4880     case PROP_CONTENT_BOX:
4881       {
4882         ClutterActorBox box = { 0, };
4883
4884         clutter_actor_get_content_box (actor, &box);
4885         g_value_set_boxed (value, &box);
4886       }
4887       break;
4888
4889     default:
4890       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4891       break;
4892     }
4893 }
4894
4895 static void
4896 clutter_actor_dispose (GObject *object)
4897 {
4898   ClutterActor *self = CLUTTER_ACTOR (object);
4899   ClutterActorPrivate *priv = self->priv;
4900
4901   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4902                 priv->id,
4903                 g_type_name (G_OBJECT_TYPE (self)),
4904                 object->ref_count);
4905
4906   g_signal_emit (self, actor_signals[DESTROY], 0);
4907
4908   /* avoid recursing when called from clutter_actor_destroy() */
4909   if (priv->parent != NULL)
4910     {
4911       ClutterActor *parent = priv->parent;
4912
4913       /* go through the Container implementation unless this
4914        * is an internal child and has been marked as such.
4915        *
4916        * removing the actor from its parent will reset the
4917        * realized and mapped states.
4918        */
4919       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4920         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4921       else
4922         clutter_actor_remove_child_internal (parent, self,
4923                                              REMOVE_CHILD_LEGACY_FLAGS);
4924     }
4925
4926   /* parent must be gone at this point */
4927   g_assert (priv->parent == NULL);
4928
4929   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4930     {
4931       /* can't be mapped or realized with no parent */
4932       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4933       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4934     }
4935
4936   g_clear_object (&priv->pango_context);
4937   g_clear_object (&priv->actions);
4938   g_clear_object (&priv->constraints);
4939   g_clear_object (&priv->effects);
4940   g_clear_object (&priv->flatten_effect);
4941
4942   if (priv->layout_manager != NULL)
4943     {
4944       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4945       g_clear_object (&priv->layout_manager);
4946     }
4947
4948   if (priv->content != NULL)
4949     {
4950       _clutter_content_detached (priv->content, self);
4951       g_clear_object (&priv->content);
4952     }
4953
4954   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4955 }
4956
4957 static void
4958 clutter_actor_finalize (GObject *object)
4959 {
4960   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4961
4962   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4963                 priv->name != NULL ? priv->name : "<none>",
4964                 priv->id,
4965                 g_type_name (G_OBJECT_TYPE (object)));
4966
4967   _clutter_context_release_id (priv->id);
4968
4969   g_free (priv->name);
4970
4971   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4972 }
4973
4974
4975 /**
4976  * clutter_actor_get_accessible:
4977  * @self: a #ClutterActor
4978  *
4979  * Returns the accessible object that describes the actor to an
4980  * assistive technology.
4981  *
4982  * If no class-specific #AtkObject implementation is available for the
4983  * actor instance in question, it will inherit an #AtkObject
4984  * implementation from the first ancestor class for which such an
4985  * implementation is defined.
4986  *
4987  * The documentation of the <ulink
4988  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4989  * library contains more information about accessible objects and
4990  * their uses.
4991  *
4992  * Returns: (transfer none): the #AtkObject associated with @actor
4993  */
4994 AtkObject *
4995 clutter_actor_get_accessible (ClutterActor *self)
4996 {
4997   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4998
4999   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5000 }
5001
5002 static AtkObject *
5003 clutter_actor_real_get_accessible (ClutterActor *actor)
5004 {
5005   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5006 }
5007
5008 static AtkObject *
5009 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5010 {
5011   AtkObject *accessible;
5012
5013   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5014   if (accessible != NULL)
5015     g_object_ref (accessible);
5016
5017   return accessible;
5018 }
5019
5020 static void
5021 atk_implementor_iface_init (AtkImplementorIface *iface)
5022 {
5023   iface->ref_accessible = _clutter_actor_ref_accessible;
5024 }
5025
5026 static gboolean
5027 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5028                                            ClutterPaintVolume *volume)
5029 {
5030   ClutterActorPrivate *priv = self->priv;
5031   gboolean res = FALSE;
5032
5033   /* we start from the allocation */
5034   clutter_paint_volume_set_width (volume,
5035                                   priv->allocation.x2 - priv->allocation.x1);
5036   clutter_paint_volume_set_height (volume,
5037                                    priv->allocation.y2 - priv->allocation.y1);
5038
5039   /* if the actor has a clip set then we have a pretty definite
5040    * size for the paint volume: the actor cannot possibly paint
5041    * outside the clip region.
5042    */
5043   if (priv->clip_to_allocation)
5044     {
5045       /* the allocation has already been set, so we just flip the
5046        * return value
5047        */
5048       res = TRUE;
5049     }
5050   else
5051     {
5052       ClutterActor *child;
5053
5054       if (priv->has_clip &&
5055           priv->clip.width >= 0 &&
5056           priv->clip.height >= 0)
5057         {
5058           ClutterVertex origin;
5059
5060           origin.x = priv->clip.x;
5061           origin.y = priv->clip.y;
5062           origin.z = 0;
5063
5064           clutter_paint_volume_set_origin (volume, &origin);
5065           clutter_paint_volume_set_width (volume, priv->clip.width);
5066           clutter_paint_volume_set_height (volume, priv->clip.height);
5067
5068           res = TRUE;
5069         }
5070
5071       /* if we don't have children we just bail out here... */
5072       if (priv->n_children == 0)
5073         return res;
5074
5075       /* ...but if we have children then we ask for their paint volume in
5076        * our coordinates. if any of our children replies that it doesn't
5077        * have a paint volume, we bail out
5078        */
5079       for (child = priv->first_child;
5080            child != NULL;
5081            child = child->priv->next_sibling)
5082         {
5083           const ClutterPaintVolume *child_volume;
5084
5085           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5086           if (child_volume == NULL)
5087             {
5088               res = FALSE;
5089               break;
5090             }
5091
5092           clutter_paint_volume_union (volume, child_volume);
5093           res = TRUE;
5094         }
5095     }
5096
5097   return res;
5098
5099 }
5100
5101 static gboolean
5102 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5103                                      ClutterPaintVolume *volume)
5104 {
5105   ClutterActorClass *klass;
5106   gboolean res;
5107
5108   klass = CLUTTER_ACTOR_GET_CLASS (self);
5109
5110   /* XXX - this thoroughly sucks, but we don't want to penalize users
5111    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5112    * redraw. This should go away in 2.0.
5113    */
5114   if (klass->paint == clutter_actor_real_paint &&
5115       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5116     {
5117       res = TRUE;
5118     }
5119   else
5120     {
5121       /* this is the default return value: we cannot know if a class
5122        * is going to paint outside its allocation, so we take the
5123        * conservative approach.
5124        */
5125       res = FALSE;
5126     }
5127
5128   if (clutter_actor_update_default_paint_volume (self, volume))
5129     return res;
5130
5131   return FALSE;
5132 }
5133
5134 /**
5135  * clutter_actor_get_default_paint_volume:
5136  * @self: a #ClutterActor
5137  *
5138  * Retrieves the default paint volume for @self.
5139  *
5140  * This function provides the same #ClutterPaintVolume that would be
5141  * computed by the default implementation inside #ClutterActor of the
5142  * #ClutterActorClass.get_paint_volume() virtual function.
5143  *
5144  * This function should only be used by #ClutterActor subclasses that
5145  * cannot chain up to the parent implementation when computing their
5146  * paint volume.
5147  *
5148  * Return value: (transfer none): a pointer to the default
5149  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5150  *   the actor could not compute a valid paint volume. The returned value
5151  *   is not guaranteed to be stable across multiple frames, so if you
5152  *   want to retain it, you will need to copy it using
5153  *   clutter_paint_volume_copy().
5154  *
5155  * Since: 1.10
5156  */
5157 const ClutterPaintVolume *
5158 clutter_actor_get_default_paint_volume (ClutterActor *self)
5159 {
5160   ClutterPaintVolume volume;
5161   ClutterPaintVolume *res;
5162
5163   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5164
5165   res = NULL;
5166   _clutter_paint_volume_init_static (&volume, self);
5167   if (clutter_actor_update_default_paint_volume (self, &volume))
5168     {
5169       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5170
5171       if (stage != NULL)
5172         {
5173           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5174           _clutter_paint_volume_copy_static (&volume, res);
5175         }
5176     }
5177
5178   clutter_paint_volume_free (&volume);
5179
5180   return res;
5181 }
5182
5183 static gboolean
5184 clutter_actor_real_has_overlaps (ClutterActor *self)
5185 {
5186   /* By default we'll assume that all actors need an offscreen redirect to get
5187    * the correct opacity. Actors such as ClutterTexture that would never need
5188    * an offscreen redirect can override this to return FALSE. */
5189   return TRUE;
5190 }
5191
5192 static void
5193 clutter_actor_real_destroy (ClutterActor *actor)
5194 {
5195   ClutterActorIter iter;
5196
5197   clutter_actor_iter_init (&iter, actor);
5198   while (clutter_actor_iter_next (&iter, NULL))
5199     clutter_actor_iter_destroy (&iter);
5200 }
5201
5202 static GObject *
5203 clutter_actor_constructor (GType gtype,
5204                            guint n_props,
5205                            GObjectConstructParam *props)
5206 {
5207   GObjectClass *gobject_class;
5208   ClutterActor *self;
5209   GObject *retval;
5210
5211   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5212   retval = gobject_class->constructor (gtype, n_props, props);
5213   self = CLUTTER_ACTOR (retval);
5214
5215   if (self->priv->layout_manager == NULL)
5216     {
5217       ClutterLayoutManager *default_layout;
5218
5219       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5220
5221       default_layout = clutter_fixed_layout_new ();
5222       clutter_actor_set_layout_manager (self, default_layout);
5223     }
5224
5225   return retval;
5226 }
5227
5228 static void
5229 clutter_actor_class_init (ClutterActorClass *klass)
5230 {
5231   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5232
5233   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5234   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5235   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5236   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5237
5238   object_class->constructor = clutter_actor_constructor;
5239   object_class->set_property = clutter_actor_set_property;
5240   object_class->get_property = clutter_actor_get_property;
5241   object_class->dispose = clutter_actor_dispose;
5242   object_class->finalize = clutter_actor_finalize;
5243
5244   klass->show = clutter_actor_real_show;
5245   klass->show_all = clutter_actor_show;
5246   klass->hide = clutter_actor_real_hide;
5247   klass->hide_all = clutter_actor_hide;
5248   klass->map = clutter_actor_real_map;
5249   klass->unmap = clutter_actor_real_unmap;
5250   klass->unrealize = clutter_actor_real_unrealize;
5251   klass->pick = clutter_actor_real_pick;
5252   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5253   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5254   klass->allocate = clutter_actor_real_allocate;
5255   klass->queue_redraw = clutter_actor_real_queue_redraw;
5256   klass->queue_relayout = clutter_actor_real_queue_relayout;
5257   klass->apply_transform = clutter_actor_real_apply_transform;
5258   klass->get_accessible = clutter_actor_real_get_accessible;
5259   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5260   klass->has_overlaps = clutter_actor_real_has_overlaps;
5261   klass->paint = clutter_actor_real_paint;
5262   klass->destroy = clutter_actor_real_destroy;
5263
5264   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5265
5266   /**
5267    * ClutterActor:x:
5268    *
5269    * X coordinate of the actor in pixels. If written, forces a fixed
5270    * position for the actor. If read, returns the fixed position if any,
5271    * otherwise the allocation if available, otherwise 0.
5272    *
5273    * The #ClutterActor:x property is animatable.
5274    */
5275   obj_props[PROP_X] =
5276     g_param_spec_float ("x",
5277                         P_("X coordinate"),
5278                         P_("X coordinate of the actor"),
5279                         -G_MAXFLOAT, G_MAXFLOAT,
5280                         0.0,
5281                         G_PARAM_READWRITE |
5282                         G_PARAM_STATIC_STRINGS |
5283                         CLUTTER_PARAM_ANIMATABLE);
5284
5285   /**
5286    * ClutterActor:y:
5287    *
5288    * Y coordinate of the actor in pixels. If written, forces a fixed
5289    * position for the actor.  If read, returns the fixed position if
5290    * any, otherwise the allocation if available, otherwise 0.
5291    *
5292    * The #ClutterActor:y property is animatable.
5293    */
5294   obj_props[PROP_Y] =
5295     g_param_spec_float ("y",
5296                         P_("Y coordinate"),
5297                         P_("Y coordinate of the actor"),
5298                         -G_MAXFLOAT, G_MAXFLOAT,
5299                         0.0,
5300                         G_PARAM_READWRITE |
5301                         G_PARAM_STATIC_STRINGS |
5302                         CLUTTER_PARAM_ANIMATABLE);
5303
5304   /**
5305    * ClutterActor:width:
5306    *
5307    * Width of the actor (in pixels). If written, forces the minimum and
5308    * natural size request of the actor to the given width. If read, returns
5309    * the allocated width if available, otherwise the width request.
5310    *
5311    * The #ClutterActor:width property is animatable.
5312    */
5313   obj_props[PROP_WIDTH] =
5314     g_param_spec_float ("width",
5315                         P_("Width"),
5316                         P_("Width of the actor"),
5317                         0.0, G_MAXFLOAT,
5318                         0.0,
5319                         G_PARAM_READWRITE |
5320                         G_PARAM_STATIC_STRINGS |
5321                         CLUTTER_PARAM_ANIMATABLE);
5322
5323   /**
5324    * ClutterActor:height:
5325    *
5326    * Height of the actor (in pixels).  If written, forces the minimum and
5327    * natural size request of the actor to the given height. If read, returns
5328    * the allocated height if available, otherwise the height request.
5329    *
5330    * The #ClutterActor:height property is animatable.
5331    */
5332   obj_props[PROP_HEIGHT] =
5333     g_param_spec_float ("height",
5334                         P_("Height"),
5335                         P_("Height of the actor"),
5336                         0.0, G_MAXFLOAT,
5337                         0.0,
5338                         G_PARAM_READWRITE |
5339                         G_PARAM_STATIC_STRINGS |
5340                         CLUTTER_PARAM_ANIMATABLE);
5341
5342   /**
5343    * ClutterActor:fixed-x:
5344    *
5345    * The fixed X position of the actor in pixels.
5346    *
5347    * Writing this property sets #ClutterActor:fixed-position-set
5348    * property as well, as a side effect
5349    *
5350    * Since: 0.8
5351    */
5352   obj_props[PROP_FIXED_X] =
5353     g_param_spec_float ("fixed-x",
5354                         P_("Fixed X"),
5355                         P_("Forced X position of the actor"),
5356                         -G_MAXFLOAT, G_MAXFLOAT,
5357                         0.0,
5358                         CLUTTER_PARAM_READWRITE);
5359
5360   /**
5361    * ClutterActor:fixed-y:
5362    *
5363    * The fixed Y position of the actor in pixels.
5364    *
5365    * Writing this property sets the #ClutterActor:fixed-position-set
5366    * property as well, as a side effect
5367    *
5368    * Since: 0.8
5369    */
5370   obj_props[PROP_FIXED_Y] =
5371     g_param_spec_float ("fixed-y",
5372                         P_("Fixed Y"),
5373                         P_("Forced Y position of the actor"),
5374                         -G_MAXFLOAT, G_MAXFLOAT,
5375                         0,
5376                         CLUTTER_PARAM_READWRITE);
5377
5378   /**
5379    * ClutterActor:fixed-position-set:
5380    *
5381    * This flag controls whether the #ClutterActor:fixed-x and
5382    * #ClutterActor:fixed-y properties are used
5383    *
5384    * Since: 0.8
5385    */
5386   obj_props[PROP_FIXED_POSITION_SET] =
5387     g_param_spec_boolean ("fixed-position-set",
5388                           P_("Fixed position set"),
5389                           P_("Whether to use fixed positioning for the actor"),
5390                           FALSE,
5391                           CLUTTER_PARAM_READWRITE);
5392
5393   /**
5394    * ClutterActor:min-width:
5395    *
5396    * A forced minimum width request for the actor, in pixels
5397    *
5398    * Writing this property sets the #ClutterActor:min-width-set property
5399    * as well, as a side effect.
5400    *
5401    *This property overrides the usual width request of the actor.
5402    *
5403    * Since: 0.8
5404    */
5405   obj_props[PROP_MIN_WIDTH] =
5406     g_param_spec_float ("min-width",
5407                         P_("Min Width"),
5408                         P_("Forced minimum width request for the actor"),
5409                         0.0, G_MAXFLOAT,
5410                         0.0,
5411                         CLUTTER_PARAM_READWRITE);
5412
5413   /**
5414    * ClutterActor:min-height:
5415    *
5416    * A forced minimum height request for the actor, in pixels
5417    *
5418    * Writing this property sets the #ClutterActor:min-height-set property
5419    * as well, as a side effect. This property overrides the usual height
5420    * request of the actor.
5421    *
5422    * Since: 0.8
5423    */
5424   obj_props[PROP_MIN_HEIGHT] =
5425     g_param_spec_float ("min-height",
5426                         P_("Min Height"),
5427                         P_("Forced minimum height request for the actor"),
5428                         0.0, G_MAXFLOAT,
5429                         0.0,
5430                         CLUTTER_PARAM_READWRITE);
5431
5432   /**
5433    * ClutterActor:natural-width:
5434    *
5435    * A forced natural width request for the actor, in pixels
5436    *
5437    * Writing this property sets the #ClutterActor:natural-width-set
5438    * property as well, as a side effect. This property overrides the
5439    * usual width request of the actor
5440    *
5441    * Since: 0.8
5442    */
5443   obj_props[PROP_NATURAL_WIDTH] =
5444     g_param_spec_float ("natural-width",
5445                         P_("Natural Width"),
5446                         P_("Forced natural width request for the actor"),
5447                         0.0, G_MAXFLOAT,
5448                         0.0,
5449                         CLUTTER_PARAM_READWRITE);
5450
5451   /**
5452    * ClutterActor:natural-height:
5453    *
5454    * A forced natural height request for the actor, in pixels
5455    *
5456    * Writing this property sets the #ClutterActor:natural-height-set
5457    * property as well, as a side effect. This property overrides the
5458    * usual height request of the actor
5459    *
5460    * Since: 0.8
5461    */
5462   obj_props[PROP_NATURAL_HEIGHT] =
5463     g_param_spec_float ("natural-height",
5464                         P_("Natural Height"),
5465                         P_("Forced natural height request for the actor"),
5466                         0.0, G_MAXFLOAT,
5467                         0.0,
5468                         CLUTTER_PARAM_READWRITE);
5469
5470   /**
5471    * ClutterActor:min-width-set:
5472    *
5473    * This flag controls whether the #ClutterActor:min-width property
5474    * is used
5475    *
5476    * Since: 0.8
5477    */
5478   obj_props[PROP_MIN_WIDTH_SET] =
5479     g_param_spec_boolean ("min-width-set",
5480                           P_("Minimum width set"),
5481                           P_("Whether to use the min-width property"),
5482                           FALSE,
5483                           CLUTTER_PARAM_READWRITE);
5484
5485   /**
5486    * ClutterActor:min-height-set:
5487    *
5488    * This flag controls whether the #ClutterActor:min-height property
5489    * is used
5490    *
5491    * Since: 0.8
5492    */
5493   obj_props[PROP_MIN_HEIGHT_SET] =
5494     g_param_spec_boolean ("min-height-set",
5495                           P_("Minimum height set"),
5496                           P_("Whether to use the min-height property"),
5497                           FALSE,
5498                           CLUTTER_PARAM_READWRITE);
5499
5500   /**
5501    * ClutterActor:natural-width-set:
5502    *
5503    * This flag controls whether the #ClutterActor:natural-width property
5504    * is used
5505    *
5506    * Since: 0.8
5507    */
5508   obj_props[PROP_NATURAL_WIDTH_SET] =
5509     g_param_spec_boolean ("natural-width-set",
5510                           P_("Natural width set"),
5511                           P_("Whether to use the natural-width property"),
5512                           FALSE,
5513                           CLUTTER_PARAM_READWRITE);
5514
5515   /**
5516    * ClutterActor:natural-height-set:
5517    *
5518    * This flag controls whether the #ClutterActor:natural-height property
5519    * is used
5520    *
5521    * Since: 0.8
5522    */
5523   obj_props[PROP_NATURAL_HEIGHT_SET] =
5524     g_param_spec_boolean ("natural-height-set",
5525                           P_("Natural height set"),
5526                           P_("Whether to use the natural-height property"),
5527                           FALSE,
5528                           CLUTTER_PARAM_READWRITE);
5529
5530   /**
5531    * ClutterActor:allocation:
5532    *
5533    * The allocation for the actor, in pixels
5534    *
5535    * This is property is read-only, but you might monitor it to know when an
5536    * actor moves or resizes
5537    *
5538    * Since: 0.8
5539    */
5540   obj_props[PROP_ALLOCATION] =
5541     g_param_spec_boxed ("allocation",
5542                         P_("Allocation"),
5543                         P_("The actor's allocation"),
5544                         CLUTTER_TYPE_ACTOR_BOX,
5545                         CLUTTER_PARAM_READABLE);
5546
5547   /**
5548    * ClutterActor:request-mode:
5549    *
5550    * Request mode for the #ClutterActor. The request mode determines the
5551    * type of geometry management used by the actor, either height for width
5552    * (the default) or width for height.
5553    *
5554    * For actors implementing height for width, the parent container should get
5555    * the preferred width first, and then the preferred height for that width.
5556    *
5557    * For actors implementing width for height, the parent container should get
5558    * the preferred height first, and then the preferred width for that height.
5559    *
5560    * For instance:
5561    *
5562    * |[
5563    *   ClutterRequestMode mode;
5564    *   gfloat natural_width, min_width;
5565    *   gfloat natural_height, min_height;
5566    *
5567    *   mode = clutter_actor_get_request_mode (child);
5568    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5569    *     {
5570    *       clutter_actor_get_preferred_width (child, -1,
5571    *                                          &amp;min_width,
5572    *                                          &amp;natural_width);
5573    *       clutter_actor_get_preferred_height (child, natural_width,
5574    *                                           &amp;min_height,
5575    *                                           &amp;natural_height);
5576    *     }
5577    *   else
5578    *     {
5579    *       clutter_actor_get_preferred_height (child, -1,
5580    *                                           &amp;min_height,
5581    *                                           &amp;natural_height);
5582    *       clutter_actor_get_preferred_width (child, natural_height,
5583    *                                          &amp;min_width,
5584    *                                          &amp;natural_width);
5585    *     }
5586    * ]|
5587    *
5588    * will retrieve the minimum and natural width and height depending on the
5589    * preferred request mode of the #ClutterActor "child".
5590    *
5591    * The clutter_actor_get_preferred_size() function will implement this
5592    * check for you.
5593    *
5594    * Since: 0.8
5595    */
5596   obj_props[PROP_REQUEST_MODE] =
5597     g_param_spec_enum ("request-mode",
5598                        P_("Request Mode"),
5599                        P_("The actor's request mode"),
5600                        CLUTTER_TYPE_REQUEST_MODE,
5601                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5602                        CLUTTER_PARAM_READWRITE);
5603
5604   /**
5605    * ClutterActor:depth:
5606    *
5607    * The position of the actor on the Z axis.
5608    *
5609    * The #ClutterActor:depth property is relative to the parent's
5610    * modelview matrix.
5611    *
5612    * The #ClutterActor:depth property is animatable.
5613    *
5614    * Since: 0.6
5615    */
5616   obj_props[PROP_DEPTH] =
5617     g_param_spec_float ("depth",
5618                         P_("Depth"),
5619                         P_("Position on the Z axis"),
5620                         -G_MAXFLOAT, G_MAXFLOAT,
5621                         0.0,
5622                         G_PARAM_READWRITE |
5623                         G_PARAM_STATIC_STRINGS |
5624                         CLUTTER_PARAM_ANIMATABLE);
5625
5626   /**
5627    * ClutterActor:opacity:
5628    *
5629    * Opacity of an actor, between 0 (fully transparent) and
5630    * 255 (fully opaque)
5631    *
5632    * The #ClutterActor:opacity property is animatable.
5633    */
5634   obj_props[PROP_OPACITY] =
5635     g_param_spec_uint ("opacity",
5636                        P_("Opacity"),
5637                        P_("Opacity of an actor"),
5638                        0, 255,
5639                        255,
5640                        G_PARAM_READWRITE |
5641                        G_PARAM_STATIC_STRINGS |
5642                        CLUTTER_PARAM_ANIMATABLE);
5643
5644   /**
5645    * ClutterActor:offscreen-redirect:
5646    *
5647    * Determines the conditions in which the actor will be redirected
5648    * to an offscreen framebuffer while being painted. For example this
5649    * can be used to cache an actor in a framebuffer or for improved
5650    * handling of transparent actors. See
5651    * clutter_actor_set_offscreen_redirect() for details.
5652    *
5653    * Since: 1.8
5654    */
5655   obj_props[PROP_OFFSCREEN_REDIRECT] =
5656     g_param_spec_flags ("offscreen-redirect",
5657                         P_("Offscreen redirect"),
5658                         P_("Flags controlling when to flatten the actor into a single image"),
5659                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5660                         0,
5661                         CLUTTER_PARAM_READWRITE);
5662
5663   /**
5664    * ClutterActor:visible:
5665    *
5666    * Whether the actor is set to be visible or not
5667    *
5668    * See also #ClutterActor:mapped
5669    */
5670   obj_props[PROP_VISIBLE] =
5671     g_param_spec_boolean ("visible",
5672                           P_("Visible"),
5673                           P_("Whether the actor is visible or not"),
5674                           FALSE,
5675                           CLUTTER_PARAM_READWRITE);
5676
5677   /**
5678    * ClutterActor:mapped:
5679    *
5680    * Whether the actor is mapped (will be painted when the stage
5681    * to which it belongs is mapped)
5682    *
5683    * Since: 1.0
5684    */
5685   obj_props[PROP_MAPPED] =
5686     g_param_spec_boolean ("mapped",
5687                           P_("Mapped"),
5688                           P_("Whether the actor will be painted"),
5689                           FALSE,
5690                           CLUTTER_PARAM_READABLE);
5691
5692   /**
5693    * ClutterActor:realized:
5694    *
5695    * Whether the actor has been realized
5696    *
5697    * Since: 1.0
5698    */
5699   obj_props[PROP_REALIZED] =
5700     g_param_spec_boolean ("realized",
5701                           P_("Realized"),
5702                           P_("Whether the actor has been realized"),
5703                           FALSE,
5704                           CLUTTER_PARAM_READABLE);
5705
5706   /**
5707    * ClutterActor:reactive:
5708    *
5709    * Whether the actor is reactive to events or not
5710    *
5711    * Only reactive actors will emit event-related signals
5712    *
5713    * Since: 0.6
5714    */
5715   obj_props[PROP_REACTIVE] =
5716     g_param_spec_boolean ("reactive",
5717                           P_("Reactive"),
5718                           P_("Whether the actor is reactive to events"),
5719                           FALSE,
5720                           CLUTTER_PARAM_READWRITE);
5721
5722   /**
5723    * ClutterActor:has-clip:
5724    *
5725    * Whether the actor has the #ClutterActor:clip property set or not
5726    */
5727   obj_props[PROP_HAS_CLIP] =
5728     g_param_spec_boolean ("has-clip",
5729                           P_("Has Clip"),
5730                           P_("Whether the actor has a clip set"),
5731                           FALSE,
5732                           CLUTTER_PARAM_READABLE);
5733
5734   /**
5735    * ClutterActor:clip:
5736    *
5737    * The clip region for the actor, in actor-relative coordinates
5738    *
5739    * Every part of the actor outside the clip region will not be
5740    * painted
5741    */
5742   obj_props[PROP_CLIP] =
5743     g_param_spec_boxed ("clip",
5744                         P_("Clip"),
5745                         P_("The clip region for the actor"),
5746                         CLUTTER_TYPE_GEOMETRY,
5747                         CLUTTER_PARAM_READWRITE);
5748
5749   /**
5750    * ClutterActor:name:
5751    *
5752    * The name of the actor
5753    *
5754    * Since: 0.2
5755    */
5756   obj_props[PROP_NAME] =
5757     g_param_spec_string ("name",
5758                          P_("Name"),
5759                          P_("Name of the actor"),
5760                          NULL,
5761                          CLUTTER_PARAM_READWRITE);
5762
5763   /**
5764    * ClutterActor:scale-x:
5765    *
5766    * The horizontal scale of the actor.
5767    *
5768    * The #ClutterActor:scale-x property is animatable.
5769    *
5770    * Since: 0.6
5771    */
5772   obj_props[PROP_SCALE_X] =
5773     g_param_spec_double ("scale-x",
5774                          P_("Scale X"),
5775                          P_("Scale factor on the X axis"),
5776                          0.0, G_MAXDOUBLE,
5777                          1.0,
5778                          G_PARAM_READWRITE |
5779                          G_PARAM_STATIC_STRINGS |
5780                          CLUTTER_PARAM_ANIMATABLE);
5781
5782   /**
5783    * ClutterActor:scale-y:
5784    *
5785    * The vertical scale of the actor.
5786    *
5787    * The #ClutterActor:scale-y property is animatable.
5788    *
5789    * Since: 0.6
5790    */
5791   obj_props[PROP_SCALE_Y] =
5792     g_param_spec_double ("scale-y",
5793                          P_("Scale Y"),
5794                          P_("Scale factor on the Y axis"),
5795                          0.0, G_MAXDOUBLE,
5796                          1.0,
5797                          G_PARAM_READWRITE |
5798                          G_PARAM_STATIC_STRINGS |
5799                          CLUTTER_PARAM_ANIMATABLE);
5800
5801   /**
5802    * ClutterActor:scale-center-x:
5803    *
5804    * The horizontal center point for scaling
5805    *
5806    * Since: 1.0
5807    */
5808   obj_props[PROP_SCALE_CENTER_X] =
5809     g_param_spec_float ("scale-center-x",
5810                         P_("Scale Center X"),
5811                         P_("Horizontal scale center"),
5812                         -G_MAXFLOAT, G_MAXFLOAT,
5813                         0.0,
5814                         CLUTTER_PARAM_READWRITE);
5815
5816   /**
5817    * ClutterActor:scale-center-y:
5818    *
5819    * The vertical center point for scaling
5820    *
5821    * Since: 1.0
5822    */
5823   obj_props[PROP_SCALE_CENTER_Y] =
5824     g_param_spec_float ("scale-center-y",
5825                         P_("Scale Center Y"),
5826                         P_("Vertical scale center"),
5827                         -G_MAXFLOAT, G_MAXFLOAT,
5828                         0.0,
5829                         CLUTTER_PARAM_READWRITE);
5830
5831   /**
5832    * ClutterActor:scale-gravity:
5833    *
5834    * The center point for scaling expressed as a #ClutterGravity
5835    *
5836    * Since: 1.0
5837    */
5838   obj_props[PROP_SCALE_GRAVITY] =
5839     g_param_spec_enum ("scale-gravity",
5840                        P_("Scale Gravity"),
5841                        P_("The center of scaling"),
5842                        CLUTTER_TYPE_GRAVITY,
5843                        CLUTTER_GRAVITY_NONE,
5844                        CLUTTER_PARAM_READWRITE);
5845
5846   /**
5847    * ClutterActor:rotation-angle-x:
5848    *
5849    * The rotation angle on the X axis.
5850    *
5851    * The #ClutterActor:rotation-angle-x property is animatable.
5852    *
5853    * Since: 0.6
5854    */
5855   obj_props[PROP_ROTATION_ANGLE_X] =
5856     g_param_spec_double ("rotation-angle-x",
5857                          P_("Rotation Angle X"),
5858                          P_("The rotation angle on the X axis"),
5859                          -G_MAXDOUBLE, G_MAXDOUBLE,
5860                          0.0,
5861                          G_PARAM_READWRITE |
5862                          G_PARAM_STATIC_STRINGS |
5863                          CLUTTER_PARAM_ANIMATABLE);
5864
5865   /**
5866    * ClutterActor:rotation-angle-y:
5867    *
5868    * The rotation angle on the Y axis
5869    *
5870    * The #ClutterActor:rotation-angle-y property is animatable.
5871    *
5872    * Since: 0.6
5873    */
5874   obj_props[PROP_ROTATION_ANGLE_Y] =
5875     g_param_spec_double ("rotation-angle-y",
5876                          P_("Rotation Angle Y"),
5877                          P_("The rotation angle on the Y axis"),
5878                          -G_MAXDOUBLE, G_MAXDOUBLE,
5879                          0.0,
5880                          G_PARAM_READWRITE |
5881                          G_PARAM_STATIC_STRINGS |
5882                          CLUTTER_PARAM_ANIMATABLE);
5883
5884   /**
5885    * ClutterActor:rotation-angle-z:
5886    *
5887    * The rotation angle on the Z axis
5888    *
5889    * The #ClutterActor:rotation-angle-z property is animatable.
5890    *
5891    * Since: 0.6
5892    */
5893   obj_props[PROP_ROTATION_ANGLE_Z] =
5894     g_param_spec_double ("rotation-angle-z",
5895                          P_("Rotation Angle Z"),
5896                          P_("The rotation angle on the Z axis"),
5897                          -G_MAXDOUBLE, G_MAXDOUBLE,
5898                          0.0,
5899                          G_PARAM_READWRITE |
5900                          G_PARAM_STATIC_STRINGS |
5901                          CLUTTER_PARAM_ANIMATABLE);
5902
5903   /**
5904    * ClutterActor:rotation-center-x:
5905    *
5906    * The rotation center on the X axis.
5907    *
5908    * Since: 0.6
5909    */
5910   obj_props[PROP_ROTATION_CENTER_X] =
5911     g_param_spec_boxed ("rotation-center-x",
5912                         P_("Rotation Center X"),
5913                         P_("The rotation center on the X axis"),
5914                         CLUTTER_TYPE_VERTEX,
5915                         CLUTTER_PARAM_READWRITE);
5916
5917   /**
5918    * ClutterActor:rotation-center-y:
5919    *
5920    * The rotation center on the Y axis.
5921    *
5922    * Since: 0.6
5923    */
5924   obj_props[PROP_ROTATION_CENTER_Y] =
5925     g_param_spec_boxed ("rotation-center-y",
5926                         P_("Rotation Center Y"),
5927                         P_("The rotation center on the Y axis"),
5928                         CLUTTER_TYPE_VERTEX,
5929                         CLUTTER_PARAM_READWRITE);
5930
5931   /**
5932    * ClutterActor:rotation-center-z:
5933    *
5934    * The rotation center on the Z axis.
5935    *
5936    * Since: 0.6
5937    */
5938   obj_props[PROP_ROTATION_CENTER_Z] =
5939     g_param_spec_boxed ("rotation-center-z",
5940                         P_("Rotation Center Z"),
5941                         P_("The rotation center on the Z axis"),
5942                         CLUTTER_TYPE_VERTEX,
5943                         CLUTTER_PARAM_READWRITE);
5944
5945   /**
5946    * ClutterActor:rotation-center-z-gravity:
5947    *
5948    * The rotation center on the Z axis expressed as a #ClutterGravity.
5949    *
5950    * Since: 1.0
5951    */
5952   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5953     g_param_spec_enum ("rotation-center-z-gravity",
5954                        P_("Rotation Center Z Gravity"),
5955                        P_("Center point for rotation around the Z axis"),
5956                        CLUTTER_TYPE_GRAVITY,
5957                        CLUTTER_GRAVITY_NONE,
5958                        CLUTTER_PARAM_READWRITE);
5959
5960   /**
5961    * ClutterActor:anchor-x:
5962    *
5963    * The X coordinate of an actor's anchor point, relative to
5964    * the actor coordinate space, in pixels
5965    *
5966    * Since: 0.8
5967    */
5968   obj_props[PROP_ANCHOR_X] =
5969     g_param_spec_float ("anchor-x",
5970                         P_("Anchor X"),
5971                         P_("X coordinate of the anchor point"),
5972                         -G_MAXFLOAT, G_MAXFLOAT,
5973                         0,
5974                         CLUTTER_PARAM_READWRITE);
5975
5976   /**
5977    * ClutterActor:anchor-y:
5978    *
5979    * The Y coordinate of an actor's anchor point, relative to
5980    * the actor coordinate space, in pixels
5981    *
5982    * Since: 0.8
5983    */
5984   obj_props[PROP_ANCHOR_Y] =
5985     g_param_spec_float ("anchor-y",
5986                         P_("Anchor Y"),
5987                         P_("Y coordinate of the anchor point"),
5988                         -G_MAXFLOAT, G_MAXFLOAT,
5989                         0,
5990                         CLUTTER_PARAM_READWRITE);
5991
5992   /**
5993    * ClutterActor:anchor-gravity:
5994    *
5995    * The anchor point expressed as a #ClutterGravity
5996    *
5997    * Since: 1.0
5998    */
5999   obj_props[PROP_ANCHOR_GRAVITY] =
6000     g_param_spec_enum ("anchor-gravity",
6001                        P_("Anchor Gravity"),
6002                        P_("The anchor point as a ClutterGravity"),
6003                        CLUTTER_TYPE_GRAVITY,
6004                        CLUTTER_GRAVITY_NONE,
6005                        CLUTTER_PARAM_READWRITE);
6006
6007   /**
6008    * ClutterActor:show-on-set-parent:
6009    *
6010    * If %TRUE, the actor is automatically shown when parented.
6011    *
6012    * Calling clutter_actor_hide() on an actor which has not been
6013    * parented will set this property to %FALSE as a side effect.
6014    *
6015    * Since: 0.8
6016    */
6017   obj_props[PROP_SHOW_ON_SET_PARENT] =
6018     g_param_spec_boolean ("show-on-set-parent",
6019                           P_("Show on set parent"),
6020                           P_("Whether the actor is shown when parented"),
6021                           TRUE,
6022                           CLUTTER_PARAM_READWRITE);
6023
6024   /**
6025    * ClutterActor:clip-to-allocation:
6026    *
6027    * Whether the clip region should track the allocated area
6028    * of the actor.
6029    *
6030    * This property is ignored if a clip area has been explicitly
6031    * set using clutter_actor_set_clip().
6032    *
6033    * Since: 1.0
6034    */
6035   obj_props[PROP_CLIP_TO_ALLOCATION] =
6036     g_param_spec_boolean ("clip-to-allocation",
6037                           P_("Clip to Allocation"),
6038                           P_("Sets the clip region to track the actor's allocation"),
6039                           FALSE,
6040                           CLUTTER_PARAM_READWRITE);
6041
6042   /**
6043    * ClutterActor:text-direction:
6044    *
6045    * The direction of the text inside a #ClutterActor.
6046    *
6047    * Since: 1.0
6048    */
6049   obj_props[PROP_TEXT_DIRECTION] =
6050     g_param_spec_enum ("text-direction",
6051                        P_("Text Direction"),
6052                        P_("Direction of the text"),
6053                        CLUTTER_TYPE_TEXT_DIRECTION,
6054                        CLUTTER_TEXT_DIRECTION_LTR,
6055                        CLUTTER_PARAM_READWRITE);
6056
6057   /**
6058    * ClutterActor:has-pointer:
6059    *
6060    * Whether the actor contains the pointer of a #ClutterInputDevice
6061    * or not.
6062    *
6063    * Since: 1.2
6064    */
6065   obj_props[PROP_HAS_POINTER] =
6066     g_param_spec_boolean ("has-pointer",
6067                           P_("Has Pointer"),
6068                           P_("Whether the actor contains the pointer of an input device"),
6069                           FALSE,
6070                           CLUTTER_PARAM_READABLE);
6071
6072   /**
6073    * ClutterActor:actions:
6074    *
6075    * Adds a #ClutterAction to the actor
6076    *
6077    * Since: 1.4
6078    */
6079   obj_props[PROP_ACTIONS] =
6080     g_param_spec_object ("actions",
6081                          P_("Actions"),
6082                          P_("Adds an action to the actor"),
6083                          CLUTTER_TYPE_ACTION,
6084                          CLUTTER_PARAM_WRITABLE);
6085
6086   /**
6087    * ClutterActor:constraints:
6088    *
6089    * Adds a #ClutterConstraint to the actor
6090    *
6091    * Since: 1.4
6092    */
6093   obj_props[PROP_CONSTRAINTS] =
6094     g_param_spec_object ("constraints",
6095                          P_("Constraints"),
6096                          P_("Adds a constraint to the actor"),
6097                          CLUTTER_TYPE_CONSTRAINT,
6098                          CLUTTER_PARAM_WRITABLE);
6099
6100   /**
6101    * ClutterActor:effect:
6102    *
6103    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6104    *
6105    * Since: 1.4
6106    */
6107   obj_props[PROP_EFFECT] =
6108     g_param_spec_object ("effect",
6109                          P_("Effect"),
6110                          P_("Add an effect to be applied on the actor"),
6111                          CLUTTER_TYPE_EFFECT,
6112                          CLUTTER_PARAM_WRITABLE);
6113
6114   /**
6115    * ClutterActor:layout-manager:
6116    *
6117    * A delegate object for controlling the layout of the children of
6118    * an actor.
6119    *
6120    * Since: 1.10
6121    */
6122   obj_props[PROP_LAYOUT_MANAGER] =
6123     g_param_spec_object ("layout-manager",
6124                          P_("Layout Manager"),
6125                          P_("The object controlling the layout of an actor's children"),
6126                          CLUTTER_TYPE_LAYOUT_MANAGER,
6127                          CLUTTER_PARAM_READWRITE);
6128
6129
6130   /**
6131    * ClutterActor:x-align:
6132    *
6133    * The alignment of an actor on the X axis, if the actor has been given
6134    * extra space for its allocation.
6135    *
6136    * Since: 1.10
6137    */
6138   obj_props[PROP_X_ALIGN] =
6139     g_param_spec_enum ("x-align",
6140                        P_("X Alignment"),
6141                        P_("The alignment of the actor on the X axis within its allocation"),
6142                        CLUTTER_TYPE_ACTOR_ALIGN,
6143                        CLUTTER_ACTOR_ALIGN_FILL,
6144                        CLUTTER_PARAM_READWRITE);
6145
6146   /**
6147    * ClutterActor:y-align:
6148    *
6149    * The alignment of an actor on the Y axis, if the actor has been given
6150    * extra space for its allocation.
6151    *
6152    * Since: 1.10
6153    */
6154   obj_props[PROP_Y_ALIGN] =
6155     g_param_spec_enum ("y-align",
6156                        P_("Y Alignment"),
6157                        P_("The alignment of the actor on the Y axis within its allocation"),
6158                        CLUTTER_TYPE_ACTOR_ALIGN,
6159                        CLUTTER_ACTOR_ALIGN_FILL,
6160                        CLUTTER_PARAM_READWRITE);
6161
6162   /**
6163    * ClutterActor:margin-top:
6164    *
6165    * The margin (in pixels) from the top of the actor.
6166    *
6167    * This property adds a margin to the actor's preferred size; the margin
6168    * will be automatically taken into account when allocating the actor.
6169    *
6170    * Since: 1.10
6171    */
6172   obj_props[PROP_MARGIN_TOP] =
6173     g_param_spec_float ("margin-top",
6174                         P_("Margin Top"),
6175                         P_("Extra space at the top"),
6176                         0.0, G_MAXFLOAT,
6177                         0.0,
6178                         CLUTTER_PARAM_READWRITE);
6179
6180   /**
6181    * ClutterActor:margin-bottom:
6182    *
6183    * The margin (in pixels) from the bottom of the actor.
6184    *
6185    * This property adds a margin to the actor's preferred size; the margin
6186    * will be automatically taken into account when allocating the actor.
6187    *
6188    * Since: 1.10
6189    */
6190   obj_props[PROP_MARGIN_BOTTOM] =
6191     g_param_spec_float ("margin-bottom",
6192                         P_("Margin Bottom"),
6193                         P_("Extra space at the bottom"),
6194                         0.0, G_MAXFLOAT,
6195                         0.0,
6196                         CLUTTER_PARAM_READWRITE);
6197
6198   /**
6199    * ClutterActor:margin-left:
6200    *
6201    * The margin (in pixels) from the left of the actor.
6202    *
6203    * This property adds a margin to the actor's preferred size; the margin
6204    * will be automatically taken into account when allocating the actor.
6205    *
6206    * Since: 1.10
6207    */
6208   obj_props[PROP_MARGIN_LEFT] =
6209     g_param_spec_float ("margin-left",
6210                         P_("Margin Left"),
6211                         P_("Extra space at the left"),
6212                         0.0, G_MAXFLOAT,
6213                         0.0,
6214                         CLUTTER_PARAM_READWRITE);
6215
6216   /**
6217    * ClutterActor:margin-right:
6218    *
6219    * The margin (in pixels) from the right of the actor.
6220    *
6221    * This property adds a margin to the actor's preferred size; the margin
6222    * will be automatically taken into account when allocating the actor.
6223    *
6224    * Since: 1.10
6225    */
6226   obj_props[PROP_MARGIN_RIGHT] =
6227     g_param_spec_float ("margin-right",
6228                         P_("Margin Right"),
6229                         P_("Extra space at the right"),
6230                         0.0, G_MAXFLOAT,
6231                         0.0,
6232                         CLUTTER_PARAM_READWRITE);
6233
6234   /**
6235    * ClutterActor:background-color-set:
6236    *
6237    * Whether the #ClutterActor:background-color property has been set.
6238    *
6239    * Since: 1.10
6240    */
6241   obj_props[PROP_BACKGROUND_COLOR_SET] =
6242     g_param_spec_boolean ("background-color-set",
6243                           P_("Background Color Set"),
6244                           P_("Whether the background color is set"),
6245                           FALSE,
6246                           CLUTTER_PARAM_READABLE);
6247
6248   /**
6249    * ClutterActor:background-color:
6250    *
6251    * Paints a solid fill of the actor's allocation using the specified
6252    * color.
6253    *
6254    * The #ClutterActor:background-color property is animatable.
6255    *
6256    * Since: 1.10
6257    */
6258   obj_props[PROP_BACKGROUND_COLOR] =
6259     clutter_param_spec_color ("background-color",
6260                               P_("Background color"),
6261                               P_("The actor's background color"),
6262                               CLUTTER_COLOR_Transparent,
6263                               G_PARAM_READWRITE |
6264                               G_PARAM_STATIC_STRINGS |
6265                               CLUTTER_PARAM_ANIMATABLE);
6266
6267   /**
6268    * ClutterActor:first-child:
6269    *
6270    * The actor's first child.
6271    *
6272    * Since: 1.10
6273    */
6274   obj_props[PROP_FIRST_CHILD] =
6275     g_param_spec_object ("first-child",
6276                          P_("First Child"),
6277                          P_("The actor's first child"),
6278                          CLUTTER_TYPE_ACTOR,
6279                          CLUTTER_PARAM_READABLE);
6280
6281   /**
6282    * ClutterActor:last-child:
6283    *
6284    * The actor's last child.
6285    *
6286    * Since: 1.10
6287    */
6288   obj_props[PROP_LAST_CHILD] =
6289     g_param_spec_object ("last-child",
6290                          P_("Last Child"),
6291                          P_("The actor's last child"),
6292                          CLUTTER_TYPE_ACTOR,
6293                          CLUTTER_PARAM_READABLE);
6294
6295   /**
6296    * ClutterActor:content:
6297    *
6298    * The #ClutterContent implementation that controls the content
6299    * of the actor.
6300    *
6301    * Since: 1.10
6302    */
6303   obj_props[PROP_CONTENT] =
6304     g_param_spec_object ("content",
6305                          P_("Content"),
6306                          P_("Delegate object for painting the actor's content"),
6307                          CLUTTER_TYPE_CONTENT,
6308                          CLUTTER_PARAM_READWRITE);
6309
6310   /**
6311    * ClutterActor:content-gravity:
6312    *
6313    * The alignment that should be honoured by the #ClutterContent
6314    * set with the #ClutterActor:content property.
6315    *
6316    * Changing the value of this property will change the bounding box of
6317    * the content; you can use the #ClutterActor:content-box property to
6318    * get the position and size of the content within the actor's
6319    * allocation.
6320    *
6321    * This property is meaningful only for #ClutterContent implementations
6322    * that have a preferred size, and if the preferred size is smaller than
6323    * the actor's allocation.
6324    *
6325    * Since: 1.10
6326    */
6327   obj_props[PROP_CONTENT_GRAVITY] =
6328     g_param_spec_enum ("content-gravity",
6329                        P_("Content Gravity"),
6330                        P_("Alignment of the actor's content"),
6331                        CLUTTER_TYPE_CONTENT_GRAVITY,
6332                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6333                        CLUTTER_PARAM_READWRITE);
6334
6335   /**
6336    * ClutterActor:content-box:
6337    *
6338    * The bounding box for the #ClutterContent used by the actor.
6339    *
6340    * The value of this property is controlled by the #ClutterActor:allocation
6341    * and #ClutterActor:content-gravity properties of #ClutterActor.
6342    *
6343    * The bounding box for the content is guaranteed to never exceed the
6344    * allocation's of the actor.
6345    *
6346    * Since: 1.10
6347    */
6348   obj_props[PROP_CONTENT_BOX] =
6349     g_param_spec_boxed ("content-box",
6350                         P_("Content Box"),
6351                         P_("The bounding box of the actor's content"),
6352                         CLUTTER_TYPE_ACTOR_BOX,
6353                         CLUTTER_PARAM_READABLE);
6354
6355   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6356
6357   /**
6358    * ClutterActor::destroy:
6359    * @actor: the #ClutterActor which emitted the signal
6360    *
6361    * The ::destroy signal notifies that all references held on the
6362    * actor which emitted it should be released.
6363    *
6364    * The ::destroy signal should be used by all holders of a reference
6365    * on @actor.
6366    *
6367    * This signal might result in the finalization of the #ClutterActor
6368    * if all references are released.
6369    *
6370    * Composite actors and actors implementing the #ClutterContainer
6371    * interface should override the default implementation of the
6372    * class handler of this signal and call clutter_actor_destroy() on
6373    * their children. When overriding the default class handler, it is
6374    * required to chain up to the parent's implementation.
6375    *
6376    * Since: 0.2
6377    */
6378   actor_signals[DESTROY] =
6379     g_signal_new (I_("destroy"),
6380                   G_TYPE_FROM_CLASS (object_class),
6381                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6382                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6383                   NULL, NULL,
6384                   _clutter_marshal_VOID__VOID,
6385                   G_TYPE_NONE, 0);
6386   /**
6387    * ClutterActor::show:
6388    * @actor: the object which received the signal
6389    *
6390    * The ::show signal is emitted when an actor is visible and
6391    * rendered on the stage.
6392    *
6393    * Since: 0.2
6394    */
6395   actor_signals[SHOW] =
6396     g_signal_new (I_("show"),
6397                   G_TYPE_FROM_CLASS (object_class),
6398                   G_SIGNAL_RUN_FIRST,
6399                   G_STRUCT_OFFSET (ClutterActorClass, show),
6400                   NULL, NULL,
6401                   _clutter_marshal_VOID__VOID,
6402                   G_TYPE_NONE, 0);
6403   /**
6404    * ClutterActor::hide:
6405    * @actor: the object which received the signal
6406    *
6407    * The ::hide signal is emitted when an actor is no longer rendered
6408    * on the stage.
6409    *
6410    * Since: 0.2
6411    */
6412   actor_signals[HIDE] =
6413     g_signal_new (I_("hide"),
6414                   G_TYPE_FROM_CLASS (object_class),
6415                   G_SIGNAL_RUN_FIRST,
6416                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6417                   NULL, NULL,
6418                   _clutter_marshal_VOID__VOID,
6419                   G_TYPE_NONE, 0);
6420   /**
6421    * ClutterActor::parent-set:
6422    * @actor: the object which received the signal
6423    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6424    *
6425    * This signal is emitted when the parent of the actor changes.
6426    *
6427    * Since: 0.2
6428    */
6429   actor_signals[PARENT_SET] =
6430     g_signal_new (I_("parent-set"),
6431                   G_TYPE_FROM_CLASS (object_class),
6432                   G_SIGNAL_RUN_LAST,
6433                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6434                   NULL, NULL,
6435                   _clutter_marshal_VOID__OBJECT,
6436                   G_TYPE_NONE, 1,
6437                   CLUTTER_TYPE_ACTOR);
6438
6439   /**
6440    * ClutterActor::queue-redraw:
6441    * @actor: the actor we're bubbling the redraw request through
6442    * @origin: the actor which initiated the redraw request
6443    *
6444    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6445    * is called on @origin.
6446    *
6447    * The default implementation for #ClutterActor chains up to the
6448    * parent actor and queues a redraw on the parent, thus "bubbling"
6449    * the redraw queue up through the actor graph. The default
6450    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6451    * in a main loop idle handler.
6452    *
6453    * Note that the @origin actor may be the stage, or a container; it
6454    * does not have to be a leaf node in the actor graph.
6455    *
6456    * Toolkits embedding a #ClutterStage which require a redraw and
6457    * relayout cycle can stop the emission of this signal using the
6458    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6459    * themselves, like:
6460    *
6461    * |[
6462    *   static void
6463    *   on_redraw_complete (gpointer data)
6464    *   {
6465    *     ClutterStage *stage = data;
6466    *
6467    *     /&ast; execute the Clutter drawing pipeline &ast;/
6468    *     clutter_stage_ensure_redraw (stage);
6469    *   }
6470    *
6471    *   static void
6472    *   on_stage_queue_redraw (ClutterStage *stage)
6473    *   {
6474    *     /&ast; this prevents the default handler to run &ast;/
6475    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6476    *
6477    *     /&ast; queue a redraw with the host toolkit and call
6478    *      &ast; a function when the redraw has been completed
6479    *      &ast;/
6480    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6481    *   }
6482    * ]|
6483    *
6484    * <note><para>This signal is emitted before the Clutter paint
6485    * pipeline is executed. If you want to know when the pipeline has
6486    * been completed you should connect to the ::paint signal on the
6487    * Stage with g_signal_connect_after().</para></note>
6488    *
6489    * Since: 1.0
6490    */
6491   actor_signals[QUEUE_REDRAW] =
6492     g_signal_new (I_("queue-redraw"),
6493                   G_TYPE_FROM_CLASS (object_class),
6494                   G_SIGNAL_RUN_LAST |
6495                   G_SIGNAL_NO_HOOKS,
6496                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6497                   NULL, NULL,
6498                   _clutter_marshal_VOID__OBJECT,
6499                   G_TYPE_NONE, 1,
6500                   CLUTTER_TYPE_ACTOR);
6501
6502   /**
6503    * ClutterActor::queue-relayout
6504    * @actor: the actor being queued for relayout
6505    *
6506    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6507    * is called on an actor.
6508    *
6509    * The default implementation for #ClutterActor chains up to the
6510    * parent actor and queues a relayout on the parent, thus "bubbling"
6511    * the relayout queue up through the actor graph.
6512    *
6513    * The main purpose of this signal is to allow relayout to be propagated
6514    * properly in the procense of #ClutterClone actors. Applications will
6515    * not normally need to connect to this signal.
6516    *
6517    * Since: 1.2
6518    */
6519   actor_signals[QUEUE_RELAYOUT] =
6520     g_signal_new (I_("queue-relayout"),
6521                   G_TYPE_FROM_CLASS (object_class),
6522                   G_SIGNAL_RUN_LAST |
6523                   G_SIGNAL_NO_HOOKS,
6524                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6525                   NULL, NULL,
6526                   _clutter_marshal_VOID__VOID,
6527                   G_TYPE_NONE, 0);
6528
6529   /**
6530    * ClutterActor::event:
6531    * @actor: the actor which received the event
6532    * @event: a #ClutterEvent
6533    *
6534    * The ::event signal is emitted each time an event is received
6535    * by the @actor. This signal will be emitted on every actor,
6536    * following the hierarchy chain, until it reaches the top-level
6537    * container (the #ClutterStage).
6538    *
6539    * Return value: %TRUE if the event has been handled by the actor,
6540    *   or %FALSE to continue the emission.
6541    *
6542    * Since: 0.6
6543    */
6544   actor_signals[EVENT] =
6545     g_signal_new (I_("event"),
6546                   G_TYPE_FROM_CLASS (object_class),
6547                   G_SIGNAL_RUN_LAST,
6548                   G_STRUCT_OFFSET (ClutterActorClass, event),
6549                   _clutter_boolean_handled_accumulator, NULL,
6550                   _clutter_marshal_BOOLEAN__BOXED,
6551                   G_TYPE_BOOLEAN, 1,
6552                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6553   /**
6554    * ClutterActor::button-press-event:
6555    * @actor: the actor which received the event
6556    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6557    *
6558    * The ::button-press-event signal is emitted each time a mouse button
6559    * is pressed on @actor.
6560    *
6561    * Return value: %TRUE if the event has been handled by the actor,
6562    *   or %FALSE to continue the emission.
6563    *
6564    * Since: 0.6
6565    */
6566   actor_signals[BUTTON_PRESS_EVENT] =
6567     g_signal_new (I_("button-press-event"),
6568                   G_TYPE_FROM_CLASS (object_class),
6569                   G_SIGNAL_RUN_LAST,
6570                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6571                   _clutter_boolean_handled_accumulator, NULL,
6572                   _clutter_marshal_BOOLEAN__BOXED,
6573                   G_TYPE_BOOLEAN, 1,
6574                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6575   /**
6576    * ClutterActor::button-release-event:
6577    * @actor: the actor which received the event
6578    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6579    *
6580    * The ::button-release-event signal is emitted each time a mouse button
6581    * is released on @actor.
6582    *
6583    * Return value: %TRUE if the event has been handled by the actor,
6584    *   or %FALSE to continue the emission.
6585    *
6586    * Since: 0.6
6587    */
6588   actor_signals[BUTTON_RELEASE_EVENT] =
6589     g_signal_new (I_("button-release-event"),
6590                   G_TYPE_FROM_CLASS (object_class),
6591                   G_SIGNAL_RUN_LAST,
6592                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6593                   _clutter_boolean_handled_accumulator, NULL,
6594                   _clutter_marshal_BOOLEAN__BOXED,
6595                   G_TYPE_BOOLEAN, 1,
6596                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6597   /**
6598    * ClutterActor::scroll-event:
6599    * @actor: the actor which received the event
6600    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6601    *
6602    * The ::scroll-event signal is emitted each time the mouse is
6603    * scrolled on @actor
6604    *
6605    * Return value: %TRUE if the event has been handled by the actor,
6606    *   or %FALSE to continue the emission.
6607    *
6608    * Since: 0.6
6609    */
6610   actor_signals[SCROLL_EVENT] =
6611     g_signal_new (I_("scroll-event"),
6612                   G_TYPE_FROM_CLASS (object_class),
6613                   G_SIGNAL_RUN_LAST,
6614                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6615                   _clutter_boolean_handled_accumulator, NULL,
6616                   _clutter_marshal_BOOLEAN__BOXED,
6617                   G_TYPE_BOOLEAN, 1,
6618                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6619   /**
6620    * ClutterActor::key-press-event:
6621    * @actor: the actor which received the event
6622    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6623    *
6624    * The ::key-press-event signal is emitted each time a keyboard button
6625    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6626    *
6627    * Return value: %TRUE if the event has been handled by the actor,
6628    *   or %FALSE to continue the emission.
6629    *
6630    * Since: 0.6
6631    */
6632   actor_signals[KEY_PRESS_EVENT] =
6633     g_signal_new (I_("key-press-event"),
6634                   G_TYPE_FROM_CLASS (object_class),
6635                   G_SIGNAL_RUN_LAST,
6636                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6637                   _clutter_boolean_handled_accumulator, NULL,
6638                   _clutter_marshal_BOOLEAN__BOXED,
6639                   G_TYPE_BOOLEAN, 1,
6640                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6641   /**
6642    * ClutterActor::key-release-event:
6643    * @actor: the actor which received the event
6644    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6645    *
6646    * The ::key-release-event signal is emitted each time a keyboard button
6647    * is released while @actor has key focus (see
6648    * clutter_stage_set_key_focus()).
6649    *
6650    * Return value: %TRUE if the event has been handled by the actor,
6651    *   or %FALSE to continue the emission.
6652    *
6653    * Since: 0.6
6654    */
6655   actor_signals[KEY_RELEASE_EVENT] =
6656     g_signal_new (I_("key-release-event"),
6657                   G_TYPE_FROM_CLASS (object_class),
6658                   G_SIGNAL_RUN_LAST,
6659                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6660                   _clutter_boolean_handled_accumulator, NULL,
6661                   _clutter_marshal_BOOLEAN__BOXED,
6662                   G_TYPE_BOOLEAN, 1,
6663                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6664   /**
6665    * ClutterActor::motion-event:
6666    * @actor: the actor which received the event
6667    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6668    *
6669    * The ::motion-event signal is emitted each time the mouse pointer is
6670    * moved over @actor.
6671    *
6672    * Return value: %TRUE if the event has been handled by the actor,
6673    *   or %FALSE to continue the emission.
6674    *
6675    * Since: 0.6
6676    */
6677   actor_signals[MOTION_EVENT] =
6678     g_signal_new (I_("motion-event"),
6679                   G_TYPE_FROM_CLASS (object_class),
6680                   G_SIGNAL_RUN_LAST,
6681                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6682                   _clutter_boolean_handled_accumulator, NULL,
6683                   _clutter_marshal_BOOLEAN__BOXED,
6684                   G_TYPE_BOOLEAN, 1,
6685                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6686
6687   /**
6688    * ClutterActor::key-focus-in:
6689    * @actor: the actor which now has key focus
6690    *
6691    * The ::key-focus-in signal is emitted when @actor receives key focus.
6692    *
6693    * Since: 0.6
6694    */
6695   actor_signals[KEY_FOCUS_IN] =
6696     g_signal_new (I_("key-focus-in"),
6697                   G_TYPE_FROM_CLASS (object_class),
6698                   G_SIGNAL_RUN_LAST,
6699                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6700                   NULL, NULL,
6701                   _clutter_marshal_VOID__VOID,
6702                   G_TYPE_NONE, 0);
6703
6704   /**
6705    * ClutterActor::key-focus-out:
6706    * @actor: the actor which now has key focus
6707    *
6708    * The ::key-focus-out signal is emitted when @actor loses key focus.
6709    *
6710    * Since: 0.6
6711    */
6712   actor_signals[KEY_FOCUS_OUT] =
6713     g_signal_new (I_("key-focus-out"),
6714                   G_TYPE_FROM_CLASS (object_class),
6715                   G_SIGNAL_RUN_LAST,
6716                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6717                   NULL, NULL,
6718                   _clutter_marshal_VOID__VOID,
6719                   G_TYPE_NONE, 0);
6720
6721   /**
6722    * ClutterActor::enter-event:
6723    * @actor: the actor which the pointer has entered.
6724    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6725    *
6726    * The ::enter-event signal is emitted when the pointer enters the @actor
6727    *
6728    * Return value: %TRUE if the event has been handled by the actor,
6729    *   or %FALSE to continue the emission.
6730    *
6731    * Since: 0.6
6732    */
6733   actor_signals[ENTER_EVENT] =
6734     g_signal_new (I_("enter-event"),
6735                   G_TYPE_FROM_CLASS (object_class),
6736                   G_SIGNAL_RUN_LAST,
6737                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6738                   _clutter_boolean_handled_accumulator, NULL,
6739                   _clutter_marshal_BOOLEAN__BOXED,
6740                   G_TYPE_BOOLEAN, 1,
6741                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6742
6743   /**
6744    * ClutterActor::leave-event:
6745    * @actor: the actor which the pointer has left
6746    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6747    *
6748    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6749    *
6750    * Return value: %TRUE if the event has been handled by the actor,
6751    *   or %FALSE to continue the emission.
6752    *
6753    * Since: 0.6
6754    */
6755   actor_signals[LEAVE_EVENT] =
6756     g_signal_new (I_("leave-event"),
6757                   G_TYPE_FROM_CLASS (object_class),
6758                   G_SIGNAL_RUN_LAST,
6759                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6760                   _clutter_boolean_handled_accumulator, NULL,
6761                   _clutter_marshal_BOOLEAN__BOXED,
6762                   G_TYPE_BOOLEAN, 1,
6763                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6764
6765   /**
6766    * ClutterActor::captured-event:
6767    * @actor: the actor which received the signal
6768    * @event: a #ClutterEvent
6769    *
6770    * The ::captured-event signal is emitted when an event is captured
6771    * by Clutter. This signal will be emitted starting from the top-level
6772    * container (the #ClutterStage) to the actor which received the event
6773    * going down the hierarchy. This signal can be used to intercept every
6774    * event before the specialized events (like
6775    * ClutterActor::button-press-event or ::key-released-event) are
6776    * emitted.
6777    *
6778    * Return value: %TRUE if the event has been handled by the actor,
6779    *   or %FALSE to continue the emission.
6780    *
6781    * Since: 0.6
6782    */
6783   actor_signals[CAPTURED_EVENT] =
6784     g_signal_new (I_("captured-event"),
6785                   G_TYPE_FROM_CLASS (object_class),
6786                   G_SIGNAL_RUN_LAST,
6787                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6788                   _clutter_boolean_handled_accumulator, NULL,
6789                   _clutter_marshal_BOOLEAN__BOXED,
6790                   G_TYPE_BOOLEAN, 1,
6791                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6792
6793   /**
6794    * ClutterActor::paint:
6795    * @actor: the #ClutterActor that received the signal
6796    *
6797    * The ::paint signal is emitted each time an actor is being painted.
6798    *
6799    * Subclasses of #ClutterActor should override the class signal handler
6800    * and paint themselves in that function.
6801    *
6802    * It is possible to connect a handler to the ::paint signal in order
6803    * to set up some custom aspect of a paint.
6804    *
6805    * Since: 0.8
6806    */
6807   actor_signals[PAINT] =
6808     g_signal_new (I_("paint"),
6809                   G_TYPE_FROM_CLASS (object_class),
6810                   G_SIGNAL_RUN_LAST |
6811                   G_SIGNAL_NO_HOOKS,
6812                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6813                   NULL, NULL,
6814                   _clutter_marshal_VOID__VOID,
6815                   G_TYPE_NONE, 0);
6816   /**
6817    * ClutterActor::realize:
6818    * @actor: the #ClutterActor that received the signal
6819    *
6820    * The ::realize signal is emitted each time an actor is being
6821    * realized.
6822    *
6823    * Since: 0.8
6824    */
6825   actor_signals[REALIZE] =
6826     g_signal_new (I_("realize"),
6827                   G_TYPE_FROM_CLASS (object_class),
6828                   G_SIGNAL_RUN_LAST,
6829                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6830                   NULL, NULL,
6831                   _clutter_marshal_VOID__VOID,
6832                   G_TYPE_NONE, 0);
6833   /**
6834    * ClutterActor::unrealize:
6835    * @actor: the #ClutterActor that received the signal
6836    *
6837    * The ::unrealize signal is emitted each time an actor is being
6838    * unrealized.
6839    *
6840    * Since: 0.8
6841    */
6842   actor_signals[UNREALIZE] =
6843     g_signal_new (I_("unrealize"),
6844                   G_TYPE_FROM_CLASS (object_class),
6845                   G_SIGNAL_RUN_LAST,
6846                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6847                   NULL, NULL,
6848                   _clutter_marshal_VOID__VOID,
6849                   G_TYPE_NONE, 0);
6850
6851   /**
6852    * ClutterActor::pick:
6853    * @actor: the #ClutterActor that received the signal
6854    * @color: the #ClutterColor to be used when picking
6855    *
6856    * The ::pick signal is emitted each time an actor is being painted
6857    * in "pick mode". The pick mode is used to identify the actor during
6858    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6859    * The actor should paint its shape using the passed @pick_color.
6860    *
6861    * Subclasses of #ClutterActor should override the class signal handler
6862    * and paint themselves in that function.
6863    *
6864    * It is possible to connect a handler to the ::pick signal in order
6865    * to set up some custom aspect of a paint in pick mode.
6866    *
6867    * Since: 1.0
6868    */
6869   actor_signals[PICK] =
6870     g_signal_new (I_("pick"),
6871                   G_TYPE_FROM_CLASS (object_class),
6872                   G_SIGNAL_RUN_LAST,
6873                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6874                   NULL, NULL,
6875                   _clutter_marshal_VOID__BOXED,
6876                   G_TYPE_NONE, 1,
6877                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6878
6879   /**
6880    * ClutterActor::allocation-changed:
6881    * @actor: the #ClutterActor that emitted the signal
6882    * @box: a #ClutterActorBox with the new allocation
6883    * @flags: #ClutterAllocationFlags for the allocation
6884    *
6885    * The ::allocation-changed signal is emitted when the
6886    * #ClutterActor:allocation property changes. Usually, application
6887    * code should just use the notifications for the :allocation property
6888    * but if you want to track the allocation flags as well, for instance
6889    * to know whether the absolute origin of @actor changed, then you might
6890    * want use this signal instead.
6891    *
6892    * Since: 1.0
6893    */
6894   actor_signals[ALLOCATION_CHANGED] =
6895     g_signal_new (I_("allocation-changed"),
6896                   G_TYPE_FROM_CLASS (object_class),
6897                   G_SIGNAL_RUN_LAST,
6898                   0,
6899                   NULL, NULL,
6900                   _clutter_marshal_VOID__BOXED_FLAGS,
6901                   G_TYPE_NONE, 2,
6902                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6903                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6904 }
6905
6906 static void
6907 clutter_actor_init (ClutterActor *self)
6908 {
6909   ClutterActorPrivate *priv;
6910
6911   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6912
6913   priv->id = _clutter_context_acquire_id (self);
6914   priv->pick_id = -1;
6915
6916   priv->opacity = 0xff;
6917   priv->show_on_set_parent = TRUE;
6918
6919   priv->needs_width_request = TRUE;
6920   priv->needs_height_request = TRUE;
6921   priv->needs_allocation = TRUE;
6922
6923   priv->cached_width_age = 1;
6924   priv->cached_height_age = 1;
6925
6926   priv->opacity_override = -1;
6927   priv->enable_model_view_transform = TRUE;
6928
6929   /* Initialize an empty paint volume to start with */
6930   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6931   priv->last_paint_volume_valid = TRUE;
6932
6933   priv->transform_valid = FALSE;
6934
6935   /* the default is to stretch the content, to match the
6936    * current behaviour of basically all actors. also, it's
6937    * the easiest thing to compute.
6938    */
6939   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6940 }
6941
6942 /**
6943  * clutter_actor_new:
6944  *
6945  * Creates a new #ClutterActor.
6946  *
6947  * A newly created actor has a floating reference, which will be sunk
6948  * when it is added to another actor.
6949  *
6950  * Return value: (transfer full): the newly created #ClutterActor
6951  *
6952  * Since: 1.10
6953  */
6954 ClutterActor *
6955 clutter_actor_new (void)
6956 {
6957   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6958 }
6959
6960 /**
6961  * clutter_actor_destroy:
6962  * @self: a #ClutterActor
6963  *
6964  * Destroys an actor.  When an actor is destroyed, it will break any
6965  * references it holds to other objects.  If the actor is inside a
6966  * container, the actor will be removed.
6967  *
6968  * When you destroy a container, its children will be destroyed as well.
6969  *
6970  * Note: you cannot destroy the #ClutterStage returned by
6971  * clutter_stage_get_default().
6972  */
6973 void
6974 clutter_actor_destroy (ClutterActor *self)
6975 {
6976   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6977
6978   g_object_ref (self);
6979
6980   /* avoid recursion while destroying */
6981   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6982     {
6983       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6984
6985       g_object_run_dispose (G_OBJECT (self));
6986
6987       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6988     }
6989
6990   g_object_unref (self);
6991 }
6992
6993 void
6994 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6995                                     ClutterPaintVolume *clip)
6996 {
6997   ClutterActorPrivate *priv = self->priv;
6998   ClutterPaintVolume *pv;
6999   gboolean clipped;
7000
7001   /* Remove queue entry early in the process, otherwise a new
7002      queue_redraw() during signal handling could put back this
7003      object in the stage redraw list (but the entry is freed as
7004      soon as we return from this function, causing a segfault
7005      later)
7006   */
7007   priv->queue_redraw_entry = NULL;
7008
7009   /* If we've been explicitly passed a clip volume then there's
7010    * nothing more to calculate, but otherwise the only thing we know
7011    * is that the change is constrained to the given actor.
7012    *
7013    * The idea is that if we know the paint volume for where the actor
7014    * was last drawn (in eye coordinates) and we also have the paint
7015    * volume for where it will be drawn next (in actor coordinates)
7016    * then if we queue a redraw for both these volumes that will cover
7017    * everything that needs to be redrawn to clear the old view and
7018    * show the latest view of the actor.
7019    *
7020    * Don't clip this redraw if we don't know what position we had for
7021    * the previous redraw since we don't know where to set the clip so
7022    * it will clear the actor as it is currently.
7023    */
7024   if (clip)
7025     {
7026       _clutter_actor_set_queue_redraw_clip (self, clip);
7027       clipped = TRUE;
7028     }
7029   else if (G_LIKELY (priv->last_paint_volume_valid))
7030     {
7031       pv = _clutter_actor_get_paint_volume_mutable (self);
7032       if (pv)
7033         {
7034           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7035
7036           /* make sure we redraw the actors old position... */
7037           _clutter_actor_set_queue_redraw_clip (stage,
7038                                                 &priv->last_paint_volume);
7039           _clutter_actor_signal_queue_redraw (stage, stage);
7040           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7041
7042           /* XXX: Ideally the redraw signal would take a clip volume
7043            * argument, but that would be an ABI break. Until we can
7044            * break the ABI we pass the argument out-of-band
7045            */
7046
7047           /* setup the clip for the actors new position... */
7048           _clutter_actor_set_queue_redraw_clip (self, pv);
7049           clipped = TRUE;
7050         }
7051       else
7052         clipped = FALSE;
7053     }
7054   else
7055     clipped = FALSE;
7056
7057   _clutter_actor_signal_queue_redraw (self, self);
7058
7059   /* Just in case anyone is manually firing redraw signals without
7060    * using the public queue_redraw() API we are careful to ensure that
7061    * our out-of-band clip member is cleared before returning...
7062    *
7063    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7064    */
7065   if (G_LIKELY (clipped))
7066     _clutter_actor_set_queue_redraw_clip (self, NULL);
7067 }
7068
7069 static void
7070 _clutter_actor_get_allocation_clip (ClutterActor *self,
7071                                     ClutterActorBox *clip)
7072 {
7073   ClutterActorBox allocation;
7074
7075   /* XXX: we don't care if we get an out of date allocation here
7076    * because clutter_actor_queue_redraw_with_clip knows to ignore
7077    * the clip if the actor's allocation is invalid.
7078    *
7079    * This is noted because clutter_actor_get_allocation_box does some
7080    * unnecessary work to support buggy code with a comment suggesting
7081    * that it could be changed later which would be good for this use
7082    * case!
7083    */
7084   clutter_actor_get_allocation_box (self, &allocation);
7085
7086   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7087    * actor's own coordinate space but the allocation is in parent
7088    * coordinates */
7089   clip->x1 = 0;
7090   clip->y1 = 0;
7091   clip->x2 = allocation.x2 - allocation.x1;
7092   clip->y2 = allocation.y2 - allocation.y1;
7093 }
7094
7095 void
7096 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7097                                   ClutterRedrawFlags  flags,
7098                                   ClutterPaintVolume *volume,
7099                                   ClutterEffect      *effect)
7100 {
7101   ClutterActorPrivate *priv = self->priv;
7102   ClutterPaintVolume allocation_pv;
7103   ClutterPaintVolume *pv;
7104   gboolean should_free_pv;
7105   ClutterActor *stage;
7106
7107   /* Here's an outline of the actor queue redraw mechanism:
7108    *
7109    * The process starts in one of the following two functions which
7110    * are wrappers for this function:
7111    * clutter_actor_queue_redraw
7112    * _clutter_actor_queue_redraw_with_clip
7113    *
7114    * additionally, an effect can queue a redraw by wrapping this
7115    * function in clutter_effect_queue_rerun
7116    *
7117    * This functions queues an entry in a list associated with the
7118    * stage which is a list of actors that queued a redraw while
7119    * updating the timelines, performing layouting and processing other
7120    * mainloop sources before the next paint starts.
7121    *
7122    * We aim to minimize the processing done at this point because
7123    * there is a good chance other events will happen while updating
7124    * the scenegraph that would invalidate any expensive work we might
7125    * otherwise try to do here. For example we don't try and resolve
7126    * the screen space bounding box of an actor at this stage so as to
7127    * minimize how much of the screen redraw because it's possible
7128    * something else will happen which will force a full redraw anyway.
7129    *
7130    * When all updates are complete and we come to paint the stage then
7131    * we iterate this list and actually emit the "queue-redraw" signals
7132    * for each of the listed actors which will bubble up to the stage
7133    * for each actor and at that point we will transform the actors
7134    * paint volume into screen coordinates to determine the clip region
7135    * for what needs to be redrawn in the next paint.
7136    *
7137    * Besides minimizing redundant work another reason for this
7138    * deferred design is that it's more likely we will be able to
7139    * determine the paint volume of an actor once we've finished
7140    * updating the scenegraph because its allocation should be up to
7141    * date. NB: If we can't determine an actors paint volume then we
7142    * can't automatically queue a clipped redraw which can make a big
7143    * difference to performance.
7144    *
7145    * So the control flow goes like this:
7146    * One of clutter_actor_queue_redraw,
7147    *        _clutter_actor_queue_redraw_with_clip
7148    *     or clutter_effect_queue_rerun
7149    *
7150    * then control moves to:
7151    *   _clutter_stage_queue_actor_redraw
7152    *
7153    * later during _clutter_stage_do_update, once relayouting is done
7154    * and the scenegraph has been updated we will call:
7155    * _clutter_stage_finish_queue_redraws
7156    *
7157    * _clutter_stage_finish_queue_redraws will call
7158    * _clutter_actor_finish_queue_redraw for each listed actor.
7159    * Note: actors *are* allowed to queue further redraws during this
7160    * process (considering clone actors or texture_new_from_actor which
7161    * respond to their source queueing a redraw by queuing a redraw
7162    * themselves). We repeat the process until the list is empty.
7163    *
7164    * This will result in the "queue-redraw" signal being fired for
7165    * each actor which will pass control to the default signal handler:
7166    * clutter_actor_real_queue_redraw
7167    *
7168    * This will bubble up to the stages handler:
7169    * clutter_stage_real_queue_redraw
7170    *
7171    * clutter_stage_real_queue_redraw will transform the actors paint
7172    * volume into screen space and add it as a clip region for the next
7173    * paint.
7174    */
7175
7176   /* ignore queueing a redraw for actors being destroyed */
7177   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7178     return;
7179
7180   stage = _clutter_actor_get_stage_internal (self);
7181
7182   /* Ignore queueing a redraw for actors not descended from a stage */
7183   if (stage == NULL)
7184     return;
7185
7186   /* ignore queueing a redraw on stages that are being destroyed */
7187   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7188     return;
7189
7190   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7191     {
7192       ClutterActorBox allocation_clip;
7193       ClutterVertex origin;
7194
7195       /* If the actor doesn't have a valid allocation then we will
7196        * queue a full stage redraw. */
7197       if (priv->needs_allocation)
7198         {
7199           /* NB: NULL denotes an undefined clip which will result in a
7200            * full redraw... */
7201           _clutter_actor_set_queue_redraw_clip (self, NULL);
7202           _clutter_actor_signal_queue_redraw (self, self);
7203           return;
7204         }
7205
7206       _clutter_paint_volume_init_static (&allocation_pv, self);
7207       pv = &allocation_pv;
7208
7209       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7210
7211       origin.x = allocation_clip.x1;
7212       origin.y = allocation_clip.y1;
7213       origin.z = 0;
7214       clutter_paint_volume_set_origin (pv, &origin);
7215       clutter_paint_volume_set_width (pv,
7216                                       allocation_clip.x2 - allocation_clip.x1);
7217       clutter_paint_volume_set_height (pv,
7218                                        allocation_clip.y2 -
7219                                        allocation_clip.y1);
7220       should_free_pv = TRUE;
7221     }
7222   else
7223     {
7224       pv = volume;
7225       should_free_pv = FALSE;
7226     }
7227
7228   self->priv->queue_redraw_entry =
7229     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7230                                        priv->queue_redraw_entry,
7231                                        self,
7232                                        pv);
7233
7234   if (should_free_pv)
7235     clutter_paint_volume_free (pv);
7236
7237   /* If this is the first redraw queued then we can directly use the
7238      effect parameter */
7239   if (!priv->is_dirty)
7240     priv->effect_to_redraw = effect;
7241   /* Otherwise we need to merge it with the existing effect parameter */
7242   else if (effect != NULL)
7243     {
7244       /* If there's already an effect then we need to use whichever is
7245          later in the chain of actors. Otherwise a full redraw has
7246          already been queued on the actor so we need to ignore the
7247          effect parameter */
7248       if (priv->effect_to_redraw != NULL)
7249         {
7250           if (priv->effects == NULL)
7251             g_warning ("Redraw queued with an effect that is "
7252                        "not applied to the actor");
7253           else
7254             {
7255               const GList *l;
7256
7257               for (l = _clutter_meta_group_peek_metas (priv->effects);
7258                    l != NULL;
7259                    l = l->next)
7260                 {
7261                   if (l->data == priv->effect_to_redraw ||
7262                       l->data == effect)
7263                     priv->effect_to_redraw = l->data;
7264                 }
7265             }
7266         }
7267     }
7268   else
7269     {
7270       /* If no effect is specified then we need to redraw the whole
7271          actor */
7272       priv->effect_to_redraw = NULL;
7273     }
7274
7275   priv->is_dirty = TRUE;
7276 }
7277
7278 /**
7279  * clutter_actor_queue_redraw:
7280  * @self: A #ClutterActor
7281  *
7282  * Queues up a redraw of an actor and any children. The redraw occurs
7283  * once the main loop becomes idle (after the current batch of events
7284  * has been processed, roughly).
7285  *
7286  * Applications rarely need to call this, as redraws are handled
7287  * automatically by modification functions.
7288  *
7289  * This function will not do anything if @self is not visible, or
7290  * if the actor is inside an invisible part of the scenegraph.
7291  *
7292  * Also be aware that painting is a NOP for actors with an opacity of
7293  * 0
7294  *
7295  * When you are implementing a custom actor you must queue a redraw
7296  * whenever some private state changes that will affect painting or
7297  * picking of your actor.
7298  */
7299 void
7300 clutter_actor_queue_redraw (ClutterActor *self)
7301 {
7302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7303
7304   _clutter_actor_queue_redraw_full (self,
7305                                     0, /* flags */
7306                                     NULL, /* clip volume */
7307                                     NULL /* effect */);
7308 }
7309
7310 /*< private >
7311  * _clutter_actor_queue_redraw_with_clip:
7312  * @self: A #ClutterActor
7313  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7314  *   this queue redraw.
7315  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7316  *   redrawn or %NULL if you are just using a @flag to state your
7317  *   desired clipping.
7318  *
7319  * Queues up a clipped redraw of an actor and any children. The redraw
7320  * occurs once the main loop becomes idle (after the current batch of
7321  * events has been processed, roughly).
7322  *
7323  * If no flags are given the clip volume is defined by @volume
7324  * specified in actor coordinates and tells Clutter that only content
7325  * within this volume has been changed so Clutter can optionally
7326  * optimize the redraw.
7327  *
7328  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7329  * should be %NULL and this tells Clutter to use the actor's current
7330  * allocation as a clip box. This flag can only be used for 2D actors,
7331  * because any actor with depth may be projected outside its
7332  * allocation.
7333  *
7334  * Applications rarely need to call this, as redraws are handled
7335  * automatically by modification functions.
7336  *
7337  * This function will not do anything if @self is not visible, or if
7338  * the actor is inside an invisible part of the scenegraph.
7339  *
7340  * Also be aware that painting is a NOP for actors with an opacity of
7341  * 0
7342  *
7343  * When you are implementing a custom actor you must queue a redraw
7344  * whenever some private state changes that will affect painting or
7345  * picking of your actor.
7346  */
7347 void
7348 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7349                                        ClutterRedrawFlags  flags,
7350                                        ClutterPaintVolume *volume)
7351 {
7352   _clutter_actor_queue_redraw_full (self,
7353                                     flags, /* flags */
7354                                     volume, /* clip volume */
7355                                     NULL /* effect */);
7356 }
7357
7358 static void
7359 _clutter_actor_queue_only_relayout (ClutterActor *self)
7360 {
7361   ClutterActorPrivate *priv = self->priv;
7362
7363   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7364     return;
7365
7366   if (priv->needs_width_request &&
7367       priv->needs_height_request &&
7368       priv->needs_allocation)
7369     return; /* save some cpu cycles */
7370
7371 #if CLUTTER_ENABLE_DEBUG
7372   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7373     {
7374       g_warning ("The actor '%s' is currently inside an allocation "
7375                  "cycle; calling clutter_actor_queue_relayout() is "
7376                  "not recommended",
7377                  _clutter_actor_get_debug_name (self));
7378     }
7379 #endif /* CLUTTER_ENABLE_DEBUG */
7380
7381   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7382 }
7383
7384 /**
7385  * clutter_actor_queue_redraw_with_clip:
7386  * @self: a #ClutterActor
7387  * @clip: (allow-none): a rectangular clip region, or %NULL
7388  *
7389  * Queues a redraw on @self limited to a specific, actor-relative
7390  * rectangular area.
7391  *
7392  * If @clip is %NULL this function is equivalent to
7393  * clutter_actor_queue_redraw().
7394  *
7395  * Since: 1.10
7396  */
7397 void
7398 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7399                                       const cairo_rectangle_int_t *clip)
7400 {
7401   ClutterPaintVolume volume;
7402   ClutterVertex origin;
7403
7404   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7405
7406   if (clip == NULL)
7407     {
7408       clutter_actor_queue_redraw (self);
7409       return;
7410     }
7411
7412   _clutter_paint_volume_init_static (&volume, self);
7413
7414   origin.x = clip->x;
7415   origin.y = clip->y;
7416   origin.z = 0.0f;
7417
7418   clutter_paint_volume_set_origin (&volume, &origin);
7419   clutter_paint_volume_set_width (&volume, clip->width);
7420   clutter_paint_volume_set_height (&volume, clip->height);
7421
7422   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7423
7424   clutter_paint_volume_free (&volume);
7425 }
7426
7427 /**
7428  * clutter_actor_queue_relayout:
7429  * @self: A #ClutterActor
7430  *
7431  * Indicates that the actor's size request or other layout-affecting
7432  * properties may have changed. This function is used inside #ClutterActor
7433  * subclass implementations, not by applications directly.
7434  *
7435  * Queueing a new layout automatically queues a redraw as well.
7436  *
7437  * Since: 0.8
7438  */
7439 void
7440 clutter_actor_queue_relayout (ClutterActor *self)
7441 {
7442   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7443
7444   _clutter_actor_queue_only_relayout (self);
7445   clutter_actor_queue_redraw (self);
7446 }
7447
7448 /**
7449  * clutter_actor_get_preferred_size:
7450  * @self: a #ClutterActor
7451  * @min_width_p: (out) (allow-none): return location for the minimum
7452  *   width, or %NULL
7453  * @min_height_p: (out) (allow-none): return location for the minimum
7454  *   height, or %NULL
7455  * @natural_width_p: (out) (allow-none): return location for the natural
7456  *   width, or %NULL
7457  * @natural_height_p: (out) (allow-none): return location for the natural
7458  *   height, or %NULL
7459  *
7460  * Computes the preferred minimum and natural size of an actor, taking into
7461  * account the actor's geometry management (either height-for-width
7462  * or width-for-height).
7463  *
7464  * The width and height used to compute the preferred height and preferred
7465  * width are the actor's natural ones.
7466  *
7467  * If you need to control the height for the preferred width, or the width for
7468  * the preferred height, you should use clutter_actor_get_preferred_width()
7469  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7470  * geometry management using the #ClutterActor:request-mode property.
7471  *
7472  * Since: 0.8
7473  */
7474 void
7475 clutter_actor_get_preferred_size (ClutterActor *self,
7476                                   gfloat       *min_width_p,
7477                                   gfloat       *min_height_p,
7478                                   gfloat       *natural_width_p,
7479                                   gfloat       *natural_height_p)
7480 {
7481   ClutterActorPrivate *priv;
7482   gfloat min_width, min_height;
7483   gfloat natural_width, natural_height;
7484
7485   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7486
7487   priv = self->priv;
7488
7489   min_width = min_height = 0;
7490   natural_width = natural_height = 0;
7491
7492   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7493     {
7494       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7495       clutter_actor_get_preferred_width (self, -1,
7496                                          &min_width,
7497                                          &natural_width);
7498       clutter_actor_get_preferred_height (self, natural_width,
7499                                           &min_height,
7500                                           &natural_height);
7501     }
7502   else
7503     {
7504       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7505       clutter_actor_get_preferred_height (self, -1,
7506                                           &min_height,
7507                                           &natural_height);
7508       clutter_actor_get_preferred_width (self, natural_height,
7509                                          &min_width,
7510                                          &natural_width);
7511     }
7512
7513   if (min_width_p)
7514     *min_width_p = min_width;
7515
7516   if (min_height_p)
7517     *min_height_p = min_height;
7518
7519   if (natural_width_p)
7520     *natural_width_p = natural_width;
7521
7522   if (natural_height_p)
7523     *natural_height_p = natural_height;
7524 }
7525
7526 /*< private >
7527  * effective_align:
7528  * @align: a #ClutterActorAlign
7529  * @direction: a #ClutterTextDirection
7530  *
7531  * Retrieves the correct alignment depending on the text direction
7532  *
7533  * Return value: the effective alignment
7534  */
7535 static ClutterActorAlign
7536 effective_align (ClutterActorAlign    align,
7537                  ClutterTextDirection direction)
7538 {
7539   ClutterActorAlign res;
7540
7541   switch (align)
7542     {
7543     case CLUTTER_ACTOR_ALIGN_START:
7544       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7545           ? CLUTTER_ACTOR_ALIGN_END
7546           : CLUTTER_ACTOR_ALIGN_START;
7547       break;
7548
7549     case CLUTTER_ACTOR_ALIGN_END:
7550       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7551           ? CLUTTER_ACTOR_ALIGN_START
7552           : CLUTTER_ACTOR_ALIGN_END;
7553       break;
7554
7555     default:
7556       res = align;
7557       break;
7558     }
7559
7560   return res;
7561 }
7562
7563 static inline void
7564 adjust_for_margin (float  margin_start,
7565                    float  margin_end,
7566                    float *minimum_size,
7567                    float *natural_size,
7568                    float *allocated_start,
7569                    float *allocated_end)
7570 {
7571   *minimum_size -= (margin_start + margin_end);
7572   *natural_size -= (margin_start + margin_end);
7573   *allocated_start += margin_start;
7574   *allocated_end -= margin_end;
7575 }
7576
7577 static inline void
7578 adjust_for_alignment (ClutterActorAlign  alignment,
7579                       float              natural_size,
7580                       float             *allocated_start,
7581                       float             *allocated_end)
7582 {
7583   float allocated_size = *allocated_end - *allocated_start;
7584
7585   switch (alignment)
7586     {
7587     case CLUTTER_ACTOR_ALIGN_FILL:
7588       /* do nothing */
7589       break;
7590
7591     case CLUTTER_ACTOR_ALIGN_START:
7592       /* keep start */
7593       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7594       break;
7595
7596     case CLUTTER_ACTOR_ALIGN_END:
7597       if (allocated_size > natural_size)
7598         {
7599           *allocated_start += (allocated_size - natural_size);
7600           *allocated_end = *allocated_start + natural_size;
7601         }
7602       break;
7603
7604     case CLUTTER_ACTOR_ALIGN_CENTER:
7605       if (allocated_size > natural_size)
7606         {
7607           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7608           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7609         }
7610       break;
7611     }
7612 }
7613
7614 /*< private >
7615  * clutter_actor_adjust_width:
7616  * @self: a #ClutterActor
7617  * @minimum_width: (inout): the actor's preferred minimum width, which
7618  *   will be adjusted depending on the margin
7619  * @natural_width: (inout): the actor's preferred natural width, which
7620  *   will be adjusted depending on the margin
7621  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7622  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7623  *
7624  * Adjusts the preferred and allocated position and size of an actor,
7625  * depending on the margin and alignment properties.
7626  */
7627 static void
7628 clutter_actor_adjust_width (ClutterActor *self,
7629                             gfloat       *minimum_width,
7630                             gfloat       *natural_width,
7631                             gfloat       *adjusted_x1,
7632                             gfloat       *adjusted_x2)
7633 {
7634   ClutterTextDirection text_dir;
7635   const ClutterLayoutInfo *info;
7636
7637   info = _clutter_actor_get_layout_info_or_defaults (self);
7638   text_dir = clutter_actor_get_text_direction (self);
7639
7640   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7641
7642   /* this will tweak natural_width to remove the margin, so that
7643    * adjust_for_alignment() will use the correct size
7644    */
7645   adjust_for_margin (info->margin.left, info->margin.right,
7646                      minimum_width, natural_width,
7647                      adjusted_x1, adjusted_x2);
7648
7649   adjust_for_alignment (effective_align (info->x_align, text_dir),
7650                         *natural_width,
7651                         adjusted_x1, adjusted_x2);
7652 }
7653
7654 /*< private >
7655  * clutter_actor_adjust_height:
7656  * @self: a #ClutterActor
7657  * @minimum_height: (inout): the actor's preferred minimum height, which
7658  *   will be adjusted depending on the margin
7659  * @natural_height: (inout): the actor's preferred natural height, which
7660  *   will be adjusted depending on the margin
7661  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7662  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7663  *
7664  * Adjusts the preferred and allocated position and size of an actor,
7665  * depending on the margin and alignment properties.
7666  */
7667 static void
7668 clutter_actor_adjust_height (ClutterActor *self,
7669                              gfloat       *minimum_height,
7670                              gfloat       *natural_height,
7671                              gfloat       *adjusted_y1,
7672                              gfloat       *adjusted_y2)
7673 {
7674   const ClutterLayoutInfo *info;
7675
7676   info = _clutter_actor_get_layout_info_or_defaults (self);
7677
7678   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7679
7680   /* this will tweak natural_height to remove the margin, so that
7681    * adjust_for_alignment() will use the correct size
7682    */
7683   adjust_for_margin (info->margin.top, info->margin.bottom,
7684                      minimum_height, natural_height,
7685                      adjusted_y1,
7686                      adjusted_y2);
7687
7688   /* we don't use effective_align() here, because text direction
7689    * only affects the horizontal axis
7690    */
7691   adjust_for_alignment (info->y_align,
7692                         *natural_height,
7693                         adjusted_y1,
7694                         adjusted_y2);
7695
7696 }
7697
7698 /* looks for a cached size request for this for_size. If not
7699  * found, returns the oldest entry so it can be overwritten */
7700 static gboolean
7701 _clutter_actor_get_cached_size_request (gfloat         for_size,
7702                                         SizeRequest   *cached_size_requests,
7703                                         SizeRequest  **result)
7704 {
7705   guint i;
7706
7707   *result = &cached_size_requests[0];
7708
7709   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7710     {
7711       SizeRequest *sr;
7712
7713       sr = &cached_size_requests[i];
7714
7715       if (sr->age > 0 &&
7716           sr->for_size == for_size)
7717         {
7718           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7719           *result = sr;
7720           return TRUE;
7721         }
7722       else if (sr->age < (*result)->age)
7723         {
7724           *result = sr;
7725         }
7726     }
7727
7728   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7729
7730   return FALSE;
7731 }
7732
7733 /**
7734  * clutter_actor_get_preferred_width:
7735  * @self: A #ClutterActor
7736  * @for_height: available height when computing the preferred width,
7737  *   or a negative value to indicate that no height is defined
7738  * @min_width_p: (out) (allow-none): return location for minimum width,
7739  *   or %NULL
7740  * @natural_width_p: (out) (allow-none): return location for the natural
7741  *   width, or %NULL
7742  *
7743  * Computes the requested minimum and natural widths for an actor,
7744  * optionally depending on the specified height, or if they are
7745  * already computed, returns the cached values.
7746  *
7747  * An actor may not get its request - depending on the layout
7748  * manager that's in effect.
7749  *
7750  * A request should not incorporate the actor's scale or anchor point;
7751  * those transformations do not affect layout, only rendering.
7752  *
7753  * Since: 0.8
7754  */
7755 void
7756 clutter_actor_get_preferred_width (ClutterActor *self,
7757                                    gfloat        for_height,
7758                                    gfloat       *min_width_p,
7759                                    gfloat       *natural_width_p)
7760 {
7761   float request_min_width, request_natural_width;
7762   SizeRequest *cached_size_request;
7763   const ClutterLayoutInfo *info;
7764   ClutterActorPrivate *priv;
7765   gboolean found_in_cache;
7766
7767   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7768
7769   priv = self->priv;
7770
7771   info = _clutter_actor_get_layout_info_or_defaults (self);
7772
7773   /* we shortcircuit the case of a fixed size set using set_width() */
7774   if (priv->min_width_set && priv->natural_width_set)
7775     {
7776       if (min_width_p != NULL)
7777         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7778
7779       if (natural_width_p != NULL)
7780         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7781
7782       return;
7783     }
7784
7785   /* the remaining cases are:
7786    *
7787    *   - either min_width or natural_width have been set
7788    *   - neither min_width or natural_width have been set
7789    *
7790    * in both cases, we go through the cache (and through the actor in case
7791    * of cache misses) and determine the authoritative value depending on
7792    * the *_set flags.
7793    */
7794
7795   if (!priv->needs_width_request)
7796     {
7797       found_in_cache =
7798         _clutter_actor_get_cached_size_request (for_height,
7799                                                 priv->width_requests,
7800                                                 &cached_size_request);
7801     }
7802   else
7803     {
7804       /* if the actor needs a width request we use the first slot */
7805       found_in_cache = FALSE;
7806       cached_size_request = &priv->width_requests[0];
7807     }
7808
7809   if (!found_in_cache)
7810     {
7811       gfloat minimum_width, natural_width;
7812       ClutterActorClass *klass;
7813
7814       minimum_width = natural_width = 0;
7815
7816       /* adjust for the margin */
7817       if (for_height >= 0)
7818         {
7819           for_height -= (info->margin.top + info->margin.bottom);
7820           if (for_height < 0)
7821             for_height = 0;
7822         }
7823
7824       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7825
7826       klass = CLUTTER_ACTOR_GET_CLASS (self);
7827       klass->get_preferred_width (self, for_height,
7828                                   &minimum_width,
7829                                   &natural_width);
7830
7831       /* adjust for the margin */
7832       minimum_width += (info->margin.left + info->margin.right);
7833       natural_width += (info->margin.left + info->margin.right);
7834
7835       /* Due to accumulated float errors, it's better not to warn
7836        * on this, but just fix it.
7837        */
7838       if (natural_width < minimum_width)
7839         natural_width = minimum_width;
7840
7841       cached_size_request->min_size = minimum_width;
7842       cached_size_request->natural_size = natural_width;
7843       cached_size_request->for_size = for_height;
7844       cached_size_request->age = priv->cached_width_age;
7845
7846       priv->cached_width_age += 1;
7847       priv->needs_width_request = FALSE;
7848     }
7849
7850   if (!priv->min_width_set)
7851     request_min_width = cached_size_request->min_size;
7852   else
7853     request_min_width = info->min_width;
7854
7855   if (!priv->natural_width_set)
7856     request_natural_width = cached_size_request->natural_size;
7857   else
7858     request_natural_width = info->natural_width;
7859
7860   if (min_width_p)
7861     *min_width_p = request_min_width;
7862
7863   if (natural_width_p)
7864     *natural_width_p = request_natural_width;
7865 }
7866
7867 /**
7868  * clutter_actor_get_preferred_height:
7869  * @self: A #ClutterActor
7870  * @for_width: available width to assume in computing desired height,
7871  *   or a negative value to indicate that no width is defined
7872  * @min_height_p: (out) (allow-none): return location for minimum height,
7873  *   or %NULL
7874  * @natural_height_p: (out) (allow-none): return location for natural
7875  *   height, or %NULL
7876  *
7877  * Computes the requested minimum and natural heights for an actor,
7878  * or if they are already computed, returns the cached values.
7879  *
7880  * An actor may not get its request - depending on the layout
7881  * manager that's in effect.
7882  *
7883  * A request should not incorporate the actor's scale or anchor point;
7884  * those transformations do not affect layout, only rendering.
7885  *
7886  * Since: 0.8
7887  */
7888 void
7889 clutter_actor_get_preferred_height (ClutterActor *self,
7890                                     gfloat        for_width,
7891                                     gfloat       *min_height_p,
7892                                     gfloat       *natural_height_p)
7893 {
7894   float request_min_height, request_natural_height;
7895   SizeRequest *cached_size_request;
7896   const ClutterLayoutInfo *info;
7897   ClutterActorPrivate *priv;
7898   gboolean found_in_cache;
7899
7900   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7901
7902   priv = self->priv;
7903
7904   info = _clutter_actor_get_layout_info_or_defaults (self);
7905
7906   /* we shortcircuit the case of a fixed size set using set_height() */
7907   if (priv->min_height_set && priv->natural_height_set)
7908     {
7909       if (min_height_p != NULL)
7910         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7911
7912       if (natural_height_p != NULL)
7913         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7914
7915       return;
7916     }
7917
7918   /* the remaining cases are:
7919    *
7920    *   - either min_height or natural_height have been set
7921    *   - neither min_height or natural_height have been set
7922    *
7923    * in both cases, we go through the cache (and through the actor in case
7924    * of cache misses) and determine the authoritative value depending on
7925    * the *_set flags.
7926    */
7927
7928   if (!priv->needs_height_request)
7929     {
7930       found_in_cache =
7931         _clutter_actor_get_cached_size_request (for_width,
7932                                                 priv->height_requests,
7933                                                 &cached_size_request);
7934     }
7935   else
7936     {
7937       found_in_cache = FALSE;
7938       cached_size_request = &priv->height_requests[0];
7939     }
7940
7941   if (!found_in_cache)
7942     {
7943       gfloat minimum_height, natural_height;
7944       ClutterActorClass *klass;
7945
7946       minimum_height = natural_height = 0;
7947
7948       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7949
7950       /* adjust for margin */
7951       if (for_width >= 0)
7952         {
7953           for_width -= (info->margin.left + info->margin.right);
7954           if (for_width < 0)
7955             for_width = 0;
7956         }
7957
7958       klass = CLUTTER_ACTOR_GET_CLASS (self);
7959       klass->get_preferred_height (self, for_width,
7960                                    &minimum_height,
7961                                    &natural_height);
7962
7963       /* adjust for margin */
7964       minimum_height += (info->margin.top + info->margin.bottom);
7965       natural_height += (info->margin.top + info->margin.bottom);
7966
7967       /* Due to accumulated float errors, it's better not to warn
7968        * on this, but just fix it.
7969        */
7970       if (natural_height < minimum_height)
7971         natural_height = minimum_height;
7972
7973       cached_size_request->min_size = minimum_height;
7974       cached_size_request->natural_size = natural_height;
7975       cached_size_request->for_size = for_width;
7976       cached_size_request->age = priv->cached_height_age;
7977
7978       priv->cached_height_age += 1;
7979       priv->needs_height_request = FALSE;
7980     }
7981
7982   if (!priv->min_height_set)
7983     request_min_height = cached_size_request->min_size;
7984   else
7985     request_min_height = info->min_height;
7986
7987   if (!priv->natural_height_set)
7988     request_natural_height = cached_size_request->natural_size;
7989   else
7990     request_natural_height = info->natural_height;
7991
7992   if (min_height_p)
7993     *min_height_p = request_min_height;
7994
7995   if (natural_height_p)
7996     *natural_height_p = request_natural_height;
7997 }
7998
7999 /**
8000  * clutter_actor_get_allocation_box:
8001  * @self: A #ClutterActor
8002  * @box: (out): the function fills this in with the actor's allocation
8003  *
8004  * Gets the layout box an actor has been assigned. The allocation can
8005  * only be assumed valid inside a paint() method; anywhere else, it
8006  * may be out-of-date.
8007  *
8008  * An allocation does not incorporate the actor's scale or anchor point;
8009  * those transformations do not affect layout, only rendering.
8010  *
8011  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8012  * of functions inside the implementation of the get_preferred_width()
8013  * or get_preferred_height() virtual functions.</note>
8014  *
8015  * Since: 0.8
8016  */
8017 void
8018 clutter_actor_get_allocation_box (ClutterActor    *self,
8019                                   ClutterActorBox *box)
8020 {
8021   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8022
8023   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8024    * which limits calling get_allocation to inside paint() basically; or
8025    * we can 2) force a layout, which could be expensive if someone calls
8026    * get_allocation somewhere silly; or we can 3) just return the latest
8027    * value, allowing it to be out-of-date, and assume people know what
8028    * they are doing.
8029    *
8030    * The least-surprises approach that keeps existing code working is
8031    * likely to be 2). People can end up doing some inefficient things,
8032    * though, and in general code that requires 2) is probably broken.
8033    */
8034
8035   /* this implements 2) */
8036   if (G_UNLIKELY (self->priv->needs_allocation))
8037     {
8038       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8039
8040       /* do not queue a relayout on an unparented actor */
8041       if (stage)
8042         _clutter_stage_maybe_relayout (stage);
8043     }
8044
8045   /* commenting out the code above and just keeping this assigment
8046    * implements 3)
8047    */
8048   *box = self->priv->allocation;
8049 }
8050
8051 /**
8052  * clutter_actor_get_allocation_geometry:
8053  * @self: A #ClutterActor
8054  * @geom: (out): allocation geometry in pixels
8055  *
8056  * Gets the layout box an actor has been assigned.  The allocation can
8057  * only be assumed valid inside a paint() method; anywhere else, it
8058  * may be out-of-date.
8059  *
8060  * An allocation does not incorporate the actor's scale or anchor point;
8061  * those transformations do not affect layout, only rendering.
8062  *
8063  * The returned rectangle is in pixels.
8064  *
8065  * Since: 0.8
8066  */
8067 void
8068 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8069                                        ClutterGeometry *geom)
8070 {
8071   ClutterActorBox box;
8072
8073   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8074   g_return_if_fail (geom != NULL);
8075
8076   clutter_actor_get_allocation_box (self, &box);
8077
8078   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8079   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8080   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8081   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8082 }
8083
8084 static void
8085 clutter_actor_update_constraints (ClutterActor    *self,
8086                                   ClutterActorBox *allocation)
8087 {
8088   ClutterActorPrivate *priv = self->priv;
8089   const GList *constraints, *l;
8090
8091   if (priv->constraints == NULL)
8092     return;
8093
8094   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8095   for (l = constraints; l != NULL; l = l->next)
8096     {
8097       ClutterConstraint *constraint = l->data;
8098       ClutterActorMeta *meta = l->data;
8099
8100       if (clutter_actor_meta_get_enabled (meta))
8101         {
8102           _clutter_constraint_update_allocation (constraint,
8103                                                  self,
8104                                                  allocation);
8105         }
8106     }
8107 }
8108
8109 /*< private >
8110  * clutter_actor_adjust_allocation:
8111  * @self: a #ClutterActor
8112  * @allocation: (inout): the allocation to adjust
8113  *
8114  * Adjusts the passed allocation box taking into account the actor's
8115  * layout information, like alignment, expansion, and margin.
8116  */
8117 static void
8118 clutter_actor_adjust_allocation (ClutterActor    *self,
8119                                  ClutterActorBox *allocation)
8120 {
8121   ClutterActorBox adj_allocation;
8122   float alloc_width, alloc_height;
8123   float min_width, min_height;
8124   float nat_width, nat_height;
8125   ClutterRequestMode req_mode;
8126
8127   adj_allocation = *allocation;
8128
8129   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8130
8131   /* we want to hit the cache, so we use the public API */
8132   req_mode = clutter_actor_get_request_mode (self);
8133
8134   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8135     {
8136       clutter_actor_get_preferred_width (self, -1,
8137                                          &min_width,
8138                                          &nat_width);
8139       clutter_actor_get_preferred_height (self, alloc_width,
8140                                           &min_height,
8141                                           &nat_height);
8142     }
8143   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8144     {
8145       clutter_actor_get_preferred_height (self, -1,
8146                                           &min_height,
8147                                           &nat_height);
8148       clutter_actor_get_preferred_height (self, alloc_height,
8149                                           &min_width,
8150                                           &nat_width);
8151     }
8152
8153 #ifdef CLUTTER_ENABLE_DEBUG
8154   /* warn about underallocations */
8155   if (_clutter_diagnostic_enabled () &&
8156       (floorf (min_width - alloc_width) > 0 ||
8157        floorf (min_height - alloc_height) > 0))
8158     {
8159       ClutterActor *parent = clutter_actor_get_parent (self);
8160
8161       /* the only actors that are allowed to be underallocated are the Stage,
8162        * as it doesn't have an implicit size, and Actors that specifically
8163        * told us that they want to opt-out from layout control mechanisms
8164        * through the NO_LAYOUT escape hatch.
8165        */
8166       if (parent != NULL &&
8167           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8168         {
8169           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8170                      "of %.2f x %.2f from its parent actor '%s', but its "
8171                      "requested minimum size is of %.2f x %.2f",
8172                      _clutter_actor_get_debug_name (self),
8173                      alloc_width, alloc_height,
8174                      _clutter_actor_get_debug_name (parent),
8175                      min_width, min_height);
8176         }
8177     }
8178 #endif
8179
8180   clutter_actor_adjust_width (self,
8181                               &min_width,
8182                               &nat_width,
8183                               &adj_allocation.x1,
8184                               &adj_allocation.x2);
8185
8186   clutter_actor_adjust_height (self,
8187                                &min_height,
8188                                &nat_height,
8189                                &adj_allocation.y1,
8190                                &adj_allocation.y2);
8191
8192   /* we maintain the invariant that an allocation cannot be adjusted
8193    * to be outside the parent-given box
8194    */
8195   if (adj_allocation.x1 < allocation->x1 ||
8196       adj_allocation.y1 < allocation->y1 ||
8197       adj_allocation.x2 > allocation->x2 ||
8198       adj_allocation.y2 > allocation->y2)
8199     {
8200       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8201                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8202                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8203                  _clutter_actor_get_debug_name (self),
8204                  adj_allocation.x1, adj_allocation.y1,
8205                  adj_allocation.x2 - adj_allocation.x1,
8206                  adj_allocation.y2 - adj_allocation.y1,
8207                  allocation->x1, allocation->y1,
8208                  allocation->x2 - allocation->x1,
8209                  allocation->y2 - allocation->y1);
8210       return;
8211     }
8212
8213   *allocation = adj_allocation;
8214 }
8215
8216 /**
8217  * clutter_actor_allocate:
8218  * @self: A #ClutterActor
8219  * @box: new allocation of the actor, in parent-relative coordinates
8220  * @flags: flags that control the allocation
8221  *
8222  * Called by the parent of an actor to assign the actor its size.
8223  * Should never be called by applications (except when implementing
8224  * a container or layout manager).
8225  *
8226  * Actors can know from their allocation box whether they have moved
8227  * with respect to their parent actor. The @flags parameter describes
8228  * additional information about the allocation, for instance whether
8229  * the parent has moved with respect to the stage, for example because
8230  * a grandparent's origin has moved.
8231  *
8232  * Since: 0.8
8233  */
8234 void
8235 clutter_actor_allocate (ClutterActor           *self,
8236                         const ClutterActorBox  *box,
8237                         ClutterAllocationFlags  flags)
8238 {
8239   ClutterActorPrivate *priv;
8240   ClutterActorClass *klass;
8241   ClutterActorBox old_allocation, real_allocation;
8242   gboolean origin_changed, child_moved, size_changed;
8243   gboolean stage_allocation_changed;
8244
8245   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8246   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8247     {
8248       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8249                  "which isn't a descendent of the stage!\n",
8250                  self, _clutter_actor_get_debug_name (self));
8251       return;
8252     }
8253
8254   priv = self->priv;
8255
8256   old_allocation = priv->allocation;
8257   real_allocation = *box;
8258
8259   /* constraints are allowed to modify the allocation only here; we do
8260    * this prior to all the other checks so that we can bail out if the
8261    * allocation did not change
8262    */
8263   clutter_actor_update_constraints (self, &real_allocation);
8264
8265   /* adjust the allocation depending on the align/margin properties */
8266   clutter_actor_adjust_allocation (self, &real_allocation);
8267
8268   if (real_allocation.x2 < real_allocation.x1 ||
8269       real_allocation.y2 < real_allocation.y1)
8270     {
8271       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8272                  _clutter_actor_get_debug_name (self),
8273                  real_allocation.x2 - real_allocation.x1,
8274                  real_allocation.y2 - real_allocation.y1);
8275     }
8276
8277   /* we allow 0-sized actors, but not negative-sized ones */
8278   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8279   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8280
8281   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8282
8283   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8284                  real_allocation.y1 != old_allocation.y1);
8285
8286   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8287                   real_allocation.y2 != old_allocation.y2);
8288
8289   if (origin_changed || child_moved || size_changed)
8290     stage_allocation_changed = TRUE;
8291   else
8292     stage_allocation_changed = FALSE;
8293
8294   /* If we get an allocation "out of the blue"
8295    * (we did not queue relayout), then we want to
8296    * ignore it. But if we have needs_allocation set,
8297    * we want to guarantee that allocate() virtual
8298    * method is always called, i.e. that queue_relayout()
8299    * always results in an allocate() invocation on
8300    * an actor.
8301    *
8302    * The optimization here is to avoid re-allocating
8303    * actors that did not queue relayout and were
8304    * not moved.
8305    */
8306   if (!priv->needs_allocation && !stage_allocation_changed)
8307     {
8308       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8309       return;
8310     }
8311
8312   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8313    * clutter_actor_allocate(), it indicates whether the parent has its
8314    * absolute origin moved; when passed in to ClutterActor::allocate()
8315    * virtual method though, it indicates whether the child has its
8316    * absolute origin moved.  So we set it when child_moved is TRUE
8317    */
8318   if (child_moved)
8319     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8320
8321   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8322
8323   klass = CLUTTER_ACTOR_GET_CLASS (self);
8324   klass->allocate (self, &real_allocation, flags);
8325
8326   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8327
8328   if (stage_allocation_changed)
8329     clutter_actor_queue_redraw (self);
8330 }
8331
8332 /**
8333  * clutter_actor_set_allocation:
8334  * @self: a #ClutterActor
8335  * @box: a #ClutterActorBox
8336  * @flags: allocation flags
8337  *
8338  * Stores the allocation of @self as defined by @box.
8339  *
8340  * This function can only be called from within the implementation of
8341  * the #ClutterActorClass.allocate() virtual function.
8342  *
8343  * The allocation should have been adjusted to take into account constraints,
8344  * alignment, and margin properties. If you are implementing a #ClutterActor
8345  * subclass that provides its own layout management policy for its children
8346  * instead of using a #ClutterLayoutManager delegate, you should not call
8347  * this function on the children of @self; instead, you should call
8348  * clutter_actor_allocate(), which will adjust the allocation box for
8349  * you.
8350  *
8351  * This function should only be used by subclasses of #ClutterActor
8352  * that wish to store their allocation but cannot chain up to the
8353  * parent's implementation; the default implementation of the
8354  * #ClutterActorClass.allocate() virtual function will call this
8355  * function.
8356  *
8357  * It is important to note that, while chaining up was the recommended
8358  * behaviour for #ClutterActor subclasses prior to the introduction of
8359  * this function, it is recommended to call clutter_actor_set_allocation()
8360  * instead.
8361  *
8362  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8363  * to handle the allocation of its children, this function will call
8364  * the clutter_layout_manager_allocate() function only if the
8365  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8366  * expected that the subclass will call clutter_layout_manager_allocate()
8367  * by itself. For instance, the following code:
8368  *
8369  * |[
8370  * static void
8371  * my_actor_allocate (ClutterActor *actor,
8372  *                    const ClutterActorBox *allocation,
8373  *                    ClutterAllocationFlags flags)
8374  * {
8375  *   ClutterActorBox new_alloc;
8376  *   ClutterAllocationFlags new_flags;
8377  *
8378  *   adjust_allocation (allocation, &amp;new_alloc);
8379  *
8380  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8381  *
8382  *   /&ast; this will use the layout manager set on the actor &ast;/
8383  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8384  * }
8385  * ]|
8386  *
8387  * is equivalent to this:
8388  *
8389  * |[
8390  * static void
8391  * my_actor_allocate (ClutterActor *actor,
8392  *                    const ClutterActorBox *allocation,
8393  *                    ClutterAllocationFlags flags)
8394  * {
8395  *   ClutterLayoutManager *layout;
8396  *   ClutterActorBox new_alloc;
8397  *
8398  *   adjust_allocation (allocation, &amp;new_alloc);
8399  *
8400  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8401  *
8402  *   layout = clutter_actor_get_layout_manager (actor);
8403  *   clutter_layout_manager_allocate (layout,
8404  *                                    CLUTTER_CONTAINER (actor),
8405  *                                    &amp;new_alloc,
8406  *                                    flags);
8407  * }
8408  * ]|
8409  *
8410  * Since: 1.10
8411  */
8412 void
8413 clutter_actor_set_allocation (ClutterActor           *self,
8414                               const ClutterActorBox  *box,
8415                               ClutterAllocationFlags  flags)
8416 {
8417   ClutterActorPrivate *priv;
8418   gboolean changed;
8419
8420   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8421   g_return_if_fail (box != NULL);
8422
8423   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8424     {
8425       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8426                   "can only be called from within the implementation of "
8427                   "the ClutterActor::allocate() virtual function.");
8428       return;
8429     }
8430
8431   priv = self->priv;
8432
8433   g_object_freeze_notify (G_OBJECT (self));
8434
8435   changed = clutter_actor_set_allocation_internal (self, box, flags);
8436
8437   /* we allocate our children before we notify changes in our geometry,
8438    * so that people connecting to properties will be able to get valid
8439    * data out of the sub-tree of the scene graph that has this actor at
8440    * the root.
8441    */
8442   clutter_actor_maybe_layout_children (self, box, flags);
8443
8444   if (changed)
8445     {
8446       ClutterActorBox signal_box = priv->allocation;
8447       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8448
8449       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8450                      &signal_box,
8451                      signal_flags);
8452     }
8453
8454   g_object_thaw_notify (G_OBJECT (self));
8455 }
8456
8457 /**
8458  * clutter_actor_set_geometry:
8459  * @self: A #ClutterActor
8460  * @geometry: A #ClutterGeometry
8461  *
8462  * Sets the actor's fixed position and forces its minimum and natural
8463  * size, in pixels. This means the untransformed actor will have the
8464  * given geometry. This is the same as calling clutter_actor_set_position()
8465  * and clutter_actor_set_size().
8466  *
8467  * Deprecated: 1.10: Use clutter_actor_set_position() and
8468  *   clutter_actor_set_size() instead.
8469  */
8470 void
8471 clutter_actor_set_geometry (ClutterActor          *self,
8472                             const ClutterGeometry *geometry)
8473 {
8474   g_object_freeze_notify (G_OBJECT (self));
8475
8476   clutter_actor_set_position (self, geometry->x, geometry->y);
8477   clutter_actor_set_size (self, geometry->width, geometry->height);
8478
8479   g_object_thaw_notify (G_OBJECT (self));
8480 }
8481
8482 /**
8483  * clutter_actor_get_geometry:
8484  * @self: A #ClutterActor
8485  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8486  *
8487  * Gets the size and position of an actor relative to its parent
8488  * actor. This is the same as calling clutter_actor_get_position() and
8489  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8490  * requested size and position if the actor's allocation is invalid.
8491  *
8492  * Deprecated: 1.10: Use clutter_actor_get_position() and
8493  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8494  *   instead.
8495  */
8496 void
8497 clutter_actor_get_geometry (ClutterActor    *self,
8498                             ClutterGeometry *geometry)
8499 {
8500   gfloat x, y, width, height;
8501
8502   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8503   g_return_if_fail (geometry != NULL);
8504
8505   clutter_actor_get_position (self, &x, &y);
8506   clutter_actor_get_size (self, &width, &height);
8507
8508   geometry->x = (int) x;
8509   geometry->y = (int) y;
8510   geometry->width = (int) width;
8511   geometry->height = (int) height;
8512 }
8513
8514 /**
8515  * clutter_actor_set_position:
8516  * @self: A #ClutterActor
8517  * @x: New left position of actor in pixels.
8518  * @y: New top position of actor in pixels.
8519  *
8520  * Sets the actor's fixed position in pixels relative to any parent
8521  * actor.
8522  *
8523  * If a layout manager is in use, this position will override the
8524  * layout manager and force a fixed position.
8525  */
8526 void
8527 clutter_actor_set_position (ClutterActor *self,
8528                             gfloat        x,
8529                             gfloat        y)
8530 {
8531   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8532
8533   g_object_freeze_notify (G_OBJECT (self));
8534
8535   clutter_actor_set_x (self, x);
8536   clutter_actor_set_y (self, y);
8537
8538   g_object_thaw_notify (G_OBJECT (self));
8539 }
8540
8541 /**
8542  * clutter_actor_get_fixed_position_set:
8543  * @self: A #ClutterActor
8544  *
8545  * Checks whether an actor has a fixed position set (and will thus be
8546  * unaffected by any layout manager).
8547  *
8548  * Return value: %TRUE if the fixed position is set on the actor
8549  *
8550  * Since: 0.8
8551  */
8552 gboolean
8553 clutter_actor_get_fixed_position_set (ClutterActor *self)
8554 {
8555   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8556
8557   return self->priv->position_set;
8558 }
8559
8560 /**
8561  * clutter_actor_set_fixed_position_set:
8562  * @self: A #ClutterActor
8563  * @is_set: whether to use fixed position
8564  *
8565  * Sets whether an actor has a fixed position set (and will thus be
8566  * unaffected by any layout manager).
8567  *
8568  * Since: 0.8
8569  */
8570 void
8571 clutter_actor_set_fixed_position_set (ClutterActor *self,
8572                                       gboolean      is_set)
8573 {
8574   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8575
8576   if (self->priv->position_set == (is_set != FALSE))
8577     return;
8578
8579   self->priv->position_set = is_set != FALSE;
8580   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8581
8582   clutter_actor_queue_relayout (self);
8583 }
8584
8585 /**
8586  * clutter_actor_move_by:
8587  * @self: A #ClutterActor
8588  * @dx: Distance to move Actor on X axis.
8589  * @dy: Distance to move Actor on Y axis.
8590  *
8591  * Moves an actor by the specified distance relative to its current
8592  * position in pixels.
8593  *
8594  * This function modifies the fixed position of an actor and thus removes
8595  * it from any layout management. Another way to move an actor is with an
8596  * anchor point, see clutter_actor_set_anchor_point().
8597  *
8598  * Since: 0.2
8599  */
8600 void
8601 clutter_actor_move_by (ClutterActor *self,
8602                        gfloat        dx,
8603                        gfloat        dy)
8604 {
8605   const ClutterLayoutInfo *info;
8606   gfloat x, y;
8607
8608   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8609
8610   info = _clutter_actor_get_layout_info_or_defaults (self);
8611   x = info->fixed_x;
8612   y = info->fixed_y;
8613
8614   clutter_actor_set_position (self, x + dx, y + dy);
8615 }
8616
8617 static void
8618 clutter_actor_set_min_width (ClutterActor *self,
8619                              gfloat        min_width)
8620 {
8621   ClutterActorPrivate *priv = self->priv;
8622   ClutterActorBox old = { 0, };
8623   ClutterLayoutInfo *info;
8624
8625   /* if we are setting the size on a top-level actor and the
8626    * backend only supports static top-levels (e.g. framebuffers)
8627    * then we ignore the passed value and we override it with
8628    * the stage implementation's preferred size.
8629    */
8630   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8631       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8632     return;
8633
8634   info = _clutter_actor_get_layout_info (self);
8635
8636   if (priv->min_width_set && min_width == info->min_width)
8637     return;
8638
8639   g_object_freeze_notify (G_OBJECT (self));
8640
8641   clutter_actor_store_old_geometry (self, &old);
8642
8643   info->min_width = min_width;
8644   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8645   clutter_actor_set_min_width_set (self, TRUE);
8646
8647   clutter_actor_notify_if_geometry_changed (self, &old);
8648
8649   g_object_thaw_notify (G_OBJECT (self));
8650
8651   clutter_actor_queue_relayout (self);
8652 }
8653
8654 static void
8655 clutter_actor_set_min_height (ClutterActor *self,
8656                               gfloat        min_height)
8657
8658 {
8659   ClutterActorPrivate *priv = self->priv;
8660   ClutterActorBox old = { 0, };
8661   ClutterLayoutInfo *info;
8662
8663   /* if we are setting the size on a top-level actor and the
8664    * backend only supports static top-levels (e.g. framebuffers)
8665    * then we ignore the passed value and we override it with
8666    * the stage implementation's preferred size.
8667    */
8668   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8669       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8670     return;
8671
8672   info = _clutter_actor_get_layout_info (self);
8673
8674   if (priv->min_height_set && min_height == info->min_height)
8675     return;
8676
8677   g_object_freeze_notify (G_OBJECT (self));
8678
8679   clutter_actor_store_old_geometry (self, &old);
8680
8681   info->min_height = min_height;
8682   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8683   clutter_actor_set_min_height_set (self, TRUE);
8684
8685   clutter_actor_notify_if_geometry_changed (self, &old);
8686
8687   g_object_thaw_notify (G_OBJECT (self));
8688
8689   clutter_actor_queue_relayout (self);
8690 }
8691
8692 static void
8693 clutter_actor_set_natural_width (ClutterActor *self,
8694                                  gfloat        natural_width)
8695 {
8696   ClutterActorPrivate *priv = self->priv;
8697   ClutterActorBox old = { 0, };
8698   ClutterLayoutInfo *info;
8699
8700   /* if we are setting the size on a top-level actor and the
8701    * backend only supports static top-levels (e.g. framebuffers)
8702    * then we ignore the passed value and we override it with
8703    * the stage implementation's preferred size.
8704    */
8705   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8706       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8707     return;
8708
8709   info = _clutter_actor_get_layout_info (self);
8710
8711   if (priv->natural_width_set && natural_width == info->natural_width)
8712     return;
8713
8714   g_object_freeze_notify (G_OBJECT (self));
8715
8716   clutter_actor_store_old_geometry (self, &old);
8717
8718   info->natural_width = natural_width;
8719   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8720   clutter_actor_set_natural_width_set (self, TRUE);
8721
8722   clutter_actor_notify_if_geometry_changed (self, &old);
8723
8724   g_object_thaw_notify (G_OBJECT (self));
8725
8726   clutter_actor_queue_relayout (self);
8727 }
8728
8729 static void
8730 clutter_actor_set_natural_height (ClutterActor *self,
8731                                   gfloat        natural_height)
8732 {
8733   ClutterActorPrivate *priv = self->priv;
8734   ClutterActorBox old = { 0, };
8735   ClutterLayoutInfo *info;
8736
8737   /* if we are setting the size on a top-level actor and the
8738    * backend only supports static top-levels (e.g. framebuffers)
8739    * then we ignore the passed value and we override it with
8740    * the stage implementation's preferred size.
8741    */
8742   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8743       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8744     return;
8745
8746   info = _clutter_actor_get_layout_info (self);
8747
8748   if (priv->natural_height_set && natural_height == info->natural_height)
8749     return;
8750
8751   g_object_freeze_notify (G_OBJECT (self));
8752
8753   clutter_actor_store_old_geometry (self, &old);
8754
8755   info->natural_height = natural_height;
8756   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8757   clutter_actor_set_natural_height_set (self, TRUE);
8758
8759   clutter_actor_notify_if_geometry_changed (self, &old);
8760
8761   g_object_thaw_notify (G_OBJECT (self));
8762
8763   clutter_actor_queue_relayout (self);
8764 }
8765
8766 static void
8767 clutter_actor_set_min_width_set (ClutterActor *self,
8768                                  gboolean      use_min_width)
8769 {
8770   ClutterActorPrivate *priv = self->priv;
8771   ClutterActorBox old = { 0, };
8772
8773   if (priv->min_width_set == (use_min_width != FALSE))
8774     return;
8775
8776   clutter_actor_store_old_geometry (self, &old);
8777
8778   priv->min_width_set = use_min_width != FALSE;
8779   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8780
8781   clutter_actor_notify_if_geometry_changed (self, &old);
8782
8783   clutter_actor_queue_relayout (self);
8784 }
8785
8786 static void
8787 clutter_actor_set_min_height_set (ClutterActor *self,
8788                                   gboolean      use_min_height)
8789 {
8790   ClutterActorPrivate *priv = self->priv;
8791   ClutterActorBox old = { 0, };
8792
8793   if (priv->min_height_set == (use_min_height != FALSE))
8794     return;
8795
8796   clutter_actor_store_old_geometry (self, &old);
8797
8798   priv->min_height_set = use_min_height != FALSE;
8799   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8800
8801   clutter_actor_notify_if_geometry_changed (self, &old);
8802
8803   clutter_actor_queue_relayout (self);
8804 }
8805
8806 static void
8807 clutter_actor_set_natural_width_set (ClutterActor *self,
8808                                      gboolean      use_natural_width)
8809 {
8810   ClutterActorPrivate *priv = self->priv;
8811   ClutterActorBox old = { 0, };
8812
8813   if (priv->natural_width_set == (use_natural_width != FALSE))
8814     return;
8815
8816   clutter_actor_store_old_geometry (self, &old);
8817
8818   priv->natural_width_set = use_natural_width != FALSE;
8819   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8820
8821   clutter_actor_notify_if_geometry_changed (self, &old);
8822
8823   clutter_actor_queue_relayout (self);
8824 }
8825
8826 static void
8827 clutter_actor_set_natural_height_set (ClutterActor *self,
8828                                       gboolean      use_natural_height)
8829 {
8830   ClutterActorPrivate *priv = self->priv;
8831   ClutterActorBox old = { 0, };
8832
8833   if (priv->natural_height_set == (use_natural_height != FALSE))
8834     return;
8835
8836   clutter_actor_store_old_geometry (self, &old);
8837
8838   priv->natural_height_set = use_natural_height != FALSE;
8839   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8840
8841   clutter_actor_notify_if_geometry_changed (self, &old);
8842
8843   clutter_actor_queue_relayout (self);
8844 }
8845
8846 /**
8847  * clutter_actor_set_request_mode:
8848  * @self: a #ClutterActor
8849  * @mode: the request mode
8850  *
8851  * Sets the geometry request mode of @self.
8852  *
8853  * The @mode determines the order for invoking
8854  * clutter_actor_get_preferred_width() and
8855  * clutter_actor_get_preferred_height()
8856  *
8857  * Since: 1.2
8858  */
8859 void
8860 clutter_actor_set_request_mode (ClutterActor       *self,
8861                                 ClutterRequestMode  mode)
8862 {
8863   ClutterActorPrivate *priv;
8864
8865   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8866
8867   priv = self->priv;
8868
8869   if (priv->request_mode == mode)
8870     return;
8871
8872   priv->request_mode = mode;
8873
8874   priv->needs_width_request = TRUE;
8875   priv->needs_height_request = TRUE;
8876
8877   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8878
8879   clutter_actor_queue_relayout (self);
8880 }
8881
8882 /**
8883  * clutter_actor_get_request_mode:
8884  * @self: a #ClutterActor
8885  *
8886  * Retrieves the geometry request mode of @self
8887  *
8888  * Return value: the request mode for the actor
8889  *
8890  * Since: 1.2
8891  */
8892 ClutterRequestMode
8893 clutter_actor_get_request_mode (ClutterActor *self)
8894 {
8895   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8896                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8897
8898   return self->priv->request_mode;
8899 }
8900
8901 /* variant of set_width() without checks and without notification
8902  * freeze+thaw, for internal usage only
8903  */
8904 static inline void
8905 clutter_actor_set_width_internal (ClutterActor *self,
8906                                   gfloat        width)
8907 {
8908   if (width >= 0)
8909     {
8910       /* the Stage will use the :min-width to control the minimum
8911        * width to be resized to, so we should not be setting it
8912        * along with the :natural-width
8913        */
8914       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8915         clutter_actor_set_min_width (self, width);
8916
8917       clutter_actor_set_natural_width (self, width);
8918     }
8919   else
8920     {
8921       /* we only unset the :natural-width for the Stage */
8922       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8923         clutter_actor_set_min_width_set (self, FALSE);
8924
8925       clutter_actor_set_natural_width_set (self, FALSE);
8926     }
8927 }
8928
8929 /* variant of set_height() without checks and without notification
8930  * freeze+thaw, for internal usage only
8931  */
8932 static inline void
8933 clutter_actor_set_height_internal (ClutterActor *self,
8934                                    gfloat        height)
8935 {
8936   if (height >= 0)
8937     {
8938       /* see the comment above in set_width_internal() */
8939       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8940         clutter_actor_set_min_height (self, height);
8941
8942       clutter_actor_set_natural_height (self, height);
8943     }
8944   else
8945     {
8946       /* see the comment above in set_width_internal() */
8947       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8948         clutter_actor_set_min_height_set (self, FALSE);
8949
8950       clutter_actor_set_natural_height_set (self, FALSE);
8951     }
8952 }
8953
8954 /**
8955  * clutter_actor_set_size:
8956  * @self: A #ClutterActor
8957  * @width: New width of actor in pixels, or -1
8958  * @height: New height of actor in pixels, or -1
8959  *
8960  * Sets the actor's size request in pixels. This overrides any
8961  * "normal" size request the actor would have. For example
8962  * a text actor might normally request the size of the text;
8963  * this function would force a specific size instead.
8964  *
8965  * If @width and/or @height are -1 the actor will use its
8966  * "normal" size request instead of overriding it, i.e.
8967  * you can "unset" the size with -1.
8968  *
8969  * This function sets or unsets both the minimum and natural size.
8970  */
8971 void
8972 clutter_actor_set_size (ClutterActor *self,
8973                         gfloat        width,
8974                         gfloat        height)
8975 {
8976   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8977
8978   g_object_freeze_notify (G_OBJECT (self));
8979
8980   clutter_actor_set_width (self, width);
8981   clutter_actor_set_height (self, height);
8982
8983   g_object_thaw_notify (G_OBJECT (self));
8984 }
8985
8986 /**
8987  * clutter_actor_get_size:
8988  * @self: A #ClutterActor
8989  * @width: (out) (allow-none): return location for the width, or %NULL.
8990  * @height: (out) (allow-none): return location for the height, or %NULL.
8991  *
8992  * This function tries to "do what you mean" and return
8993  * the size an actor will have. If the actor has a valid
8994  * allocation, the allocation will be returned; otherwise,
8995  * the actors natural size request will be returned.
8996  *
8997  * If you care whether you get the request vs. the allocation, you
8998  * should probably call a different function like
8999  * clutter_actor_get_allocation_box() or
9000  * clutter_actor_get_preferred_width().
9001  *
9002  * Since: 0.2
9003  */
9004 void
9005 clutter_actor_get_size (ClutterActor *self,
9006                         gfloat       *width,
9007                         gfloat       *height)
9008 {
9009   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9010
9011   if (width)
9012     *width = clutter_actor_get_width (self);
9013
9014   if (height)
9015     *height = clutter_actor_get_height (self);
9016 }
9017
9018 /**
9019  * clutter_actor_get_position:
9020  * @self: a #ClutterActor
9021  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9022  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9023  *
9024  * This function tries to "do what you mean" and tell you where the
9025  * actor is, prior to any transformations. Retrieves the fixed
9026  * position of an actor in pixels, if one has been set; otherwise, if
9027  * the allocation is valid, returns the actor's allocated position;
9028  * otherwise, returns 0,0.
9029  *
9030  * The returned position is in pixels.
9031  *
9032  * Since: 0.6
9033  */
9034 void
9035 clutter_actor_get_position (ClutterActor *self,
9036                             gfloat       *x,
9037                             gfloat       *y)
9038 {
9039   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9040
9041   if (x)
9042     *x = clutter_actor_get_x (self);
9043
9044   if (y)
9045     *y = clutter_actor_get_y (self);
9046 }
9047
9048 /**
9049  * clutter_actor_get_transformed_position:
9050  * @self: A #ClutterActor
9051  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9052  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9053  *
9054  * Gets the absolute position of an actor, in pixels relative to the stage.
9055  *
9056  * Since: 0.8
9057  */
9058 void
9059 clutter_actor_get_transformed_position (ClutterActor *self,
9060                                         gfloat       *x,
9061                                         gfloat       *y)
9062 {
9063   ClutterVertex v1;
9064   ClutterVertex v2;
9065
9066   v1.x = v1.y = v1.z = 0;
9067   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9068
9069   if (x)
9070     *x = v2.x;
9071
9072   if (y)
9073     *y = v2.y;
9074 }
9075
9076 /**
9077  * clutter_actor_get_transformed_size:
9078  * @self: A #ClutterActor
9079  * @width: (out) (allow-none): return location for the width, or %NULL
9080  * @height: (out) (allow-none): return location for the height, or %NULL
9081  *
9082  * Gets the absolute size of an actor in pixels, taking into account the
9083  * scaling factors.
9084  *
9085  * If the actor has a valid allocation, the allocated size will be used.
9086  * If the actor has not a valid allocation then the preferred size will
9087  * be transformed and returned.
9088  *
9089  * If you want the transformed allocation, see
9090  * clutter_actor_get_abs_allocation_vertices() instead.
9091  *
9092  * <note>When the actor (or one of its ancestors) is rotated around the
9093  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9094  * as a generic quadrangle; in that case this function returns the size
9095  * of the smallest rectangle that encapsulates the entire quad. Please
9096  * note that in this case no assumptions can be made about the relative
9097  * position of this envelope to the absolute position of the actor, as
9098  * returned by clutter_actor_get_transformed_position(); if you need this
9099  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9100  * to get the coords of the actual quadrangle.</note>
9101  *
9102  * Since: 0.8
9103  */
9104 void
9105 clutter_actor_get_transformed_size (ClutterActor *self,
9106                                     gfloat       *width,
9107                                     gfloat       *height)
9108 {
9109   ClutterActorPrivate *priv;
9110   ClutterVertex v[4];
9111   gfloat x_min, x_max, y_min, y_max;
9112   gint i;
9113
9114   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9115
9116   priv = self->priv;
9117
9118   /* if the actor hasn't been allocated yet, get the preferred
9119    * size and transform that
9120    */
9121   if (priv->needs_allocation)
9122     {
9123       gfloat natural_width, natural_height;
9124       ClutterActorBox box;
9125
9126       /* Make a fake allocation to transform.
9127        *
9128        * NB: _clutter_actor_transform_and_project_box expects a box in
9129        * the actor's coordinate space... */
9130
9131       box.x1 = 0;
9132       box.y1 = 0;
9133
9134       natural_width = natural_height = 0;
9135       clutter_actor_get_preferred_size (self, NULL, NULL,
9136                                         &natural_width,
9137                                         &natural_height);
9138
9139       box.x2 = natural_width;
9140       box.y2 = natural_height;
9141
9142       _clutter_actor_transform_and_project_box (self, &box, v);
9143     }
9144   else
9145     clutter_actor_get_abs_allocation_vertices (self, v);
9146
9147   x_min = x_max = v[0].x;
9148   y_min = y_max = v[0].y;
9149
9150   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9151     {
9152       if (v[i].x < x_min)
9153         x_min = v[i].x;
9154
9155       if (v[i].x > x_max)
9156         x_max = v[i].x;
9157
9158       if (v[i].y < y_min)
9159         y_min = v[i].y;
9160
9161       if (v[i].y > y_max)
9162         y_max = v[i].y;
9163     }
9164
9165   if (width)
9166     *width  = x_max - x_min;
9167
9168   if (height)
9169     *height = y_max - y_min;
9170 }
9171
9172 /**
9173  * clutter_actor_get_width:
9174  * @self: A #ClutterActor
9175  *
9176  * Retrieves the width of a #ClutterActor.
9177  *
9178  * If the actor has a valid allocation, this function will return the
9179  * width of the allocated area given to the actor.
9180  *
9181  * If the actor does not have a valid allocation, this function will
9182  * return the actor's natural width, that is the preferred width of
9183  * the actor.
9184  *
9185  * If you care whether you get the preferred width or the width that
9186  * has been assigned to the actor, you should probably call a different
9187  * function like clutter_actor_get_allocation_box() to retrieve the
9188  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9189  * preferred width.
9190  *
9191  * If an actor has a fixed width, for instance a width that has been
9192  * assigned using clutter_actor_set_width(), the width returned will
9193  * be the same value.
9194  *
9195  * Return value: the width of the actor, in pixels
9196  */
9197 gfloat
9198 clutter_actor_get_width (ClutterActor *self)
9199 {
9200   ClutterActorPrivate *priv;
9201
9202   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9203
9204   priv = self->priv;
9205
9206   if (priv->needs_allocation)
9207     {
9208       gfloat natural_width = 0;
9209
9210       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9211         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9212       else
9213         {
9214           gfloat natural_height = 0;
9215
9216           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9217           clutter_actor_get_preferred_width (self, natural_height,
9218                                              NULL,
9219                                              &natural_width);
9220         }
9221
9222       return natural_width;
9223     }
9224   else
9225     return priv->allocation.x2 - priv->allocation.x1;
9226 }
9227
9228 /**
9229  * clutter_actor_get_height:
9230  * @self: A #ClutterActor
9231  *
9232  * Retrieves the height of a #ClutterActor.
9233  *
9234  * If the actor has a valid allocation, this function will return the
9235  * height of the allocated area given to the actor.
9236  *
9237  * If the actor does not have a valid allocation, this function will
9238  * return the actor's natural height, that is the preferred height of
9239  * the actor.
9240  *
9241  * If you care whether you get the preferred height or the height that
9242  * has been assigned to the actor, you should probably call a different
9243  * function like clutter_actor_get_allocation_box() to retrieve the
9244  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9245  * preferred height.
9246  *
9247  * If an actor has a fixed height, for instance a height that has been
9248  * assigned using clutter_actor_set_height(), the height returned will
9249  * be the same value.
9250  *
9251  * Return value: the height of the actor, in pixels
9252  */
9253 gfloat
9254 clutter_actor_get_height (ClutterActor *self)
9255 {
9256   ClutterActorPrivate *priv;
9257
9258   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9259
9260   priv = self->priv;
9261
9262   if (priv->needs_allocation)
9263     {
9264       gfloat natural_height = 0;
9265
9266       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9267         {
9268           gfloat natural_width = 0;
9269
9270           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9271           clutter_actor_get_preferred_height (self, natural_width,
9272                                               NULL, &natural_height);
9273         }
9274       else
9275         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9276
9277       return natural_height;
9278     }
9279   else
9280     return priv->allocation.y2 - priv->allocation.y1;
9281 }
9282
9283 /**
9284  * clutter_actor_set_width:
9285  * @self: A #ClutterActor
9286  * @width: Requested new width for the actor, in pixels, or -1
9287  *
9288  * Forces a width on an actor, causing the actor's preferred width
9289  * and height (if any) to be ignored.
9290  *
9291  * If @width is -1 the actor will use its preferred width request
9292  * instead of overriding it, i.e. you can "unset" the width with -1.
9293  *
9294  * This function sets both the minimum and natural size of the actor.
9295  *
9296  * since: 0.2
9297  */
9298 void
9299 clutter_actor_set_width (ClutterActor *self,
9300                          gfloat        width)
9301 {
9302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9303
9304   if (clutter_actor_get_easing_duration (self) != 0)
9305     {
9306       ClutterTransition *transition;
9307
9308       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9309       if (transition == NULL)
9310         {
9311           float old_width = clutter_actor_get_width (self);
9312
9313           transition = _clutter_actor_create_transition (self,
9314                                                          obj_props[PROP_WIDTH],
9315                                                          old_width,
9316                                                          width);
9317           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9318         }
9319       else
9320         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9321
9322       clutter_actor_queue_relayout (self);
9323     }
9324   else
9325     {
9326       g_object_freeze_notify (G_OBJECT (self));
9327
9328       clutter_actor_set_width_internal (self, width);
9329
9330       g_object_thaw_notify (G_OBJECT (self));
9331     }
9332 }
9333
9334 /**
9335  * clutter_actor_set_height:
9336  * @self: A #ClutterActor
9337  * @height: Requested new height for the actor, in pixels, or -1
9338  *
9339  * Forces a height on an actor, causing the actor's preferred width
9340  * and height (if any) to be ignored.
9341  *
9342  * If @height is -1 the actor will use its preferred height instead of
9343  * overriding it, i.e. you can "unset" the height with -1.
9344  *
9345  * This function sets both the minimum and natural size of the actor.
9346  *
9347  * since: 0.2
9348  */
9349 void
9350 clutter_actor_set_height (ClutterActor *self,
9351                           gfloat        height)
9352 {
9353   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9354
9355   if (clutter_actor_get_easing_duration (self) != 0)
9356     {
9357       ClutterTransition *transition;
9358
9359       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9360       if (transition ==  NULL)
9361         {
9362           float old_height = clutter_actor_get_height (self);
9363
9364           transition = _clutter_actor_create_transition (self,
9365                                                          obj_props[PROP_HEIGHT],
9366                                                          old_height,
9367                                                          height);
9368           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9369         }
9370       else
9371         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9372
9373       clutter_actor_queue_relayout (self);
9374     }
9375   else
9376     {
9377       g_object_freeze_notify (G_OBJECT (self));
9378
9379       clutter_actor_set_height_internal (self, height);
9380
9381       g_object_thaw_notify (G_OBJECT (self));
9382     }
9383 }
9384
9385 static inline void
9386 clutter_actor_set_x_internal (ClutterActor *self,
9387                               float         x)
9388 {
9389   ClutterActorPrivate *priv = self->priv;
9390   ClutterLayoutInfo *linfo;
9391   ClutterActorBox old = { 0, };
9392
9393   linfo = _clutter_actor_get_layout_info (self);
9394
9395   if (priv->position_set && linfo->fixed_x == x)
9396     return;
9397
9398   clutter_actor_store_old_geometry (self, &old);
9399
9400   linfo->fixed_x = x;
9401   clutter_actor_set_fixed_position_set (self, TRUE);
9402
9403   clutter_actor_notify_if_geometry_changed (self, &old);
9404
9405   clutter_actor_queue_relayout (self);
9406 }
9407
9408 static inline void
9409 clutter_actor_set_y_internal (ClutterActor *self,
9410                               float         y)
9411 {
9412   ClutterActorPrivate *priv = self->priv;
9413   ClutterLayoutInfo *linfo;
9414   ClutterActorBox old = { 0, };
9415
9416   linfo = _clutter_actor_get_layout_info (self);
9417
9418   if (priv->position_set && linfo->fixed_y == y)
9419     return;
9420
9421   clutter_actor_store_old_geometry (self, &old);
9422
9423   linfo->fixed_y = y;
9424   clutter_actor_set_fixed_position_set (self, TRUE);
9425
9426   clutter_actor_notify_if_geometry_changed (self, &old);
9427 }
9428
9429 /**
9430  * clutter_actor_set_x:
9431  * @self: a #ClutterActor
9432  * @x: the actor's position on the X axis
9433  *
9434  * Sets the actor's X coordinate, relative to its parent, in pixels.
9435  *
9436  * Overrides any layout manager and forces a fixed position for
9437  * the actor.
9438  *
9439  * The #ClutterActor:x property is animatable.
9440  *
9441  * Since: 0.6
9442  */
9443 void
9444 clutter_actor_set_x (ClutterActor *self,
9445                      gfloat        x)
9446 {
9447   const ClutterLayoutInfo *linfo;
9448
9449   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9450
9451   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9452
9453   if (clutter_actor_get_easing_duration (self) != 0)
9454     {
9455       ClutterTransition *transition;
9456
9457       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9458       if (transition == NULL)
9459         {
9460           transition = _clutter_actor_create_transition (self,
9461                                                          obj_props[PROP_X],
9462                                                          linfo->fixed_x,
9463                                                          x);
9464
9465           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9466         }
9467       else
9468         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9469
9470       clutter_actor_queue_relayout (self);
9471     }
9472   else
9473     clutter_actor_set_x_internal (self, x);
9474 }
9475
9476 /**
9477  * clutter_actor_set_y:
9478  * @self: a #ClutterActor
9479  * @y: the actor's position on the Y axis
9480  *
9481  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9482  *
9483  * Overrides any layout manager and forces a fixed position for
9484  * the actor.
9485  *
9486  * The #ClutterActor:y property is animatable.
9487  *
9488  * Since: 0.6
9489  */
9490 void
9491 clutter_actor_set_y (ClutterActor *self,
9492                      gfloat        y)
9493 {
9494   const ClutterLayoutInfo *linfo;
9495
9496   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9497
9498   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9499
9500   if (clutter_actor_get_easing_duration (self) != 0)
9501     {
9502       ClutterTransition *transition;
9503
9504       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9505       if (transition == NULL)
9506         {
9507           transition = _clutter_actor_create_transition (self,
9508                                                          obj_props[PROP_Y],
9509                                                          linfo->fixed_y,
9510                                                          y);
9511
9512           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9513         }
9514       else
9515         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9516
9517       clutter_actor_queue_relayout (self);
9518     }
9519   else
9520     clutter_actor_set_y_internal (self, y);
9521
9522   clutter_actor_queue_relayout (self);
9523 }
9524
9525 /**
9526  * clutter_actor_get_x:
9527  * @self: A #ClutterActor
9528  *
9529  * Retrieves the X coordinate of a #ClutterActor.
9530  *
9531  * This function tries to "do what you mean", by returning the
9532  * correct value depending on the actor's state.
9533  *
9534  * If the actor has a valid allocation, this function will return
9535  * the X coordinate of the origin of the allocation box.
9536  *
9537  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9538  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9539  * function will return that coordinate.
9540  *
9541  * If both the allocation and a fixed position are missing, this function
9542  * will return 0.
9543  *
9544  * Return value: the X coordinate, in pixels, ignoring any
9545  *   transformation (i.e. scaling, rotation)
9546  */
9547 gfloat
9548 clutter_actor_get_x (ClutterActor *self)
9549 {
9550   ClutterActorPrivate *priv;
9551
9552   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9553
9554   priv = self->priv;
9555
9556   if (priv->needs_allocation)
9557     {
9558       if (priv->position_set)
9559         {
9560           const ClutterLayoutInfo *info;
9561
9562           info = _clutter_actor_get_layout_info_or_defaults (self);
9563
9564           return info->fixed_x;
9565         }
9566       else
9567         return 0;
9568     }
9569   else
9570     return priv->allocation.x1;
9571 }
9572
9573 /**
9574  * clutter_actor_get_y:
9575  * @self: A #ClutterActor
9576  *
9577  * Retrieves the Y coordinate of a #ClutterActor.
9578  *
9579  * This function tries to "do what you mean", by returning the
9580  * correct value depending on the actor's state.
9581  *
9582  * If the actor has a valid allocation, this function will return
9583  * the Y coordinate of the origin of the allocation box.
9584  *
9585  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9586  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9587  * function will return that coordinate.
9588  *
9589  * If both the allocation and a fixed position are missing, this function
9590  * will return 0.
9591  *
9592  * Return value: the Y coordinate, in pixels, ignoring any
9593  *   transformation (i.e. scaling, rotation)
9594  */
9595 gfloat
9596 clutter_actor_get_y (ClutterActor *self)
9597 {
9598   ClutterActorPrivate *priv;
9599
9600   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9601
9602   priv = self->priv;
9603
9604   if (priv->needs_allocation)
9605     {
9606       if (priv->position_set)
9607         {
9608           const ClutterLayoutInfo *info;
9609
9610           info = _clutter_actor_get_layout_info_or_defaults (self);
9611
9612           return info->fixed_y;
9613         }
9614       else
9615         return 0;
9616     }
9617   else
9618     return priv->allocation.y1;
9619 }
9620
9621 /**
9622  * clutter_actor_set_scale:
9623  * @self: A #ClutterActor
9624  * @scale_x: double factor to scale actor by horizontally.
9625  * @scale_y: double factor to scale actor by vertically.
9626  *
9627  * Scales an actor with the given factors. The scaling is relative to
9628  * the scale center and the anchor point. The scale center is
9629  * unchanged by this function and defaults to 0,0.
9630  *
9631  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9632  * animatable.
9633  *
9634  * Since: 0.2
9635  */
9636 void
9637 clutter_actor_set_scale (ClutterActor *self,
9638                          gdouble       scale_x,
9639                          gdouble       scale_y)
9640 {
9641   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9642
9643   g_object_freeze_notify (G_OBJECT (self));
9644
9645   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9646   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9647
9648   g_object_thaw_notify (G_OBJECT (self));
9649 }
9650
9651 /**
9652  * clutter_actor_set_scale_full:
9653  * @self: A #ClutterActor
9654  * @scale_x: double factor to scale actor by horizontally.
9655  * @scale_y: double factor to scale actor by vertically.
9656  * @center_x: X coordinate of the center of the scale.
9657  * @center_y: Y coordinate of the center of the scale
9658  *
9659  * Scales an actor with the given factors around the given center
9660  * point. The center point is specified in pixels relative to the
9661  * anchor point (usually the top left corner of the actor).
9662  *
9663  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9664  * are animatable.
9665  *
9666  * Since: 1.0
9667  */
9668 void
9669 clutter_actor_set_scale_full (ClutterActor *self,
9670                               gdouble       scale_x,
9671                               gdouble       scale_y,
9672                               gfloat        center_x,
9673                               gfloat        center_y)
9674 {
9675   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9676
9677   g_object_freeze_notify (G_OBJECT (self));
9678
9679   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9680   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9681   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9682   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9683
9684   g_object_thaw_notify (G_OBJECT (self));
9685 }
9686
9687 /**
9688  * clutter_actor_set_scale_with_gravity:
9689  * @self: A #ClutterActor
9690  * @scale_x: double factor to scale actor by horizontally.
9691  * @scale_y: double factor to scale actor by vertically.
9692  * @gravity: the location of the scale center expressed as a compass
9693  * direction.
9694  *
9695  * Scales an actor with the given factors around the given
9696  * center point. The center point is specified as one of the compass
9697  * directions in #ClutterGravity. For example, setting it to north
9698  * will cause the top of the actor to remain unchanged and the rest of
9699  * the actor to expand left, right and downwards.
9700  *
9701  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9702  * animatable.
9703  *
9704  * Since: 1.0
9705  */
9706 void
9707 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9708                                       gdouble         scale_x,
9709                                       gdouble         scale_y,
9710                                       ClutterGravity  gravity)
9711 {
9712   ClutterTransformInfo *info;
9713   GObject *obj;
9714
9715   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9716
9717   obj = G_OBJECT (self);
9718
9719   g_object_freeze_notify (obj);
9720
9721   info = _clutter_actor_get_transform_info (self);
9722   info->scale_x = scale_x;
9723   info->scale_y = scale_y;
9724
9725   if (gravity == CLUTTER_GRAVITY_NONE)
9726     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9727   else
9728     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9729
9730   self->priv->transform_valid = FALSE;
9731
9732   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9733   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9734   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9735   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9736   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9737
9738   clutter_actor_queue_redraw (self);
9739
9740   g_object_thaw_notify (obj);
9741 }
9742
9743 /**
9744  * clutter_actor_get_scale:
9745  * @self: A #ClutterActor
9746  * @scale_x: (out) (allow-none): Location to store horizonal
9747  *   scale factor, or %NULL.
9748  * @scale_y: (out) (allow-none): Location to store vertical
9749  *   scale factor, or %NULL.
9750  *
9751  * Retrieves an actors scale factors.
9752  *
9753  * Since: 0.2
9754  */
9755 void
9756 clutter_actor_get_scale (ClutterActor *self,
9757                          gdouble      *scale_x,
9758                          gdouble      *scale_y)
9759 {
9760   const ClutterTransformInfo *info;
9761
9762   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9763
9764   info = _clutter_actor_get_transform_info_or_defaults (self);
9765
9766   if (scale_x)
9767     *scale_x = info->scale_x;
9768
9769   if (scale_y)
9770     *scale_y = info->scale_y;
9771 }
9772
9773 /**
9774  * clutter_actor_get_scale_center:
9775  * @self: A #ClutterActor
9776  * @center_x: (out) (allow-none): Location to store the X position
9777  *   of the scale center, or %NULL.
9778  * @center_y: (out) (allow-none): Location to store the Y position
9779  *   of the scale center, or %NULL.
9780  *
9781  * Retrieves the scale center coordinate in pixels relative to the top
9782  * left corner of the actor. If the scale center was specified using a
9783  * #ClutterGravity this will calculate the pixel offset using the
9784  * current size of the actor.
9785  *
9786  * Since: 1.0
9787  */
9788 void
9789 clutter_actor_get_scale_center (ClutterActor *self,
9790                                 gfloat       *center_x,
9791                                 gfloat       *center_y)
9792 {
9793   const ClutterTransformInfo *info;
9794
9795   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9796
9797   info = _clutter_actor_get_transform_info_or_defaults (self);
9798
9799   clutter_anchor_coord_get_units (self, &info->scale_center,
9800                                   center_x,
9801                                   center_y,
9802                                   NULL);
9803 }
9804
9805 /**
9806  * clutter_actor_get_scale_gravity:
9807  * @self: A #ClutterActor
9808  *
9809  * Retrieves the scale center as a compass direction. If the scale
9810  * center was specified in pixels or units this will return
9811  * %CLUTTER_GRAVITY_NONE.
9812  *
9813  * Return value: the scale gravity
9814  *
9815  * Since: 1.0
9816  */
9817 ClutterGravity
9818 clutter_actor_get_scale_gravity (ClutterActor *self)
9819 {
9820   const ClutterTransformInfo *info;
9821
9822   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9823
9824   info = _clutter_actor_get_transform_info_or_defaults (self);
9825
9826   return clutter_anchor_coord_get_gravity (&info->scale_center);
9827 }
9828
9829 static inline void
9830 clutter_actor_set_opacity_internal (ClutterActor *self,
9831                                     guint8        opacity)
9832 {
9833   ClutterActorPrivate *priv = self->priv;
9834
9835   if (priv->opacity != opacity)
9836     {
9837       priv->opacity = opacity;
9838
9839       /* Queue a redraw from the flatten effect so that it can use
9840          its cached image if available instead of having to redraw the
9841          actual actor. If it doesn't end up using the FBO then the
9842          effect is still able to continue the paint anyway. If there
9843          is no flatten effect yet then this is equivalent to queueing
9844          a full redraw */
9845       _clutter_actor_queue_redraw_full (self,
9846                                         0, /* flags */
9847                                         NULL, /* clip */
9848                                         priv->flatten_effect);
9849
9850       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9851     }
9852 }
9853
9854 /**
9855  * clutter_actor_set_opacity:
9856  * @self: A #ClutterActor
9857  * @opacity: New opacity value for the actor.
9858  *
9859  * Sets the actor's opacity, with zero being completely transparent and
9860  * 255 (0xff) being fully opaque.
9861  *
9862  * The #ClutterActor:opacity property is animatable.
9863  */
9864 void
9865 clutter_actor_set_opacity (ClutterActor *self,
9866                            guint8        opacity)
9867 {
9868   ClutterActorPrivate *priv;
9869
9870   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9871
9872   priv = self->priv;
9873
9874   if (clutter_actor_get_easing_duration (self) != 0)
9875     {
9876       ClutterTransition *transition;
9877
9878       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9879       if (transition == NULL)
9880         {
9881           transition = _clutter_actor_create_transition (self,
9882                                                          obj_props[PROP_OPACITY],
9883                                                          priv->opacity,
9884                                                          opacity);
9885           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9886         }
9887       else
9888         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9889
9890       clutter_actor_queue_redraw (self);
9891     }
9892   else
9893     clutter_actor_set_opacity_internal (self, opacity);
9894 }
9895
9896 /*
9897  * clutter_actor_get_paint_opacity_internal:
9898  * @self: a #ClutterActor
9899  *
9900  * Retrieves the absolute opacity of the actor, as it appears on the stage
9901  *
9902  * This function does not do type checks
9903  *
9904  * Return value: the absolute opacity of the actor
9905  */
9906 static guint8
9907 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9908 {
9909   ClutterActorPrivate *priv = self->priv;
9910   ClutterActor *parent;
9911
9912   /* override the top-level opacity to always be 255; even in
9913    * case of ClutterStage:use-alpha being TRUE we want the rest
9914    * of the scene to be painted
9915    */
9916   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9917     return 255;
9918
9919   if (priv->opacity_override >= 0)
9920     return priv->opacity_override;
9921
9922   parent = priv->parent;
9923
9924   /* Factor in the actual actors opacity with parents */
9925   if (parent != NULL)
9926     {
9927       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9928
9929       if (opacity != 0xff)
9930         return (opacity * priv->opacity) / 0xff;
9931     }
9932
9933   return priv->opacity;
9934
9935 }
9936
9937 /**
9938  * clutter_actor_get_paint_opacity:
9939  * @self: A #ClutterActor
9940  *
9941  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9942  *
9943  * This function traverses the hierarchy chain and composites the opacity of
9944  * the actor with that of its parents.
9945  *
9946  * This function is intended for subclasses to use in the paint virtual
9947  * function, to paint themselves with the correct opacity.
9948  *
9949  * Return value: The actor opacity value.
9950  *
9951  * Since: 0.8
9952  */
9953 guint8
9954 clutter_actor_get_paint_opacity (ClutterActor *self)
9955 {
9956   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9957
9958   return clutter_actor_get_paint_opacity_internal (self);
9959 }
9960
9961 /**
9962  * clutter_actor_get_opacity:
9963  * @self: a #ClutterActor
9964  *
9965  * Retrieves the opacity value of an actor, as set by
9966  * clutter_actor_set_opacity().
9967  *
9968  * For retrieving the absolute opacity of the actor inside a paint
9969  * virtual function, see clutter_actor_get_paint_opacity().
9970  *
9971  * Return value: the opacity of the actor
9972  */
9973 guint8
9974 clutter_actor_get_opacity (ClutterActor *self)
9975 {
9976   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9977
9978   return self->priv->opacity;
9979 }
9980
9981 /**
9982  * clutter_actor_set_offscreen_redirect:
9983  * @self: A #ClutterActor
9984  * @redirect: New offscreen redirect flags for the actor.
9985  *
9986  * Defines the circumstances where the actor should be redirected into
9987  * an offscreen image. The offscreen image is used to flatten the
9988  * actor into a single image while painting for two main reasons.
9989  * Firstly, when the actor is painted a second time without any of its
9990  * contents changing it can simply repaint the cached image without
9991  * descending further down the actor hierarchy. Secondly, it will make
9992  * the opacity look correct even if there are overlapping primitives
9993  * in the actor.
9994  *
9995  * Caching the actor could in some cases be a performance win and in
9996  * some cases be a performance lose so it is important to determine
9997  * which value is right for an actor before modifying this value. For
9998  * example, there is never any reason to flatten an actor that is just
9999  * a single texture (such as a #ClutterTexture) because it is
10000  * effectively already cached in an image so the offscreen would be
10001  * redundant. Also if the actor contains primitives that are far apart
10002  * with a large transparent area in the middle (such as a large
10003  * CluterGroup with a small actor in the top left and a small actor in
10004  * the bottom right) then the cached image will contain the entire
10005  * image of the large area and the paint will waste time blending all
10006  * of the transparent pixels in the middle.
10007  *
10008  * The default method of implementing opacity on a container simply
10009  * forwards on the opacity to all of the children. If the children are
10010  * overlapping then it will appear as if they are two separate glassy
10011  * objects and there will be a break in the color where they
10012  * overlap. By redirecting to an offscreen buffer it will be as if the
10013  * two opaque objects are combined into one and then made transparent
10014  * which is usually what is expected.
10015  *
10016  * The image below demonstrates the difference between redirecting and
10017  * not. The image shows two Clutter groups, each containing a red and
10018  * a green rectangle which overlap. The opacity on the group is set to
10019  * 128 (which is 50%). When the offscreen redirect is not used, the
10020  * red rectangle can be seen through the blue rectangle as if the two
10021  * rectangles were separately transparent. When the redirect is used
10022  * the group as a whole is transparent instead so the red rectangle is
10023  * not visible where they overlap.
10024  *
10025  * <figure id="offscreen-redirect">
10026  *   <title>Sample of using an offscreen redirect for transparency</title>
10027  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10028  * </figure>
10029  *
10030  * The default value for this property is 0, so we effectively will
10031  * never redirect an actor offscreen by default. This means that there
10032  * are times that transparent actors may look glassy as described
10033  * above. The reason this is the default is because there is a
10034  * performance trade off between quality and performance here. In many
10035  * cases the default form of glassy opacity looks good enough, but if
10036  * it's not you will need to set the
10037  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10038  * redirection for opacity.
10039  *
10040  * Custom actors that don't contain any overlapping primitives are
10041  * recommended to override the has_overlaps() virtual to return %FALSE
10042  * for maximum efficiency.
10043  *
10044  * Since: 1.8
10045  */
10046 void
10047 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10048                                       ClutterOffscreenRedirect redirect)
10049 {
10050   ClutterActorPrivate *priv;
10051
10052   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10053
10054   priv = self->priv;
10055
10056   if (priv->offscreen_redirect != redirect)
10057     {
10058       priv->offscreen_redirect = redirect;
10059
10060       /* Queue a redraw from the effect so that it can use its cached
10061          image if available instead of having to redraw the actual
10062          actor. If it doesn't end up using the FBO then the effect is
10063          still able to continue the paint anyway. If there is no
10064          effect then this is equivalent to queuing a full redraw */
10065       _clutter_actor_queue_redraw_full (self,
10066                                         0, /* flags */
10067                                         NULL, /* clip */
10068                                         priv->flatten_effect);
10069
10070       g_object_notify_by_pspec (G_OBJECT (self),
10071                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10072     }
10073 }
10074
10075 /**
10076  * clutter_actor_get_offscreen_redirect:
10077  * @self: a #ClutterActor
10078  *
10079  * Retrieves whether to redirect the actor to an offscreen buffer, as
10080  * set by clutter_actor_set_offscreen_redirect().
10081  *
10082  * Return value: the value of the offscreen-redirect property of the actor
10083  *
10084  * Since: 1.8
10085  */
10086 ClutterOffscreenRedirect
10087 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10088 {
10089   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10090
10091   return self->priv->offscreen_redirect;
10092 }
10093
10094 /**
10095  * clutter_actor_set_name:
10096  * @self: A #ClutterActor
10097  * @name: Textual tag to apply to actor
10098  *
10099  * Sets the given name to @self. The name can be used to identify
10100  * a #ClutterActor.
10101  */
10102 void
10103 clutter_actor_set_name (ClutterActor *self,
10104                         const gchar  *name)
10105 {
10106   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10107
10108   g_free (self->priv->name);
10109   self->priv->name = g_strdup (name);
10110
10111   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10112 }
10113
10114 /**
10115  * clutter_actor_get_name:
10116  * @self: A #ClutterActor
10117  *
10118  * Retrieves the name of @self.
10119  *
10120  * Return value: the name of the actor, or %NULL. The returned string is
10121  *   owned by the actor and should not be modified or freed.
10122  */
10123 const gchar *
10124 clutter_actor_get_name (ClutterActor *self)
10125 {
10126   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10127
10128   return self->priv->name;
10129 }
10130
10131 /**
10132  * clutter_actor_get_gid:
10133  * @self: A #ClutterActor
10134  *
10135  * Retrieves the unique id for @self.
10136  *
10137  * Return value: Globally unique value for this object instance.
10138  *
10139  * Since: 0.6
10140  *
10141  * Deprecated: 1.8: The id is not used any longer.
10142  */
10143 guint32
10144 clutter_actor_get_gid (ClutterActor *self)
10145 {
10146   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10147
10148   return self->priv->id;
10149 }
10150
10151 static inline void
10152 clutter_actor_set_depth_internal (ClutterActor *self,
10153                                   float         depth)
10154 {
10155   ClutterTransformInfo *info;
10156
10157   info = _clutter_actor_get_transform_info (self);
10158
10159   if (info->depth != depth)
10160     {
10161       /* Sets Z value - XXX 2.0: should we invert? */
10162       info->depth = depth;
10163
10164       self->priv->transform_valid = FALSE;
10165
10166       /* FIXME - remove this crap; sadly, there are still containers
10167        * in Clutter that depend on this utter brain damage
10168        */
10169       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10170
10171       clutter_actor_queue_redraw (self);
10172
10173       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10174     }
10175 }
10176
10177 /**
10178  * clutter_actor_set_depth:
10179  * @self: a #ClutterActor
10180  * @depth: Z co-ord
10181  *
10182  * Sets the Z coordinate of @self to @depth.
10183  *
10184  * The unit used by @depth is dependant on the perspective setup. See
10185  * also clutter_stage_set_perspective().
10186  */
10187 void
10188 clutter_actor_set_depth (ClutterActor *self,
10189                          gfloat        depth)
10190 {
10191   const ClutterTransformInfo *tinfo;
10192
10193   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10194
10195   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10196
10197   if (clutter_actor_get_easing_duration (self) != 0)
10198     {
10199       ClutterTransition *transition;
10200
10201       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10202       if (transition == NULL)
10203         {
10204           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10205                                                          tinfo->depth,
10206                                                          depth);
10207           clutter_timeline_start (CLUTTER_TIMELINE (transition));
10208         }
10209       else
10210         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10211
10212       clutter_actor_queue_redraw (self);
10213     }
10214   else
10215     clutter_actor_set_depth_internal (self, depth);
10216 }
10217
10218 /**
10219  * clutter_actor_get_depth:
10220  * @self: a #ClutterActor
10221  *
10222  * Retrieves the depth of @self.
10223  *
10224  * Return value: the depth of the actor
10225  */
10226 gfloat
10227 clutter_actor_get_depth (ClutterActor *self)
10228 {
10229   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10230
10231   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10232 }
10233
10234 /**
10235  * clutter_actor_set_rotation:
10236  * @self: a #ClutterActor
10237  * @axis: the axis of rotation
10238  * @angle: the angle of rotation
10239  * @x: X coordinate of the rotation center
10240  * @y: Y coordinate of the rotation center
10241  * @z: Z coordinate of the rotation center
10242  *
10243  * Sets the rotation angle of @self around the given axis.
10244  *
10245  * The rotation center coordinates used depend on the value of @axis:
10246  * <itemizedlist>
10247  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10248  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10249  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10250  * </itemizedlist>
10251  *
10252  * The rotation coordinates are relative to the anchor point of the
10253  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10254  * point is set, the upper left corner is assumed as the origin.
10255  *
10256  * Since: 0.8
10257  */
10258 void
10259 clutter_actor_set_rotation (ClutterActor      *self,
10260                             ClutterRotateAxis  axis,
10261                             gdouble            angle,
10262                             gfloat             x,
10263                             gfloat             y,
10264                             gfloat             z)
10265 {
10266   ClutterVertex v;
10267
10268   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10269
10270   v.x = x;
10271   v.y = y;
10272   v.z = z;
10273
10274   g_object_freeze_notify (G_OBJECT (self));
10275
10276   clutter_actor_set_rotation_angle (self, axis, angle);
10277   clutter_actor_set_rotation_center_internal (self, axis, &v);
10278
10279   g_object_thaw_notify (G_OBJECT (self));
10280 }
10281
10282 /**
10283  * clutter_actor_set_z_rotation_from_gravity:
10284  * @self: a #ClutterActor
10285  * @angle: the angle of rotation
10286  * @gravity: the center point of the rotation
10287  *
10288  * Sets the rotation angle of @self around the Z axis using the center
10289  * point specified as a compass point. For example to rotate such that
10290  * the center of the actor remains static you can use
10291  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10292  * will move accordingly.
10293  *
10294  * Since: 1.0
10295  */
10296 void
10297 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10298                                            gdouble         angle,
10299                                            ClutterGravity  gravity)
10300 {
10301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10302
10303   if (gravity == CLUTTER_GRAVITY_NONE)
10304     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10305   else
10306     {
10307       GObject *obj = G_OBJECT (self);
10308       ClutterTransformInfo *info;
10309
10310       info = _clutter_actor_get_transform_info (self);
10311
10312       g_object_freeze_notify (obj);
10313
10314       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10315
10316       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10317       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10318       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10319
10320       g_object_thaw_notify (obj);
10321     }
10322 }
10323
10324 /**
10325  * clutter_actor_get_rotation:
10326  * @self: a #ClutterActor
10327  * @axis: the axis of rotation
10328  * @x: (out): return value for the X coordinate of the center of rotation
10329  * @y: (out): return value for the Y coordinate of the center of rotation
10330  * @z: (out): return value for the Z coordinate of the center of rotation
10331  *
10332  * Retrieves the angle and center of rotation on the given axis,
10333  * set using clutter_actor_set_rotation().
10334  *
10335  * Return value: the angle of rotation
10336  *
10337  * Since: 0.8
10338  */
10339 gdouble
10340 clutter_actor_get_rotation (ClutterActor      *self,
10341                             ClutterRotateAxis  axis,
10342                             gfloat            *x,
10343                             gfloat            *y,
10344                             gfloat            *z)
10345 {
10346   const ClutterTransformInfo *info;
10347   const AnchorCoord *anchor_coord;
10348   gdouble retval = 0;
10349
10350   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10351
10352   info = _clutter_actor_get_transform_info_or_defaults (self);
10353
10354   switch (axis)
10355     {
10356     case CLUTTER_X_AXIS:
10357       anchor_coord = &info->rx_center;
10358       retval = info->rx_angle;
10359       break;
10360
10361     case CLUTTER_Y_AXIS:
10362       anchor_coord = &info->ry_center;
10363       retval = info->ry_angle;
10364       break;
10365
10366     case CLUTTER_Z_AXIS:
10367       anchor_coord = &info->rz_center;
10368       retval = info->rz_angle;
10369       break;
10370
10371     default:
10372       anchor_coord = NULL;
10373       retval = 0.0;
10374       break;
10375     }
10376
10377   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10378
10379   return retval;
10380 }
10381
10382 /**
10383  * clutter_actor_get_z_rotation_gravity:
10384  * @self: A #ClutterActor
10385  *
10386  * Retrieves the center for the rotation around the Z axis as a
10387  * compass direction. If the center was specified in pixels or units
10388  * this will return %CLUTTER_GRAVITY_NONE.
10389  *
10390  * Return value: the Z rotation center
10391  *
10392  * Since: 1.0
10393  */
10394 ClutterGravity
10395 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10396 {
10397   const ClutterTransformInfo *info;
10398
10399   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10400
10401   info = _clutter_actor_get_transform_info_or_defaults (self);
10402
10403   return clutter_anchor_coord_get_gravity (&info->rz_center);
10404 }
10405
10406 /**
10407  * clutter_actor_set_clip:
10408  * @self: A #ClutterActor
10409  * @xoff: X offset of the clip rectangle
10410  * @yoff: Y offset of the clip rectangle
10411  * @width: Width of the clip rectangle
10412  * @height: Height of the clip rectangle
10413  *
10414  * Sets clip area for @self. The clip area is always computed from the
10415  * upper left corner of the actor, even if the anchor point is set
10416  * otherwise.
10417  *
10418  * Since: 0.6
10419  */
10420 void
10421 clutter_actor_set_clip (ClutterActor *self,
10422                         gfloat        xoff,
10423                         gfloat        yoff,
10424                         gfloat        width,
10425                         gfloat        height)
10426 {
10427   ClutterActorPrivate *priv;
10428
10429   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10430
10431   priv = self->priv;
10432
10433   if (priv->has_clip &&
10434       priv->clip.x == xoff &&
10435       priv->clip.y == yoff &&
10436       priv->clip.width == width &&
10437       priv->clip.height == height)
10438     return;
10439
10440   priv->clip.x = xoff;
10441   priv->clip.y = yoff;
10442   priv->clip.width = width;
10443   priv->clip.height = height;
10444
10445   priv->has_clip = TRUE;
10446
10447   clutter_actor_queue_redraw (self);
10448
10449   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10450   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10451 }
10452
10453 /**
10454  * clutter_actor_remove_clip:
10455  * @self: A #ClutterActor
10456  *
10457  * Removes clip area from @self.
10458  */
10459 void
10460 clutter_actor_remove_clip (ClutterActor *self)
10461 {
10462   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10463
10464   if (!self->priv->has_clip)
10465     return;
10466
10467   self->priv->has_clip = FALSE;
10468
10469   clutter_actor_queue_redraw (self);
10470
10471   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10472 }
10473
10474 /**
10475  * clutter_actor_has_clip:
10476  * @self: a #ClutterActor
10477  *
10478  * Determines whether the actor has a clip area set or not.
10479  *
10480  * Return value: %TRUE if the actor has a clip area set.
10481  *
10482  * Since: 0.1.1
10483  */
10484 gboolean
10485 clutter_actor_has_clip (ClutterActor *self)
10486 {
10487   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10488
10489   return self->priv->has_clip;
10490 }
10491
10492 /**
10493  * clutter_actor_get_clip:
10494  * @self: a #ClutterActor
10495  * @xoff: (out) (allow-none): return location for the X offset of
10496  *   the clip rectangle, or %NULL
10497  * @yoff: (out) (allow-none): return location for the Y offset of
10498  *   the clip rectangle, or %NULL
10499  * @width: (out) (allow-none): return location for the width of
10500  *   the clip rectangle, or %NULL
10501  * @height: (out) (allow-none): return location for the height of
10502  *   the clip rectangle, or %NULL
10503  *
10504  * Gets the clip area for @self, if any is set
10505  *
10506  * Since: 0.6
10507  */
10508 void
10509 clutter_actor_get_clip (ClutterActor *self,
10510                         gfloat       *xoff,
10511                         gfloat       *yoff,
10512                         gfloat       *width,
10513                         gfloat       *height)
10514 {
10515   ClutterActorPrivate *priv;
10516
10517   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10518
10519   priv = self->priv;
10520
10521   if (!priv->has_clip)
10522     return;
10523
10524   if (xoff != NULL)
10525     *xoff = priv->clip.x;
10526
10527   if (yoff != NULL)
10528     *yoff = priv->clip.y;
10529
10530   if (width != NULL)
10531     *width = priv->clip.width;
10532
10533   if (height != NULL)
10534     *height = priv->clip.height;
10535 }
10536
10537 /**
10538  * clutter_actor_get_children:
10539  * @self: a #ClutterActor
10540  *
10541  * Retrieves the list of children of @self.
10542  *
10543  * Return value: (transfer container) (element-type ClutterActor): A newly
10544  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10545  *   done.
10546  *
10547  * Since: 1.10
10548  */
10549 GList *
10550 clutter_actor_get_children (ClutterActor *self)
10551 {
10552   ClutterActor *iter;
10553   GList *res;
10554
10555   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10556
10557   /* we walk the list backward so that we can use prepend(),
10558    * which is O(1)
10559    */
10560   for (iter = self->priv->last_child, res = NULL;
10561        iter != NULL;
10562        iter = iter->priv->prev_sibling)
10563     {
10564       res = g_list_prepend (res, iter);
10565     }
10566
10567   return res;
10568 }
10569
10570 /*< private >
10571  * insert_child_at_depth:
10572  * @self: a #ClutterActor
10573  * @child: a #ClutterActor
10574  *
10575  * Inserts @child inside the list of children held by @self, using
10576  * the depth as the insertion criteria.
10577  *
10578  * This sadly makes the insertion not O(1), but we can keep the
10579  * list sorted so that the painters algorithm we use for painting
10580  * the children will work correctly.
10581  */
10582 static void
10583 insert_child_at_depth (ClutterActor *self,
10584                        ClutterActor *child,
10585                        gpointer      dummy G_GNUC_UNUSED)
10586 {
10587   ClutterActor *iter;
10588   float child_depth;
10589
10590   child->priv->parent = self;
10591
10592   child_depth =
10593     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10594
10595   /* special-case the first child */
10596   if (self->priv->n_children == 0)
10597     {
10598       self->priv->first_child = child;
10599       self->priv->last_child = child;
10600
10601       child->priv->next_sibling = NULL;
10602       child->priv->prev_sibling = NULL;
10603
10604       return;
10605     }
10606
10607   /* Find the right place to insert the child so that it will still be
10608      sorted and the child will be after all of the actors at the same
10609      dept */
10610   for (iter = self->priv->first_child;
10611        iter != NULL;
10612        iter = iter->priv->next_sibling)
10613     {
10614       float iter_depth;
10615
10616       iter_depth =
10617         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10618
10619       if (iter_depth > child_depth)
10620         break;
10621     }
10622
10623   if (iter != NULL)
10624     {
10625       ClutterActor *tmp = iter->priv->prev_sibling;
10626
10627       if (tmp != NULL)
10628         tmp->priv->next_sibling = child;
10629
10630       /* Insert the node before the found one */
10631       child->priv->prev_sibling = iter->priv->prev_sibling;
10632       child->priv->next_sibling = iter;
10633       iter->priv->prev_sibling = child;
10634     }
10635   else
10636     {
10637       ClutterActor *tmp = self->priv->last_child;
10638
10639       if (tmp != NULL)
10640         tmp->priv->next_sibling = child;
10641
10642       /* insert the node at the end of the list */
10643       child->priv->prev_sibling = self->priv->last_child;
10644       child->priv->next_sibling = NULL;
10645     }
10646
10647   if (child->priv->prev_sibling == NULL)
10648     self->priv->first_child = child;
10649
10650   if (child->priv->next_sibling == NULL)
10651     self->priv->last_child = child;
10652 }
10653
10654 static void
10655 insert_child_at_index (ClutterActor *self,
10656                        ClutterActor *child,
10657                        gpointer      data_)
10658 {
10659   gint index_ = GPOINTER_TO_INT (data_);
10660
10661   child->priv->parent = self;
10662
10663   if (index_ == 0)
10664     {
10665       ClutterActor *tmp = self->priv->first_child;
10666
10667       if (tmp != NULL)
10668         tmp->priv->prev_sibling = child;
10669
10670       child->priv->prev_sibling = NULL;
10671       child->priv->next_sibling = tmp;
10672     }
10673   else if (index_ < 0 || index_ >= self->priv->n_children)
10674     {
10675       ClutterActor *tmp = self->priv->last_child;
10676
10677       if (tmp != NULL)
10678         tmp->priv->next_sibling = child;
10679
10680       child->priv->prev_sibling = tmp;
10681       child->priv->next_sibling = NULL;
10682     }
10683   else
10684     {
10685       ClutterActor *iter;
10686       int i;
10687
10688       for (iter = self->priv->first_child, i = 0;
10689            iter != NULL;
10690            iter = iter->priv->next_sibling, i += 1)
10691         {
10692           if (index_ == i)
10693             {
10694               ClutterActor *tmp = iter->priv->prev_sibling;
10695
10696               child->priv->prev_sibling = tmp;
10697               child->priv->next_sibling = iter;
10698
10699               iter->priv->prev_sibling = child;
10700
10701               if (tmp != NULL)
10702                 tmp->priv->next_sibling = child;
10703
10704               break;
10705             }
10706         }
10707     }
10708
10709   if (child->priv->prev_sibling == NULL)
10710     self->priv->first_child = child;
10711
10712   if (child->priv->next_sibling == NULL)
10713     self->priv->last_child = child;
10714 }
10715
10716 static void
10717 insert_child_above (ClutterActor *self,
10718                     ClutterActor *child,
10719                     gpointer      data)
10720 {
10721   ClutterActor *sibling = data;
10722
10723   child->priv->parent = self;
10724
10725   if (sibling == NULL)
10726     sibling = self->priv->last_child;
10727
10728   child->priv->prev_sibling = sibling;
10729
10730   if (sibling != NULL)
10731     {
10732       ClutterActor *tmp = sibling->priv->next_sibling;
10733
10734       child->priv->next_sibling = tmp;
10735
10736       if (tmp != NULL)
10737         tmp->priv->prev_sibling = child;
10738
10739       sibling->priv->next_sibling = child;
10740     }
10741   else
10742     child->priv->next_sibling = NULL;
10743
10744   if (child->priv->prev_sibling == NULL)
10745     self->priv->first_child = child;
10746
10747   if (child->priv->next_sibling == NULL)
10748     self->priv->last_child = child;
10749 }
10750
10751 static void
10752 insert_child_below (ClutterActor *self,
10753                     ClutterActor *child,
10754                     gpointer      data)
10755 {
10756   ClutterActor *sibling = data;
10757
10758   child->priv->parent = self;
10759
10760   if (sibling == NULL)
10761     sibling = self->priv->first_child;
10762
10763   child->priv->next_sibling = sibling;
10764
10765   if (sibling != NULL)
10766     {
10767       ClutterActor *tmp = sibling->priv->prev_sibling;
10768
10769       child->priv->prev_sibling = tmp;
10770
10771       if (tmp != NULL)
10772         tmp->priv->next_sibling = child;
10773
10774       sibling->priv->prev_sibling = child;
10775     }
10776   else
10777     child->priv->prev_sibling = NULL;
10778
10779   if (child->priv->prev_sibling == NULL)
10780     self->priv->first_child = child;
10781
10782   if (child->priv->next_sibling == NULL)
10783     self->priv->last_child = child;
10784 }
10785
10786 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10787                                            ClutterActor *child,
10788                                            gpointer      data);
10789
10790 typedef enum {
10791   ADD_CHILD_CREATE_META       = 1 << 0,
10792   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10793   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10794   ADD_CHILD_CHECK_STATE       = 1 << 3,
10795   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10796
10797   /* default flags for public API */
10798   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10799                                ADD_CHILD_EMIT_PARENT_SET |
10800                                ADD_CHILD_EMIT_ACTOR_ADDED |
10801                                ADD_CHILD_CHECK_STATE |
10802                                ADD_CHILD_NOTIFY_FIRST_LAST,
10803
10804   /* flags for legacy/deprecated API */
10805   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10806                                ADD_CHILD_CHECK_STATE |
10807                                ADD_CHILD_NOTIFY_FIRST_LAST
10808 } ClutterActorAddChildFlags;
10809
10810 /*< private >
10811  * clutter_actor_add_child_internal:
10812  * @self: a #ClutterActor
10813  * @child: a #ClutterActor
10814  * @flags: control flags for actions
10815  * @add_func: delegate function
10816  * @data: (closure): data to pass to @add_func
10817  *
10818  * Adds @child to the list of children of @self.
10819  *
10820  * The actual insertion inside the list is delegated to @add_func: this
10821  * function will just set up the state, perform basic checks, and emit
10822  * signals.
10823  *
10824  * The @flags argument is used to perform additional operations.
10825  */
10826 static inline void
10827 clutter_actor_add_child_internal (ClutterActor              *self,
10828                                   ClutterActor              *child,
10829                                   ClutterActorAddChildFlags  flags,
10830                                   ClutterActorAddChildFunc   add_func,
10831                                   gpointer                   data)
10832 {
10833   ClutterTextDirection text_dir;
10834   gboolean create_meta;
10835   gboolean emit_parent_set, emit_actor_added;
10836   gboolean check_state;
10837   gboolean notify_first_last;
10838   ClutterActor *old_first_child, *old_last_child;
10839
10840   if (child->priv->parent != NULL)
10841     {
10842       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10843                  "use clutter_actor_remove_child() first.",
10844                  _clutter_actor_get_debug_name (child),
10845                  _clutter_actor_get_debug_name (child->priv->parent));
10846       return;
10847     }
10848
10849   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10850     {
10851       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10852                  "a child of another actor.",
10853                  _clutter_actor_get_debug_name (child));
10854       return;
10855     }
10856
10857 #if 0
10858   /* XXX - this check disallows calling methods that change the stacking
10859    * order within the destruction sequence, by triggering a critical
10860    * warning first, and leaving the actor in an undefined state, which
10861    * then ends up being caught by an assertion.
10862    *
10863    * the reproducible sequence is:
10864    *
10865    *   - actor gets destroyed;
10866    *   - another actor, linked to the first, will try to change the
10867    *     stacking order of the first actor;
10868    *   - changing the stacking order is a composite operation composed
10869    *     by the following steps:
10870    *     1. ref() the child;
10871    *     2. remove_child_internal(), which removes the reference;
10872    *     3. add_child_internal(), which adds a reference;
10873    *   - the state of the actor is not changed between (2) and (3), as
10874    *     it could be an expensive recomputation;
10875    *   - if (3) bails out, then the actor is in an undefined state, but
10876    *     still alive;
10877    *   - the destruction sequence terminates, but the actor is unparented
10878    *     while its state indicates being parented instead.
10879    *   - assertion failure.
10880    *
10881    * the obvious fix would be to decompose each set_child_*_sibling()
10882    * method into proper remove_child()/add_child(), with state validation;
10883    * this may cause excessive work, though, and trigger a cascade of other
10884    * bugs in code that assumes that a change in the stacking order is an
10885    * atomic operation.
10886    *
10887    * another potential fix is to just remove this check here, and let
10888    * code doing stacking order changes inside the destruction sequence
10889    * of an actor continue doing the work.
10890    *
10891    * the third fix is to silently bail out early from every
10892    * set_child_*_sibling() and set_child_at_index() method, and avoid
10893    * doing work.
10894    *
10895    * I have a preference for the second solution, since it involves the
10896    * least amount of work, and the least amount of code duplication.
10897    *
10898    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10899    */
10900   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10901     {
10902       g_warning ("The actor '%s' is currently being destroyed, and "
10903                  "cannot be added as a child of another actor.",
10904                  _clutter_actor_get_debug_name (child));
10905       return;
10906     }
10907 #endif
10908
10909   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10910   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10911   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10912   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10913   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10914
10915   old_first_child = self->priv->first_child;
10916   old_last_child = self->priv->last_child;
10917
10918   g_object_freeze_notify (G_OBJECT (self));
10919
10920   if (create_meta)
10921     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10922
10923   g_object_ref_sink (child);
10924   child->priv->parent = NULL;
10925   child->priv->next_sibling = NULL;
10926   child->priv->prev_sibling = NULL;
10927
10928   /* delegate the actual insertion */
10929   add_func (self, child, data);
10930
10931   g_assert (child->priv->parent == self);
10932
10933   self->priv->n_children += 1;
10934
10935   self->priv->age += 1;
10936
10937   /* if push_internal() has been called then we automatically set
10938    * the flag on the actor
10939    */
10940   if (self->priv->internal_child)
10941     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10942
10943   /* clutter_actor_reparent() will emit ::parent-set for us */
10944   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10945     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10946
10947   if (check_state)
10948     {
10949       /* If parent is mapped or realized, we need to also be mapped or
10950        * realized once we're inside the parent.
10951        */
10952       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10953
10954       /* propagate the parent's text direction to the child */
10955       text_dir = clutter_actor_get_text_direction (self);
10956       clutter_actor_set_text_direction (child, text_dir);
10957     }
10958
10959   if (child->priv->show_on_set_parent)
10960     clutter_actor_show (child);
10961
10962   if (CLUTTER_ACTOR_IS_MAPPED (child))
10963     clutter_actor_queue_redraw (child);
10964
10965   /* maintain the invariant that if an actor needs layout,
10966    * its parents do as well
10967    */
10968   if (child->priv->needs_width_request ||
10969       child->priv->needs_height_request ||
10970       child->priv->needs_allocation)
10971     {
10972       /* we work around the short-circuiting we do
10973        * in clutter_actor_queue_relayout() since we
10974        * want to force a relayout
10975        */
10976       child->priv->needs_width_request = TRUE;
10977       child->priv->needs_height_request = TRUE;
10978       child->priv->needs_allocation = TRUE;
10979
10980       clutter_actor_queue_relayout (child->priv->parent);
10981     }
10982
10983   if (emit_actor_added)
10984     g_signal_emit_by_name (self, "actor-added", child);
10985
10986   if (notify_first_last)
10987     {
10988       if (old_first_child != self->priv->first_child)
10989         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10990
10991       if (old_last_child != self->priv->last_child)
10992         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10993     }
10994
10995   g_object_thaw_notify (G_OBJECT (self));
10996 }
10997
10998 /**
10999  * clutter_actor_add_child:
11000  * @self: a #ClutterActor
11001  * @child: a #ClutterActor
11002  *
11003  * Adds @child to the children of @self.
11004  *
11005  * This function will acquire a reference on @child that will only
11006  * be released when calling clutter_actor_remove_child().
11007  *
11008  * This function will take into consideration the #ClutterActor:depth
11009  * of @child, and will keep the list of children sorted.
11010  *
11011  * This function will emit the #ClutterContainer::actor-added signal
11012  * on @self.
11013  *
11014  * Since: 1.10
11015  */
11016 void
11017 clutter_actor_add_child (ClutterActor *self,
11018                          ClutterActor *child)
11019 {
11020   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11021   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11022   g_return_if_fail (self != child);
11023   g_return_if_fail (child->priv->parent == NULL);
11024
11025   clutter_actor_add_child_internal (self, child,
11026                                     ADD_CHILD_DEFAULT_FLAGS,
11027                                     insert_child_at_depth,
11028                                     NULL);
11029 }
11030
11031 /**
11032  * clutter_actor_insert_child_at_index:
11033  * @self: a #ClutterActor
11034  * @child: a #ClutterActor
11035  * @index_: the index
11036  *
11037  * Inserts @child into the list of children of @self, using the
11038  * given @index_. If @index_ is greater than the number of children
11039  * in @self, or is less than 0, then the new child is added at the end.
11040  *
11041  * This function will acquire a reference on @child that will only
11042  * be released when calling clutter_actor_remove_child().
11043  *
11044  * This function will not take into consideration the #ClutterActor:depth
11045  * of @child.
11046  *
11047  * This function will emit the #ClutterContainer::actor-added signal
11048  * on @self.
11049  *
11050  * Since: 1.10
11051  */
11052 void
11053 clutter_actor_insert_child_at_index (ClutterActor *self,
11054                                      ClutterActor *child,
11055                                      gint          index_)
11056 {
11057   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11058   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11059   g_return_if_fail (self != child);
11060   g_return_if_fail (child->priv->parent == NULL);
11061
11062   clutter_actor_add_child_internal (self, child,
11063                                     ADD_CHILD_DEFAULT_FLAGS,
11064                                     insert_child_at_index,
11065                                     GINT_TO_POINTER (index_));
11066 }
11067
11068 /**
11069  * clutter_actor_insert_child_above:
11070  * @self: a #ClutterActor
11071  * @child: a #ClutterActor
11072  * @sibling: (allow-none): a child of @self, or %NULL
11073  *
11074  * Inserts @child into the list of children of @self, above another
11075  * child of @self or, if @sibling is %NULL, above all the children
11076  * of @self.
11077  *
11078  * This function will acquire a reference on @child that will only
11079  * be released when calling clutter_actor_remove_child().
11080  *
11081  * This function will not take into consideration the #ClutterActor:depth
11082  * of @child.
11083  *
11084  * This function will emit the #ClutterContainer::actor-added signal
11085  * on @self.
11086  *
11087  * Since: 1.10
11088  */
11089 void
11090 clutter_actor_insert_child_above (ClutterActor *self,
11091                                   ClutterActor *child,
11092                                   ClutterActor *sibling)
11093 {
11094   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11095   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11096   g_return_if_fail (self != child);
11097   g_return_if_fail (child != sibling);
11098   g_return_if_fail (child->priv->parent == NULL);
11099   g_return_if_fail (sibling == NULL ||
11100                     (CLUTTER_IS_ACTOR (sibling) &&
11101                      sibling->priv->parent == self));
11102
11103   clutter_actor_add_child_internal (self, child,
11104                                     ADD_CHILD_DEFAULT_FLAGS,
11105                                     insert_child_above,
11106                                     sibling);
11107 }
11108
11109 /**
11110  * clutter_actor_insert_child_below:
11111  * @self: a #ClutterActor
11112  * @child: a #ClutterActor
11113  * @sibling: (allow-none): a child of @self, or %NULL
11114  *
11115  * Inserts @child into the list of children of @self, below another
11116  * child of @self or, if @sibling is %NULL, below all the children
11117  * of @self.
11118  *
11119  * This function will acquire a reference on @child that will only
11120  * be released when calling clutter_actor_remove_child().
11121  *
11122  * This function will not take into consideration the #ClutterActor:depth
11123  * of @child.
11124  *
11125  * This function will emit the #ClutterContainer::actor-added signal
11126  * on @self.
11127  *
11128  * Since: 1.10
11129  */
11130 void
11131 clutter_actor_insert_child_below (ClutterActor *self,
11132                                   ClutterActor *child,
11133                                   ClutterActor *sibling)
11134 {
11135   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11136   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11137   g_return_if_fail (self != child);
11138   g_return_if_fail (child != sibling);
11139   g_return_if_fail (child->priv->parent == NULL);
11140   g_return_if_fail (sibling == NULL ||
11141                     (CLUTTER_IS_ACTOR (sibling) &&
11142                      sibling->priv->parent == self));
11143
11144   clutter_actor_add_child_internal (self, child,
11145                                     ADD_CHILD_DEFAULT_FLAGS,
11146                                     insert_child_below,
11147                                     sibling);
11148 }
11149
11150 /**
11151  * clutter_actor_set_parent:
11152  * @self: A #ClutterActor
11153  * @parent: A new #ClutterActor parent
11154  *
11155  * Sets the parent of @self to @parent.
11156  *
11157  * This function will result in @parent acquiring a reference on @self,
11158  * eventually by sinking its floating reference first. The reference
11159  * will be released by clutter_actor_unparent().
11160  *
11161  * This function should only be called by legacy #ClutterActor<!-- -->s
11162  * implementing the #ClutterContainer interface.
11163  *
11164  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11165  */
11166 void
11167 clutter_actor_set_parent (ClutterActor *self,
11168                           ClutterActor *parent)
11169 {
11170   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11171   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11172   g_return_if_fail (self != parent);
11173   g_return_if_fail (self->priv->parent == NULL);
11174
11175   /* as this function will be called inside ClutterContainer::add
11176    * implementations or when building up a composite actor, we have
11177    * to preserve the old behaviour, and not create child meta or
11178    * emit the ::actor-added signal, to avoid recursion or double
11179    * emissions
11180    */
11181   clutter_actor_add_child_internal (parent, self,
11182                                     ADD_CHILD_LEGACY_FLAGS,
11183                                     insert_child_at_depth,
11184                                     NULL);
11185 }
11186
11187 /**
11188  * clutter_actor_get_parent:
11189  * @self: A #ClutterActor
11190  *
11191  * Retrieves the parent of @self.
11192  *
11193  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11194  *  if no parent is set
11195  */
11196 ClutterActor *
11197 clutter_actor_get_parent (ClutterActor *self)
11198 {
11199   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11200
11201   return self->priv->parent;
11202 }
11203
11204 /**
11205  * clutter_actor_get_paint_visibility:
11206  * @self: A #ClutterActor
11207  *
11208  * Retrieves the 'paint' visibility of an actor recursively checking for non
11209  * visible parents.
11210  *
11211  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11212  *
11213  * Return Value: %TRUE if the actor is visibile and will be painted.
11214  *
11215  * Since: 0.8.4
11216  */
11217 gboolean
11218 clutter_actor_get_paint_visibility (ClutterActor *actor)
11219 {
11220   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11221
11222   return CLUTTER_ACTOR_IS_MAPPED (actor);
11223 }
11224
11225 /**
11226  * clutter_actor_remove_child:
11227  * @self: a #ClutterActor
11228  * @child: a #ClutterActor
11229  *
11230  * Removes @child from the children of @self.
11231  *
11232  * This function will release the reference added by
11233  * clutter_actor_add_child(), so if you want to keep using @child
11234  * you will have to acquire a referenced on it before calling this
11235  * function.
11236  *
11237  * This function will emit the #ClutterContainer::actor-removed
11238  * signal on @self.
11239  *
11240  * Since: 1.10
11241  */
11242 void
11243 clutter_actor_remove_child (ClutterActor *self,
11244                             ClutterActor *child)
11245 {
11246   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11247   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11248   g_return_if_fail (self != child);
11249   g_return_if_fail (child->priv->parent != NULL);
11250   g_return_if_fail (child->priv->parent == self);
11251
11252   clutter_actor_remove_child_internal (self, child,
11253                                        REMOVE_CHILD_DEFAULT_FLAGS);
11254 }
11255
11256 /**
11257  * clutter_actor_remove_all_children:
11258  * @self: a #ClutterActor
11259  *
11260  * Removes all children of @self.
11261  *
11262  * This function releases the reference added by inserting a child actor
11263  * in the list of children of @self.
11264  *
11265  * If the reference count of a child drops to zero, the child will be
11266  * destroyed. If you want to ensure the destruction of all the children
11267  * of @self, use clutter_actor_destroy_all_children().
11268  *
11269  * Since: 1.10
11270  */
11271 void
11272 clutter_actor_remove_all_children (ClutterActor *self)
11273 {
11274   ClutterActorIter iter;
11275
11276   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11277
11278   if (self->priv->n_children == 0)
11279     return;
11280
11281   g_object_freeze_notify (G_OBJECT (self));
11282
11283   clutter_actor_iter_init (&iter, self);
11284   while (clutter_actor_iter_next (&iter, NULL))
11285     clutter_actor_iter_remove (&iter);
11286
11287   g_object_thaw_notify (G_OBJECT (self));
11288
11289   /* sanity check */
11290   g_assert (self->priv->first_child == NULL);
11291   g_assert (self->priv->last_child == NULL);
11292   g_assert (self->priv->n_children == 0);
11293 }
11294
11295 /**
11296  * clutter_actor_destroy_all_children:
11297  * @self: a #ClutterActor
11298  *
11299  * Destroys all children of @self.
11300  *
11301  * This function releases the reference added by inserting a child
11302  * actor in the list of children of @self, and ensures that the
11303  * #ClutterActor::destroy signal is emitted on each child of the
11304  * actor.
11305  *
11306  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11307  * when its reference count drops to 0; the default handler of the
11308  * #ClutterActor::destroy signal will destroy all the children of an
11309  * actor. This function ensures that all children are destroyed, instead
11310  * of just removed from @self, unlike clutter_actor_remove_all_children()
11311  * which will merely release the reference and remove each child.
11312  *
11313  * Unless you acquired an additional reference on each child of @self
11314  * prior to calling clutter_actor_remove_all_children() and want to reuse
11315  * the actors, you should use clutter_actor_destroy_all_children() in
11316  * order to make sure that children are destroyed and signal handlers
11317  * are disconnected even in cases where circular references prevent this
11318  * from automatically happening through reference counting alone.
11319  *
11320  * Since: 1.10
11321  */
11322 void
11323 clutter_actor_destroy_all_children (ClutterActor *self)
11324 {
11325   ClutterActorIter iter;
11326
11327   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11328
11329   if (self->priv->n_children == 0)
11330     return;
11331
11332   g_object_freeze_notify (G_OBJECT (self));
11333
11334   clutter_actor_iter_init (&iter, self);
11335   while (clutter_actor_iter_next (&iter, NULL))
11336     clutter_actor_iter_destroy (&iter);
11337
11338   g_object_thaw_notify (G_OBJECT (self));
11339
11340   /* sanity check */
11341   g_assert (self->priv->first_child == NULL);
11342   g_assert (self->priv->last_child == NULL);
11343   g_assert (self->priv->n_children == 0);
11344 }
11345
11346 typedef struct _InsertBetweenData {
11347   ClutterActor *prev_sibling;
11348   ClutterActor *next_sibling;
11349 } InsertBetweenData;
11350
11351 static void
11352 insert_child_between (ClutterActor *self,
11353                       ClutterActor *child,
11354                       gpointer      data_)
11355 {
11356   InsertBetweenData *data = data_;
11357   ClutterActor *prev_sibling = data->prev_sibling;
11358   ClutterActor *next_sibling = data->next_sibling;
11359
11360   child->priv->parent = self;
11361   child->priv->prev_sibling = prev_sibling;
11362   child->priv->next_sibling = next_sibling;
11363
11364   if (prev_sibling != NULL)
11365     prev_sibling->priv->next_sibling = child;
11366
11367   if (next_sibling != NULL)
11368     next_sibling->priv->prev_sibling = child;
11369
11370   if (child->priv->prev_sibling == NULL)
11371     self->priv->first_child = child;
11372
11373   if (child->priv->next_sibling == NULL)
11374     self->priv->last_child = child;
11375 }
11376
11377 /**
11378  * clutter_actor_replace_child:
11379  * @self: a #ClutterActor
11380  * @old_child: the child of @self to replace
11381  * @new_child: the #ClutterActor to replace @old_child
11382  *
11383  * Replaces @old_child with @new_child in the list of children of @self.
11384  *
11385  * Since: 1.10
11386  */
11387 void
11388 clutter_actor_replace_child (ClutterActor *self,
11389                              ClutterActor *old_child,
11390                              ClutterActor *new_child)
11391 {
11392   ClutterActor *prev_sibling, *next_sibling;
11393   InsertBetweenData clos;
11394
11395   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11396   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11397   g_return_if_fail (old_child->priv->parent == self);
11398   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11399   g_return_if_fail (old_child != new_child);
11400   g_return_if_fail (new_child != self);
11401   g_return_if_fail (new_child->priv->parent == NULL);
11402
11403   prev_sibling = old_child->priv->prev_sibling;
11404   next_sibling = old_child->priv->next_sibling;
11405   clutter_actor_remove_child_internal (self, old_child,
11406                                        REMOVE_CHILD_DEFAULT_FLAGS);
11407
11408   clos.prev_sibling = prev_sibling;
11409   clos.next_sibling = next_sibling;
11410   clutter_actor_add_child_internal (self, new_child,
11411                                     ADD_CHILD_DEFAULT_FLAGS,
11412                                     insert_child_between,
11413                                     &clos);
11414 }
11415
11416 /**
11417  * clutter_actor_unparent:
11418  * @self: a #ClutterActor
11419  *
11420  * Removes the parent of @self.
11421  *
11422  * This will cause the parent of @self to release the reference
11423  * acquired when calling clutter_actor_set_parent(), so if you
11424  * want to keep @self you will have to acquire a reference of
11425  * your own, through g_object_ref().
11426  *
11427  * This function should only be called by legacy #ClutterActor<!-- -->s
11428  * implementing the #ClutterContainer interface.
11429  *
11430  * Since: 0.1.1
11431  *
11432  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11433  */
11434 void
11435 clutter_actor_unparent (ClutterActor *self)
11436 {
11437   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11438
11439   if (self->priv->parent == NULL)
11440     return;
11441
11442   clutter_actor_remove_child_internal (self->priv->parent, self,
11443                                        REMOVE_CHILD_LEGACY_FLAGS);
11444 }
11445
11446 /**
11447  * clutter_actor_reparent:
11448  * @self: a #ClutterActor
11449  * @new_parent: the new #ClutterActor parent
11450  *
11451  * Resets the parent actor of @self.
11452  *
11453  * This function is logically equivalent to calling clutter_actor_unparent()
11454  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11455  * ensures the child is not finalized when unparented, and emits the
11456  * #ClutterActor::parent-set signal only once.
11457  *
11458  * In reality, calling this function is less useful than it sounds, as some
11459  * application code may rely on changes in the intermediate state between
11460  * removal and addition of the actor from its old parent to the @new_parent.
11461  * Thus, it is strongly encouraged to avoid using this function in application
11462  * code.
11463  *
11464  * Since: 0.2
11465  *
11466  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11467  *   clutter_actor_add_child() instead; remember to take a reference on
11468  *   the actor being removed before calling clutter_actor_remove_child()
11469  *   to avoid the reference count dropping to zero and the actor being
11470  *   destroyed.
11471  */
11472 void
11473 clutter_actor_reparent (ClutterActor *self,
11474                         ClutterActor *new_parent)
11475 {
11476   ClutterActorPrivate *priv;
11477
11478   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11479   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11480   g_return_if_fail (self != new_parent);
11481
11482   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11483     {
11484       g_warning ("Cannot set a parent on a toplevel actor");
11485       return;
11486     }
11487
11488   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11489     {
11490       g_warning ("Cannot set a parent currently being destroyed");
11491       return;
11492     }
11493
11494   priv = self->priv;
11495
11496   if (priv->parent != new_parent)
11497     {
11498       ClutterActor *old_parent;
11499
11500       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11501
11502       old_parent = priv->parent;
11503
11504       g_object_ref (self);
11505
11506       if (old_parent != NULL)
11507         {
11508          /* go through the Container implementation if this is a regular
11509           * child and not an internal one
11510           */
11511          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11512            {
11513              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11514
11515              /* this will have to call unparent() */
11516              clutter_container_remove_actor (parent, self);
11517            }
11518          else
11519            clutter_actor_remove_child_internal (old_parent, self,
11520                                                 REMOVE_CHILD_LEGACY_FLAGS);
11521         }
11522
11523       /* Note, will call set_parent() */
11524       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11525         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11526       else
11527         clutter_actor_add_child_internal (new_parent, self,
11528                                           ADD_CHILD_LEGACY_FLAGS,
11529                                           insert_child_at_depth,
11530                                           NULL);
11531
11532       /* we emit the ::parent-set signal once */
11533       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11534
11535       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11536
11537       /* the IN_REPARENT flag suspends state updates */
11538       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11539
11540       g_object_unref (self);
11541    }
11542 }
11543
11544 /**
11545  * clutter_actor_contains:
11546  * @self: A #ClutterActor
11547  * @descendant: A #ClutterActor, possibly contained in @self
11548  *
11549  * Determines if @descendant is contained inside @self (either as an
11550  * immediate child, or as a deeper descendant). If @self and
11551  * @descendant point to the same actor then it will also return %TRUE.
11552  *
11553  * Return value: whether @descendent is contained within @self
11554  *
11555  * Since: 1.4
11556  */
11557 gboolean
11558 clutter_actor_contains (ClutterActor *self,
11559                         ClutterActor *descendant)
11560 {
11561   ClutterActor *actor;
11562
11563   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11564   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11565
11566   for (actor = descendant; actor; actor = actor->priv->parent)
11567     if (actor == self)
11568       return TRUE;
11569
11570   return FALSE;
11571 }
11572
11573 /**
11574  * clutter_actor_set_child_above_sibling:
11575  * @self: a #ClutterActor
11576  * @child: a #ClutterActor child of @self
11577  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11578  *
11579  * Sets @child to be above @sibling in the list of children of @self.
11580  *
11581  * If @sibling is %NULL, @child will be the new last child of @self.
11582  *
11583  * This function is logically equivalent to removing @child and using
11584  * clutter_actor_insert_child_above(), but it will not emit signals
11585  * or change state on @child.
11586  *
11587  * Since: 1.10
11588  */
11589 void
11590 clutter_actor_set_child_above_sibling (ClutterActor *self,
11591                                        ClutterActor *child,
11592                                        ClutterActor *sibling)
11593 {
11594   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11595   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11596   g_return_if_fail (child->priv->parent == self);
11597   g_return_if_fail (child != sibling);
11598   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11599
11600   if (sibling != NULL)
11601     g_return_if_fail (sibling->priv->parent == self);
11602
11603   /* we don't want to change the state of child, or emit signals, or
11604    * regenerate ChildMeta instances here, but we still want to follow
11605    * the correct sequence of steps encoded in remove_child() and
11606    * add_child(), so that correctness is ensured, and we only go
11607    * through one known code path.
11608    */
11609   g_object_ref (child);
11610   clutter_actor_remove_child_internal (self, child, 0);
11611   clutter_actor_add_child_internal (self, child,
11612                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11613                                     insert_child_above,
11614                                     sibling);
11615
11616   clutter_actor_queue_relayout (self);
11617 }
11618
11619 /**
11620  * clutter_actor_set_child_below_sibling:
11621  * @self: a #ClutterActor
11622  * @child: a #ClutterActor child of @self
11623  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11624  *
11625  * Sets @child to be below @sibling in the list of children of @self.
11626  *
11627  * If @sibling is %NULL, @child will be the new first child of @self.
11628  *
11629  * This function is logically equivalent to removing @self and using
11630  * clutter_actor_insert_child_below(), but it will not emit signals
11631  * or change state on @child.
11632  *
11633  * Since: 1.10
11634  */
11635 void
11636 clutter_actor_set_child_below_sibling (ClutterActor *self,
11637                                        ClutterActor *child,
11638                                        ClutterActor *sibling)
11639 {
11640   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11641   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11642   g_return_if_fail (child->priv->parent == self);
11643   g_return_if_fail (child != sibling);
11644   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11645
11646   if (sibling != NULL)
11647     g_return_if_fail (sibling->priv->parent == self);
11648
11649   /* see the comment in set_child_above_sibling() */
11650   g_object_ref (child);
11651   clutter_actor_remove_child_internal (self, child, 0);
11652   clutter_actor_add_child_internal (self, child,
11653                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11654                                     insert_child_below,
11655                                     sibling);
11656
11657   clutter_actor_queue_relayout (self);
11658 }
11659
11660 /**
11661  * clutter_actor_set_child_at_index:
11662  * @self: a #ClutterActor
11663  * @child: a #ClutterActor child of @self
11664  * @index_: the new index for @child
11665  *
11666  * Changes the index of @child in the list of children of @self.
11667  *
11668  * This function is logically equivalent to removing @child and
11669  * calling clutter_actor_insert_child_at_index(), but it will not
11670  * emit signals or change state on @child.
11671  *
11672  * Since: 1.10
11673  */
11674 void
11675 clutter_actor_set_child_at_index (ClutterActor *self,
11676                                   ClutterActor *child,
11677                                   gint          index_)
11678 {
11679   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11680   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11681   g_return_if_fail (child->priv->parent == self);
11682   g_return_if_fail (index_ <= self->priv->n_children);
11683
11684   g_object_ref (child);
11685   clutter_actor_remove_child_internal (self, child, 0);
11686   clutter_actor_add_child_internal (self, child,
11687                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11688                                     insert_child_at_index,
11689                                     GINT_TO_POINTER (index_));
11690
11691   clutter_actor_queue_relayout (self);
11692 }
11693
11694 /**
11695  * clutter_actor_raise:
11696  * @self: A #ClutterActor
11697  * @below: (allow-none): A #ClutterActor to raise above.
11698  *
11699  * Puts @self above @below.
11700  *
11701  * Both actors must have the same parent, and the parent must implement
11702  * the #ClutterContainer interface
11703  *
11704  * This function calls clutter_container_raise_child() internally.
11705  *
11706  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11707  */
11708 void
11709 clutter_actor_raise (ClutterActor *self,
11710                      ClutterActor *below)
11711 {
11712   ClutterActor *parent;
11713
11714   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11715
11716   parent = clutter_actor_get_parent (self);
11717   if (parent == NULL)
11718     {
11719       g_warning ("%s: Actor '%s' is not inside a container",
11720                  G_STRFUNC,
11721                  _clutter_actor_get_debug_name (self));
11722       return;
11723     }
11724
11725   if (below != NULL)
11726     {
11727       if (parent != clutter_actor_get_parent (below))
11728         {
11729           g_warning ("%s Actor '%s' is not in the same container as "
11730                      "actor '%s'",
11731                      G_STRFUNC,
11732                      _clutter_actor_get_debug_name (self),
11733                      _clutter_actor_get_debug_name (below));
11734           return;
11735         }
11736     }
11737
11738   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11739 }
11740
11741 /**
11742  * clutter_actor_lower:
11743  * @self: A #ClutterActor
11744  * @above: (allow-none): A #ClutterActor to lower below
11745  *
11746  * Puts @self below @above.
11747  *
11748  * Both actors must have the same parent, and the parent must implement
11749  * the #ClutterContainer interface.
11750  *
11751  * This function calls clutter_container_lower_child() internally.
11752  *
11753  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11754  */
11755 void
11756 clutter_actor_lower (ClutterActor *self,
11757                      ClutterActor *above)
11758 {
11759   ClutterActor *parent;
11760
11761   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11762
11763   parent = clutter_actor_get_parent (self);
11764   if (parent == NULL)
11765     {
11766       g_warning ("%s: Actor of type %s is not inside a container",
11767                  G_STRFUNC,
11768                  _clutter_actor_get_debug_name (self));
11769       return;
11770     }
11771
11772   if (above)
11773     {
11774       if (parent != clutter_actor_get_parent (above))
11775         {
11776           g_warning ("%s: Actor '%s' is not in the same container as "
11777                      "actor '%s'",
11778                      G_STRFUNC,
11779                      _clutter_actor_get_debug_name (self),
11780                      _clutter_actor_get_debug_name (above));
11781           return;
11782         }
11783     }
11784
11785   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11786 }
11787
11788 /**
11789  * clutter_actor_raise_top:
11790  * @self: A #ClutterActor
11791  *
11792  * Raises @self to the top.
11793  *
11794  * This function calls clutter_actor_raise() internally.
11795  *
11796  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11797  *   a %NULL sibling, instead.
11798  */
11799 void
11800 clutter_actor_raise_top (ClutterActor *self)
11801 {
11802   clutter_actor_raise (self, NULL);
11803 }
11804
11805 /**
11806  * clutter_actor_lower_bottom:
11807  * @self: A #ClutterActor
11808  *
11809  * Lowers @self to the bottom.
11810  *
11811  * This function calls clutter_actor_lower() internally.
11812  *
11813  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11814  *   a %NULL sibling, instead.
11815  */
11816 void
11817 clutter_actor_lower_bottom (ClutterActor *self)
11818 {
11819   clutter_actor_lower (self, NULL);
11820 }
11821
11822 /*
11823  * Event handling
11824  */
11825
11826 /**
11827  * clutter_actor_event:
11828  * @actor: a #ClutterActor
11829  * @event: a #ClutterEvent
11830  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11831  *
11832  * This function is used to emit an event on the main stage.
11833  * You should rarely need to use this function, except for
11834  * synthetising events.
11835  *
11836  * Return value: the return value from the signal emission: %TRUE
11837  *   if the actor handled the event, or %FALSE if the event was
11838  *   not handled
11839  *
11840  * Since: 0.6
11841  */
11842 gboolean
11843 clutter_actor_event (ClutterActor *actor,
11844                      ClutterEvent *event,
11845                      gboolean      capture)
11846 {
11847   gboolean retval = FALSE;
11848   gint signal_num = -1;
11849
11850   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11851   g_return_val_if_fail (event != NULL, FALSE);
11852
11853   g_object_ref (actor);
11854
11855   if (capture)
11856     {
11857       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11858                      event,
11859                      &retval);
11860       goto out;
11861     }
11862
11863   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11864
11865   if (!retval)
11866     {
11867       switch (event->type)
11868         {
11869         case CLUTTER_NOTHING:
11870           break;
11871         case CLUTTER_BUTTON_PRESS:
11872           signal_num = BUTTON_PRESS_EVENT;
11873           break;
11874         case CLUTTER_BUTTON_RELEASE:
11875           signal_num = BUTTON_RELEASE_EVENT;
11876           break;
11877         case CLUTTER_SCROLL:
11878           signal_num = SCROLL_EVENT;
11879           break;
11880         case CLUTTER_KEY_PRESS:
11881           signal_num = KEY_PRESS_EVENT;
11882           break;
11883         case CLUTTER_KEY_RELEASE:
11884           signal_num = KEY_RELEASE_EVENT;
11885           break;
11886         case CLUTTER_MOTION:
11887           signal_num = MOTION_EVENT;
11888           break;
11889         case CLUTTER_ENTER:
11890           signal_num = ENTER_EVENT;
11891           break;
11892         case CLUTTER_LEAVE:
11893           signal_num = LEAVE_EVENT;
11894           break;
11895         case CLUTTER_DELETE:
11896         case CLUTTER_DESTROY_NOTIFY:
11897         case CLUTTER_CLIENT_MESSAGE:
11898         default:
11899           signal_num = -1;
11900           break;
11901         }
11902
11903       if (signal_num != -1)
11904         g_signal_emit (actor, actor_signals[signal_num], 0,
11905                        event, &retval);
11906     }
11907
11908 out:
11909   g_object_unref (actor);
11910
11911   return retval;
11912 }
11913
11914 /**
11915  * clutter_actor_set_reactive:
11916  * @actor: a #ClutterActor
11917  * @reactive: whether the actor should be reactive to events
11918  *
11919  * Sets @actor as reactive. Reactive actors will receive events.
11920  *
11921  * Since: 0.6
11922  */
11923 void
11924 clutter_actor_set_reactive (ClutterActor *actor,
11925                             gboolean      reactive)
11926 {
11927   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11928
11929   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11930     return;
11931
11932   if (reactive)
11933     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11934   else
11935     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11936
11937   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11938 }
11939
11940 /**
11941  * clutter_actor_get_reactive:
11942  * @actor: a #ClutterActor
11943  *
11944  * Checks whether @actor is marked as reactive.
11945  *
11946  * Return value: %TRUE if the actor is reactive
11947  *
11948  * Since: 0.6
11949  */
11950 gboolean
11951 clutter_actor_get_reactive (ClutterActor *actor)
11952 {
11953   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11954
11955   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11956 }
11957
11958 /**
11959  * clutter_actor_get_anchor_point:
11960  * @self: a #ClutterActor
11961  * @anchor_x: (out): return location for the X coordinate of the anchor point
11962  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11963  *
11964  * Gets the current anchor point of the @actor in pixels.
11965  *
11966  * Since: 0.6
11967  */
11968 void
11969 clutter_actor_get_anchor_point (ClutterActor *self,
11970                                 gfloat       *anchor_x,
11971                                 gfloat       *anchor_y)
11972 {
11973   const ClutterTransformInfo *info;
11974
11975   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11976
11977   info = _clutter_actor_get_transform_info_or_defaults (self);
11978   clutter_anchor_coord_get_units (self, &info->anchor,
11979                                   anchor_x,
11980                                   anchor_y,
11981                                   NULL);
11982 }
11983
11984 /**
11985  * clutter_actor_set_anchor_point:
11986  * @self: a #ClutterActor
11987  * @anchor_x: X coordinate of the anchor point
11988  * @anchor_y: Y coordinate of the anchor point
11989  *
11990  * Sets an anchor point for @self. The anchor point is a point in the
11991  * coordinate space of an actor to which the actor position within its
11992  * parent is relative; the default is (0, 0), i.e. the top-left corner
11993  * of the actor.
11994  *
11995  * Since: 0.6
11996  */
11997 void
11998 clutter_actor_set_anchor_point (ClutterActor *self,
11999                                 gfloat        anchor_x,
12000                                 gfloat        anchor_y)
12001 {
12002   ClutterTransformInfo *info;
12003   ClutterActorPrivate *priv;
12004   gboolean changed = FALSE;
12005   gfloat old_anchor_x, old_anchor_y;
12006   GObject *obj;
12007
12008   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12009
12010   obj = G_OBJECT (self);
12011   priv = self->priv;
12012   info = _clutter_actor_get_transform_info (self);
12013
12014   g_object_freeze_notify (obj);
12015
12016   clutter_anchor_coord_get_units (self, &info->anchor,
12017                                   &old_anchor_x,
12018                                   &old_anchor_y,
12019                                   NULL);
12020
12021   if (info->anchor.is_fractional)
12022     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12023
12024   if (old_anchor_x != anchor_x)
12025     {
12026       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12027       changed = TRUE;
12028     }
12029
12030   if (old_anchor_y != anchor_y)
12031     {
12032       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12033       changed = TRUE;
12034     }
12035
12036   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12037
12038   if (changed)
12039     {
12040       priv->transform_valid = FALSE;
12041       clutter_actor_queue_redraw (self);
12042     }
12043
12044   g_object_thaw_notify (obj);
12045 }
12046
12047 /**
12048  * clutter_actor_get_anchor_point_gravity:
12049  * @self: a #ClutterActor
12050  *
12051  * Retrieves the anchor position expressed as a #ClutterGravity. If
12052  * the anchor point was specified using pixels or units this will
12053  * return %CLUTTER_GRAVITY_NONE.
12054  *
12055  * Return value: the #ClutterGravity used by the anchor point
12056  *
12057  * Since: 1.0
12058  */
12059 ClutterGravity
12060 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12061 {
12062   const ClutterTransformInfo *info;
12063
12064   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12065
12066   info = _clutter_actor_get_transform_info_or_defaults (self);
12067
12068   return clutter_anchor_coord_get_gravity (&info->anchor);
12069 }
12070
12071 /**
12072  * clutter_actor_move_anchor_point:
12073  * @self: a #ClutterActor
12074  * @anchor_x: X coordinate of the anchor point
12075  * @anchor_y: Y coordinate of the anchor point
12076  *
12077  * Sets an anchor point for the actor, and adjusts the actor postion so that
12078  * the relative position of the actor toward its parent remains the same.
12079  *
12080  * Since: 0.6
12081  */
12082 void
12083 clutter_actor_move_anchor_point (ClutterActor *self,
12084                                  gfloat        anchor_x,
12085                                  gfloat        anchor_y)
12086 {
12087   gfloat old_anchor_x, old_anchor_y;
12088   const ClutterTransformInfo *info;
12089
12090   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12091
12092   info = _clutter_actor_get_transform_info (self);
12093   clutter_anchor_coord_get_units (self, &info->anchor,
12094                                   &old_anchor_x,
12095                                   &old_anchor_y,
12096                                   NULL);
12097
12098   g_object_freeze_notify (G_OBJECT (self));
12099
12100   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12101
12102   if (self->priv->position_set)
12103     clutter_actor_move_by (self,
12104                            anchor_x - old_anchor_x,
12105                            anchor_y - old_anchor_y);
12106
12107   g_object_thaw_notify (G_OBJECT (self));
12108 }
12109
12110 /**
12111  * clutter_actor_move_anchor_point_from_gravity:
12112  * @self: a #ClutterActor
12113  * @gravity: #ClutterGravity.
12114  *
12115  * Sets an anchor point on the actor based on the given gravity, adjusting the
12116  * actor postion so that its relative position within its parent remains
12117  * unchanged.
12118  *
12119  * Since version 1.0 the anchor point will be stored as a gravity so
12120  * that if the actor changes size then the anchor point will move. For
12121  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12122  * and later double the size of the actor, the anchor point will move
12123  * to the bottom right.
12124  *
12125  * Since: 0.6
12126  */
12127 void
12128 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12129                                               ClutterGravity  gravity)
12130 {
12131   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12132   const ClutterTransformInfo *info;
12133   ClutterActorPrivate *priv;
12134
12135   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12136
12137   priv = self->priv;
12138   info = _clutter_actor_get_transform_info (self);
12139
12140   g_object_freeze_notify (G_OBJECT (self));
12141
12142   clutter_anchor_coord_get_units (self, &info->anchor,
12143                                   &old_anchor_x,
12144                                   &old_anchor_y,
12145                                   NULL);
12146   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12147   clutter_anchor_coord_get_units (self, &info->anchor,
12148                                   &new_anchor_x,
12149                                   &new_anchor_y,
12150                                   NULL);
12151
12152   if (priv->position_set)
12153     clutter_actor_move_by (self,
12154                            new_anchor_x - old_anchor_x,
12155                            new_anchor_y - old_anchor_y);
12156
12157   g_object_thaw_notify (G_OBJECT (self));
12158 }
12159
12160 /**
12161  * clutter_actor_set_anchor_point_from_gravity:
12162  * @self: a #ClutterActor
12163  * @gravity: #ClutterGravity.
12164  *
12165  * Sets an anchor point on the actor, based on the given gravity (this is a
12166  * convenience function wrapping clutter_actor_set_anchor_point()).
12167  *
12168  * Since version 1.0 the anchor point will be stored as a gravity so
12169  * that if the actor changes size then the anchor point will move. For
12170  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12171  * and later double the size of the actor, the anchor point will move
12172  * to the bottom right.
12173  *
12174  * Since: 0.6
12175  */
12176 void
12177 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12178                                              ClutterGravity  gravity)
12179 {
12180   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12181
12182   if (gravity == CLUTTER_GRAVITY_NONE)
12183     clutter_actor_set_anchor_point (self, 0, 0);
12184   else
12185     {
12186       GObject *obj = G_OBJECT (self);
12187       ClutterTransformInfo *info;
12188
12189       g_object_freeze_notify (obj);
12190
12191       info = _clutter_actor_get_transform_info (self);
12192       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12193
12194       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12195       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12196       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12197
12198       self->priv->transform_valid = FALSE;
12199
12200       clutter_actor_queue_redraw (self);
12201
12202       g_object_thaw_notify (obj);
12203     }
12204 }
12205
12206 static void
12207 clutter_container_iface_init (ClutterContainerIface *iface)
12208 {
12209   /* we don't override anything, as ClutterContainer already has a default
12210    * implementation that we can use, and which calls into our own API.
12211    */
12212 }
12213
12214 typedef enum
12215 {
12216   PARSE_X,
12217   PARSE_Y,
12218   PARSE_WIDTH,
12219   PARSE_HEIGHT,
12220   PARSE_ANCHOR_X,
12221   PARSE_ANCHOR_Y
12222 } ParseDimension;
12223
12224 static gfloat
12225 parse_units (ClutterActor   *self,
12226              ParseDimension  dimension,
12227              JsonNode       *node)
12228 {
12229   GValue value = { 0, };
12230   gfloat retval = 0;
12231
12232   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12233     return 0;
12234
12235   json_node_get_value (node, &value);
12236
12237   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12238     {
12239       retval = (gfloat) g_value_get_int64 (&value);
12240     }
12241   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12242     {
12243       retval = g_value_get_double (&value);
12244     }
12245   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12246     {
12247       ClutterUnits units;
12248       gboolean res;
12249
12250       res = clutter_units_from_string (&units, g_value_get_string (&value));
12251       if (res)
12252         retval = clutter_units_to_pixels (&units);
12253       else
12254         {
12255           g_warning ("Invalid value '%s': integers, strings or floating point "
12256                      "values can be used for the x, y, width and height "
12257                      "properties. Valid modifiers for strings are 'px', 'mm', "
12258                      "'pt' and 'em'.",
12259                      g_value_get_string (&value));
12260           retval = 0;
12261         }
12262     }
12263   else
12264     {
12265       g_warning ("Invalid value of type '%s': integers, strings of floating "
12266                  "point values can be used for the x, y, width, height "
12267                  "anchor-x and anchor-y properties.",
12268                  g_type_name (G_VALUE_TYPE (&value)));
12269     }
12270
12271   g_value_unset (&value);
12272
12273   return retval;
12274 }
12275
12276 typedef struct {
12277   ClutterRotateAxis axis;
12278
12279   gdouble angle;
12280
12281   gfloat center_x;
12282   gfloat center_y;
12283   gfloat center_z;
12284 } RotationInfo;
12285
12286 static inline gboolean
12287 parse_rotation_array (ClutterActor *actor,
12288                       JsonArray    *array,
12289                       RotationInfo *info)
12290 {
12291   JsonNode *element;
12292
12293   if (json_array_get_length (array) != 2)
12294     return FALSE;
12295
12296   /* angle */
12297   element = json_array_get_element (array, 0);
12298   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12299     info->angle = json_node_get_double (element);
12300   else
12301     return FALSE;
12302
12303   /* center */
12304   element = json_array_get_element (array, 1);
12305   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12306     {
12307       JsonArray *center = json_node_get_array (element);
12308
12309       if (json_array_get_length (center) != 2)
12310         return FALSE;
12311
12312       switch (info->axis)
12313         {
12314         case CLUTTER_X_AXIS:
12315           info->center_y = parse_units (actor, PARSE_Y,
12316                                         json_array_get_element (center, 0));
12317           info->center_z = parse_units (actor, PARSE_Y,
12318                                         json_array_get_element (center, 1));
12319           return TRUE;
12320
12321         case CLUTTER_Y_AXIS:
12322           info->center_x = parse_units (actor, PARSE_X,
12323                                         json_array_get_element (center, 0));
12324           info->center_z = parse_units (actor, PARSE_X,
12325                                         json_array_get_element (center, 1));
12326           return TRUE;
12327
12328         case CLUTTER_Z_AXIS:
12329           info->center_x = parse_units (actor, PARSE_X,
12330                                         json_array_get_element (center, 0));
12331           info->center_y = parse_units (actor, PARSE_Y,
12332                                         json_array_get_element (center, 1));
12333           return TRUE;
12334         }
12335     }
12336
12337   return FALSE;
12338 }
12339
12340 static gboolean
12341 parse_rotation (ClutterActor *actor,
12342                 JsonNode     *node,
12343                 RotationInfo *info)
12344 {
12345   JsonArray *array;
12346   guint len, i;
12347   gboolean retval = FALSE;
12348
12349   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12350     {
12351       g_warning ("Invalid node of type '%s' found, expecting an array",
12352                  json_node_type_name (node));
12353       return FALSE;
12354     }
12355
12356   array = json_node_get_array (node);
12357   len = json_array_get_length (array);
12358
12359   for (i = 0; i < len; i++)
12360     {
12361       JsonNode *element = json_array_get_element (array, i);
12362       JsonObject *object;
12363       JsonNode *member;
12364
12365       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12366         {
12367           g_warning ("Invalid node of type '%s' found, expecting an object",
12368                      json_node_type_name (element));
12369           return FALSE;
12370         }
12371
12372       object = json_node_get_object (element);
12373
12374       if (json_object_has_member (object, "x-axis"))
12375         {
12376           member = json_object_get_member (object, "x-axis");
12377
12378           info->axis = CLUTTER_X_AXIS;
12379
12380           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12381             {
12382               info->angle = json_node_get_double (member);
12383               retval = TRUE;
12384             }
12385           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12386             retval = parse_rotation_array (actor,
12387                                            json_node_get_array (member),
12388                                            info);
12389           else
12390             retval = FALSE;
12391         }
12392       else if (json_object_has_member (object, "y-axis"))
12393         {
12394           member = json_object_get_member (object, "y-axis");
12395
12396           info->axis = CLUTTER_Y_AXIS;
12397
12398           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12399             {
12400               info->angle = json_node_get_double (member);
12401               retval = TRUE;
12402             }
12403           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12404             retval = parse_rotation_array (actor,
12405                                            json_node_get_array (member),
12406                                            info);
12407           else
12408             retval = FALSE;
12409         }
12410       else if (json_object_has_member (object, "z-axis"))
12411         {
12412           member = json_object_get_member (object, "z-axis");
12413
12414           info->axis = CLUTTER_Z_AXIS;
12415
12416           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12417             {
12418               info->angle = json_node_get_double (member);
12419               retval = TRUE;
12420             }
12421           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12422             retval = parse_rotation_array (actor,
12423                                            json_node_get_array (member),
12424                                            info);
12425           else
12426             retval = FALSE;
12427         }
12428     }
12429
12430   return retval;
12431 }
12432
12433 static GSList *
12434 parse_actor_metas (ClutterScript *script,
12435                    ClutterActor  *actor,
12436                    JsonNode      *node)
12437 {
12438   GList *elements, *l;
12439   GSList *retval = NULL;
12440
12441   if (!JSON_NODE_HOLDS_ARRAY (node))
12442     return NULL;
12443
12444   elements = json_array_get_elements (json_node_get_array (node));
12445
12446   for (l = elements; l != NULL; l = l->next)
12447     {
12448       JsonNode *element = l->data;
12449       const gchar *id_ = _clutter_script_get_id_from_node (element);
12450       GObject *meta;
12451
12452       if (id_ == NULL || *id_ == '\0')
12453         continue;
12454
12455       meta = clutter_script_get_object (script, id_);
12456       if (meta == NULL)
12457         continue;
12458
12459       retval = g_slist_prepend (retval, meta);
12460     }
12461
12462   g_list_free (elements);
12463
12464   return g_slist_reverse (retval);
12465 }
12466
12467 static GSList *
12468 parse_behaviours (ClutterScript *script,
12469                   ClutterActor  *actor,
12470                   JsonNode      *node)
12471 {
12472   GList *elements, *l;
12473   GSList *retval = NULL;
12474
12475   if (!JSON_NODE_HOLDS_ARRAY (node))
12476     return NULL;
12477
12478   elements = json_array_get_elements (json_node_get_array (node));
12479
12480   for (l = elements; l != NULL; l = l->next)
12481     {
12482       JsonNode *element = l->data;
12483       const gchar *id_ = _clutter_script_get_id_from_node (element);
12484       GObject *behaviour;
12485
12486       if (id_ == NULL || *id_ == '\0')
12487         continue;
12488
12489       behaviour = clutter_script_get_object (script, id_);
12490       if (behaviour == NULL)
12491         continue;
12492
12493       retval = g_slist_prepend (retval, behaviour);
12494     }
12495
12496   g_list_free (elements);
12497
12498   return g_slist_reverse (retval);
12499 }
12500
12501 static gboolean
12502 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12503                                  ClutterScript     *script,
12504                                  GValue            *value,
12505                                  const gchar       *name,
12506                                  JsonNode          *node)
12507 {
12508   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12509   gboolean retval = FALSE;
12510
12511   if ((name[0] == 'x' && name[1] == '\0') ||
12512       (name[0] == 'y' && name[1] == '\0') ||
12513       (strcmp (name, "width") == 0) ||
12514       (strcmp (name, "height") == 0) ||
12515       (strcmp (name, "anchor_x") == 0) ||
12516       (strcmp (name, "anchor_y") == 0))
12517     {
12518       ParseDimension dimension;
12519       gfloat units;
12520
12521       if (name[0] == 'x')
12522         dimension = PARSE_X;
12523       else if (name[0] == 'y')
12524         dimension = PARSE_Y;
12525       else if (name[0] == 'w')
12526         dimension = PARSE_WIDTH;
12527       else if (name[0] == 'h')
12528         dimension = PARSE_HEIGHT;
12529       else if (name[0] == 'a' && name[7] == 'x')
12530         dimension = PARSE_ANCHOR_X;
12531       else if (name[0] == 'a' && name[7] == 'y')
12532         dimension = PARSE_ANCHOR_Y;
12533       else
12534         return FALSE;
12535
12536       units = parse_units (actor, dimension, node);
12537
12538       /* convert back to pixels: all properties are pixel-based */
12539       g_value_init (value, G_TYPE_FLOAT);
12540       g_value_set_float (value, units);
12541
12542       retval = TRUE;
12543     }
12544   else if (strcmp (name, "rotation") == 0)
12545     {
12546       RotationInfo *info;
12547
12548       info = g_slice_new0 (RotationInfo);
12549       retval = parse_rotation (actor, node, info);
12550
12551       if (retval)
12552         {
12553           g_value_init (value, G_TYPE_POINTER);
12554           g_value_set_pointer (value, info);
12555         }
12556       else
12557         g_slice_free (RotationInfo, info);
12558     }
12559   else if (strcmp (name, "behaviours") == 0)
12560     {
12561       GSList *l;
12562
12563 #ifdef CLUTTER_ENABLE_DEBUG
12564       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12565         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12566                                      "and it should not be used in newly "
12567                                      "written ClutterScript definitions.");
12568 #endif
12569
12570       l = parse_behaviours (script, actor, node);
12571
12572       g_value_init (value, G_TYPE_POINTER);
12573       g_value_set_pointer (value, l);
12574
12575       retval = TRUE;
12576     }
12577   else if (strcmp (name, "actions") == 0 ||
12578            strcmp (name, "constraints") == 0 ||
12579            strcmp (name, "effects") == 0)
12580     {
12581       GSList *l;
12582
12583       l = parse_actor_metas (script, actor, node);
12584
12585       g_value_init (value, G_TYPE_POINTER);
12586       g_value_set_pointer (value, l);
12587
12588       retval = TRUE;
12589     }
12590
12591   return retval;
12592 }
12593
12594 static void
12595 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12596                                    ClutterScript     *script,
12597                                    const gchar       *name,
12598                                    const GValue      *value)
12599 {
12600   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12601
12602 #ifdef CLUTTER_ENABLE_DEBUG
12603   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12604     {
12605       gchar *tmp = g_strdup_value_contents (value);
12606
12607       CLUTTER_NOTE (SCRIPT,
12608                     "in ClutterActor::set_custom_property('%s') = %s",
12609                     name,
12610                     tmp);
12611
12612       g_free (tmp);
12613     }
12614 #endif /* CLUTTER_ENABLE_DEBUG */
12615
12616   if (strcmp (name, "rotation") == 0)
12617     {
12618       RotationInfo *info;
12619
12620       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12621         return;
12622
12623       info = g_value_get_pointer (value);
12624
12625       clutter_actor_set_rotation (actor,
12626                                   info->axis, info->angle,
12627                                   info->center_x,
12628                                   info->center_y,
12629                                   info->center_z);
12630
12631       g_slice_free (RotationInfo, info);
12632
12633       return;
12634     }
12635
12636   if (strcmp (name, "behaviours") == 0)
12637     {
12638       GSList *behaviours, *l;
12639
12640       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12641         return;
12642
12643       behaviours = g_value_get_pointer (value);
12644       for (l = behaviours; l != NULL; l = l->next)
12645         {
12646           ClutterBehaviour *behaviour = l->data;
12647
12648           clutter_behaviour_apply (behaviour, actor);
12649         }
12650
12651       g_slist_free (behaviours);
12652
12653       return;
12654     }
12655
12656   if (strcmp (name, "actions") == 0 ||
12657       strcmp (name, "constraints") == 0 ||
12658       strcmp (name, "effects") == 0)
12659     {
12660       GSList *metas, *l;
12661
12662       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12663         return;
12664
12665       metas = g_value_get_pointer (value);
12666       for (l = metas; l != NULL; l = l->next)
12667         {
12668           if (name[0] == 'a')
12669             clutter_actor_add_action (actor, l->data);
12670
12671           if (name[0] == 'c')
12672             clutter_actor_add_constraint (actor, l->data);
12673
12674           if (name[0] == 'e')
12675             clutter_actor_add_effect (actor, l->data);
12676         }
12677
12678       g_slist_free (metas);
12679
12680       return;
12681     }
12682
12683   g_object_set_property (G_OBJECT (scriptable), name, value);
12684 }
12685
12686 static void
12687 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12688 {
12689   iface->parse_custom_node = clutter_actor_parse_custom_node;
12690   iface->set_custom_property = clutter_actor_set_custom_property;
12691 }
12692
12693 static ClutterActorMeta *
12694 get_meta_from_animation_property (ClutterActor  *actor,
12695                                   const gchar   *name,
12696                                   gchar        **name_p)
12697 {
12698   ClutterActorPrivate *priv = actor->priv;
12699   ClutterActorMeta *meta = NULL;
12700   gchar **tokens;
12701
12702   /* if this is not a special property, fall through */
12703   if (name[0] != '@')
12704     return NULL;
12705
12706   /* detect the properties named using the following spec:
12707    *
12708    *   @<section>.<meta-name>.<property-name>
12709    *
12710    * where <section> can be one of the following:
12711    *
12712    *   - actions
12713    *   - constraints
12714    *   - effects
12715    *
12716    * and <meta-name> is the name set on a specific ActorMeta
12717    */
12718
12719   tokens = g_strsplit (name + 1, ".", -1);
12720   if (tokens == NULL || g_strv_length (tokens) != 3)
12721     {
12722       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12723                     name + 1);
12724       g_strfreev (tokens);
12725       return NULL;
12726     }
12727
12728   if (strcmp (tokens[0], "actions") == 0)
12729     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12730
12731   if (strcmp (tokens[0], "constraints") == 0)
12732     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12733
12734   if (strcmp (tokens[0], "effects") == 0)
12735     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12736
12737   if (name_p != NULL)
12738     *name_p = g_strdup (tokens[2]);
12739
12740   CLUTTER_NOTE (ANIMATION,
12741                 "Looking for property '%s' of object '%s' in section '%s'",
12742                 tokens[2],
12743                 tokens[1],
12744                 tokens[0]);
12745
12746   g_strfreev (tokens);
12747
12748   return meta;
12749 }
12750
12751 static GParamSpec *
12752 clutter_actor_find_property (ClutterAnimatable *animatable,
12753                              const gchar       *property_name)
12754 {
12755   ClutterActorMeta *meta = NULL;
12756   GObjectClass *klass = NULL;
12757   GParamSpec *pspec = NULL;
12758   gchar *p_name = NULL;
12759
12760   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12761                                            property_name,
12762                                            &p_name);
12763
12764   if (meta != NULL)
12765     {
12766       klass = G_OBJECT_GET_CLASS (meta);
12767
12768       pspec = g_object_class_find_property (klass, p_name);
12769     }
12770   else
12771     {
12772       klass = G_OBJECT_GET_CLASS (animatable);
12773
12774       pspec = g_object_class_find_property (klass, property_name);
12775     }
12776
12777   g_free (p_name);
12778
12779   return pspec;
12780 }
12781
12782 static void
12783 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12784                                  const gchar       *property_name,
12785                                  GValue            *initial)
12786 {
12787   ClutterActorMeta *meta = NULL;
12788   gchar *p_name = NULL;
12789
12790   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12791                                            property_name,
12792                                            &p_name);
12793
12794   if (meta != NULL)
12795     g_object_get_property (G_OBJECT (meta), p_name, initial);
12796   else
12797     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12798
12799   g_free (p_name);
12800 }
12801
12802 /*
12803  * clutter_actor_set_animatable_property:
12804  * @actor: a #ClutterActor
12805  * @prop_id: the paramspec id
12806  * @value: the value to set
12807  * @pspec: the paramspec
12808  *
12809  * Sets values of animatable properties.
12810  *
12811  * This is a variant of clutter_actor_set_property() that gets called
12812  * by the #ClutterAnimatable implementation of #ClutterActor for the
12813  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12814  * #GParamSpec.
12815  *
12816  * Unlike the implementation of #GObjectClass.set_property(), this
12817  * function will not update the interval if a transition involving an
12818  * animatable property is in progress - this avoids cycles with the
12819  * transition API calling the public API.
12820  */
12821 static void
12822 clutter_actor_set_animatable_property (ClutterActor *actor,
12823                                        guint         prop_id,
12824                                        const GValue *value,
12825                                        GParamSpec   *pspec)
12826 {
12827   switch (prop_id)
12828     {
12829     case PROP_X:
12830       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12831       break;
12832
12833     case PROP_Y:
12834       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12835       break;
12836
12837     case PROP_WIDTH:
12838       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12839       break;
12840
12841     case PROP_HEIGHT:
12842       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12843       break;
12844
12845     case PROP_DEPTH:
12846       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12847       break;
12848
12849     case PROP_OPACITY:
12850       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12851       break;
12852
12853     case PROP_BACKGROUND_COLOR:
12854       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12855       break;
12856
12857     case PROP_SCALE_X:
12858       clutter_actor_set_scale_factor_internal (actor,
12859                                                g_value_get_double (value),
12860                                                pspec);
12861       break;
12862
12863     case PROP_SCALE_Y:
12864       clutter_actor_set_scale_factor_internal (actor,
12865                                                g_value_get_double (value),
12866                                                pspec);
12867       break;
12868
12869     case PROP_ROTATION_ANGLE_X:
12870       clutter_actor_set_rotation_angle_internal (actor,
12871                                                  CLUTTER_X_AXIS,
12872                                                  g_value_get_double (value));
12873       break;
12874
12875     case PROP_ROTATION_ANGLE_Y:
12876       clutter_actor_set_rotation_angle_internal (actor,
12877                                                  CLUTTER_Y_AXIS,
12878                                                  g_value_get_double (value));
12879       break;
12880
12881     case PROP_ROTATION_ANGLE_Z:
12882       clutter_actor_set_rotation_angle_internal (actor,
12883                                                  CLUTTER_Z_AXIS,
12884                                                  g_value_get_double (value));
12885       break;
12886
12887     default:
12888       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12889       break;
12890     }
12891 }
12892
12893 static void
12894 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12895                                const gchar       *property_name,
12896                                const GValue      *final)
12897 {
12898   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12899   ClutterActorMeta *meta = NULL;
12900   gchar *p_name = NULL;
12901
12902   meta = get_meta_from_animation_property (actor,
12903                                            property_name,
12904                                            &p_name);
12905   if (meta != NULL)
12906     g_object_set_property (G_OBJECT (meta), p_name, final);
12907   else
12908     {
12909       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12910       GParamSpec *pspec;
12911
12912       pspec = g_object_class_find_property (obj_class, property_name);
12913
12914       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12915         {
12916           /* XXX - I'm going to the special hell for this */
12917           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12918         }
12919       else
12920         g_object_set_property (G_OBJECT (animatable), property_name, final);
12921     }
12922
12923   g_free (p_name);
12924 }
12925
12926 static void
12927 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12928 {
12929   iface->find_property = clutter_actor_find_property;
12930   iface->get_initial_state = clutter_actor_get_initial_state;
12931   iface->set_final_state = clutter_actor_set_final_state;
12932 }
12933
12934 /**
12935  * clutter_actor_transform_stage_point:
12936  * @self: A #ClutterActor
12937  * @x: (in): x screen coordinate of the point to unproject
12938  * @y: (in): y screen coordinate of the point to unproject
12939  * @x_out: (out): return location for the unprojected x coordinance
12940  * @y_out: (out): return location for the unprojected y coordinance
12941  *
12942  * This function translates screen coordinates (@x, @y) to
12943  * coordinates relative to the actor. For example, it can be used to translate
12944  * screen events from global screen coordinates into actor-local coordinates.
12945  *
12946  * The conversion can fail, notably if the transform stack results in the
12947  * actor being projected on the screen as a mere line.
12948  *
12949  * The conversion should not be expected to be pixel-perfect due to the
12950  * nature of the operation. In general the error grows when the skewing
12951  * of the actor rectangle on screen increases.
12952  *
12953  * <note><para>This function can be computationally intensive.</para></note>
12954  *
12955  * <note><para>This function only works when the allocation is up-to-date,
12956  * i.e. inside of paint().</para></note>
12957  *
12958  * Return value: %TRUE if conversion was successful.
12959  *
12960  * Since: 0.6
12961  */
12962 gboolean
12963 clutter_actor_transform_stage_point (ClutterActor *self,
12964                                      gfloat        x,
12965                                      gfloat        y,
12966                                      gfloat       *x_out,
12967                                      gfloat       *y_out)
12968 {
12969   ClutterVertex v[4];
12970   float ST[3][3];
12971   float RQ[3][3];
12972   int du, dv, xi, yi;
12973   float px, py;
12974   float xf, yf, wf, det;
12975   ClutterActorPrivate *priv;
12976
12977   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12978
12979   priv = self->priv;
12980
12981   /* This implementation is based on the quad -> quad projection algorithm
12982    * described by Paul Heckbert in:
12983    *
12984    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12985    *
12986    * and the sample implementation at:
12987    *
12988    *   http://www.cs.cmu.edu/~ph/src/texfund/
12989    *
12990    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12991    * quad to rectangle only, which significantly simplifies things; the
12992    * function calls have been unrolled, and most of the math is done in fixed
12993    * point.
12994    */
12995
12996   clutter_actor_get_abs_allocation_vertices (self, v);
12997
12998   /* Keeping these as ints simplifies the multiplication (no significant
12999    * loss of precision here).
13000    */
13001   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13002   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13003
13004   if (!du || !dv)
13005     return FALSE;
13006
13007 #define UX2FP(x)        (x)
13008 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13009
13010   /* First, find mapping from unit uv square to xy quadrilateral; this
13011    * equivalent to the pmap_square_quad() functions in the sample
13012    * implementation, which we can simplify, since our target is always
13013    * a rectangle.
13014    */
13015   px = v[0].x - v[1].x + v[3].x - v[2].x;
13016   py = v[0].y - v[1].y + v[3].y - v[2].y;
13017
13018   if (!px && !py)
13019     {
13020       /* affine transform */
13021       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13022       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13023       RQ[2][0] = UX2FP (v[0].x);
13024       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13025       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13026       RQ[2][1] = UX2FP (v[0].y);
13027       RQ[0][2] = 0;
13028       RQ[1][2] = 0;
13029       RQ[2][2] = 1.0;
13030     }
13031   else
13032     {
13033       /* projective transform */
13034       double dx1, dx2, dy1, dy2, del;
13035
13036       dx1 = UX2FP (v[1].x - v[3].x);
13037       dx2 = UX2FP (v[2].x - v[3].x);
13038       dy1 = UX2FP (v[1].y - v[3].y);
13039       dy2 = UX2FP (v[2].y - v[3].y);
13040
13041       del = DET2FP (dx1, dx2, dy1, dy2);
13042       if (!del)
13043         return FALSE;
13044
13045       /*
13046        * The division here needs to be done in floating point for
13047        * precisions reasons.
13048        */
13049       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13050       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13051       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13052       RQ[2][2] = 1.0;
13053       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13054       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13055       RQ[2][0] = UX2FP (v[0].x);
13056       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13057       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13058       RQ[2][1] = UX2FP (v[0].y);
13059     }
13060
13061   /*
13062    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13063    * square. Since our rectangle is based at 0,0 we only need to scale.
13064    */
13065   RQ[0][0] /= du;
13066   RQ[1][0] /= dv;
13067   RQ[0][1] /= du;
13068   RQ[1][1] /= dv;
13069   RQ[0][2] /= du;
13070   RQ[1][2] /= dv;
13071
13072   /*
13073    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13074    * inverse of that.
13075    */
13076   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13077   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13078   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13079   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13080   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13081   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13082   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13083   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13084   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13085
13086   /*
13087    * Check the resulting matrix is OK.
13088    */
13089   det = (RQ[0][0] * ST[0][0])
13090       + (RQ[0][1] * ST[0][1])
13091       + (RQ[0][2] * ST[0][2]);
13092   if (!det)
13093     return FALSE;
13094
13095   /*
13096    * Now transform our point with the ST matrix; the notional w
13097    * coordinate is 1, hence the last part is simply added.
13098    */
13099   xi = (int) x;
13100   yi = (int) y;
13101
13102   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13103   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13104   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13105
13106   if (x_out)
13107     *x_out = xf / wf;
13108
13109   if (y_out)
13110     *y_out = yf / wf;
13111
13112 #undef UX2FP
13113 #undef DET2FP
13114
13115   return TRUE;
13116 }
13117
13118 /*
13119  * ClutterGeometry
13120  */
13121
13122 static ClutterGeometry*
13123 clutter_geometry_copy (const ClutterGeometry *geometry)
13124 {
13125   return g_slice_dup (ClutterGeometry, geometry);
13126 }
13127
13128 static void
13129 clutter_geometry_free (ClutterGeometry *geometry)
13130 {
13131   if (G_LIKELY (geometry != NULL))
13132     g_slice_free (ClutterGeometry, geometry);
13133 }
13134
13135 /**
13136  * clutter_geometry_union:
13137  * @geometry_a: a #ClutterGeometry
13138  * @geometry_b: another #ClutterGeometry
13139  * @result: (out): location to store the result
13140  *
13141  * Find the union of two rectangles represented as #ClutterGeometry.
13142  *
13143  * Since: 1.4
13144  */
13145 void
13146 clutter_geometry_union (const ClutterGeometry *geometry_a,
13147                         const ClutterGeometry *geometry_b,
13148                         ClutterGeometry       *result)
13149 {
13150   /* We don't try to handle rectangles that can't be represented
13151    * as a signed integer box */
13152   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13153   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13154   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13155                   geometry_b->x + (gint)geometry_b->width);
13156   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13157                   geometry_b->y + (gint)geometry_b->height);
13158   result->x = x_1;
13159   result->y = y_1;
13160   result->width = x_2 - x_1;
13161   result->height = y_2 - y_1;
13162 }
13163
13164 /**
13165  * clutter_geometry_intersects:
13166  * @geometry0: The first geometry to test
13167  * @geometry1: The second geometry to test
13168  *
13169  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13170  * they do else %FALSE.
13171  *
13172  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13173  * %FALSE.
13174  *
13175  * Since: 1.4
13176  */
13177 gboolean
13178 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13179                              const ClutterGeometry *geometry1)
13180 {
13181   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13182       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13183       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13184       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13185     return FALSE;
13186   else
13187     return TRUE;
13188 }
13189
13190 static gboolean
13191 clutter_geometry_progress (const GValue *a,
13192                            const GValue *b,
13193                            gdouble       progress,
13194                            GValue       *retval)
13195 {
13196   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13197   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13198   ClutterGeometry res = { 0, };
13199   gint a_width = a_geom->width;
13200   gint b_width = b_geom->width;
13201   gint a_height = a_geom->height;
13202   gint b_height = b_geom->height;
13203
13204   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13205   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13206
13207   res.width = a_width + (b_width - a_width) * progress;
13208   res.height = a_height + (b_height - a_height) * progress;
13209
13210   g_value_set_boxed (retval, &res);
13211
13212   return TRUE;
13213 }
13214
13215 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13216                                clutter_geometry_copy,
13217                                clutter_geometry_free,
13218                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13219
13220 /*
13221  * ClutterVertices
13222  */
13223
13224 /**
13225  * clutter_vertex_new:
13226  * @x: X coordinate
13227  * @y: Y coordinate
13228  * @z: Z coordinate
13229  *
13230  * Creates a new #ClutterVertex for the point in 3D space
13231  * identified by the 3 coordinates @x, @y, @z
13232  *
13233  * Return value: the newly allocate #ClutterVertex. Use
13234  *   clutter_vertex_free() to free the resources
13235  *
13236  * Since: 1.0
13237  */
13238 ClutterVertex *
13239 clutter_vertex_new (gfloat x,
13240                     gfloat y,
13241                     gfloat z)
13242 {
13243   ClutterVertex *vertex;
13244
13245   vertex = g_slice_new (ClutterVertex);
13246   vertex->x = x;
13247   vertex->y = y;
13248   vertex->z = z;
13249
13250   return vertex;
13251 }
13252
13253 /**
13254  * clutter_vertex_copy:
13255  * @vertex: a #ClutterVertex
13256  *
13257  * Copies @vertex
13258  *
13259  * Return value: a newly allocated copy of #ClutterVertex. Use
13260  *   clutter_vertex_free() to free the allocated resources
13261  *
13262  * Since: 1.0
13263  */
13264 ClutterVertex *
13265 clutter_vertex_copy (const ClutterVertex *vertex)
13266 {
13267   if (G_LIKELY (vertex != NULL))
13268     return g_slice_dup (ClutterVertex, vertex);
13269
13270   return NULL;
13271 }
13272
13273 /**
13274  * clutter_vertex_free:
13275  * @vertex: a #ClutterVertex
13276  *
13277  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13278  *
13279  * Since: 1.0
13280  */
13281 void
13282 clutter_vertex_free (ClutterVertex *vertex)
13283 {
13284   if (G_UNLIKELY (vertex != NULL))
13285     g_slice_free (ClutterVertex, vertex);
13286 }
13287
13288 /**
13289  * clutter_vertex_equal:
13290  * @vertex_a: a #ClutterVertex
13291  * @vertex_b: a #ClutterVertex
13292  *
13293  * Compares @vertex_a and @vertex_b for equality
13294  *
13295  * Return value: %TRUE if the passed #ClutterVertex are equal
13296  *
13297  * Since: 1.0
13298  */
13299 gboolean
13300 clutter_vertex_equal (const ClutterVertex *vertex_a,
13301                       const ClutterVertex *vertex_b)
13302 {
13303   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13304
13305   if (vertex_a == vertex_b)
13306     return TRUE;
13307
13308   return vertex_a->x == vertex_b->x &&
13309          vertex_a->y == vertex_b->y &&
13310          vertex_a->z == vertex_b->z;
13311 }
13312
13313 static gboolean
13314 clutter_vertex_progress (const GValue *a,
13315                          const GValue *b,
13316                          gdouble       progress,
13317                          GValue       *retval)
13318 {
13319   const ClutterVertex *av = g_value_get_boxed (a);
13320   const ClutterVertex *bv = g_value_get_boxed (b);
13321   ClutterVertex res = { 0, };
13322
13323   res.x = av->x + (bv->x - av->x) * progress;
13324   res.y = av->y + (bv->y - av->y) * progress;
13325   res.z = av->z + (bv->z - av->z) * progress;
13326
13327   g_value_set_boxed (retval, &res);
13328
13329   return TRUE;
13330 }
13331
13332 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13333                                clutter_vertex_copy,
13334                                clutter_vertex_free,
13335                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13336
13337 /**
13338  * clutter_actor_is_rotated:
13339  * @self: a #ClutterActor
13340  *
13341  * Checks whether any rotation is applied to the actor.
13342  *
13343  * Return value: %TRUE if the actor is rotated.
13344  *
13345  * Since: 0.6
13346  */
13347 gboolean
13348 clutter_actor_is_rotated (ClutterActor *self)
13349 {
13350   const ClutterTransformInfo *info;
13351
13352   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13353
13354   info = _clutter_actor_get_transform_info_or_defaults (self);
13355
13356   if (info->rx_angle || info->ry_angle || info->rz_angle)
13357     return TRUE;
13358
13359   return FALSE;
13360 }
13361
13362 /**
13363  * clutter_actor_is_scaled:
13364  * @self: a #ClutterActor
13365  *
13366  * Checks whether the actor is scaled in either dimension.
13367  *
13368  * Return value: %TRUE if the actor is scaled.
13369  *
13370  * Since: 0.6
13371  */
13372 gboolean
13373 clutter_actor_is_scaled (ClutterActor *self)
13374 {
13375   const ClutterTransformInfo *info;
13376
13377   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13378
13379   info = _clutter_actor_get_transform_info_or_defaults (self);
13380
13381   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13382     return TRUE;
13383
13384   return FALSE;
13385 }
13386
13387 ClutterActor *
13388 _clutter_actor_get_stage_internal (ClutterActor *actor)
13389 {
13390   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13391     actor = actor->priv->parent;
13392
13393   return actor;
13394 }
13395
13396 /**
13397  * clutter_actor_get_stage:
13398  * @actor: a #ClutterActor
13399  *
13400  * Retrieves the #ClutterStage where @actor is contained.
13401  *
13402  * Return value: (transfer none) (type Clutter.Stage): the stage
13403  *   containing the actor, or %NULL
13404  *
13405  * Since: 0.8
13406  */
13407 ClutterActor *
13408 clutter_actor_get_stage (ClutterActor *actor)
13409 {
13410   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13411
13412   return _clutter_actor_get_stage_internal (actor);
13413 }
13414
13415 /**
13416  * clutter_actor_allocate_available_size:
13417  * @self: a #ClutterActor
13418  * @x: the actor's X coordinate
13419  * @y: the actor's Y coordinate
13420  * @available_width: the maximum available width, or -1 to use the
13421  *   actor's natural width
13422  * @available_height: the maximum available height, or -1 to use the
13423  *   actor's natural height
13424  * @flags: flags controlling the allocation
13425  *
13426  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13427  * preferred size, but limiting it to the maximum available width
13428  * and height provided.
13429  *
13430  * This function will do the right thing when dealing with the
13431  * actor's request mode.
13432  *
13433  * The implementation of this function is equivalent to:
13434  *
13435  * |[
13436  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13437  *     {
13438  *       clutter_actor_get_preferred_width (self, available_height,
13439  *                                          &amp;min_width,
13440  *                                          &amp;natural_width);
13441  *       width = CLAMP (natural_width, min_width, available_width);
13442  *
13443  *       clutter_actor_get_preferred_height (self, width,
13444  *                                           &amp;min_height,
13445  *                                           &amp;natural_height);
13446  *       height = CLAMP (natural_height, min_height, available_height);
13447  *     }
13448  *   else
13449  *     {
13450  *       clutter_actor_get_preferred_height (self, available_width,
13451  *                                           &amp;min_height,
13452  *                                           &amp;natural_height);
13453  *       height = CLAMP (natural_height, min_height, available_height);
13454  *
13455  *       clutter_actor_get_preferred_width (self, height,
13456  *                                          &amp;min_width,
13457  *                                          &amp;natural_width);
13458  *       width = CLAMP (natural_width, min_width, available_width);
13459  *     }
13460  *
13461  *   box.x1 = x; box.y1 = y;
13462  *   box.x2 = box.x1 + available_width;
13463  *   box.y2 = box.y1 + available_height;
13464  *   clutter_actor_allocate (self, &amp;box, flags);
13465  * ]|
13466  *
13467  * This function can be used by fluid layout managers to allocate
13468  * an actor's preferred size without making it bigger than the area
13469  * available for the container.
13470  *
13471  * Since: 1.0
13472  */
13473 void
13474 clutter_actor_allocate_available_size (ClutterActor           *self,
13475                                        gfloat                  x,
13476                                        gfloat                  y,
13477                                        gfloat                  available_width,
13478                                        gfloat                  available_height,
13479                                        ClutterAllocationFlags  flags)
13480 {
13481   ClutterActorPrivate *priv;
13482   gfloat width, height;
13483   gfloat min_width, min_height;
13484   gfloat natural_width, natural_height;
13485   ClutterActorBox box;
13486
13487   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13488
13489   priv = self->priv;
13490
13491   width = height = 0.0;
13492
13493   switch (priv->request_mode)
13494     {
13495     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13496       clutter_actor_get_preferred_width (self, available_height,
13497                                          &min_width,
13498                                          &natural_width);
13499       width  = CLAMP (natural_width, min_width, available_width);
13500
13501       clutter_actor_get_preferred_height (self, width,
13502                                           &min_height,
13503                                           &natural_height);
13504       height = CLAMP (natural_height, min_height, available_height);
13505       break;
13506
13507     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13508       clutter_actor_get_preferred_height (self, available_width,
13509                                           &min_height,
13510                                           &natural_height);
13511       height = CLAMP (natural_height, min_height, available_height);
13512
13513       clutter_actor_get_preferred_width (self, height,
13514                                          &min_width,
13515                                          &natural_width);
13516       width  = CLAMP (natural_width, min_width, available_width);
13517       break;
13518     }
13519
13520
13521   box.x1 = x;
13522   box.y1 = y;
13523   box.x2 = box.x1 + width;
13524   box.y2 = box.y1 + height;
13525   clutter_actor_allocate (self, &box, flags);
13526 }
13527
13528 /**
13529  * clutter_actor_allocate_preferred_size:
13530  * @self: a #ClutterActor
13531  * @flags: flags controlling the allocation
13532  *
13533  * Allocates the natural size of @self.
13534  *
13535  * This function is a utility call for #ClutterActor implementations
13536  * that allocates the actor's preferred natural size. It can be used
13537  * by fixed layout managers (like #ClutterGroup or so called
13538  * 'composite actors') inside the ClutterActor::allocate
13539  * implementation to give each child exactly how much space it
13540  * requires.
13541  *
13542  * This function is not meant to be used by applications. It is also
13543  * not meant to be used outside the implementation of the
13544  * ClutterActor::allocate virtual function.
13545  *
13546  * Since: 0.8
13547  */
13548 void
13549 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13550                                        ClutterAllocationFlags  flags)
13551 {
13552   gfloat actor_x, actor_y;
13553   gfloat natural_width, natural_height;
13554   ClutterActorBox actor_box;
13555
13556   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13557
13558   actor_x = clutter_actor_get_x (self);
13559   actor_y = clutter_actor_get_y (self);
13560
13561   clutter_actor_get_preferred_size (self,
13562                                     NULL, NULL,
13563                                     &natural_width,
13564                                     &natural_height);
13565
13566   actor_box.x1 = actor_x;
13567   actor_box.y1 = actor_y;
13568   actor_box.x2 = actor_box.x1 + natural_width;
13569   actor_box.y2 = actor_box.y1 + natural_height;
13570
13571   clutter_actor_allocate (self, &actor_box, flags);
13572 }
13573
13574 /**
13575  * clutter_actor_allocate_align_fill:
13576  * @self: a #ClutterActor
13577  * @box: a #ClutterActorBox, containing the available width and height
13578  * @x_align: the horizontal alignment, between 0 and 1
13579  * @y_align: the vertical alignment, between 0 and 1
13580  * @x_fill: whether the actor should fill horizontally
13581  * @y_fill: whether the actor should fill vertically
13582  * @flags: allocation flags to be passed to clutter_actor_allocate()
13583  *
13584  * Allocates @self by taking into consideration the available allocation
13585  * area; an alignment factor on either axis; and whether the actor should
13586  * fill the allocation on either axis.
13587  *
13588  * The @box should contain the available allocation width and height;
13589  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13590  * allocation will be offset by their value.
13591  *
13592  * This function takes into consideration the geometry request specified by
13593  * the #ClutterActor:request-mode property, and the text direction.
13594  *
13595  * This function is useful for fluid layout managers, like #ClutterBinLayout
13596  * or #ClutterTableLayout
13597  *
13598  * Since: 1.4
13599  */
13600 void
13601 clutter_actor_allocate_align_fill (ClutterActor           *self,
13602                                    const ClutterActorBox  *box,
13603                                    gdouble                 x_align,
13604                                    gdouble                 y_align,
13605                                    gboolean                x_fill,
13606                                    gboolean                y_fill,
13607                                    ClutterAllocationFlags  flags)
13608 {
13609   ClutterActorPrivate *priv;
13610   ClutterActorBox allocation = { 0, };
13611   gfloat x_offset, y_offset;
13612   gfloat available_width, available_height;
13613   gfloat child_width, child_height;
13614
13615   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13616   g_return_if_fail (box != NULL);
13617   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13618   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13619
13620   priv = self->priv;
13621
13622   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13623   clutter_actor_box_get_size (box, &available_width, &available_height);
13624
13625   if (available_width < 0)
13626     available_width = 0;
13627
13628   if (available_height < 0)
13629     available_height = 0;
13630
13631   if (x_fill)
13632     {
13633       allocation.x1 = x_offset;
13634       allocation.x2 = allocation.x1 + available_width;
13635     }
13636
13637   if (y_fill)
13638     {
13639       allocation.y1 = y_offset;
13640       allocation.y2 = allocation.y1 + available_height;
13641     }
13642
13643   /* if we are filling horizontally and vertically then we're done */
13644   if (x_fill && y_fill)
13645     goto out;
13646
13647   child_width = child_height = 0.0f;
13648
13649   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13650     {
13651       gfloat min_width, natural_width;
13652       gfloat min_height, natural_height;
13653
13654       clutter_actor_get_preferred_width (self, available_height,
13655                                          &min_width,
13656                                          &natural_width);
13657
13658       child_width = CLAMP (natural_width, min_width, available_width);
13659
13660       if (!y_fill)
13661         {
13662           clutter_actor_get_preferred_height (self, child_width,
13663                                               &min_height,
13664                                               &natural_height);
13665
13666           child_height = CLAMP (natural_height, min_height, available_height);
13667         }
13668     }
13669   else
13670     {
13671       gfloat min_width, natural_width;
13672       gfloat min_height, natural_height;
13673
13674       clutter_actor_get_preferred_height (self, available_width,
13675                                           &min_height,
13676                                           &natural_height);
13677
13678       child_height = CLAMP (natural_height, min_height, available_height);
13679
13680       if (!x_fill)
13681         {
13682           clutter_actor_get_preferred_width (self, child_height,
13683                                              &min_width,
13684                                              &natural_width);
13685
13686           child_width = CLAMP (natural_width, min_width, available_width);
13687         }
13688     }
13689
13690   /* invert the horizontal alignment for RTL languages */
13691   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13692     x_align = 1.0 - x_align;
13693
13694   if (!x_fill)
13695     {
13696       allocation.x1 = x_offset
13697                     + ((available_width - child_width) * x_align);
13698       allocation.x2 = allocation.x1 + child_width;
13699     }
13700
13701   if (!y_fill)
13702     {
13703       allocation.y1 = y_offset
13704                     + ((available_height - child_height) * y_align);
13705       allocation.y2 = allocation.y1 + child_height;
13706     }
13707
13708 out:
13709   clutter_actor_box_clamp_to_pixel (&allocation);
13710   clutter_actor_allocate (self, &allocation, flags);
13711 }
13712
13713 /**
13714  * clutter_actor_grab_key_focus:
13715  * @self: a #ClutterActor
13716  *
13717  * Sets the key focus of the #ClutterStage including @self
13718  * to this #ClutterActor.
13719  *
13720  * Since: 1.0
13721  */
13722 void
13723 clutter_actor_grab_key_focus (ClutterActor *self)
13724 {
13725   ClutterActor *stage;
13726
13727   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13728
13729   stage = _clutter_actor_get_stage_internal (self);
13730   if (stage != NULL)
13731     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13732 }
13733
13734 /**
13735  * clutter_actor_get_pango_context:
13736  * @self: a #ClutterActor
13737  *
13738  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13739  * is already configured using the appropriate font map, resolution
13740  * and font options.
13741  *
13742  * Unlike clutter_actor_create_pango_context(), this context is owend
13743  * by the #ClutterActor and it will be updated each time the options
13744  * stored by the #ClutterBackend change.
13745  *
13746  * You can use the returned #PangoContext to create a #PangoLayout
13747  * and render text using cogl_pango_render_layout() to reuse the
13748  * glyphs cache also used by Clutter.
13749  *
13750  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13751  *   The returned #PangoContext is owned by the actor and should not be
13752  *   unreferenced by the application code
13753  *
13754  * Since: 1.0
13755  */
13756 PangoContext *
13757 clutter_actor_get_pango_context (ClutterActor *self)
13758 {
13759   ClutterActorPrivate *priv;
13760
13761   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13762
13763   priv = self->priv;
13764
13765   if (priv->pango_context != NULL)
13766     return priv->pango_context;
13767
13768   priv->pango_context = _clutter_context_get_pango_context ();
13769   g_object_ref (priv->pango_context);
13770
13771   return priv->pango_context;
13772 }
13773
13774 /**
13775  * clutter_actor_create_pango_context:
13776  * @self: a #ClutterActor
13777  *
13778  * Creates a #PangoContext for the given actor. The #PangoContext
13779  * is already configured using the appropriate font map, resolution
13780  * and font options.
13781  *
13782  * See also clutter_actor_get_pango_context().
13783  *
13784  * Return value: (transfer full): the newly created #PangoContext.
13785  *   Use g_object_unref() on the returned value to deallocate its
13786  *   resources
13787  *
13788  * Since: 1.0
13789  */
13790 PangoContext *
13791 clutter_actor_create_pango_context (ClutterActor *self)
13792 {
13793   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13794
13795   return _clutter_context_create_pango_context ();
13796 }
13797
13798 /**
13799  * clutter_actor_create_pango_layout:
13800  * @self: a #ClutterActor
13801  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13802  *
13803  * Creates a new #PangoLayout from the same #PangoContext used
13804  * by the #ClutterActor. The #PangoLayout is already configured
13805  * with the font map, resolution and font options, and the
13806  * given @text.
13807  *
13808  * If you want to keep around a #PangoLayout created by this
13809  * function you will have to connect to the #ClutterBackend::font-changed
13810  * and #ClutterBackend::resolution-changed signals, and call
13811  * pango_layout_context_changed() in response to them.
13812  *
13813  * Return value: (transfer full): the newly created #PangoLayout.
13814  *   Use g_object_unref() when done
13815  *
13816  * Since: 1.0
13817  */
13818 PangoLayout *
13819 clutter_actor_create_pango_layout (ClutterActor *self,
13820                                    const gchar  *text)
13821 {
13822   PangoContext *context;
13823   PangoLayout *layout;
13824
13825   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13826
13827   context = clutter_actor_get_pango_context (self);
13828   layout = pango_layout_new (context);
13829
13830   if (text)
13831     pango_layout_set_text (layout, text, -1);
13832
13833   return layout;
13834 }
13835
13836 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13837  * ClutterOffscreenEffect.
13838  */
13839 void
13840 _clutter_actor_set_opacity_override (ClutterActor *self,
13841                                      gint          opacity)
13842 {
13843   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13844
13845   self->priv->opacity_override = opacity;
13846 }
13847
13848 gint
13849 _clutter_actor_get_opacity_override (ClutterActor *self)
13850 {
13851   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13852
13853   return self->priv->opacity_override;
13854 }
13855
13856 /* Allows you to disable applying the actors model view transform during
13857  * a paint. Used by ClutterClone. */
13858 void
13859 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13860                                                 gboolean      enable)
13861 {
13862   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13863
13864   self->priv->enable_model_view_transform = enable;
13865 }
13866
13867 void
13868 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13869                                           gboolean      enable)
13870 {
13871   ClutterActorPrivate *priv;
13872
13873   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13874
13875   priv = self->priv;
13876
13877   priv->enable_paint_unmapped = enable;
13878
13879   if (priv->enable_paint_unmapped)
13880     {
13881       /* Make sure that the parents of the widget are realized first;
13882        * otherwise checks in clutter_actor_update_map_state() will
13883        * fail.
13884        */
13885       clutter_actor_realize (self);
13886
13887       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13888     }
13889   else
13890     {
13891       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13892     }
13893 }
13894
13895 static void
13896 clutter_anchor_coord_get_units (ClutterActor      *self,
13897                                 const AnchorCoord *coord,
13898                                 gfloat            *x,
13899                                 gfloat            *y,
13900                                 gfloat            *z)
13901 {
13902   if (coord->is_fractional)
13903     {
13904       gfloat actor_width, actor_height;
13905
13906       clutter_actor_get_size (self, &actor_width, &actor_height);
13907
13908       if (x)
13909         *x = actor_width * coord->v.fraction.x;
13910
13911       if (y)
13912         *y = actor_height * coord->v.fraction.y;
13913
13914       if (z)
13915         *z = 0;
13916     }
13917   else
13918     {
13919       if (x)
13920         *x = coord->v.units.x;
13921
13922       if (y)
13923         *y = coord->v.units.y;
13924
13925       if (z)
13926         *z = coord->v.units.z;
13927     }
13928 }
13929
13930 static void
13931 clutter_anchor_coord_set_units (AnchorCoord *coord,
13932                                 gfloat       x,
13933                                 gfloat       y,
13934                                 gfloat       z)
13935 {
13936   coord->is_fractional = FALSE;
13937   coord->v.units.x = x;
13938   coord->v.units.y = y;
13939   coord->v.units.z = z;
13940 }
13941
13942 static ClutterGravity
13943 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13944 {
13945   if (coord->is_fractional)
13946     {
13947       if (coord->v.fraction.x == 0.0)
13948         {
13949           if (coord->v.fraction.y == 0.0)
13950             return CLUTTER_GRAVITY_NORTH_WEST;
13951           else if (coord->v.fraction.y == 0.5)
13952             return CLUTTER_GRAVITY_WEST;
13953           else if (coord->v.fraction.y == 1.0)
13954             return CLUTTER_GRAVITY_SOUTH_WEST;
13955           else
13956             return CLUTTER_GRAVITY_NONE;
13957         }
13958       else if (coord->v.fraction.x == 0.5)
13959         {
13960           if (coord->v.fraction.y == 0.0)
13961             return CLUTTER_GRAVITY_NORTH;
13962           else if (coord->v.fraction.y == 0.5)
13963             return CLUTTER_GRAVITY_CENTER;
13964           else if (coord->v.fraction.y == 1.0)
13965             return CLUTTER_GRAVITY_SOUTH;
13966           else
13967             return CLUTTER_GRAVITY_NONE;
13968         }
13969       else if (coord->v.fraction.x == 1.0)
13970         {
13971           if (coord->v.fraction.y == 0.0)
13972             return CLUTTER_GRAVITY_NORTH_EAST;
13973           else if (coord->v.fraction.y == 0.5)
13974             return CLUTTER_GRAVITY_EAST;
13975           else if (coord->v.fraction.y == 1.0)
13976             return CLUTTER_GRAVITY_SOUTH_EAST;
13977           else
13978             return CLUTTER_GRAVITY_NONE;
13979         }
13980       else
13981         return CLUTTER_GRAVITY_NONE;
13982     }
13983   else
13984     return CLUTTER_GRAVITY_NONE;
13985 }
13986
13987 static void
13988 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13989                                   ClutterGravity  gravity)
13990 {
13991   switch (gravity)
13992     {
13993     case CLUTTER_GRAVITY_NORTH:
13994       coord->v.fraction.x = 0.5;
13995       coord->v.fraction.y = 0.0;
13996       break;
13997
13998     case CLUTTER_GRAVITY_NORTH_EAST:
13999       coord->v.fraction.x = 1.0;
14000       coord->v.fraction.y = 0.0;
14001       break;
14002
14003     case CLUTTER_GRAVITY_EAST:
14004       coord->v.fraction.x = 1.0;
14005       coord->v.fraction.y = 0.5;
14006       break;
14007
14008     case CLUTTER_GRAVITY_SOUTH_EAST:
14009       coord->v.fraction.x = 1.0;
14010       coord->v.fraction.y = 1.0;
14011       break;
14012
14013     case CLUTTER_GRAVITY_SOUTH:
14014       coord->v.fraction.x = 0.5;
14015       coord->v.fraction.y = 1.0;
14016       break;
14017
14018     case CLUTTER_GRAVITY_SOUTH_WEST:
14019       coord->v.fraction.x = 0.0;
14020       coord->v.fraction.y = 1.0;
14021       break;
14022
14023     case CLUTTER_GRAVITY_WEST:
14024       coord->v.fraction.x = 0.0;
14025       coord->v.fraction.y = 0.5;
14026       break;
14027
14028     case CLUTTER_GRAVITY_NORTH_WEST:
14029       coord->v.fraction.x = 0.0;
14030       coord->v.fraction.y = 0.0;
14031       break;
14032
14033     case CLUTTER_GRAVITY_CENTER:
14034       coord->v.fraction.x = 0.5;
14035       coord->v.fraction.y = 0.5;
14036       break;
14037
14038     default:
14039       coord->v.fraction.x = 0.0;
14040       coord->v.fraction.y = 0.0;
14041       break;
14042     }
14043
14044   coord->is_fractional = TRUE;
14045 }
14046
14047 static gboolean
14048 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14049 {
14050   if (coord->is_fractional)
14051     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14052   else
14053     return (coord->v.units.x == 0.0
14054             && coord->v.units.y == 0.0
14055             && coord->v.units.z == 0.0);
14056 }
14057
14058 /**
14059  * clutter_actor_get_flags:
14060  * @self: a #ClutterActor
14061  *
14062  * Retrieves the flags set on @self
14063  *
14064  * Return value: a bitwise or of #ClutterActorFlags or 0
14065  *
14066  * Since: 1.0
14067  */
14068 ClutterActorFlags
14069 clutter_actor_get_flags (ClutterActor *self)
14070 {
14071   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14072
14073   return self->flags;
14074 }
14075
14076 /**
14077  * clutter_actor_set_flags:
14078  * @self: a #ClutterActor
14079  * @flags: the flags to set
14080  *
14081  * Sets @flags on @self
14082  *
14083  * This function will emit notifications for the changed properties
14084  *
14085  * Since: 1.0
14086  */
14087 void
14088 clutter_actor_set_flags (ClutterActor      *self,
14089                          ClutterActorFlags  flags)
14090 {
14091   ClutterActorFlags old_flags;
14092   GObject *obj;
14093   gboolean was_reactive_set, reactive_set;
14094   gboolean was_realized_set, realized_set;
14095   gboolean was_mapped_set, mapped_set;
14096   gboolean was_visible_set, visible_set;
14097
14098   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14099
14100   if (self->flags == flags)
14101     return;
14102
14103   obj = G_OBJECT (self);
14104   g_object_ref (obj);
14105   g_object_freeze_notify (obj);
14106
14107   old_flags = self->flags;
14108
14109   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14110   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14111   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14112   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14113
14114   self->flags |= flags;
14115
14116   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14117   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14118   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14119   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14120
14121   if (reactive_set != was_reactive_set)
14122     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14123
14124   if (realized_set != was_realized_set)
14125     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14126
14127   if (mapped_set != was_mapped_set)
14128     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14129
14130   if (visible_set != was_visible_set)
14131     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14132
14133   g_object_thaw_notify (obj);
14134   g_object_unref (obj);
14135 }
14136
14137 /**
14138  * clutter_actor_unset_flags:
14139  * @self: a #ClutterActor
14140  * @flags: the flags to unset
14141  *
14142  * Unsets @flags on @self
14143  *
14144  * This function will emit notifications for the changed properties
14145  *
14146  * Since: 1.0
14147  */
14148 void
14149 clutter_actor_unset_flags (ClutterActor      *self,
14150                            ClutterActorFlags  flags)
14151 {
14152   ClutterActorFlags old_flags;
14153   GObject *obj;
14154   gboolean was_reactive_set, reactive_set;
14155   gboolean was_realized_set, realized_set;
14156   gboolean was_mapped_set, mapped_set;
14157   gboolean was_visible_set, visible_set;
14158
14159   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14160
14161   obj = G_OBJECT (self);
14162   g_object_freeze_notify (obj);
14163
14164   old_flags = self->flags;
14165
14166   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14167   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14168   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14169   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14170
14171   self->flags &= ~flags;
14172
14173   if (self->flags == old_flags)
14174     return;
14175
14176   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14177   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14178   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14179   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14180
14181   if (reactive_set != was_reactive_set)
14182     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14183
14184   if (realized_set != was_realized_set)
14185     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14186
14187   if (mapped_set != was_mapped_set)
14188     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14189
14190   if (visible_set != was_visible_set)
14191     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14192
14193   g_object_thaw_notify (obj);
14194 }
14195
14196 /**
14197  * clutter_actor_get_transformation_matrix:
14198  * @self: a #ClutterActor
14199  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14200  *
14201  * Retrieves the transformations applied to @self relative to its
14202  * parent.
14203  *
14204  * Since: 1.0
14205  */
14206 void
14207 clutter_actor_get_transformation_matrix (ClutterActor *self,
14208                                          CoglMatrix   *matrix)
14209 {
14210   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14211
14212   cogl_matrix_init_identity (matrix);
14213
14214   _clutter_actor_apply_modelview_transform (self, matrix);
14215 }
14216
14217 void
14218 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14219                                    gboolean      is_in_clone_paint)
14220 {
14221   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14222   self->priv->in_clone_paint = is_in_clone_paint;
14223 }
14224
14225 /**
14226  * clutter_actor_is_in_clone_paint:
14227  * @self: a #ClutterActor
14228  *
14229  * Checks whether @self is being currently painted by a #ClutterClone
14230  *
14231  * This function is useful only inside the ::paint virtual function
14232  * implementations or within handlers for the #ClutterActor::paint
14233  * signal
14234  *
14235  * This function should not be used by applications
14236  *
14237  * Return value: %TRUE if the #ClutterActor is currently being painted
14238  *   by a #ClutterClone, and %FALSE otherwise
14239  *
14240  * Since: 1.0
14241  */
14242 gboolean
14243 clutter_actor_is_in_clone_paint (ClutterActor *self)
14244 {
14245   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14246
14247   return self->priv->in_clone_paint;
14248 }
14249
14250 static gboolean
14251 set_direction_recursive (ClutterActor *actor,
14252                          gpointer      user_data)
14253 {
14254   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14255
14256   clutter_actor_set_text_direction (actor, text_dir);
14257
14258   return TRUE;
14259 }
14260
14261 /**
14262  * clutter_actor_set_text_direction:
14263  * @self: a #ClutterActor
14264  * @text_dir: the text direction for @self
14265  *
14266  * Sets the #ClutterTextDirection for an actor
14267  *
14268  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14269  *
14270  * If @self implements #ClutterContainer then this function will recurse
14271  * inside all the children of @self (including the internal ones).
14272  *
14273  * Composite actors not implementing #ClutterContainer, or actors requiring
14274  * special handling when the text direction changes, should connect to
14275  * the #GObject::notify signal for the #ClutterActor:text-direction property
14276  *
14277  * Since: 1.2
14278  */
14279 void
14280 clutter_actor_set_text_direction (ClutterActor         *self,
14281                                   ClutterTextDirection  text_dir)
14282 {
14283   ClutterActorPrivate *priv;
14284
14285   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14286   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14287
14288   priv = self->priv;
14289
14290   if (priv->text_direction != text_dir)
14291     {
14292       priv->text_direction = text_dir;
14293
14294       /* we need to emit the notify::text-direction first, so that
14295        * the sub-classes can catch that and do specific handling of
14296        * the text direction; see clutter_text_direction_changed_cb()
14297        * inside clutter-text.c
14298        */
14299       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14300
14301       _clutter_actor_foreach_child (self, set_direction_recursive,
14302                                     GINT_TO_POINTER (text_dir));
14303
14304       clutter_actor_queue_relayout (self);
14305     }
14306 }
14307
14308 void
14309 _clutter_actor_set_has_pointer (ClutterActor *self,
14310                                 gboolean      has_pointer)
14311 {
14312   ClutterActorPrivate *priv = self->priv;
14313
14314   if (priv->has_pointer != has_pointer)
14315     {
14316       priv->has_pointer = has_pointer;
14317
14318       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14319     }
14320 }
14321
14322 /**
14323  * clutter_actor_get_text_direction:
14324  * @self: a #ClutterActor
14325  *
14326  * Retrieves the value set using clutter_actor_set_text_direction()
14327  *
14328  * If no text direction has been previously set, the default text
14329  * direction, as returned by clutter_get_default_text_direction(), will
14330  * be returned instead
14331  *
14332  * Return value: the #ClutterTextDirection for the actor
14333  *
14334  * Since: 1.2
14335  */
14336 ClutterTextDirection
14337 clutter_actor_get_text_direction (ClutterActor *self)
14338 {
14339   ClutterActorPrivate *priv;
14340
14341   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14342                         CLUTTER_TEXT_DIRECTION_LTR);
14343
14344   priv = self->priv;
14345
14346   /* if no direction has been set yet use the default */
14347   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14348     priv->text_direction = clutter_get_default_text_direction ();
14349
14350   return priv->text_direction;
14351 }
14352
14353 /**
14354  * clutter_actor_push_internal:
14355  * @self: a #ClutterActor
14356  *
14357  * Should be used by actors implementing the #ClutterContainer and with
14358  * internal children added through clutter_actor_set_parent(), for instance:
14359  *
14360  * |[
14361  *   static void
14362  *   my_actor_init (MyActor *self)
14363  *   {
14364  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14365  *
14366  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14367  *
14368  *     /&ast; calling clutter_actor_set_parent() now will result in
14369  *      &ast; the internal flag being set on a child of MyActor
14370  *      &ast;/
14371  *
14372  *     /&ast; internal child - a background texture &ast;/
14373  *     self->priv->background_tex = clutter_texture_new ();
14374  *     clutter_actor_set_parent (self->priv->background_tex,
14375  *                               CLUTTER_ACTOR (self));
14376  *
14377  *     /&ast; internal child - a label &ast;/
14378  *     self->priv->label = clutter_text_new ();
14379  *     clutter_actor_set_parent (self->priv->label,
14380  *                               CLUTTER_ACTOR (self));
14381  *
14382  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14383  *
14384  *     /&ast; calling clutter_actor_set_parent() now will not result in
14385  *      &ast; the internal flag being set on a child of MyActor
14386  *      &ast;/
14387  *   }
14388  * ]|
14389  *
14390  * This function will be used by Clutter to toggle an "internal child"
14391  * flag whenever clutter_actor_set_parent() is called; internal children
14392  * are handled differently by Clutter, specifically when destroying their
14393  * parent.
14394  *
14395  * Call clutter_actor_pop_internal() when you finished adding internal
14396  * children.
14397  *
14398  * Nested calls to clutter_actor_push_internal() are allowed, but each
14399  * one must by followed by a clutter_actor_pop_internal() call.
14400  *
14401  * Since: 1.2
14402  *
14403  * Deprecated: 1.10: All children of an actor are accessible through
14404  *   the #ClutterActor API, and #ClutterActor implements the
14405  *   #ClutterContainer interface, so this function is only useful
14406  *   for legacy containers overriding the default implementation.
14407  */
14408 void
14409 clutter_actor_push_internal (ClutterActor *self)
14410 {
14411   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14412
14413   self->priv->internal_child += 1;
14414 }
14415
14416 /**
14417  * clutter_actor_pop_internal:
14418  * @self: a #ClutterActor
14419  *
14420  * Disables the effects of clutter_actor_push_internal().
14421  *
14422  * Since: 1.2
14423  *
14424  * Deprecated: 1.10: All children of an actor are accessible through
14425  *   the #ClutterActor API. This function is only useful for legacy
14426  *   containers overriding the default implementation of the
14427  *   #ClutterContainer interface.
14428  */
14429 void
14430 clutter_actor_pop_internal (ClutterActor *self)
14431 {
14432   ClutterActorPrivate *priv;
14433
14434   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14435
14436   priv = self->priv;
14437
14438   if (priv->internal_child == 0)
14439     {
14440       g_warning ("Mismatched %s: you need to call "
14441                  "clutter_actor_push_composite() at least once before "
14442                  "calling this function", G_STRFUNC);
14443       return;
14444     }
14445
14446   priv->internal_child -= 1;
14447 }
14448
14449 /**
14450  * clutter_actor_has_pointer:
14451  * @self: a #ClutterActor
14452  *
14453  * Checks whether an actor contains the pointer of a
14454  * #ClutterInputDevice
14455  *
14456  * Return value: %TRUE if the actor contains the pointer, and
14457  *   %FALSE otherwise
14458  *
14459  * Since: 1.2
14460  */
14461 gboolean
14462 clutter_actor_has_pointer (ClutterActor *self)
14463 {
14464   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14465
14466   return self->priv->has_pointer;
14467 }
14468
14469 /* XXX: This is a workaround for not being able to break the ABI of
14470  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14471  * clutter_actor_queue_clipped_redraw() for details.
14472  */
14473 ClutterPaintVolume *
14474 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14475 {
14476   return g_object_get_data (G_OBJECT (self),
14477                             "-clutter-actor-queue-redraw-clip");
14478 }
14479
14480 void
14481 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14482                                       ClutterPaintVolume *clip)
14483 {
14484   g_object_set_data (G_OBJECT (self),
14485                      "-clutter-actor-queue-redraw-clip",
14486                      clip);
14487 }
14488
14489 /**
14490  * clutter_actor_has_allocation:
14491  * @self: a #ClutterActor
14492  *
14493  * Checks if the actor has an up-to-date allocation assigned to
14494  * it. This means that the actor should have an allocation: it's
14495  * visible and has a parent. It also means that there is no
14496  * outstanding relayout request in progress for the actor or its
14497  * children (There might be other outstanding layout requests in
14498  * progress that will cause the actor to get a new allocation
14499  * when the stage is laid out, however).
14500  *
14501  * If this function returns %FALSE, then the actor will normally
14502  * be allocated before it is next drawn on the screen.
14503  *
14504  * Return value: %TRUE if the actor has an up-to-date allocation
14505  *
14506  * Since: 1.4
14507  */
14508 gboolean
14509 clutter_actor_has_allocation (ClutterActor *self)
14510 {
14511   ClutterActorPrivate *priv;
14512
14513   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14514
14515   priv = self->priv;
14516
14517   return priv->parent != NULL &&
14518          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14519          !priv->needs_allocation;
14520 }
14521
14522 /**
14523  * clutter_actor_add_action:
14524  * @self: a #ClutterActor
14525  * @action: a #ClutterAction
14526  *
14527  * Adds @action to the list of actions applied to @self
14528  *
14529  * A #ClutterAction can only belong to one actor at a time
14530  *
14531  * The #ClutterActor will hold a reference on @action until either
14532  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14533  * is called
14534  *
14535  * Since: 1.4
14536  */
14537 void
14538 clutter_actor_add_action (ClutterActor  *self,
14539                           ClutterAction *action)
14540 {
14541   ClutterActorPrivate *priv;
14542
14543   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14544   g_return_if_fail (CLUTTER_IS_ACTION (action));
14545
14546   priv = self->priv;
14547
14548   if (priv->actions == NULL)
14549     {
14550       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14551       priv->actions->actor = self;
14552     }
14553
14554   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14555
14556   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14557 }
14558
14559 /**
14560  * clutter_actor_add_action_with_name:
14561  * @self: a #ClutterActor
14562  * @name: the name to set on the action
14563  * @action: a #ClutterAction
14564  *
14565  * A convenience function for setting the name of a #ClutterAction
14566  * while adding it to the list of actions applied to @self
14567  *
14568  * This function is the logical equivalent of:
14569  *
14570  * |[
14571  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14572  *   clutter_actor_add_action (self, action);
14573  * ]|
14574  *
14575  * Since: 1.4
14576  */
14577 void
14578 clutter_actor_add_action_with_name (ClutterActor  *self,
14579                                     const gchar   *name,
14580                                     ClutterAction *action)
14581 {
14582   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14583   g_return_if_fail (name != NULL);
14584   g_return_if_fail (CLUTTER_IS_ACTION (action));
14585
14586   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14587   clutter_actor_add_action (self, action);
14588 }
14589
14590 /**
14591  * clutter_actor_remove_action:
14592  * @self: a #ClutterActor
14593  * @action: a #ClutterAction
14594  *
14595  * Removes @action from the list of actions applied to @self
14596  *
14597  * The reference held by @self on the #ClutterAction will be released
14598  *
14599  * Since: 1.4
14600  */
14601 void
14602 clutter_actor_remove_action (ClutterActor  *self,
14603                              ClutterAction *action)
14604 {
14605   ClutterActorPrivate *priv;
14606
14607   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14608   g_return_if_fail (CLUTTER_IS_ACTION (action));
14609
14610   priv = self->priv;
14611
14612   if (priv->actions == NULL)
14613     return;
14614
14615   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14616
14617   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14618 }
14619
14620 /**
14621  * clutter_actor_remove_action_by_name:
14622  * @self: a #ClutterActor
14623  * @name: the name of the action to remove
14624  *
14625  * Removes the #ClutterAction with the given name from the list
14626  * of actions applied to @self
14627  *
14628  * Since: 1.4
14629  */
14630 void
14631 clutter_actor_remove_action_by_name (ClutterActor *self,
14632                                      const gchar  *name)
14633 {
14634   ClutterActorPrivate *priv;
14635   ClutterActorMeta *meta;
14636
14637   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14638   g_return_if_fail (name != NULL);
14639
14640   priv = self->priv;
14641
14642   if (priv->actions == NULL)
14643     return;
14644
14645   meta = _clutter_meta_group_get_meta (priv->actions, name);
14646   if (meta == NULL)
14647     return;
14648
14649   _clutter_meta_group_remove_meta (priv->actions, meta);
14650
14651   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14652 }
14653
14654 /**
14655  * clutter_actor_get_actions:
14656  * @self: a #ClutterActor
14657  *
14658  * Retrieves the list of actions applied to @self
14659  *
14660  * Return value: (transfer container) (element-type Clutter.Action): a copy
14661  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14662  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14663  *   allocated by the returned #GList
14664  *
14665  * Since: 1.4
14666  */
14667 GList *
14668 clutter_actor_get_actions (ClutterActor *self)
14669 {
14670   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14671
14672   if (self->priv->actions == NULL)
14673     return NULL;
14674
14675   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14676 }
14677
14678 /**
14679  * clutter_actor_get_action:
14680  * @self: a #ClutterActor
14681  * @name: the name of the action to retrieve
14682  *
14683  * Retrieves the #ClutterAction with the given name in the list
14684  * of actions applied to @self
14685  *
14686  * Return value: (transfer none): a #ClutterAction for the given
14687  *   name, or %NULL. The returned #ClutterAction is owned by the
14688  *   actor and it should not be unreferenced directly
14689  *
14690  * Since: 1.4
14691  */
14692 ClutterAction *
14693 clutter_actor_get_action (ClutterActor *self,
14694                           const gchar  *name)
14695 {
14696   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14697   g_return_val_if_fail (name != NULL, NULL);
14698
14699   if (self->priv->actions == NULL)
14700     return NULL;
14701
14702   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14703 }
14704
14705 /**
14706  * clutter_actor_clear_actions:
14707  * @self: a #ClutterActor
14708  *
14709  * Clears the list of actions applied to @self
14710  *
14711  * Since: 1.4
14712  */
14713 void
14714 clutter_actor_clear_actions (ClutterActor *self)
14715 {
14716   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14717
14718   if (self->priv->actions == NULL)
14719     return;
14720
14721   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14722 }
14723
14724 /**
14725  * clutter_actor_add_constraint:
14726  * @self: a #ClutterActor
14727  * @constraint: a #ClutterConstraint
14728  *
14729  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14730  * to @self
14731  *
14732  * The #ClutterActor will hold a reference on the @constraint until
14733  * either clutter_actor_remove_constraint() or
14734  * clutter_actor_clear_constraints() is called.
14735  *
14736  * Since: 1.4
14737  */
14738 void
14739 clutter_actor_add_constraint (ClutterActor      *self,
14740                               ClutterConstraint *constraint)
14741 {
14742   ClutterActorPrivate *priv;
14743
14744   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14745   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14746
14747   priv = self->priv;
14748
14749   if (priv->constraints == NULL)
14750     {
14751       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14752       priv->constraints->actor = self;
14753     }
14754
14755   _clutter_meta_group_add_meta (priv->constraints,
14756                                 CLUTTER_ACTOR_META (constraint));
14757   clutter_actor_queue_relayout (self);
14758
14759   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14760 }
14761
14762 /**
14763  * clutter_actor_add_constraint_with_name:
14764  * @self: a #ClutterActor
14765  * @name: the name to set on the constraint
14766  * @constraint: a #ClutterConstraint
14767  *
14768  * A convenience function for setting the name of a #ClutterConstraint
14769  * while adding it to the list of constraints applied to @self
14770  *
14771  * This function is the logical equivalent of:
14772  *
14773  * |[
14774  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14775  *   clutter_actor_add_constraint (self, constraint);
14776  * ]|
14777  *
14778  * Since: 1.4
14779  */
14780 void
14781 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14782                                         const gchar       *name,
14783                                         ClutterConstraint *constraint)
14784 {
14785   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14786   g_return_if_fail (name != NULL);
14787   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14788
14789   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14790   clutter_actor_add_constraint (self, constraint);
14791 }
14792
14793 /**
14794  * clutter_actor_remove_constraint:
14795  * @self: a #ClutterActor
14796  * @constraint: a #ClutterConstraint
14797  *
14798  * Removes @constraint from the list of constraints applied to @self
14799  *
14800  * The reference held by @self on the #ClutterConstraint will be released
14801  *
14802  * Since: 1.4
14803  */
14804 void
14805 clutter_actor_remove_constraint (ClutterActor      *self,
14806                                  ClutterConstraint *constraint)
14807 {
14808   ClutterActorPrivate *priv;
14809
14810   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14811   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14812
14813   priv = self->priv;
14814
14815   if (priv->constraints == NULL)
14816     return;
14817
14818   _clutter_meta_group_remove_meta (priv->constraints,
14819                                    CLUTTER_ACTOR_META (constraint));
14820   clutter_actor_queue_relayout (self);
14821
14822   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14823 }
14824
14825 /**
14826  * clutter_actor_remove_constraint_by_name:
14827  * @self: a #ClutterActor
14828  * @name: the name of the constraint to remove
14829  *
14830  * Removes the #ClutterConstraint with the given name from the list
14831  * of constraints applied to @self
14832  *
14833  * Since: 1.4
14834  */
14835 void
14836 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14837                                          const gchar  *name)
14838 {
14839   ClutterActorPrivate *priv;
14840   ClutterActorMeta *meta;
14841
14842   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14843   g_return_if_fail (name != NULL);
14844
14845   priv = self->priv;
14846
14847   if (priv->constraints == NULL)
14848     return;
14849
14850   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14851   if (meta == NULL)
14852     return;
14853
14854   _clutter_meta_group_remove_meta (priv->constraints, meta);
14855   clutter_actor_queue_relayout (self);
14856 }
14857
14858 /**
14859  * clutter_actor_get_constraints:
14860  * @self: a #ClutterActor
14861  *
14862  * Retrieves the list of constraints applied to @self
14863  *
14864  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14865  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14866  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14867  *   allocated by the returned #GList
14868  *
14869  * Since: 1.4
14870  */
14871 GList *
14872 clutter_actor_get_constraints (ClutterActor *self)
14873 {
14874   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14875
14876   if (self->priv->constraints == NULL)
14877     return NULL;
14878
14879   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14880 }
14881
14882 /**
14883  * clutter_actor_get_constraint:
14884  * @self: a #ClutterActor
14885  * @name: the name of the constraint to retrieve
14886  *
14887  * Retrieves the #ClutterConstraint with the given name in the list
14888  * of constraints applied to @self
14889  *
14890  * Return value: (transfer none): a #ClutterConstraint for the given
14891  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14892  *   actor and it should not be unreferenced directly
14893  *
14894  * Since: 1.4
14895  */
14896 ClutterConstraint *
14897 clutter_actor_get_constraint (ClutterActor *self,
14898                               const gchar  *name)
14899 {
14900   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14901   g_return_val_if_fail (name != NULL, NULL);
14902
14903   if (self->priv->constraints == NULL)
14904     return NULL;
14905
14906   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14907 }
14908
14909 /**
14910  * clutter_actor_clear_constraints:
14911  * @self: a #ClutterActor
14912  *
14913  * Clears the list of constraints applied to @self
14914  *
14915  * Since: 1.4
14916  */
14917 void
14918 clutter_actor_clear_constraints (ClutterActor *self)
14919 {
14920   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14921
14922   if (self->priv->constraints == NULL)
14923     return;
14924
14925   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14926
14927   clutter_actor_queue_relayout (self);
14928 }
14929
14930 /**
14931  * clutter_actor_set_clip_to_allocation:
14932  * @self: a #ClutterActor
14933  * @clip_set: %TRUE to apply a clip tracking the allocation
14934  *
14935  * Sets whether @self should be clipped to the same size as its
14936  * allocation
14937  *
14938  * Since: 1.4
14939  */
14940 void
14941 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14942                                       gboolean      clip_set)
14943 {
14944   ClutterActorPrivate *priv;
14945
14946   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14947
14948   clip_set = !!clip_set;
14949
14950   priv = self->priv;
14951
14952   if (priv->clip_to_allocation != clip_set)
14953     {
14954       priv->clip_to_allocation = clip_set;
14955
14956       clutter_actor_queue_redraw (self);
14957
14958       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14959     }
14960 }
14961
14962 /**
14963  * clutter_actor_get_clip_to_allocation:
14964  * @self: a #ClutterActor
14965  *
14966  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14967  *
14968  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14969  *
14970  * Since: 1.4
14971  */
14972 gboolean
14973 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14974 {
14975   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14976
14977   return self->priv->clip_to_allocation;
14978 }
14979
14980 /**
14981  * clutter_actor_add_effect:
14982  * @self: a #ClutterActor
14983  * @effect: a #ClutterEffect
14984  *
14985  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14986  *
14987  * The #ClutterActor will hold a reference on the @effect until either
14988  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14989  * called.
14990  *
14991  * Since: 1.4
14992  */
14993 void
14994 clutter_actor_add_effect (ClutterActor  *self,
14995                           ClutterEffect *effect)
14996 {
14997   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14998   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14999
15000   _clutter_actor_add_effect_internal (self, effect);
15001
15002   clutter_actor_queue_redraw (self);
15003
15004   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15005 }
15006
15007 /**
15008  * clutter_actor_add_effect_with_name:
15009  * @self: a #ClutterActor
15010  * @name: the name to set on the effect
15011  * @effect: a #ClutterEffect
15012  *
15013  * A convenience function for setting the name of a #ClutterEffect
15014  * while adding it to the list of effectss applied to @self
15015  *
15016  * This function is the logical equivalent of:
15017  *
15018  * |[
15019  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15020  *   clutter_actor_add_effect (self, effect);
15021  * ]|
15022  *
15023  * Since: 1.4
15024  */
15025 void
15026 clutter_actor_add_effect_with_name (ClutterActor  *self,
15027                                     const gchar   *name,
15028                                     ClutterEffect *effect)
15029 {
15030   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15031   g_return_if_fail (name != NULL);
15032   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15033
15034   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15035   clutter_actor_add_effect (self, effect);
15036 }
15037
15038 /**
15039  * clutter_actor_remove_effect:
15040  * @self: a #ClutterActor
15041  * @effect: a #ClutterEffect
15042  *
15043  * Removes @effect from the list of effects applied to @self
15044  *
15045  * The reference held by @self on the #ClutterEffect will be released
15046  *
15047  * Since: 1.4
15048  */
15049 void
15050 clutter_actor_remove_effect (ClutterActor  *self,
15051                              ClutterEffect *effect)
15052 {
15053   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15054   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15055
15056   _clutter_actor_remove_effect_internal (self, effect);
15057
15058   clutter_actor_queue_redraw (self);
15059
15060   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15061 }
15062
15063 /**
15064  * clutter_actor_remove_effect_by_name:
15065  * @self: a #ClutterActor
15066  * @name: the name of the effect to remove
15067  *
15068  * Removes the #ClutterEffect with the given name from the list
15069  * of effects applied to @self
15070  *
15071  * Since: 1.4
15072  */
15073 void
15074 clutter_actor_remove_effect_by_name (ClutterActor *self,
15075                                      const gchar  *name)
15076 {
15077   ClutterActorPrivate *priv;
15078   ClutterActorMeta *meta;
15079
15080   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15081   g_return_if_fail (name != NULL);
15082
15083   priv = self->priv;
15084
15085   if (priv->effects == NULL)
15086     return;
15087
15088   meta = _clutter_meta_group_get_meta (priv->effects, name);
15089   if (meta == NULL)
15090     return;
15091
15092   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15093 }
15094
15095 /**
15096  * clutter_actor_get_effects:
15097  * @self: a #ClutterActor
15098  *
15099  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15100  *
15101  * Return value: (transfer container) (element-type Clutter.Effect): a list
15102  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15103  *   list are owned by Clutter and they should not be freed. You should
15104  *   free the returned list using g_list_free() when done
15105  *
15106  * Since: 1.4
15107  */
15108 GList *
15109 clutter_actor_get_effects (ClutterActor *self)
15110 {
15111   ClutterActorPrivate *priv;
15112
15113   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15114
15115   priv = self->priv;
15116
15117   if (priv->effects == NULL)
15118     return NULL;
15119
15120   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15121 }
15122
15123 /**
15124  * clutter_actor_get_effect:
15125  * @self: a #ClutterActor
15126  * @name: the name of the effect to retrieve
15127  *
15128  * Retrieves the #ClutterEffect with the given name in the list
15129  * of effects applied to @self
15130  *
15131  * Return value: (transfer none): a #ClutterEffect for the given
15132  *   name, or %NULL. The returned #ClutterEffect is owned by the
15133  *   actor and it should not be unreferenced directly
15134  *
15135  * Since: 1.4
15136  */
15137 ClutterEffect *
15138 clutter_actor_get_effect (ClutterActor *self,
15139                           const gchar  *name)
15140 {
15141   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15142   g_return_val_if_fail (name != NULL, NULL);
15143
15144   if (self->priv->effects == NULL)
15145     return NULL;
15146
15147   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15148 }
15149
15150 /**
15151  * clutter_actor_clear_effects:
15152  * @self: a #ClutterActor
15153  *
15154  * Clears the list of effects applied to @self
15155  *
15156  * Since: 1.4
15157  */
15158 void
15159 clutter_actor_clear_effects (ClutterActor *self)
15160 {
15161   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15162
15163   if (self->priv->effects == NULL)
15164     return;
15165
15166   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15167
15168   clutter_actor_queue_redraw (self);
15169 }
15170
15171 /**
15172  * clutter_actor_has_key_focus:
15173  * @self: a #ClutterActor
15174  *
15175  * Checks whether @self is the #ClutterActor that has key focus
15176  *
15177  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15178  *
15179  * Since: 1.4
15180  */
15181 gboolean
15182 clutter_actor_has_key_focus (ClutterActor *self)
15183 {
15184   ClutterActor *stage;
15185
15186   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15187
15188   stage = _clutter_actor_get_stage_internal (self);
15189   if (stage == NULL)
15190     return FALSE;
15191
15192   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15193 }
15194
15195 static gboolean
15196 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15197                                       ClutterPaintVolume *pv)
15198 {
15199   ClutterActorPrivate *priv = self->priv;
15200
15201   /* Actors are only expected to report a valid paint volume
15202    * while they have a valid allocation. */
15203   if (G_UNLIKELY (priv->needs_allocation))
15204     {
15205       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15206                     "Actor needs allocation",
15207                     _clutter_actor_get_debug_name (self));
15208       return FALSE;
15209     }
15210
15211   /* Check if there are any handlers connected to the paint
15212    * signal. If there are then all bets are off for what the paint
15213    * volume for this actor might possibly be!
15214    *
15215    * XXX: It's expected that this is going to end up being quite a
15216    * costly check to have to do here, but we haven't come up with
15217    * another solution that can reliably catch paint signal handlers at
15218    * the right time to either avoid artefacts due to invalid stage
15219    * clipping or due to incorrect culling.
15220    *
15221    * Previously we checked in clutter_actor_paint(), but at that time
15222    * we may already be using a stage clip that could be derived from
15223    * an invalid paint-volume. We used to try and handle that by
15224    * queuing a follow up, unclipped, redraw but still the previous
15225    * checking wasn't enough to catch invalid volumes involved in
15226    * culling (considering that containers may derive their volume from
15227    * children that haven't yet been painted)
15228    *
15229    * Longer term, improved solutions could be:
15230    * - Disallow painting in the paint signal, only allow using it
15231    *   for tracking when paints happen. We can add another API that
15232    *   allows monkey patching the paint of arbitrary actors but in a
15233    *   more controlled way and that also supports modifying the
15234    *   paint-volume.
15235    * - If we could be notified somehow when signal handlers are
15236    *   connected we wouldn't have to poll for handlers like this.
15237    */
15238   if (g_signal_has_handler_pending (self,
15239                                     actor_signals[PAINT],
15240                                     0,
15241                                     TRUE))
15242     {
15243       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15244                     "Actor has \"paint\" signal handlers",
15245                     _clutter_actor_get_debug_name (self));
15246       return FALSE;
15247     }
15248
15249   _clutter_paint_volume_init_static (pv, self);
15250
15251   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15252     {
15253       clutter_paint_volume_free (pv);
15254       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15255                     "Actor failed to report a volume",
15256                     _clutter_actor_get_debug_name (self));
15257       return FALSE;
15258     }
15259
15260   /* since effects can modify the paint volume, we allow them to actually
15261    * do this by making get_paint_volume() "context sensitive"
15262    */
15263   if (priv->effects != NULL)
15264     {
15265       if (priv->current_effect != NULL)
15266         {
15267           const GList *effects, *l;
15268
15269           /* if we are being called from within the paint sequence of
15270            * an actor, get the paint volume up to the current effect
15271            */
15272           effects = _clutter_meta_group_peek_metas (priv->effects);
15273           for (l = effects;
15274                l != NULL || (l != NULL && l->data != priv->current_effect);
15275                l = l->next)
15276             {
15277               if (!_clutter_effect_get_paint_volume (l->data, pv))
15278                 {
15279                   clutter_paint_volume_free (pv);
15280                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15281                                 "Effect (%s) failed to report a volume",
15282                                 _clutter_actor_get_debug_name (self),
15283                                 _clutter_actor_meta_get_debug_name (l->data));
15284                   return FALSE;
15285                 }
15286             }
15287         }
15288       else
15289         {
15290           const GList *effects, *l;
15291
15292           /* otherwise, get the cumulative volume */
15293           effects = _clutter_meta_group_peek_metas (priv->effects);
15294           for (l = effects; l != NULL; l = l->next)
15295             if (!_clutter_effect_get_paint_volume (l->data, pv))
15296               {
15297                 clutter_paint_volume_free (pv);
15298                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15299                               "Effect (%s) failed to report a volume",
15300                               _clutter_actor_get_debug_name (self),
15301                               _clutter_actor_meta_get_debug_name (l->data));
15302                 return FALSE;
15303               }
15304         }
15305     }
15306
15307   return TRUE;
15308 }
15309
15310 /* The public clutter_actor_get_paint_volume API returns a const
15311  * pointer since we return a pointer directly to the cached
15312  * PaintVolume associated with the actor and don't want the user to
15313  * inadvertently modify it, but for internal uses we sometimes need
15314  * access to the same PaintVolume but need to apply some book-keeping
15315  * modifications to it so we don't want a const pointer.
15316  */
15317 static ClutterPaintVolume *
15318 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15319 {
15320   ClutterActorPrivate *priv;
15321
15322   priv = self->priv;
15323
15324   if (priv->paint_volume_valid)
15325     clutter_paint_volume_free (&priv->paint_volume);
15326
15327   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15328     {
15329       priv->paint_volume_valid = TRUE;
15330       return &priv->paint_volume;
15331     }
15332   else
15333     {
15334       priv->paint_volume_valid = FALSE;
15335       return NULL;
15336     }
15337 }
15338
15339 /**
15340  * clutter_actor_get_paint_volume:
15341  * @self: a #ClutterActor
15342  *
15343  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15344  * when a paint volume can't be determined.
15345  *
15346  * The paint volume is defined as the 3D space occupied by an actor
15347  * when being painted.
15348  *
15349  * This function will call the <function>get_paint_volume()</function>
15350  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15351  * should not usually care about overriding the default implementation,
15352  * unless they are, for instance: painting outside their allocation, or
15353  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15354  * 3D depth).
15355  *
15356  * <note>2D actors overriding <function>get_paint_volume()</function>
15357  * ensure their volume has a depth of 0. (This will be true so long as
15358  * you don't call clutter_paint_volume_set_depth().)</note>
15359  *
15360  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15361  *   or %NULL if no volume could be determined. The returned pointer
15362  *   is not guaranteed to be valid across multiple frames; if you want
15363  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15364  *
15365  * Since: 1.6
15366  */
15367 const ClutterPaintVolume *
15368 clutter_actor_get_paint_volume (ClutterActor *self)
15369 {
15370   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15371
15372   return _clutter_actor_get_paint_volume_mutable (self);
15373 }
15374
15375 /**
15376  * clutter_actor_get_transformed_paint_volume:
15377  * @self: a #ClutterActor
15378  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15379  *    (or %NULL for the stage)
15380  *
15381  * Retrieves the 3D paint volume of an actor like
15382  * clutter_actor_get_paint_volume() does (Please refer to the
15383  * documentation of clutter_actor_get_paint_volume() for more
15384  * details.) and it additionally transforms the paint volume into the
15385  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15386  * is passed for @relative_to_ancestor)
15387  *
15388  * This can be used by containers that base their paint volume on
15389  * the volume of their children. Such containers can query the
15390  * transformed paint volume of all of its children and union them
15391  * together using clutter_paint_volume_union().
15392  *
15393  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15394  *   or %NULL if no volume could be determined. The returned pointer is
15395  *   not guaranteed to be valid across multiple frames; if you wish to
15396  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15397  *
15398  * Since: 1.6
15399  */
15400 const ClutterPaintVolume *
15401 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15402                                             ClutterActor *relative_to_ancestor)
15403 {
15404   const ClutterPaintVolume *volume;
15405   ClutterActor *stage;
15406   ClutterPaintVolume *transformed_volume;
15407
15408   stage = _clutter_actor_get_stage_internal (self);
15409   if (G_UNLIKELY (stage == NULL))
15410     return NULL;
15411
15412   if (relative_to_ancestor == NULL)
15413     relative_to_ancestor = stage;
15414
15415   volume = clutter_actor_get_paint_volume (self);
15416   if (volume == NULL)
15417     return NULL;
15418
15419   transformed_volume =
15420     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15421
15422   _clutter_paint_volume_copy_static (volume, transformed_volume);
15423
15424   _clutter_paint_volume_transform_relative (transformed_volume,
15425                                             relative_to_ancestor);
15426
15427   return transformed_volume;
15428 }
15429
15430 /**
15431  * clutter_actor_get_paint_box:
15432  * @self: a #ClutterActor
15433  * @box: (out): return location for a #ClutterActorBox
15434  *
15435  * Retrieves the paint volume of the passed #ClutterActor, and
15436  * transforms it into a 2D bounding box in stage coordinates.
15437  *
15438  * This function is useful to determine the on screen area occupied by
15439  * the actor. The box is only an approximation and may often be
15440  * considerably larger due to the optimizations used to calculate the
15441  * box. The box is never smaller though, so it can reliably be used
15442  * for culling.
15443  *
15444  * There are times when a 2D paint box can't be determined, e.g.
15445  * because the actor isn't yet parented under a stage or because
15446  * the actor is unable to determine a paint volume.
15447  *
15448  * Return value: %TRUE if a 2D paint box could be determined, else
15449  * %FALSE.
15450  *
15451  * Since: 1.6
15452  */
15453 gboolean
15454 clutter_actor_get_paint_box (ClutterActor    *self,
15455                              ClutterActorBox *box)
15456 {
15457   ClutterActor *stage;
15458   ClutterPaintVolume *pv;
15459
15460   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15461   g_return_val_if_fail (box != NULL, FALSE);
15462
15463   stage = _clutter_actor_get_stage_internal (self);
15464   if (G_UNLIKELY (!stage))
15465     return FALSE;
15466
15467   pv = _clutter_actor_get_paint_volume_mutable (self);
15468   if (G_UNLIKELY (!pv))
15469     return FALSE;
15470
15471   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15472
15473   return TRUE;
15474 }
15475
15476 /**
15477  * clutter_actor_has_overlaps:
15478  * @self: A #ClutterActor
15479  *
15480  * Asks the actor's implementation whether it may contain overlapping
15481  * primitives.
15482  *
15483  * For example; Clutter may use this to determine whether the painting
15484  * should be redirected to an offscreen buffer to correctly implement
15485  * the opacity property.
15486  *
15487  * Custom actors can override the default response by implementing the
15488  * #ClutterActor <function>has_overlaps</function> virtual function. See
15489  * clutter_actor_set_offscreen_redirect() for more information.
15490  *
15491  * Return value: %TRUE if the actor may have overlapping primitives, and
15492  *   %FALSE otherwise
15493  *
15494  * Since: 1.8
15495  */
15496 gboolean
15497 clutter_actor_has_overlaps (ClutterActor *self)
15498 {
15499   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15500
15501   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15502 }
15503
15504 /**
15505  * clutter_actor_has_effects:
15506  * @self: A #ClutterActor
15507  *
15508  * Returns whether the actor has any effects applied.
15509  *
15510  * Return value: %TRUE if the actor has any effects,
15511  *   %FALSE otherwise
15512  *
15513  * Since: 1.10
15514  */
15515 gboolean
15516 clutter_actor_has_effects (ClutterActor *self)
15517 {
15518   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15519
15520   if (self->priv->effects == NULL)
15521     return FALSE;
15522
15523   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15524 }
15525
15526 /**
15527  * clutter_actor_has_constraints:
15528  * @self: A #ClutterActor
15529  *
15530  * Returns whether the actor has any constraints applied.
15531  *
15532  * Return value: %TRUE if the actor has any constraints,
15533  *   %FALSE otherwise
15534  *
15535  * Since: 1.10
15536  */
15537 gboolean
15538 clutter_actor_has_constraints (ClutterActor *self)
15539 {
15540   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15541
15542   return self->priv->constraints != NULL;
15543 }
15544
15545 /**
15546  * clutter_actor_has_actions:
15547  * @self: A #ClutterActor
15548  *
15549  * Returns whether the actor has any actions applied.
15550  *
15551  * Return value: %TRUE if the actor has any actions,
15552  *   %FALSE otherwise
15553  *
15554  * Since: 1.10
15555  */
15556 gboolean
15557 clutter_actor_has_actions (ClutterActor *self)
15558 {
15559   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15560
15561   return self->priv->actions != NULL;
15562 }
15563
15564 /**
15565  * clutter_actor_get_n_children:
15566  * @self: a #ClutterActor
15567  *
15568  * Retrieves the number of children of @self.
15569  *
15570  * Return value: the number of children of an actor
15571  *
15572  * Since: 1.10
15573  */
15574 gint
15575 clutter_actor_get_n_children (ClutterActor *self)
15576 {
15577   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15578
15579   return self->priv->n_children;
15580 }
15581
15582 /**
15583  * clutter_actor_get_child_at_index:
15584  * @self: a #ClutterActor
15585  * @index_: the position in the list of children
15586  *
15587  * Retrieves the actor at the given @index_ inside the list of
15588  * children of @self.
15589  *
15590  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15591  *
15592  * Since: 1.10
15593  */
15594 ClutterActor *
15595 clutter_actor_get_child_at_index (ClutterActor *self,
15596                                   gint          index_)
15597 {
15598   ClutterActor *iter;
15599   int i;
15600
15601   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15602   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15603
15604   for (iter = self->priv->first_child, i = 0;
15605        iter != NULL && i < index_;
15606        iter = iter->priv->next_sibling, i += 1)
15607     ;
15608
15609   return iter;
15610 }
15611
15612 /*< private >
15613  * _clutter_actor_foreach_child:
15614  * @actor: The actor whos children you want to iterate
15615  * @callback: The function to call for each child
15616  * @user_data: Private data to pass to @callback
15617  *
15618  * Calls a given @callback once for each child of the specified @actor and
15619  * passing the @user_data pointer each time.
15620  *
15621  * Return value: returns %TRUE if all children were iterated, else
15622  *    %FALSE if a callback broke out of iteration early.
15623  */
15624 gboolean
15625 _clutter_actor_foreach_child (ClutterActor           *self,
15626                               ClutterForeachCallback  callback,
15627                               gpointer                user_data)
15628 {
15629   ClutterActorPrivate *priv = self->priv;
15630   ClutterActor *iter;
15631   gboolean cont;
15632
15633   for (cont = TRUE, iter = priv->first_child;
15634        cont && iter != NULL;
15635        iter = iter->priv->next_sibling)
15636     {
15637       cont = callback (iter, user_data);
15638     }
15639
15640   return cont;
15641 }
15642
15643 #if 0
15644 /* For debugging purposes this gives us a simple way to print out
15645  * the scenegraph e.g in gdb using:
15646  * [|
15647  *   _clutter_actor_traverse (stage,
15648  *                            0,
15649  *                            clutter_debug_print_actor_cb,
15650  *                            NULL,
15651  *                            NULL);
15652  * |]
15653  */
15654 static ClutterActorTraverseVisitFlags
15655 clutter_debug_print_actor_cb (ClutterActor *actor,
15656                               int depth,
15657                               void *user_data)
15658 {
15659   g_print ("%*s%s:%p\n",
15660            depth * 2, "",
15661            _clutter_actor_get_debug_name (actor),
15662            actor);
15663
15664   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15665 }
15666 #endif
15667
15668 static void
15669 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15670                                  ClutterTraverseCallback callback,
15671                                  gpointer                user_data)
15672 {
15673   GQueue *queue = g_queue_new ();
15674   ClutterActor dummy;
15675   int current_depth = 0;
15676
15677   g_queue_push_tail (queue, actor);
15678   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15679
15680   while ((actor = g_queue_pop_head (queue)))
15681     {
15682       ClutterActorTraverseVisitFlags flags;
15683
15684       if (actor == &dummy)
15685         {
15686           current_depth++;
15687           g_queue_push_tail (queue, &dummy);
15688           continue;
15689         }
15690
15691       flags = callback (actor, current_depth, user_data);
15692       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15693         break;
15694       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15695         {
15696           ClutterActor *iter;
15697
15698           for (iter = actor->priv->first_child;
15699                iter != NULL;
15700                iter = iter->priv->next_sibling)
15701             {
15702               g_queue_push_tail (queue, iter);
15703             }
15704         }
15705     }
15706
15707   g_queue_free (queue);
15708 }
15709
15710 static ClutterActorTraverseVisitFlags
15711 _clutter_actor_traverse_depth (ClutterActor           *actor,
15712                                ClutterTraverseCallback before_children_callback,
15713                                ClutterTraverseCallback after_children_callback,
15714                                int                     current_depth,
15715                                gpointer                user_data)
15716 {
15717   ClutterActorTraverseVisitFlags flags;
15718
15719   flags = before_children_callback (actor, current_depth, user_data);
15720   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15721     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15722
15723   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15724     {
15725       ClutterActor *iter;
15726
15727       for (iter = actor->priv->first_child;
15728            iter != NULL;
15729            iter = iter->priv->next_sibling)
15730         {
15731           flags = _clutter_actor_traverse_depth (iter,
15732                                                  before_children_callback,
15733                                                  after_children_callback,
15734                                                  current_depth + 1,
15735                                                  user_data);
15736
15737           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15738             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15739         }
15740     }
15741
15742   if (after_children_callback)
15743     return after_children_callback (actor, current_depth, user_data);
15744   else
15745     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15746 }
15747
15748 /* _clutter_actor_traverse:
15749  * @actor: The actor to start traversing the graph from
15750  * @flags: These flags may affect how the traversal is done
15751  * @before_children_callback: A function to call before visiting the
15752  *   children of the current actor.
15753  * @after_children_callback: A function to call after visiting the
15754  *   children of the current actor. (Ignored if
15755  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15756  * @user_data: The private data to pass to the callbacks
15757  *
15758  * Traverses the scenegraph starting at the specified @actor and
15759  * descending through all its children and its children's children.
15760  * For each actor traversed @before_children_callback and
15761  * @after_children_callback are called with the specified
15762  * @user_data, before and after visiting that actor's children.
15763  *
15764  * The callbacks can return flags that affect the ongoing traversal
15765  * such as by skipping over an actors children or bailing out of
15766  * any further traversing.
15767  */
15768 void
15769 _clutter_actor_traverse (ClutterActor              *actor,
15770                          ClutterActorTraverseFlags  flags,
15771                          ClutterTraverseCallback    before_children_callback,
15772                          ClutterTraverseCallback    after_children_callback,
15773                          gpointer                   user_data)
15774 {
15775   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15776     _clutter_actor_traverse_breadth (actor,
15777                                      before_children_callback,
15778                                      user_data);
15779   else /* DEPTH_FIRST */
15780     _clutter_actor_traverse_depth (actor,
15781                                    before_children_callback,
15782                                    after_children_callback,
15783                                    0, /* start depth */
15784                                    user_data);
15785 }
15786
15787 static void
15788 on_layout_manager_changed (ClutterLayoutManager *manager,
15789                            ClutterActor         *self)
15790 {
15791   clutter_actor_queue_relayout (self);
15792 }
15793
15794 /**
15795  * clutter_actor_set_layout_manager:
15796  * @self: a #ClutterActor
15797  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15798  *
15799  * Sets the #ClutterLayoutManager delegate object that will be used to
15800  * lay out the children of @self.
15801  *
15802  * The #ClutterActor will take a reference on the passed @manager which
15803  * will be released either when the layout manager is removed, or when
15804  * the actor is destroyed.
15805  *
15806  * Since: 1.10
15807  */
15808 void
15809 clutter_actor_set_layout_manager (ClutterActor         *self,
15810                                   ClutterLayoutManager *manager)
15811 {
15812   ClutterActorPrivate *priv;
15813
15814   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15815   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15816
15817   priv = self->priv;
15818
15819   if (priv->layout_manager != NULL)
15820     {
15821       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15822                                             G_CALLBACK (on_layout_manager_changed),
15823                                             self);
15824       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15825       g_object_unref (priv->layout_manager);
15826     }
15827
15828   priv->layout_manager = manager;
15829
15830   if (priv->layout_manager != NULL)
15831     {
15832       g_object_ref_sink (priv->layout_manager);
15833       clutter_layout_manager_set_container (priv->layout_manager,
15834                                             CLUTTER_CONTAINER (self));
15835       g_signal_connect (priv->layout_manager, "layout-changed",
15836                         G_CALLBACK (on_layout_manager_changed),
15837                         self);
15838     }
15839
15840   clutter_actor_queue_relayout (self);
15841
15842   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15843 }
15844
15845 /**
15846  * clutter_actor_get_layout_manager:
15847  * @self: a #ClutterActor
15848  *
15849  * Retrieves the #ClutterLayoutManager used by @self.
15850  *
15851  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15852  *   or %NULL
15853  *
15854  * Since: 1.10
15855  */
15856 ClutterLayoutManager *
15857 clutter_actor_get_layout_manager (ClutterActor *self)
15858 {
15859   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15860
15861   return self->priv->layout_manager;
15862 }
15863
15864 static const ClutterLayoutInfo default_layout_info = {
15865   0.f,                          /* fixed-x */
15866   0.f,                          /* fixed-y */
15867   { 0, 0, 0, 0 },               /* margin */
15868   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15869   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15870   0.f, 0.f,                     /* min_width, natural_width */
15871   0.f, 0.f,                     /* natual_width, natural_height */
15872 };
15873
15874 static void
15875 layout_info_free (gpointer data)
15876 {
15877   if (G_LIKELY (data != NULL))
15878     g_slice_free (ClutterLayoutInfo, data);
15879 }
15880
15881 /*< private >
15882  * _clutter_actor_get_layout_info:
15883  * @self: a #ClutterActor
15884  *
15885  * Retrieves a pointer to the ClutterLayoutInfo structure.
15886  *
15887  * If the actor does not have a ClutterLayoutInfo associated to it, one
15888  * will be created and initialized to the default values.
15889  *
15890  * This function should be used for setters.
15891  *
15892  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15893  * instead.
15894  *
15895  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15896  */
15897 ClutterLayoutInfo *
15898 _clutter_actor_get_layout_info (ClutterActor *self)
15899 {
15900   ClutterLayoutInfo *retval;
15901
15902   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15903   if (retval == NULL)
15904     {
15905       retval = g_slice_new (ClutterLayoutInfo);
15906
15907       *retval = default_layout_info;
15908
15909       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15910                                retval,
15911                                layout_info_free);
15912     }
15913
15914   return retval;
15915 }
15916
15917 /*< private >
15918  * _clutter_actor_get_layout_info_or_defaults:
15919  * @self: a #ClutterActor
15920  *
15921  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15922  *
15923  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15924  * then the default structure will be returned.
15925  *
15926  * This function should only be used for getters.
15927  *
15928  * Return value: a const pointer to the ClutterLayoutInfo structure
15929  */
15930 const ClutterLayoutInfo *
15931 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15932 {
15933   const ClutterLayoutInfo *info;
15934
15935   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15936   if (info == NULL)
15937     return &default_layout_info;
15938
15939   return info;
15940 }
15941
15942 /**
15943  * clutter_actor_set_x_align:
15944  * @self: a #ClutterActor
15945  * @x_align: the horizontal alignment policy
15946  *
15947  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15948  * actor received extra horizontal space.
15949  *
15950  * See also the #ClutterActor:x-align property.
15951  *
15952  * Since: 1.10
15953  */
15954 void
15955 clutter_actor_set_x_align (ClutterActor      *self,
15956                            ClutterActorAlign  x_align)
15957 {
15958   ClutterLayoutInfo *info;
15959
15960   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15961
15962   info = _clutter_actor_get_layout_info (self);
15963
15964   if (info->x_align != x_align)
15965     {
15966       info->x_align = x_align;
15967
15968       clutter_actor_queue_relayout (self);
15969
15970       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15971     }
15972 }
15973
15974 /**
15975  * clutter_actor_get_x_align:
15976  * @self: a #ClutterActor
15977  *
15978  * Retrieves the horizontal alignment policy set using
15979  * clutter_actor_set_x_align().
15980  *
15981  * Return value: the horizontal alignment policy.
15982  *
15983  * Since: 1.10
15984  */
15985 ClutterActorAlign
15986 clutter_actor_get_x_align (ClutterActor *self)
15987 {
15988   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15989
15990   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15991 }
15992
15993 /**
15994  * clutter_actor_set_y_align:
15995  * @self: a #ClutterActor
15996  * @y_align: the vertical alignment policy
15997  *
15998  * Sets the vertical alignment policy of a #ClutterActor, in case the
15999  * actor received extra vertical space.
16000  *
16001  * See also the #ClutterActor:y-align property.
16002  *
16003  * Since: 1.10
16004  */
16005 void
16006 clutter_actor_set_y_align (ClutterActor      *self,
16007                            ClutterActorAlign  y_align)
16008 {
16009   ClutterLayoutInfo *info;
16010
16011   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16012
16013   info = _clutter_actor_get_layout_info (self);
16014
16015   if (info->y_align != y_align)
16016     {
16017       info->y_align = y_align;
16018
16019       clutter_actor_queue_relayout (self);
16020
16021       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16022     }
16023 }
16024
16025 /**
16026  * clutter_actor_get_y_align:
16027  * @self: a #ClutterActor
16028  *
16029  * Retrieves the vertical alignment policy set using
16030  * clutter_actor_set_y_align().
16031  *
16032  * Return value: the vertical alignment policy.
16033  *
16034  * Since: 1.10
16035  */
16036 ClutterActorAlign
16037 clutter_actor_get_y_align (ClutterActor *self)
16038 {
16039   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16040
16041   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16042 }
16043
16044
16045 /**
16046  * clutter_margin_new:
16047  *
16048  * Creates a new #ClutterMargin.
16049  *
16050  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16051  *   clutter_margin_free() to free the resources associated with it when
16052  *   done.
16053  *
16054  * Since: 1.10
16055  */
16056 ClutterMargin *
16057 clutter_margin_new (void)
16058 {
16059   return g_slice_new0 (ClutterMargin);
16060 }
16061
16062 /**
16063  * clutter_margin_copy:
16064  * @margin_: a #ClutterMargin
16065  *
16066  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16067  * the newly created structure.
16068  *
16069  * Return value: (transfer full): a copy of the #ClutterMargin.
16070  *
16071  * Since: 1.10
16072  */
16073 ClutterMargin *
16074 clutter_margin_copy (const ClutterMargin *margin_)
16075 {
16076   if (G_LIKELY (margin_ != NULL))
16077     return g_slice_dup (ClutterMargin, margin_);
16078
16079   return NULL;
16080 }
16081
16082 /**
16083  * clutter_margin_free:
16084  * @margin_: a #ClutterMargin
16085  *
16086  * Frees the resources allocated by clutter_margin_new() and
16087  * clutter_margin_copy().
16088  *
16089  * Since: 1.10
16090  */
16091 void
16092 clutter_margin_free (ClutterMargin *margin_)
16093 {
16094   if (G_LIKELY (margin_ != NULL))
16095     g_slice_free (ClutterMargin, margin_);
16096 }
16097
16098 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16099                      clutter_margin_copy,
16100                      clutter_margin_free)
16101
16102 /**
16103  * clutter_actor_set_margin:
16104  * @self: a #ClutterActor
16105  * @margin: a #ClutterMargin
16106  *
16107  * Sets all the components of the margin of a #ClutterActor.
16108  *
16109  * Since: 1.10
16110  */
16111 void
16112 clutter_actor_set_margin (ClutterActor        *self,
16113                           const ClutterMargin *margin)
16114 {
16115   ClutterLayoutInfo *info;
16116   gboolean changed;
16117   GObject *obj;
16118
16119   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16120   g_return_if_fail (margin != NULL);
16121
16122   obj = G_OBJECT (self);
16123   changed = FALSE;
16124
16125   g_object_freeze_notify (obj);
16126
16127   info = _clutter_actor_get_layout_info (self);
16128
16129   if (info->margin.top != margin->top)
16130     {
16131       info->margin.top = margin->top;
16132       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16133       changed = TRUE;
16134     }
16135
16136   if (info->margin.right != margin->right)
16137     {
16138       info->margin.right = margin->right;
16139       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16140       changed = TRUE;
16141     }
16142
16143   if (info->margin.bottom != margin->bottom)
16144     {
16145       info->margin.bottom = margin->bottom;
16146       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16147       changed = TRUE;
16148     }
16149
16150   if (info->margin.left != margin->left)
16151     {
16152       info->margin.left = margin->left;
16153       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16154       changed = TRUE;
16155     }
16156
16157   if (changed)
16158     clutter_actor_queue_relayout (self);
16159
16160   g_object_thaw_notify (obj);
16161 }
16162
16163 /**
16164  * clutter_actor_get_margin:
16165  * @self: a #ClutterActor
16166  * @margin: (out caller-allocates): return location for a #ClutterMargin
16167  *
16168  * Retrieves all the components of the margin of a #ClutterActor.
16169  *
16170  * Since: 1.10
16171  */
16172 void
16173 clutter_actor_get_margin (ClutterActor  *self,
16174                           ClutterMargin *margin)
16175 {
16176   const ClutterLayoutInfo *info;
16177
16178   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16179   g_return_if_fail (margin != NULL);
16180
16181   info = _clutter_actor_get_layout_info_or_defaults (self);
16182
16183   *margin = info->margin;
16184 }
16185
16186 /**
16187  * clutter_actor_set_margin_top:
16188  * @self: a #ClutterActor
16189  * @margin: the top margin
16190  *
16191  * Sets the margin from the top of a #ClutterActor.
16192  *
16193  * Since: 1.10
16194  */
16195 void
16196 clutter_actor_set_margin_top (ClutterActor *self,
16197                               gfloat        margin)
16198 {
16199   ClutterLayoutInfo *info;
16200
16201   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16202   g_return_if_fail (margin >= 0.f);
16203
16204   info = _clutter_actor_get_layout_info (self);
16205
16206   if (info->margin.top == margin)
16207     return;
16208
16209   info->margin.top = margin;
16210
16211   clutter_actor_queue_relayout (self);
16212
16213   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16214 }
16215
16216 /**
16217  * clutter_actor_get_margin_top:
16218  * @self: a #ClutterActor
16219  *
16220  * Retrieves the top margin of a #ClutterActor.
16221  *
16222  * Return value: the top margin
16223  *
16224  * Since: 1.10
16225  */
16226 gfloat
16227 clutter_actor_get_margin_top (ClutterActor *self)
16228 {
16229   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16230
16231   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16232 }
16233
16234 /**
16235  * clutter_actor_set_margin_bottom:
16236  * @self: a #ClutterActor
16237  * @margin: the bottom margin
16238  *
16239  * Sets the margin from the bottom of a #ClutterActor.
16240  *
16241  * Since: 1.10
16242  */
16243 void
16244 clutter_actor_set_margin_bottom (ClutterActor *self,
16245                                  gfloat        margin)
16246 {
16247   ClutterLayoutInfo *info;
16248
16249   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16250   g_return_if_fail (margin >= 0.f);
16251
16252   info = _clutter_actor_get_layout_info (self);
16253
16254   if (info->margin.bottom == margin)
16255     return;
16256
16257   info->margin.bottom = margin;
16258
16259   clutter_actor_queue_relayout (self);
16260
16261   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16262 }
16263
16264 /**
16265  * clutter_actor_get_margin_bottom:
16266  * @self: a #ClutterActor
16267  *
16268  * Retrieves the bottom margin of a #ClutterActor.
16269  *
16270  * Return value: the bottom margin
16271  *
16272  * Since: 1.10
16273  */
16274 gfloat
16275 clutter_actor_get_margin_bottom (ClutterActor *self)
16276 {
16277   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16278
16279   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16280 }
16281
16282 /**
16283  * clutter_actor_set_margin_left:
16284  * @self: a #ClutterActor
16285  * @margin: the left margin
16286  *
16287  * Sets the margin from the left of a #ClutterActor.
16288  *
16289  * Since: 1.10
16290  */
16291 void
16292 clutter_actor_set_margin_left (ClutterActor *self,
16293                                gfloat        margin)
16294 {
16295   ClutterLayoutInfo *info;
16296
16297   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16298   g_return_if_fail (margin >= 0.f);
16299
16300   info = _clutter_actor_get_layout_info (self);
16301
16302   if (info->margin.left == margin)
16303     return;
16304
16305   info->margin.left = margin;
16306
16307   clutter_actor_queue_relayout (self);
16308
16309   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16310 }
16311
16312 /**
16313  * clutter_actor_get_margin_left:
16314  * @self: a #ClutterActor
16315  *
16316  * Retrieves the left margin of a #ClutterActor.
16317  *
16318  * Return value: the left margin
16319  *
16320  * Since: 1.10
16321  */
16322 gfloat
16323 clutter_actor_get_margin_left (ClutterActor *self)
16324 {
16325   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16326
16327   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16328 }
16329
16330 /**
16331  * clutter_actor_set_margin_right:
16332  * @self: a #ClutterActor
16333  * @margin: the right margin
16334  *
16335  * Sets the margin from the right of a #ClutterActor.
16336  *
16337  * Since: 1.10
16338  */
16339 void
16340 clutter_actor_set_margin_right (ClutterActor *self,
16341                                 gfloat        margin)
16342 {
16343   ClutterLayoutInfo *info;
16344
16345   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16346   g_return_if_fail (margin >= 0.f);
16347
16348   info = _clutter_actor_get_layout_info (self);
16349
16350   if (info->margin.right == margin)
16351     return;
16352
16353   info->margin.right = margin;
16354
16355   clutter_actor_queue_relayout (self);
16356
16357   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16358 }
16359
16360 /**
16361  * clutter_actor_get_margin_right:
16362  * @self: a #ClutterActor
16363  *
16364  * Retrieves the right margin of a #ClutterActor.
16365  *
16366  * Return value: the right margin
16367  *
16368  * Since: 1.10
16369  */
16370 gfloat
16371 clutter_actor_get_margin_right (ClutterActor *self)
16372 {
16373   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16374
16375   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16376 }
16377
16378 static inline void
16379 clutter_actor_set_background_color_internal (ClutterActor *self,
16380                                              const ClutterColor *color)
16381 {
16382   ClutterActorPrivate *priv = self->priv;
16383   GObject *obj;
16384
16385   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16386     return;
16387
16388   obj = G_OBJECT (self);
16389
16390   priv->bg_color = *color;
16391   priv->bg_color_set = TRUE;
16392
16393   clutter_actor_queue_redraw (self);
16394
16395   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16396   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16397 }
16398
16399 /**
16400  * clutter_actor_set_background_color:
16401  * @self: a #ClutterActor
16402  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16403  *  set color
16404  *
16405  * Sets the background color of a #ClutterActor.
16406  *
16407  * The background color will be used to cover the whole allocation of the
16408  * actor. The default background color of an actor is transparent.
16409  *
16410  * To check whether an actor has a background color, you can use the
16411  * #ClutterActor:background-color-set actor property.
16412  *
16413  * The #ClutterActor:background-color property is animatable.
16414  *
16415  * Since: 1.10
16416  */
16417 void
16418 clutter_actor_set_background_color (ClutterActor       *self,
16419                                     const ClutterColor *color)
16420 {
16421   ClutterActorPrivate *priv;
16422   GObject *obj;
16423   GParamSpec *bg_color_pspec;
16424
16425   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16426
16427   obj = G_OBJECT (self);
16428
16429   priv = self->priv;
16430
16431   if (color == NULL)
16432     {
16433       priv->bg_color_set = FALSE;
16434       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16435       clutter_actor_queue_redraw (self);
16436       return;
16437     }
16438
16439   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16440   if (clutter_actor_get_easing_duration (self) != 0)
16441     {
16442       ClutterTransition *transition;
16443
16444       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16445       if (transition == NULL)
16446         {
16447           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16448                                                          &priv->bg_color,
16449                                                          color);
16450           clutter_timeline_start (CLUTTER_TIMELINE (transition));
16451         }
16452       else
16453         _clutter_actor_update_transition (self, bg_color_pspec, color);
16454
16455       clutter_actor_queue_redraw (self);
16456     }
16457   else
16458     clutter_actor_set_background_color_internal (self, color);
16459 }
16460
16461 /**
16462  * clutter_actor_get_background_color:
16463  * @self: a #ClutterActor
16464  * @color: (out caller-allocates): return location for a #ClutterColor
16465  *
16466  * Retrieves the color set using clutter_actor_set_background_color().
16467  *
16468  * Since: 1.10
16469  */
16470 void
16471 clutter_actor_get_background_color (ClutterActor *self,
16472                                     ClutterColor *color)
16473 {
16474   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16475   g_return_if_fail (color != NULL);
16476
16477   *color = self->priv->bg_color;
16478 }
16479
16480 /**
16481  * clutter_actor_get_previous_sibling:
16482  * @self: a #ClutterActor
16483  *
16484  * Retrieves the sibling of @self that comes before it in the list
16485  * of children of @self's parent.
16486  *
16487  * The returned pointer is only valid until the scene graph changes; it
16488  * is not safe to modify the list of children of @self while iterating
16489  * it.
16490  *
16491  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16492  *
16493  * Since: 1.10
16494  */
16495 ClutterActor *
16496 clutter_actor_get_previous_sibling (ClutterActor *self)
16497 {
16498   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16499
16500   return self->priv->prev_sibling;
16501 }
16502
16503 /**
16504  * clutter_actor_get_next_sibling:
16505  * @self: a #ClutterActor
16506  *
16507  * Retrieves the sibling of @self that comes after it in the list
16508  * of children of @self's parent.
16509  *
16510  * The returned pointer is only valid until the scene graph changes; it
16511  * is not safe to modify the list of children of @self while iterating
16512  * it.
16513  *
16514  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16515  *
16516  * Since: 1.10
16517  */
16518 ClutterActor *
16519 clutter_actor_get_next_sibling (ClutterActor *self)
16520 {
16521   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16522
16523   return self->priv->next_sibling;
16524 }
16525
16526 /**
16527  * clutter_actor_get_first_child:
16528  * @self: a #ClutterActor
16529  *
16530  * Retrieves the first child of @self.
16531  *
16532  * The returned pointer is only valid until the scene graph changes; it
16533  * is not safe to modify the list of children of @self while iterating
16534  * it.
16535  *
16536  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16537  *
16538  * Since: 1.10
16539  */
16540 ClutterActor *
16541 clutter_actor_get_first_child (ClutterActor *self)
16542 {
16543   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16544
16545   return self->priv->first_child;
16546 }
16547
16548 /**
16549  * clutter_actor_get_last_child:
16550  * @self: a #ClutterActor
16551  *
16552  * Retrieves the last child of @self.
16553  *
16554  * The returned pointer is only valid until the scene graph changes; it
16555  * is not safe to modify the list of children of @self while iterating
16556  * it.
16557  *
16558  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16559  *
16560  * Since: 1.10
16561  */
16562 ClutterActor *
16563 clutter_actor_get_last_child (ClutterActor *self)
16564 {
16565   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16566
16567   return self->priv->last_child;
16568 }
16569
16570 /* easy way to have properly named fields instead of the dummy ones
16571  * we use in the public structure
16572  */
16573 typedef struct _RealActorIter
16574 {
16575   ClutterActor *root;           /* dummy1 */
16576   ClutterActor *current;        /* dummy2 */
16577   gpointer padding_1;           /* dummy3 */
16578   gint age;                     /* dummy4 */
16579   gpointer padding_2;           /* dummy5 */
16580 } RealActorIter;
16581
16582 /**
16583  * clutter_actor_iter_init:
16584  * @iter: a #ClutterActorIter
16585  * @root: a #ClutterActor
16586  *
16587  * Initializes a #ClutterActorIter, which can then be used to iterate
16588  * efficiently over a section of the scene graph, and associates it
16589  * with @root.
16590  *
16591  * Modifying the scene graph section that contains @root will invalidate
16592  * the iterator.
16593  *
16594  * |[
16595  *   ClutterActorIter iter;
16596  *   ClutterActor *child;
16597  *
16598  *   clutter_actor_iter_init (&iter, container);
16599  *   while (clutter_actor_iter_next (&iter, &child))
16600  *     {
16601  *       /&ast; do something with child &ast;/
16602  *     }
16603  * ]|
16604  *
16605  * Since: 1.10
16606  */
16607 void
16608 clutter_actor_iter_init (ClutterActorIter *iter,
16609                          ClutterActor     *root)
16610 {
16611   RealActorIter *ri = (RealActorIter *) iter;
16612
16613   g_return_if_fail (iter != NULL);
16614   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16615
16616   ri->root = root;
16617   ri->current = NULL;
16618   ri->age = root->priv->age;
16619 }
16620
16621 /**
16622  * clutter_actor_iter_next:
16623  * @iter: a #ClutterActorIter
16624  * @child: (out): return location for a #ClutterActor
16625  *
16626  * Advances the @iter and retrieves the next child of the root #ClutterActor
16627  * that was used to initialize the #ClutterActorIterator.
16628  *
16629  * If the iterator can advance, this function returns %TRUE and sets the
16630  * @child argument.
16631  *
16632  * If the iterator cannot advance, this function returns %FALSE, and
16633  * the contents of @child are undefined.
16634  *
16635  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16636  *
16637  * Since: 1.10
16638  */
16639 gboolean
16640 clutter_actor_iter_next (ClutterActorIter  *iter,
16641                          ClutterActor     **child)
16642 {
16643   RealActorIter *ri = (RealActorIter *) iter;
16644
16645   g_return_val_if_fail (iter != NULL, FALSE);
16646   g_return_val_if_fail (ri->root != NULL, FALSE);
16647 #ifndef G_DISABLE_ASSERT
16648   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16649 #endif
16650
16651   if (ri->current == NULL)
16652     ri->current = ri->root->priv->first_child;
16653   else
16654     ri->current = ri->current->priv->next_sibling;
16655
16656   if (child != NULL)
16657     *child = ri->current;
16658
16659   return ri->current != NULL;
16660 }
16661
16662 /**
16663  * clutter_actor_iter_prev:
16664  * @iter: a #ClutterActorIter
16665  * @child: (out): return location for a #ClutterActor
16666  *
16667  * Advances the @iter and retrieves the previous child of the root
16668  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16669  *
16670  * If the iterator can advance, this function returns %TRUE and sets the
16671  * @child argument.
16672  *
16673  * If the iterator cannot advance, this function returns %FALSE, and
16674  * the contents of @child are undefined.
16675  *
16676  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16677  *
16678  * Since: 1.10
16679  */
16680 gboolean
16681 clutter_actor_iter_prev (ClutterActorIter  *iter,
16682                          ClutterActor     **child)
16683 {
16684   RealActorIter *ri = (RealActorIter *) iter;
16685
16686   g_return_val_if_fail (iter != NULL, FALSE);
16687   g_return_val_if_fail (ri->root != NULL, FALSE);
16688 #ifndef G_DISABLE_ASSERT
16689   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16690 #endif
16691
16692   if (ri->current == NULL)
16693     ri->current = ri->root->priv->last_child;
16694   else
16695     ri->current = ri->current->priv->prev_sibling;
16696
16697   if (child != NULL)
16698     *child = ri->current;
16699
16700   return ri->current != NULL;
16701 }
16702
16703 /**
16704  * clutter_actor_iter_remove:
16705  * @iter: a #ClutterActorIter
16706  *
16707  * Safely removes the #ClutterActor currently pointer to by the iterator
16708  * from its parent.
16709  *
16710  * This function can only be called after clutter_actor_iter_next() or
16711  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16712  * than once for the same actor.
16713  *
16714  * This function will call clutter_actor_remove_child() internally.
16715  *
16716  * Since: 1.10
16717  */
16718 void
16719 clutter_actor_iter_remove (ClutterActorIter *iter)
16720 {
16721   RealActorIter *ri = (RealActorIter *) iter;
16722   ClutterActor *cur;
16723
16724   g_return_if_fail (iter != NULL);
16725   g_return_if_fail (ri->root != NULL);
16726 #ifndef G_DISABLE_ASSERT
16727   g_return_if_fail (ri->age == ri->root->priv->age);
16728 #endif
16729   g_return_if_fail (ri->current != NULL);
16730
16731   cur = ri->current;
16732
16733   if (cur != NULL)
16734     {
16735       ri->current = cur->priv->prev_sibling;
16736
16737       clutter_actor_remove_child_internal (ri->root, cur,
16738                                            REMOVE_CHILD_DEFAULT_FLAGS);
16739
16740       ri->age += 1;
16741     }
16742 }
16743
16744 /**
16745  * clutter_actor_iter_destroy:
16746  * @iter: a #ClutterActorIter
16747  *
16748  * Safely destroys the #ClutterActor currently pointer to by the iterator
16749  * from its parent.
16750  *
16751  * This function can only be called after clutter_actor_iter_next() or
16752  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16753  * than once for the same actor.
16754  *
16755  * This function will call clutter_actor_destroy() internally.
16756  *
16757  * Since: 1.10
16758  */
16759 void
16760 clutter_actor_iter_destroy (ClutterActorIter *iter)
16761 {
16762   RealActorIter *ri = (RealActorIter *) iter;
16763   ClutterActor *cur;
16764
16765   g_return_if_fail (iter != NULL);
16766   g_return_if_fail (ri->root != NULL);
16767 #ifndef G_DISABLE_ASSERT
16768   g_return_if_fail (ri->age == ri->root->priv->age);
16769 #endif
16770   g_return_if_fail (ri->current != NULL);
16771
16772   cur = ri->current;
16773
16774   if (cur != NULL)
16775     {
16776       ri->current = cur->priv->prev_sibling;
16777
16778       clutter_actor_destroy (cur);
16779
16780       ri->age += 1;
16781     }
16782 }
16783
16784 static const ClutterAnimationInfo default_animation_info = {
16785   NULL,         /* transitions */
16786   NULL,         /* states */
16787   NULL,         /* cur_state */
16788 };
16789
16790 static void
16791 clutter_animation_info_free (gpointer data)
16792 {
16793   if (data != NULL)
16794     {
16795       ClutterAnimationInfo *info = data;
16796
16797       if (info->transitions != NULL)
16798         g_hash_table_unref (info->transitions);
16799
16800       if (info->states != NULL)
16801         g_array_unref (info->states);
16802
16803       g_slice_free (ClutterAnimationInfo, info);
16804     }
16805 }
16806
16807 const ClutterAnimationInfo *
16808 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16809 {
16810   const ClutterAnimationInfo *res;
16811   GObject *obj = G_OBJECT (self);
16812
16813   res = g_object_get_qdata (obj, quark_actor_animation_info);
16814   if (res != NULL)
16815     return res;
16816
16817   return &default_animation_info;
16818 }
16819
16820 ClutterAnimationInfo *
16821 _clutter_actor_get_animation_info (ClutterActor *self)
16822 {
16823   GObject *obj = G_OBJECT (self);
16824   ClutterAnimationInfo *res;
16825
16826   res = g_object_get_qdata (obj, quark_actor_animation_info);
16827   if (res == NULL)
16828     {
16829       res = g_slice_new (ClutterAnimationInfo);
16830
16831       *res = default_animation_info;
16832
16833       g_object_set_qdata_full (obj, quark_actor_animation_info,
16834                                res,
16835                                clutter_animation_info_free);
16836     }
16837
16838   return res;
16839 }
16840
16841 ClutterTransition *
16842 _clutter_actor_get_transition (ClutterActor *actor,
16843                                GParamSpec   *pspec)
16844 {
16845   const ClutterAnimationInfo *info;
16846
16847   info = _clutter_actor_get_animation_info_or_defaults (actor);
16848
16849   if (info->transitions == NULL)
16850     return NULL;
16851
16852   return g_hash_table_lookup (info->transitions, pspec->name);
16853 }
16854
16855 typedef struct _TransitionClosure
16856 {
16857   ClutterActor *actor;
16858   ClutterTransition *transition;
16859   gchar *name;
16860   gulong completed_id;
16861 } TransitionClosure;
16862
16863 static void
16864 transition_closure_free (gpointer data)
16865 {
16866   if (G_LIKELY (data != NULL))
16867     {
16868       TransitionClosure *clos = data;
16869
16870       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16871       g_free (clos->name);
16872
16873       g_slice_free (TransitionClosure, clos);
16874     }
16875 }
16876
16877 static void
16878 on_transition_completed (ClutterTransition *transition,
16879                          TransitionClosure *clos)
16880 {
16881   ClutterAnimationInfo *info;
16882
16883   info = _clutter_actor_get_animation_info (clos->actor);
16884
16885   /* this will take care of cleaning clos for us */
16886   g_hash_table_remove (info->transitions, clos->name);
16887 }
16888
16889 void
16890 _clutter_actor_update_transition (ClutterActor *actor,
16891                                   GParamSpec   *pspec,
16892                                   ...)
16893 {
16894   TransitionClosure *clos;
16895   ClutterInterval *interval;
16896   const ClutterAnimationInfo *info;
16897   va_list var_args;
16898   GType ptype;
16899   GValue initial = G_VALUE_INIT;
16900   GValue final = G_VALUE_INIT;
16901   char *error = NULL;
16902
16903   info = _clutter_actor_get_animation_info_or_defaults (actor);
16904
16905   if (info->transitions == NULL)
16906     return;
16907
16908   clos = g_hash_table_lookup (info->transitions, pspec->name);
16909   if (clos == NULL)
16910     return;
16911
16912   va_start (var_args, pspec);
16913
16914   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16915
16916   g_value_init (&initial, ptype);
16917   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16918                                         pspec->name,
16919                                         &initial);
16920
16921   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16922   if (error != NULL)
16923     {
16924       g_critical ("%s: %s", G_STRLOC, error);
16925       g_free (error);
16926       goto out;
16927     }
16928
16929   interval = clutter_transition_get_interval (clos->transition);
16930   clutter_interval_set_initial_value (interval, &initial);
16931   clutter_interval_set_final_value (interval, &final);
16932
16933   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16934
16935 out:
16936   g_value_unset (&initial);
16937   g_value_unset (&final);
16938
16939   va_end (var_args);
16940 }
16941
16942 /*< private >*
16943  * _clutter_actor_create_transition:
16944  * @actor: a #ClutterActor
16945  * @pspec: the property used for the transition
16946  * @...: initial and final state
16947  *
16948  * Creates a #ClutterTransition for the property represented by @pspec.
16949  *
16950  * Return value: a #ClutterTransition
16951  */
16952 ClutterTransition *
16953 _clutter_actor_create_transition (ClutterActor *actor,
16954                                   GParamSpec   *pspec,
16955                                   ...)
16956 {
16957   ClutterAnimationInfo *info;
16958   ClutterTransition *res = NULL;
16959   gboolean call_restore = FALSE;
16960   TransitionClosure *clos;
16961   va_list var_args;
16962
16963   info = _clutter_actor_get_animation_info (actor);
16964
16965   if (info->states == NULL)
16966     {
16967       clutter_actor_save_easing_state (actor);
16968       call_restore = TRUE;
16969     }
16970
16971   if (info->transitions == NULL)
16972     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16973                                                NULL,
16974                                                transition_closure_free);
16975
16976   va_start (var_args, pspec);
16977
16978   clos = g_hash_table_lookup (info->transitions, pspec->name);
16979   if (clos == NULL)
16980     {
16981       ClutterInterval *interval;
16982       GValue initial = G_VALUE_INIT;
16983       GValue final = G_VALUE_INIT;
16984       GType ptype;
16985       char *error;
16986
16987       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16988
16989       G_VALUE_COLLECT_INIT (&initial, ptype,
16990                             var_args, 0,
16991                             &error);
16992       if (error != NULL)
16993         {
16994           g_critical ("%s: %s", G_STRLOC, error);
16995           g_free (error);
16996           goto out;
16997         }
16998
16999       G_VALUE_COLLECT_INIT (&final, ptype,
17000                             var_args, 0,
17001                             &error);
17002
17003       if (error != NULL)
17004         {
17005           g_critical ("%s: %s", G_STRLOC, error);
17006           g_value_unset (&initial);
17007           g_free (error);
17008           goto out;
17009         }
17010
17011       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17012
17013       g_value_unset (&initial);
17014       g_value_unset (&final);
17015
17016       res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17017                                              pspec->name);
17018
17019       clutter_transition_set_interval (res, interval);
17020       clutter_transition_set_remove_on_complete (res, TRUE);
17021
17022       clutter_actor_add_transition (actor, pspec->name, res);
17023     }
17024   else
17025     res = clos->transition;
17026
17027 out:
17028   if (call_restore)
17029     clutter_actor_restore_easing_state (actor);
17030
17031   va_end (var_args);
17032
17033   return res;
17034 }
17035
17036 /**
17037  * clutter_actor_add_transition:
17038  * @self: a #ClutterActor
17039  * @name: the name of the transition to add
17040  * @transition: the #ClutterTransition to add
17041  *
17042  * Adds a @transition to the #ClutterActor's list of animations.
17043  *
17044  * The @name string is a per-actor unique identifier of the @transition: only
17045  * one #ClutterTransition can be associated to the specified @name.
17046  *
17047  * The @transition will be given the easing duration, mode, and delay
17048  * associated to the actor's current easing state; it is possible to modify
17049  * these values after calling clutter_actor_add_transition().
17050  *
17051  * This function is usually called implicitly when modifying an animatable
17052  * property.
17053  *
17054  * Since: 1.10
17055  */
17056 void
17057 clutter_actor_add_transition (ClutterActor      *self,
17058                               const char        *name,
17059                               ClutterTransition *transition)
17060 {
17061   ClutterTimeline *timeline;
17062   TransitionClosure *clos;
17063   ClutterAnimationInfo *info;
17064
17065   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17066   g_return_if_fail (name != NULL);
17067   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17068
17069   info = _clutter_actor_get_animation_info (self);
17070
17071   if (info->cur_state == NULL)
17072     {
17073       g_warning ("No easing state is defined for the actor '%s'; you "
17074                  "must call clutter_actor_save_easing_state() before "
17075                  "calling clutter_actor_add_transition().",
17076                  _clutter_actor_get_debug_name (self));
17077       return;
17078     }
17079
17080   if (info->transitions == NULL)
17081     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17082                                                NULL,
17083                                                transition_closure_free);
17084
17085   if (g_hash_table_lookup (info->transitions, name) != NULL)
17086     {
17087       g_warning ("A transition with name '%s' already exists for "
17088                  "the actor '%s'",
17089                  name,
17090                  _clutter_actor_get_debug_name (self));
17091       return;
17092     }
17093
17094   timeline = CLUTTER_TIMELINE (transition);
17095
17096   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17097   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17098   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17099
17100   clos = g_slice_new (TransitionClosure);
17101   clos->actor = self;
17102   clos->transition = transition;
17103   clos->name = g_strdup (name);
17104   clos->completed_id = g_signal_connect (timeline, "completed",
17105                                          G_CALLBACK (on_transition_completed),
17106                                          clos);
17107
17108   g_hash_table_insert (info->transitions, clos->name, clos);
17109 }
17110
17111 /**
17112  * clutter_actor_remove_transition:
17113  * @self: a #ClutterActor
17114  * @name: the name of the transition to remove
17115  *
17116  * Removes the transition stored inside a #ClutterActor using @name
17117  * identifier.
17118  *
17119  * Since: 1.10
17120  */
17121 void
17122 clutter_actor_remove_transition (ClutterActor *self,
17123                                  const char   *name)
17124 {
17125   const ClutterAnimationInfo *info;
17126
17127   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17128   g_return_if_fail (name != NULL);
17129
17130   info = _clutter_actor_get_animation_info_or_defaults (self);
17131
17132   if (info->transitions == NULL)
17133     return;
17134
17135   g_hash_table_remove (info->transitions, name);
17136 }
17137
17138 /**
17139  * clutter_actor_remove_all_transitions:
17140  * @self: a #ClutterActor
17141  *
17142  * Removes all transitions associated to @self.
17143  *
17144  * Since: 1.10
17145  */
17146 void
17147 clutter_actor_remove_all_transitions (ClutterActor *self)
17148 {
17149   const ClutterAnimationInfo *info;
17150
17151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17152
17153   info = _clutter_actor_get_animation_info_or_defaults (self);
17154   if (info->transitions == NULL)
17155     return;
17156
17157   g_hash_table_remove_all (info->transitions);
17158 }
17159
17160 /**
17161  * clutter_actor_set_easing_duration:
17162  * @self: a #ClutterActor
17163  * @msecs: the duration of the easing, or %NULL
17164  *
17165  * Sets the duration of the tweening for animatable properties
17166  * of @self for the current easing state.
17167  *
17168  * Calling this function will implicitly call
17169  * clutter_actor_save_easing_state() if no previous call to
17170  * that function was made.
17171  *
17172  * Since: 1.10
17173  */
17174 void
17175 clutter_actor_set_easing_duration (ClutterActor *self,
17176                                    guint         msecs)
17177 {
17178   ClutterAnimationInfo *info;
17179
17180   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17181
17182   info = _clutter_actor_get_animation_info (self);
17183
17184   if (info->states == NULL)
17185     clutter_actor_save_easing_state (self);
17186
17187   if (info->cur_state->easing_duration != msecs)
17188     info->cur_state->easing_duration = msecs;
17189 }
17190
17191 /**
17192  * clutter_actor_get_easing_duration:
17193  * @self: a #ClutterActor
17194  *
17195  * Retrieves the duration of the tweening for animatable
17196  * properties of @self for the current easing state.
17197  *
17198  * Return value: the duration of the tweening, in milliseconds
17199  *
17200  * Since: 1.10
17201  */
17202 guint
17203 clutter_actor_get_easing_duration (ClutterActor *self)
17204 {
17205   const ClutterAnimationInfo *info;
17206
17207   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17208
17209   info = _clutter_actor_get_animation_info_or_defaults (self);
17210
17211   if (info->cur_state != NULL)
17212     return info->cur_state->easing_duration;
17213
17214   return 0;
17215 }
17216
17217 /**
17218  * clutter_actor_set_easing_mode:
17219  * @self: a #ClutterActor
17220  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17221  *
17222  * Sets the easing mode for the tweening of animatable properties
17223  * of @self.
17224  *
17225  * Calling this function will implicitly call
17226  * clutter_actor_save_easing_state() if no previous calls to
17227  * that function were made.
17228  *
17229  * Since: 1.10
17230  */
17231 void
17232 clutter_actor_set_easing_mode (ClutterActor         *self,
17233                                ClutterAnimationMode  mode)
17234 {
17235   ClutterAnimationInfo *info;
17236
17237   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17238   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17239   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17240
17241   info = _clutter_actor_get_animation_info (self);
17242
17243   if (info->states == NULL)
17244     clutter_actor_save_easing_state (self);
17245
17246   if (info->cur_state->easing_mode != mode)
17247     info->cur_state->easing_mode = mode;
17248 }
17249
17250 /**
17251  * clutter_actor_get_easing_mode:
17252  * @self: a #ClutterActor
17253  *
17254  * Retrieves the easing mode for the tweening of animatable properties
17255  * of @self for the current easing state.
17256  *
17257  * Return value: an easing mode
17258  *
17259  * Since: 1.10
17260  */
17261 ClutterAnimationMode
17262 clutter_actor_get_easing_mode (ClutterActor *self)
17263 {
17264   const ClutterAnimationInfo *info;
17265
17266   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17267
17268   info = _clutter_actor_get_animation_info_or_defaults (self);
17269
17270   if (info->cur_state != NULL)
17271     return info->cur_state->easing_mode;
17272
17273   return CLUTTER_EASE_OUT_CUBIC;
17274 }
17275
17276 /**
17277  * clutter_actor_set_easing_delay:
17278  * @self: a #ClutterActor
17279  * @msecs: the delay before the start of the tweening, in milliseconds
17280  *
17281  * Sets the delay that should be applied before tweening animatable
17282  * properties.
17283  *
17284  * Calling this function will implicitly call
17285  * clutter_actor_save_easing_state() if no previous calls to
17286  * that function were made.
17287  *
17288  * Since: 1.10
17289  */
17290 void
17291 clutter_actor_set_easing_delay (ClutterActor *self,
17292                                 guint         msecs)
17293 {
17294   ClutterAnimationInfo *info;
17295
17296   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17297
17298   info = _clutter_actor_get_animation_info (self);
17299
17300   if (info->states == NULL)
17301     clutter_actor_save_easing_state (self);
17302
17303   if (info->cur_state->easing_delay != msecs)
17304     info->cur_state->easing_delay = msecs;
17305 }
17306
17307 /**
17308  * clutter_actor_get_easing_delay:
17309  * @self: a #ClutterActor
17310  *
17311  * Retrieves the delay that should be applied when tweening animatable
17312  * properties.
17313  *
17314  * Return value: a delay, in milliseconds
17315  *
17316  * Since: 1.10
17317  */
17318 guint
17319 clutter_actor_get_easing_delay (ClutterActor *self)
17320 {
17321   const ClutterAnimationInfo *info;
17322
17323   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17324
17325   info = _clutter_actor_get_animation_info_or_defaults (self);
17326
17327   if (info->cur_state != NULL)
17328     return info->cur_state->easing_delay;
17329
17330   return 0;
17331 }
17332
17333 /**
17334  * clutter_actor_get_transition:
17335  * @self: a #ClutterActor
17336  * @name: the name of the transition
17337  *
17338  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17339  * transition @name.
17340  *
17341  * Transitions created for animatable properties use the name of the
17342  * property itself, for instance the code below:
17343  *
17344  * |[
17345  *   clutter_actor_set_easing_duration (actor, 1000);
17346  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17347  *
17348  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17349  *   g_signal_connect (transition, "completed",
17350  *                     G_CALLBACK (on_transition_complete),
17351  *                     actor);
17352  * ]|
17353  *
17354  * will call the <function>on_transition_complete</function> callback when
17355  * the transition is complete.
17356  *
17357  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17358  *   was found to match the passed name; the returned instance is owned
17359  *   by Clutter and it should not be freed
17360  *
17361  * Since: 1.10
17362  */
17363 ClutterTransition *
17364 clutter_actor_get_transition (ClutterActor *self,
17365                               const char   *name)
17366 {
17367   TransitionClosure *clos;
17368   const ClutterAnimationInfo *info;
17369
17370   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17371   g_return_val_if_fail (name != NULL, NULL);
17372
17373   info = _clutter_actor_get_animation_info_or_defaults (self);
17374
17375   if (info->transitions == NULL)
17376     return NULL;
17377
17378   clos = g_hash_table_lookup (info->transitions, name);
17379   if (clos == NULL)
17380     return NULL;
17381
17382   return clos->transition;
17383 }
17384
17385 /**
17386  * clutter_actor_save_easing_state:
17387  * @self: a #ClutterActor
17388  *
17389  * Saves the current easing state for animatable properties, and creates
17390  * a new state with the default values for easing mode and duration.
17391  *
17392  * Since: 1.10
17393  */
17394 void
17395 clutter_actor_save_easing_state (ClutterActor *self)
17396 {
17397   ClutterAnimationInfo *info;
17398   AState new_state;
17399
17400   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17401
17402   info = _clutter_actor_get_animation_info (self);
17403
17404   if (info->states == NULL)
17405     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17406
17407   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17408   new_state.easing_duration = 250;
17409   new_state.easing_delay = 0;
17410
17411   g_array_append_val (info->states, new_state);
17412
17413   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17414 }
17415
17416 /**
17417  * clutter_actor_restore_easing_state:
17418  * @self: a #ClutterActor
17419  *
17420  * Restores the easing state as it was prior to a call to
17421  * clutter_actor_save_easing_state().
17422  *
17423  * Since: 1.10
17424  */
17425 void
17426 clutter_actor_restore_easing_state (ClutterActor *self)
17427 {
17428   ClutterAnimationInfo *info;
17429
17430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17431
17432   info = _clutter_actor_get_animation_info (self);
17433
17434   if (info->states == NULL)
17435     {
17436       g_critical ("The function clutter_actor_restore_easing_state() has "
17437                   "called without a previous call to "
17438                   "clutter_actor_save_easing_state().");
17439       return;
17440     }
17441
17442   g_array_remove_index (info->states, info->states->len - 1);
17443   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17444 }
17445
17446 /**
17447  * clutter_actor_set_content:
17448  * @self: a #ClutterActor
17449  * @content: (allow-none): a #ClutterContent, or %NULL
17450  *
17451  * Sets the contents of a #ClutterActor.
17452  *
17453  * Since: 1.10
17454  */
17455 void
17456 clutter_actor_set_content (ClutterActor   *self,
17457                            ClutterContent *content)
17458 {
17459   ClutterActorPrivate *priv;
17460
17461   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17462   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17463
17464   priv = self->priv;
17465
17466   if (priv->content != NULL)
17467     {
17468       _clutter_content_detached (priv->content, self);
17469       g_object_unref (priv->content);
17470     }
17471
17472   priv->content = content;
17473
17474   if (priv->content != NULL)
17475     {
17476       g_object_ref (priv->content);
17477       _clutter_content_attached (priv->content, self);
17478     }
17479
17480   /* given that the content is always painted within the allocation,
17481    * we only need to queue a redraw here
17482    */
17483   clutter_actor_queue_redraw (self);
17484
17485   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17486
17487   /* if the content gravity is not resize-fill, and the new content has a
17488    * different preferred size than the previous one, then the content box
17489    * may have been changed. since we compute that lazily, we just notify
17490    * here, and let whomever watches :content-box do whatever they need to
17491    * do.
17492    */
17493   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17494     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17495 }
17496
17497 /**
17498  * clutter_actor_get_content:
17499  * @self: a #ClutterActor
17500  *
17501  * Retrieves the contents of @self.
17502  *
17503  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17504  *   or %NULL if none was set
17505  *
17506  * Since: 1.10
17507  */
17508 ClutterContent *
17509 clutter_actor_get_content (ClutterActor *self)
17510 {
17511   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17512
17513   return self->priv->content;
17514 }
17515
17516 /**
17517  * clutter_actor_set_content_gravity:
17518  * @self: a #ClutterActor
17519  * @gravity: the #ClutterContentGravity
17520  *
17521  * Sets the gravity of the #ClutterContent used by @self.
17522  *
17523  * See the description of the #ClutterActor:content-gravity property for
17524  * more information.
17525  *
17526  * Since: 1.10
17527  */
17528 void
17529 clutter_actor_set_content_gravity (ClutterActor *self,
17530                                    ClutterContentGravity  gravity)
17531 {
17532   ClutterActorPrivate *priv;
17533
17534   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17535
17536   priv = self->priv;
17537
17538   if (priv->content_gravity == gravity)
17539     return;
17540
17541   priv->content_gravity = gravity;
17542
17543   clutter_actor_queue_redraw (self);
17544
17545   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17546   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17547 }
17548
17549 /**
17550  * clutter_actor_get_content_gravity:
17551  * @self: a #ClutterActor
17552  *
17553  * Retrieves the content gravity as set using
17554  * clutter_actor_get_content_gravity().
17555  *
17556  * Return value: the content gravity
17557  *
17558  * Since: 1.10
17559  */
17560 ClutterContentGravity
17561 clutter_actor_get_content_gravity (ClutterActor *self)
17562 {
17563   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17564                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17565
17566   return self->priv->content_gravity;
17567 }
17568
17569 /**
17570  * clutter_actor_get_content_box:
17571  * @self: a #ClutterActor
17572  * @box: (out caller-allocates): the return location for the bounding
17573  *   box for the #ClutterContent
17574  *
17575  * Retrieves the bounding box for the #ClutterContent of @self.
17576  *
17577  * If no #ClutterContent is set for @self, or if @self has not been
17578  * allocated yet, then the result is undefined.
17579  *
17580  * The content box is guaranteed to be, at most, as big as the allocation
17581  * of the #ClutterActor.
17582  *
17583  * If the #ClutterContent used by the actor has a preferred size, then
17584  * it is possible to modify the content box by using the
17585  * #ClutterActor:content-gravity property.
17586  *
17587  * Since: 1.10
17588  */
17589 void
17590 clutter_actor_get_content_box (ClutterActor    *self,
17591                                ClutterActorBox *box)
17592 {
17593   ClutterActorPrivate *priv;
17594   gfloat content_w, content_h;
17595   gfloat alloc_w, alloc_h;
17596
17597   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17598   g_return_if_fail (box != NULL);
17599
17600   priv = self->priv;
17601
17602   if (!clutter_actor_has_allocation (self))
17603     return;
17604
17605   box->x1 = 0.f;
17606   box->y1 = 0.f;
17607   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17608   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17609
17610   if (priv->content == NULL)
17611     return;
17612
17613   /* no need to do any more work */
17614   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17615     return;
17616
17617   /* if the content does not have a preferred size then there is
17618    * no point in computing the content box
17619    */
17620   if (!clutter_content_get_preferred_size (priv->content,
17621                                            &content_w,
17622                                            &content_h))
17623     return;
17624
17625   clutter_actor_box_get_size (&priv->allocation, &alloc_w, &alloc_h);
17626
17627   switch (priv->content_gravity)
17628     {
17629     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17630       box->x2 = box->x1 + MIN (content_w, alloc_w);
17631       box->y2 = box->y1 + MIN (content_h, alloc_h);
17632       break;
17633
17634     case CLUTTER_CONTENT_GRAVITY_TOP:
17635       if (alloc_w > content_w)
17636         {
17637           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17638           box->x2 = box->x1 + content_w;
17639         }
17640       box->y2 = box->y1 + MIN (content_h, alloc_h);
17641       break;
17642
17643     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17644       if (alloc_w > content_w)
17645         {
17646           box->x1 += (alloc_w - content_w);
17647           box->x2 = box->x1 + content_w;
17648         }
17649       box->y2 = box->y1 + MIN (content_h, alloc_h);
17650       break;
17651
17652     case CLUTTER_CONTENT_GRAVITY_LEFT:
17653       box->x2 = box->x1 + MIN (content_w, alloc_w);
17654       if (alloc_h > content_h)
17655         {
17656           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17657           box->y2 = box->y1 + content_h;
17658         }
17659       break;
17660
17661     case CLUTTER_CONTENT_GRAVITY_CENTER:
17662       if (alloc_w > content_w)
17663         {
17664           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17665           box->x2 = box->x1 + content_w;
17666         }
17667       if (alloc_h > content_h)
17668         {
17669           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17670           box->y2 = box->y1 + content_h;
17671         }
17672       break;
17673
17674     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17675       if (alloc_w > content_w)
17676         {
17677           box->x1 += (alloc_w - content_w);
17678           box->x2 = box->x1 + content_w;
17679         }
17680       if (alloc_h > content_h)
17681         {
17682           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17683           box->y2 = box->y1 + content_h;
17684         }
17685       break;
17686
17687     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17688       box->x2 = box->x1 + MIN (content_w, alloc_w);
17689       if (alloc_h > content_h)
17690         {
17691           box->y1 += (alloc_h - content_h);
17692           box->y2 = box->y1 + content_h;
17693         }
17694       break;
17695
17696     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17697       if (alloc_w > content_w)
17698         {
17699           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17700           box->x2 = box->x1 + content_w;
17701         }
17702       if (alloc_h > content_h)
17703         {
17704           box->y1 += (alloc_h - content_h);
17705           box->y2 = box->y1 + content_h;
17706         }
17707       break;
17708
17709     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17710       if (alloc_w > content_w)
17711         {
17712           box->x1 += (alloc_w - content_w);
17713           box->x2 = box->x1 + content_w;
17714         }
17715       if (alloc_h > content_h)
17716         {
17717           box->y1 += (alloc_h - content_h);
17718           box->y2 = box->y1 + content_h;
17719         }
17720       break;
17721
17722     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17723       g_assert_not_reached ();
17724       break;
17725
17726     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17727       if (content_w >= content_h && content_h > 0)
17728         {
17729           double ratio = content_w / content_h;
17730
17731           box->x2 = box->x1 + alloc_w;
17732
17733           box->y1 += ceilf ((alloc_h - (alloc_h / ratio)) / 2.0);
17734           box->y2 = box->y1 + (alloc_h / ratio);
17735         }
17736       else if (content_h > content_w && content_w > 0)
17737         {
17738           double ratio = content_h / content_w;
17739
17740           box->x1 += ceilf ((alloc_w - (alloc_w / ratio)) / 2.0);
17741           box->x2 = box->x2 + (alloc_w / ratio);
17742
17743           box->y2 = box->x1 + alloc_h;
17744         }
17745       break;
17746     }
17747 }