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