actor: Add delay to the easing state
[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-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  *
243  * <refsect2 id="ClutterActor-animatable-properties">
244  *   <title>Animatable properties</title>
245  *   <para>Certain properties on #ClutterActor are marked as "animatable";
246  *   these properties will be automatically tweened between the current
247  *   value and the new value when one is set.</para>
248  *   <para>For backward compatibility, animatable properties will only be
249  *   tweened if the easing duration is greater than 0, or if a new easing
250  *   state is set, for instance the following example:</para>
251  *   <informalexample><programlisting>
252  * clutter_actor_save_easing_state (actor);
253  * clutter_actor_set_position (actor, 200, 200);
254  * clutter_actor_restore_easing_state (actor);
255  *   </programlisting></informalexample>
256  *   will tween the actor to the (200, 200) coordinates using the default
257  *   easing mode and duration of a new easing state. The example above is
258  *   equivalent to the following code:</para>
259  *   <informalexample><programlisting>
260  * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
261  * clutter_actor_set_easing_duration (actor, 250);
262  * clutter_actor_set_position (actor, 200, 200);
263  * clutter_actor_restore_easing_state (actor);
264  *   </programlisting></informalexample>
265  *   <para>It is possible to nest easing states to tween animatable
266  *   properties using different modes and durations, for instance:</para>
267  *   <informalexample><programlisting>
268  * clutter_actor_save_easing_state (actor); /&ast; outer state &ast;/
269  *
270  * /&ast; set the duration of the animation to 2 seconds and change position &ast;/
271  * clutter_actor_set_easing_duration (actor, 2000);
272  * clutter_actor_set_position (actor, 0, 0);
273  *
274  * clutter_actor_save_easing_state (actor); /&ast; inner state &ast;/
275  *
276  * /&ast; set the duration of the animation to 5 seconds and change depth and opacity &ast;/
277  * clutter_actor_set_easing_duration (actor, 5000);
278  * clutter_actor_set_depth (actor, 200);
279  * clutter_actor_set_opacity (actor, 0);
280  *
281  * clutter_actor_restore_easing_state (actor);
282  *
283  * clutter_actor_restore_easing_state (actor);
284  *   </programlisting></informalexample>
285  * </refsect2>
286  */
287
288 /**
289  * CLUTTER_ACTOR_IS_MAPPED:
290  * @a: a #ClutterActor
291  *
292  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
293  *
294  * The mapped state is set when the actor is visible and all its parents up
295  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
296  *
297  * This check can be used to see if an actor is going to be painted, as only
298  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
299  *
300  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
301  * not be checked directly; instead, the recommended usage is to connect a
302  * handler on the #GObject::notify signal for the #ClutterActor:mapped
303  * property of #ClutterActor, and check the presence of
304  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
305  *
306  * It is also important to note that Clutter may delay the changes of
307  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
308  * limitations, or during the reparenting of an actor, to optimize
309  * unnecessary (and potentially expensive) state changes.
310  *
311  * Since: 0.2
312  */
313
314 /**
315  * CLUTTER_ACTOR_IS_REALIZED:
316  * @a: a #ClutterActor
317  *
318  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
319  *
320  * The realized state has an actor-dependant interpretation. If an
321  * actor wants to delay allocating resources until it is attached to a
322  * stage, it may use the realize state to do so. However it is
323  * perfectly acceptable for an actor to allocate Cogl resources before
324  * being realized because there is only one drawing context used by Clutter
325  * so any resources will work on any stage.  If an actor is mapped it
326  * must also be realized, but an actor can be realized and unmapped
327  * (this is so hiding an actor temporarily doesn't do an expensive
328  * unrealize/realize).
329  *
330  * To be realized an actor must be inside a stage, and all its parents
331  * must be realized.
332  *
333  * Since: 0.2
334  */
335
336 /**
337  * CLUTTER_ACTOR_IS_VISIBLE:
338  * @a: a #ClutterActor
339  *
340  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
341  * Equivalent to the ClutterActor::visible object property.
342  *
343  * Note that an actor is only painted onscreen if it's mapped, which
344  * means it's visible, and all its parents are visible, and one of the
345  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
346  *
347  * Since: 0.2
348  */
349
350 /**
351  * CLUTTER_ACTOR_IS_REACTIVE:
352  * @a: a #ClutterActor
353  *
354  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
355  *
356  * Only reactive actors will receive event-related signals.
357  *
358  * Since: 0.6
359  */
360
361 #ifdef HAVE_CONFIG_H
362 #include "config.h"
363 #endif
364
365 #include <math.h>
366
367 #include <gobject/gvaluecollector.h>
368
369 #include <cogl/cogl.h>
370
371 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
372 #define CLUTTER_ENABLE_EXPERIMENTAL_API
373
374 #include "clutter-actor-private.h"
375
376 #include "clutter-action.h"
377 #include "clutter-actor-meta-private.h"
378 #include "clutter-animatable.h"
379 #include "clutter-color-static.h"
380 #include "clutter-color.h"
381 #include "clutter-constraint.h"
382 #include "clutter-container.h"
383 #include "clutter-debug.h"
384 #include "clutter-effect-private.h"
385 #include "clutter-enum-types.h"
386 #include "clutter-fixed-layout.h"
387 #include "clutter-flatten-effect.h"
388 #include "clutter-interval.h"
389 #include "clutter-main.h"
390 #include "clutter-marshal.h"
391 #include "clutter-paint-volume-private.h"
392 #include "clutter-private.h"
393 #include "clutter-profile.h"
394 #include "clutter-property-transition.h"
395 #include "clutter-scriptable.h"
396 #include "clutter-script-private.h"
397 #include "clutter-stage-private.h"
398 #include "clutter-timeline.h"
399 #include "clutter-transition.h"
400 #include "clutter-units.h"
401
402 #include "deprecated/clutter-actor.h"
403 #include "deprecated/clutter-behaviour.h"
404 #include "deprecated/clutter-container.h"
405
406 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
407 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
408
409 /* Internal enum used to control mapped state update.  This is a hint
410  * which indicates when to do something other than just enforce
411  * invariants.
412  */
413 typedef enum {
414   MAP_STATE_CHECK,           /* just enforce invariants. */
415   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
416                               * used when about to unparent.
417                               */
418   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
419                               * used to set mapped on toplevels.
420                               */
421   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
422                               * used just before unmapping parent.
423                               */
424 } MapStateChange;
425
426 /* 3 entries should be a good compromise, few layout managers
427  * will ask for 3 different preferred size in each allocation cycle */
428 #define N_CACHED_SIZE_REQUESTS 3
429
430 struct _ClutterActorPrivate
431 {
432   /* request mode */
433   ClutterRequestMode request_mode;
434
435   /* our cached size requests for different width / height */
436   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
437   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
438
439   /* An age of 0 means the entry is not set */
440   guint cached_height_age;
441   guint cached_width_age;
442
443   /* the bounding box of the actor, relative to the parent's
444    * allocation
445    */
446   ClutterActorBox allocation;
447   ClutterAllocationFlags allocation_flags;
448
449   /* clip, in actor coordinates */
450   cairo_rectangle_t clip;
451
452   /* the cached transformation matrix; see apply_transform() */
453   CoglMatrix transform;
454
455   guint8 opacity;
456   gint opacity_override;
457
458   ClutterOffscreenRedirect offscreen_redirect;
459
460   /* This is an internal effect used to implement the
461      offscreen-redirect property */
462   ClutterEffect *flatten_effect;
463
464   /* scene graph */
465   ClutterActor *parent;
466   ClutterActor *prev_sibling;
467   ClutterActor *next_sibling;
468   ClutterActor *first_child;
469   ClutterActor *last_child;
470
471   gint n_children;
472
473   /* tracks whenever the children of an actor are changed; the
474    * age is incremented by 1 whenever an actor is added or
475    * removed. the age is not incremented when the first or the
476    * last child pointers are changed, or when grandchildren of
477    * an actor are changed.
478    */
479   gint age;
480
481   gchar *name; /* a non-unique name, used for debugging */
482   guint32 id; /* unique id, used for backward compatibility */
483
484   gint32 pick_id; /* per-stage unique id, used for picking */
485
486   /* a back-pointer to the Pango context that we can use
487    * to create pre-configured PangoLayout
488    */
489   PangoContext *pango_context;
490
491   /* the text direction configured for this child - either by
492    * application code, or by the actor's parent
493    */
494   ClutterTextDirection text_direction;
495
496   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
497   gint internal_child;
498
499   /* meta classes */
500   ClutterMetaGroup *actions;
501   ClutterMetaGroup *constraints;
502   ClutterMetaGroup *effects;
503
504   /* delegate object used to allocate the children of this actor */
505   ClutterLayoutManager *layout_manager;
506
507   /* used when painting, to update the paint volume */
508   ClutterEffect *current_effect;
509
510   /* This is used to store an effect which needs to be redrawn. A
511      redraw can be queued to start from a particular effect. This is
512      used by parametrised effects that can cache an image of the
513      actor. If a parameter of the effect changes then it only needs to
514      redraw the cached image, not the actual actor. The pointer is
515      only valid if is_dirty == TRUE. If the pointer is NULL then the
516      whole actor is dirty. */
517   ClutterEffect *effect_to_redraw;
518
519   /* This is used when painting effects to implement the
520      clutter_actor_continue_paint() function. It points to the node in
521      the list of effects that is next in the chain */
522   const GList *next_effect_to_paint;
523
524   ClutterPaintVolume paint_volume;
525
526   /* NB: This volume isn't relative to this actor, it is in eye
527    * coordinates so that it can remain valid after the actor changes.
528    */
529   ClutterPaintVolume last_paint_volume;
530
531   ClutterStageQueueRedrawEntry *queue_redraw_entry;
532
533   ClutterColor bg_color;
534
535   /* bitfields */
536
537   /* fixed position and sizes */
538   guint position_set                : 1;
539   guint min_width_set               : 1;
540   guint min_height_set              : 1;
541   guint natural_width_set           : 1;
542   guint natural_height_set          : 1;
543   /* cached request is invalid (implies allocation is too) */
544   guint needs_width_request         : 1;
545   /* cached request is invalid (implies allocation is too) */
546   guint needs_height_request        : 1;
547   /* cached allocation is invalid (request has changed, probably) */
548   guint needs_allocation            : 1;
549   guint show_on_set_parent          : 1;
550   guint has_clip                    : 1;
551   guint clip_to_allocation          : 1;
552   guint enable_model_view_transform : 1;
553   guint enable_paint_unmapped       : 1;
554   guint has_pointer                 : 1;
555   guint propagated_one_redraw       : 1;
556   guint paint_volume_valid          : 1;
557   guint last_paint_volume_valid     : 1;
558   guint in_clone_paint              : 1;
559   guint transform_valid             : 1;
560   /* This is TRUE if anything has queued a redraw since we were last
561      painted. In this case effect_to_redraw will point to an effect
562      the redraw was queued from or it will be NULL if the redraw was
563      queued without an effect. */
564   guint is_dirty                    : 1;
565   guint bg_color_set                : 1;
566 };
567
568 enum
569 {
570   PROP_0,
571
572   PROP_NAME,
573
574   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
575    * when set they force a size request, when gotten they
576    * get the allocation if the allocation is valid, and the
577    * request otherwise
578    */
579   PROP_X,
580   PROP_Y,
581   PROP_WIDTH,
582   PROP_HEIGHT,
583
584   /* Then the rest of these size-related properties are the "actual"
585    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
586    */
587   PROP_FIXED_X,
588   PROP_FIXED_Y,
589
590   PROP_FIXED_POSITION_SET,
591
592   PROP_MIN_WIDTH,
593   PROP_MIN_WIDTH_SET,
594
595   PROP_MIN_HEIGHT,
596   PROP_MIN_HEIGHT_SET,
597
598   PROP_NATURAL_WIDTH,
599   PROP_NATURAL_WIDTH_SET,
600
601   PROP_NATURAL_HEIGHT,
602   PROP_NATURAL_HEIGHT_SET,
603
604   PROP_REQUEST_MODE,
605
606   /* Allocation properties are read-only */
607   PROP_ALLOCATION,
608
609   PROP_DEPTH,
610
611   PROP_CLIP,
612   PROP_HAS_CLIP,
613   PROP_CLIP_TO_ALLOCATION,
614
615   PROP_OPACITY,
616
617   PROP_OFFSCREEN_REDIRECT,
618
619   PROP_VISIBLE,
620   PROP_MAPPED,
621   PROP_REALIZED,
622   PROP_REACTIVE,
623
624   PROP_SCALE_X,
625   PROP_SCALE_Y,
626   PROP_SCALE_CENTER_X,
627   PROP_SCALE_CENTER_Y,
628   PROP_SCALE_GRAVITY,
629
630   PROP_ROTATION_ANGLE_X,
631   PROP_ROTATION_ANGLE_Y,
632   PROP_ROTATION_ANGLE_Z,
633   PROP_ROTATION_CENTER_X,
634   PROP_ROTATION_CENTER_Y,
635   PROP_ROTATION_CENTER_Z,
636   /* This property only makes sense for the z rotation because the
637      others would depend on the actor having a size along the
638      z-axis */
639   PROP_ROTATION_CENTER_Z_GRAVITY,
640
641   PROP_ANCHOR_X,
642   PROP_ANCHOR_Y,
643   PROP_ANCHOR_GRAVITY,
644
645   PROP_SHOW_ON_SET_PARENT,
646
647   PROP_TEXT_DIRECTION,
648   PROP_HAS_POINTER,
649
650   PROP_ACTIONS,
651   PROP_CONSTRAINTS,
652   PROP_EFFECT,
653
654   PROP_LAYOUT_MANAGER,
655
656   PROP_X_ALIGN,
657   PROP_Y_ALIGN,
658   PROP_MARGIN_TOP,
659   PROP_MARGIN_BOTTOM,
660   PROP_MARGIN_LEFT,
661   PROP_MARGIN_RIGHT,
662
663   PROP_BACKGROUND_COLOR,
664   PROP_BACKGROUND_COLOR_SET,
665
666   PROP_FIRST_CHILD,
667   PROP_LAST_CHILD,
668
669   PROP_LAST
670 };
671
672 static GParamSpec *obj_props[PROP_LAST];
673
674 enum
675 {
676   SHOW,
677   HIDE,
678   DESTROY,
679   PARENT_SET,
680   KEY_FOCUS_IN,
681   KEY_FOCUS_OUT,
682   PAINT,
683   PICK,
684   REALIZE,
685   UNREALIZE,
686   QUEUE_REDRAW,
687   QUEUE_RELAYOUT,
688   EVENT,
689   CAPTURED_EVENT,
690   BUTTON_PRESS_EVENT,
691   BUTTON_RELEASE_EVENT,
692   SCROLL_EVENT,
693   KEY_PRESS_EVENT,
694   KEY_RELEASE_EVENT,
695   MOTION_EVENT,
696   ENTER_EVENT,
697   LEAVE_EVENT,
698   ALLOCATION_CHANGED,
699
700   LAST_SIGNAL
701 };
702
703 static guint actor_signals[LAST_SIGNAL] = { 0, };
704
705 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
706 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
707 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
708 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
709
710 /* These setters are all static for now, maybe they should be in the
711  * public API, but they are perhaps obscure enough to leave only as
712  * properties
713  */
714 static void clutter_actor_set_min_width          (ClutterActor *self,
715                                                   gfloat        min_width);
716 static void clutter_actor_set_min_height         (ClutterActor *self,
717                                                   gfloat        min_height);
718 static void clutter_actor_set_natural_width      (ClutterActor *self,
719                                                   gfloat        natural_width);
720 static void clutter_actor_set_natural_height     (ClutterActor *self,
721                                                   gfloat        natural_height);
722 static void clutter_actor_set_min_width_set      (ClutterActor *self,
723                                                   gboolean      use_min_width);
724 static void clutter_actor_set_min_height_set     (ClutterActor *self,
725                                                   gboolean      use_min_height);
726 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
727                                                   gboolean  use_natural_width);
728 static void clutter_actor_set_natural_height_set (ClutterActor *self,
729                                                   gboolean  use_natural_height);
730 static void clutter_actor_update_map_state       (ClutterActor  *self,
731                                                   MapStateChange change);
732 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
733
734 /* Helper routines for managing anchor coords */
735 static void clutter_anchor_coord_get_units (ClutterActor      *self,
736                                             const AnchorCoord *coord,
737                                             gfloat            *x,
738                                             gfloat            *y,
739                                             gfloat            *z);
740 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
741                                             gfloat             x,
742                                             gfloat             y,
743                                             gfloat             z);
744
745 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
746 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
747                                                         ClutterGravity     gravity);
748
749 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
750
751 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
752
753 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
754                                                                ClutterActor *ancestor,
755                                                                CoglMatrix *matrix);
756
757 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
758
759 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
760
761 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
762                                                                 const ClutterColor *color);
763
764 static void on_layout_manager_changed (ClutterLayoutManager *manager,
765                                        ClutterActor         *self);
766
767 /* Helper macro which translates by the anchor coord, applies the
768    given transformation and then translates back */
769 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
770   gfloat _tx, _ty, _tz;                                                \
771   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
772   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
773   { _transform; }                                                      \
774   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
775
776 static GQuark quark_shader_data = 0;
777 static GQuark quark_actor_layout_info = 0;
778 static GQuark quark_actor_transform_info = 0;
779 static GQuark quark_actor_animation_info = 0;
780
781 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
782                          clutter_actor,
783                          G_TYPE_INITIALLY_UNOWNED,
784                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
785                                                 clutter_container_iface_init)
786                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
787                                                 clutter_scriptable_iface_init)
788                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
789                                                 clutter_animatable_iface_init)
790                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
791                                                 atk_implementor_iface_init));
792
793 /*< private >
794  * clutter_actor_get_debug_name:
795  * @actor: a #ClutterActor
796  *
797  * Retrieves a printable name of @actor for debugging messages
798  *
799  * Return value: a string with a printable name
800  */
801 const gchar *
802 _clutter_actor_get_debug_name (ClutterActor *actor)
803 {
804   return actor->priv->name != NULL ? actor->priv->name
805                                    : G_OBJECT_TYPE_NAME (actor);
806 }
807
808 #ifdef CLUTTER_ENABLE_DEBUG
809 /* XXX - this is for debugging only, remove once working (or leave
810  * in only in some debug mode). Should leave it for a little while
811  * until we're confident in the new map/realize/visible handling.
812  */
813 static inline void
814 clutter_actor_verify_map_state (ClutterActor *self)
815 {
816   ClutterActorPrivate *priv = self->priv;
817
818   if (CLUTTER_ACTOR_IS_REALIZED (self))
819     {
820       /* all bets are off during reparent when we're potentially realized,
821        * but should not be according to invariants
822        */
823       if (!CLUTTER_ACTOR_IN_REPARENT (self))
824         {
825           if (priv->parent == NULL)
826             {
827               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
828                 {
829                 }
830               else
831                 g_warning ("Realized non-toplevel actor '%s' should "
832                            "have a parent",
833                            _clutter_actor_get_debug_name (self));
834             }
835           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
836             {
837               g_warning ("Realized actor %s has an unrealized parent %s",
838                          _clutter_actor_get_debug_name (self),
839                          _clutter_actor_get_debug_name (priv->parent));
840             }
841         }
842     }
843
844   if (CLUTTER_ACTOR_IS_MAPPED (self))
845     {
846       if (!CLUTTER_ACTOR_IS_REALIZED (self))
847         g_warning ("Actor '%s' is mapped but not realized",
848                    _clutter_actor_get_debug_name (self));
849
850       /* remaining bets are off during reparent when we're potentially
851        * mapped, but should not be according to invariants
852        */
853       if (!CLUTTER_ACTOR_IN_REPARENT (self))
854         {
855           if (priv->parent == NULL)
856             {
857               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
858                 {
859                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
860                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
861                     {
862                       g_warning ("Toplevel actor '%s' is mapped "
863                                  "but not visible",
864                                  _clutter_actor_get_debug_name (self));
865                     }
866                 }
867               else
868                 {
869                   g_warning ("Mapped actor '%s' should have a parent",
870                              _clutter_actor_get_debug_name (self));
871                 }
872             }
873           else
874             {
875               ClutterActor *iter = self;
876
877               /* check for the enable_paint_unmapped flag on the actor
878                * and parents; if the flag is enabled at any point of this
879                * branch of the scene graph then all the later checks
880                * become pointless
881                */
882               while (iter != NULL)
883                 {
884                   if (iter->priv->enable_paint_unmapped)
885                     return;
886
887                   iter = iter->priv->parent;
888                 }
889
890               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
891                 {
892                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
893                              "is not visible",
894                              _clutter_actor_get_debug_name (self),
895                              _clutter_actor_get_debug_name (priv->parent));
896                 }
897
898               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
899                 {
900                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
901                              "is not realized",
902                              _clutter_actor_get_debug_name (self),
903                              _clutter_actor_get_debug_name (priv->parent));
904                 }
905
906               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
907                 {
908                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
909                     g_warning ("Actor '%s' is mapped but its non-toplevel "
910                                "parent '%s' is not mapped",
911                                _clutter_actor_get_debug_name (self),
912                                _clutter_actor_get_debug_name (priv->parent));
913                 }
914             }
915         }
916     }
917 }
918
919 #endif /* CLUTTER_ENABLE_DEBUG */
920
921 static void
922 clutter_actor_set_mapped (ClutterActor *self,
923                           gboolean      mapped)
924 {
925   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
926     return;
927
928   if (mapped)
929     {
930       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
931       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
932     }
933   else
934     {
935       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
936       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
937     }
938 }
939
940 /* this function updates the mapped and realized states according to
941  * invariants, in the appropriate order.
942  */
943 static void
944 clutter_actor_update_map_state (ClutterActor  *self,
945                                 MapStateChange change)
946 {
947   gboolean was_mapped;
948
949   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
950
951   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
952     {
953       /* the mapped flag on top-level actors must be set by the
954        * per-backend implementation because it might be asynchronous.
955        *
956        * That is, the MAPPED flag on toplevels currently tracks the X
957        * server mapped-ness of the window, while the expected behavior
958        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
959        * This creates some weird complexity by breaking the invariant
960        * that if we're visible and all ancestors shown then we are
961        * also mapped - instead, we are mapped if all ancestors
962        * _possibly excepting_ the stage are mapped. The stage
963        * will map/unmap for example when it is minimized or
964        * moved to another workspace.
965        *
966        * So, the only invariant on the stage is that if visible it
967        * should be realized, and that it has to be visible to be
968        * mapped.
969        */
970       if (CLUTTER_ACTOR_IS_VISIBLE (self))
971         clutter_actor_realize (self);
972
973       switch (change)
974         {
975         case MAP_STATE_CHECK:
976           break;
977
978         case MAP_STATE_MAKE_MAPPED:
979           g_assert (!was_mapped);
980           clutter_actor_set_mapped (self, TRUE);
981           break;
982
983         case MAP_STATE_MAKE_UNMAPPED:
984           g_assert (was_mapped);
985           clutter_actor_set_mapped (self, FALSE);
986           break;
987
988         case MAP_STATE_MAKE_UNREALIZED:
989           /* we only use MAKE_UNREALIZED in unparent,
990            * and unparenting a stage isn't possible.
991            * If someone wants to just unrealize a stage
992            * then clutter_actor_unrealize() doesn't
993            * go through this codepath.
994            */
995           g_warning ("Trying to force unrealize stage is not allowed");
996           break;
997         }
998
999       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1000           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1001           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1002         {
1003           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1004                      "it is somehow still mapped",
1005                      _clutter_actor_get_debug_name (self));
1006         }
1007     }
1008   else
1009     {
1010       ClutterActorPrivate *priv = self->priv;
1011       ClutterActor *parent = priv->parent;
1012       gboolean should_be_mapped;
1013       gboolean may_be_realized;
1014       gboolean must_be_realized;
1015
1016       should_be_mapped = FALSE;
1017       may_be_realized = TRUE;
1018       must_be_realized = FALSE;
1019
1020       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1021         {
1022           may_be_realized = FALSE;
1023         }
1024       else
1025         {
1026           /* Maintain invariant that if parent is mapped, and we are
1027            * visible, then we are mapped ...  unless parent is a
1028            * stage, in which case we map regardless of parent's map
1029            * state but do require stage to be visible and realized.
1030            *
1031            * If parent is realized, that does not force us to be
1032            * realized; but if parent is unrealized, that does force
1033            * us to be unrealized.
1034            *
1035            * The reason we don't force children to realize with
1036            * parents is _clutter_actor_rerealize(); if we require that
1037            * a realized parent means children are realized, then to
1038            * unrealize an actor we would have to unrealize its
1039            * parents, which would end up meaning unrealizing and
1040            * hiding the entire stage. So we allow unrealizing a
1041            * child (as long as that child is not mapped) while that
1042            * child still has a realized parent.
1043            *
1044            * Also, if we unrealize from leaf nodes to root, and
1045            * realize from root to leaf, the invariants are never
1046            * violated if we allow children to be unrealized
1047            * while parents are realized.
1048            *
1049            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1050            * to force us to unmap, even though parent is still
1051            * mapped. This is because we're unmapping from leaf nodes
1052            * up to root nodes.
1053            */
1054           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1055               change != MAP_STATE_MAKE_UNMAPPED)
1056             {
1057               gboolean parent_is_visible_realized_toplevel;
1058
1059               parent_is_visible_realized_toplevel =
1060                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1061                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1062                  CLUTTER_ACTOR_IS_REALIZED (parent));
1063
1064               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1065                   parent_is_visible_realized_toplevel)
1066                 {
1067                   must_be_realized = TRUE;
1068                   should_be_mapped = TRUE;
1069                 }
1070             }
1071
1072           /* if the actor has been set to be painted even if unmapped
1073            * then we should map it and check for realization as well;
1074            * this is an override for the branch of the scene graph
1075            * which begins with this node
1076            */
1077           if (priv->enable_paint_unmapped)
1078             {
1079               if (priv->parent == NULL)
1080                 g_warning ("Attempting to map an unparented actor '%s'",
1081                            _clutter_actor_get_debug_name (self));
1082
1083               should_be_mapped = TRUE;
1084               must_be_realized = TRUE;
1085             }
1086
1087           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1088             may_be_realized = FALSE;
1089         }
1090
1091       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1092         {
1093           if (parent == NULL)
1094             g_warning ("Attempting to map a child that does not "
1095                        "meet the necessary invariants: the actor '%s' "
1096                        "has no parent",
1097                        _clutter_actor_get_debug_name (self));
1098           else
1099             g_warning ("Attempting to map a child that does not "
1100                        "meet the necessary invariants: the actor '%s' "
1101                        "is parented to an unmapped actor '%s'",
1102                        _clutter_actor_get_debug_name (self),
1103                        _clutter_actor_get_debug_name (priv->parent));
1104         }
1105
1106       /* If in reparent, we temporarily suspend unmap and unrealize.
1107        *
1108        * We want to go in the order "realize, map" and "unmap, unrealize"
1109        */
1110
1111       /* Unmap */
1112       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1113         clutter_actor_set_mapped (self, FALSE);
1114
1115       /* Realize */
1116       if (must_be_realized)
1117         clutter_actor_realize (self);
1118
1119       /* if we must be realized then we may be, presumably */
1120       g_assert (!(must_be_realized && !may_be_realized));
1121
1122       /* Unrealize */
1123       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1124         clutter_actor_unrealize_not_hiding (self);
1125
1126       /* Map */
1127       if (should_be_mapped)
1128         {
1129           if (!must_be_realized)
1130             g_warning ("Somehow we think actor '%s' should be mapped but "
1131                        "not realized, which isn't allowed",
1132                        _clutter_actor_get_debug_name (self));
1133
1134           /* realization is allowed to fail (though I don't know what
1135            * an app is supposed to do about that - shouldn't it just
1136            * be a g_error? anyway, we have to avoid mapping if this
1137            * happens)
1138            */
1139           if (CLUTTER_ACTOR_IS_REALIZED (self))
1140             clutter_actor_set_mapped (self, TRUE);
1141         }
1142     }
1143
1144 #ifdef CLUTTER_ENABLE_DEBUG
1145   /* check all invariants were kept */
1146   clutter_actor_verify_map_state (self);
1147 #endif
1148 }
1149
1150 static void
1151 clutter_actor_real_map (ClutterActor *self)
1152 {
1153   ClutterActorPrivate *priv = self->priv;
1154   ClutterActor *stage, *iter;
1155
1156   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1157
1158   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1159                 _clutter_actor_get_debug_name (self));
1160
1161   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1162
1163   stage = _clutter_actor_get_stage_internal (self);
1164   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1165
1166   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1167                 priv->pick_id,
1168                 _clutter_actor_get_debug_name (self));
1169
1170   /* notify on parent mapped before potentially mapping
1171    * children, so apps see a top-down notification.
1172    */
1173   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1174
1175   for (iter = self->priv->first_child;
1176        iter != NULL;
1177        iter = iter->priv->next_sibling)
1178     {
1179       clutter_actor_map (iter);
1180     }
1181 }
1182
1183 /**
1184  * clutter_actor_map:
1185  * @self: A #ClutterActor
1186  *
1187  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1188  * and realizes its children if they are visible. Does nothing if the
1189  * actor is not visible.
1190  *
1191  * Calling this function is strongly disencouraged: the default
1192  * implementation of #ClutterActorClass.map() will map all the children
1193  * of an actor when mapping its parent.
1194  *
1195  * When overriding map, it is mandatory to chain up to the parent
1196  * implementation.
1197  *
1198  * Since: 1.0
1199  */
1200 void
1201 clutter_actor_map (ClutterActor *self)
1202 {
1203   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1204
1205   if (CLUTTER_ACTOR_IS_MAPPED (self))
1206     return;
1207
1208   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1209     return;
1210
1211   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1212 }
1213
1214 static void
1215 clutter_actor_real_unmap (ClutterActor *self)
1216 {
1217   ClutterActorPrivate *priv = self->priv;
1218   ClutterActor *iter;
1219
1220   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1221
1222   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1223                 _clutter_actor_get_debug_name (self));
1224
1225   for (iter = self->priv->first_child;
1226        iter != NULL;
1227        iter = iter->priv->next_sibling)
1228     {
1229       clutter_actor_unmap (iter);
1230     }
1231
1232   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1233
1234   /* clear the contents of the last paint volume, so that hiding + moving +
1235    * showing will not result in the wrong area being repainted
1236    */
1237   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1238   priv->last_paint_volume_valid = TRUE;
1239
1240   /* notify on parent mapped after potentially unmapping
1241    * children, so apps see a bottom-up notification.
1242    */
1243   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1244
1245   /* relinquish keyboard focus if we were unmapped while owning it */
1246   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1247     {
1248       ClutterStage *stage;
1249
1250       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1251
1252       if (stage != NULL)
1253         _clutter_stage_release_pick_id (stage, priv->pick_id);
1254
1255       priv->pick_id = -1;
1256
1257       if (stage != NULL &&
1258           clutter_stage_get_key_focus (stage) == self)
1259         {
1260           clutter_stage_set_key_focus (stage, NULL);
1261         }
1262     }
1263 }
1264
1265 /**
1266  * clutter_actor_unmap:
1267  * @self: A #ClutterActor
1268  *
1269  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1270  * unmaps its children if they were mapped.
1271  *
1272  * Calling this function is not encouraged: the default #ClutterActor
1273  * implementation of #ClutterActorClass.unmap() will also unmap any
1274  * eventual children by default when their parent is unmapped.
1275  *
1276  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1277  * chain up to the parent implementation.
1278  *
1279  * <note>It is important to note that the implementation of the
1280  * #ClutterActorClass.unmap() virtual function may be called after
1281  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1282  * implementation, but it is guaranteed to be called before the
1283  * #GObjectClass.finalize() implementation.</note>
1284  *
1285  * Since: 1.0
1286  */
1287 void
1288 clutter_actor_unmap (ClutterActor *self)
1289 {
1290   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1291
1292   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1293     return;
1294
1295   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1296 }
1297
1298 static void
1299 clutter_actor_real_show (ClutterActor *self)
1300 {
1301   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1302     {
1303       ClutterActorPrivate *priv = self->priv;
1304
1305       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1306
1307       /* we notify on the "visible" flag in the clutter_actor_show()
1308        * wrapper so the entire show signal emission completes first
1309        * (?)
1310        */
1311       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1312
1313       /* we queue a relayout unless the actor is inside a
1314        * container that explicitly told us not to
1315        */
1316       if (priv->parent != NULL &&
1317           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1318         {
1319           /* While an actor is hidden the parent may not have
1320            * allocated/requested so we need to start from scratch
1321            * and avoid the short-circuiting in
1322            * clutter_actor_queue_relayout().
1323            */
1324           priv->needs_width_request  = FALSE;
1325           priv->needs_height_request = FALSE;
1326           priv->needs_allocation     = FALSE;
1327           clutter_actor_queue_relayout (self);
1328         }
1329     }
1330 }
1331
1332 static inline void
1333 set_show_on_set_parent (ClutterActor *self,
1334                         gboolean      set_show)
1335 {
1336   ClutterActorPrivate *priv = self->priv;
1337
1338   set_show = !!set_show;
1339
1340   if (priv->show_on_set_parent == set_show)
1341     return;
1342
1343   if (priv->parent == NULL)
1344     {
1345       priv->show_on_set_parent = set_show;
1346       g_object_notify_by_pspec (G_OBJECT (self),
1347                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1348     }
1349 }
1350
1351 /**
1352  * clutter_actor_show:
1353  * @self: A #ClutterActor
1354  *
1355  * Flags an actor to be displayed. An actor that isn't shown will not
1356  * be rendered on the stage.
1357  *
1358  * Actors are visible by default.
1359  *
1360  * If this function is called on an actor without a parent, the
1361  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1362  * effect.
1363  */
1364 void
1365 clutter_actor_show (ClutterActor *self)
1366 {
1367   ClutterActorPrivate *priv;
1368
1369   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1370
1371   /* simple optimization */
1372   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1373     {
1374       /* we still need to set the :show-on-set-parent property, in
1375        * case show() is called on an unparented actor
1376        */
1377       set_show_on_set_parent (self, TRUE);
1378       return;
1379     }
1380
1381 #ifdef CLUTTER_ENABLE_DEBUG
1382   clutter_actor_verify_map_state (self);
1383 #endif
1384
1385   priv = self->priv;
1386
1387   g_object_freeze_notify (G_OBJECT (self));
1388
1389   set_show_on_set_parent (self, TRUE);
1390
1391   g_signal_emit (self, actor_signals[SHOW], 0);
1392   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1393
1394   if (priv->parent != NULL)
1395     clutter_actor_queue_redraw (priv->parent);
1396
1397   g_object_thaw_notify (G_OBJECT (self));
1398 }
1399
1400 /**
1401  * clutter_actor_show_all:
1402  * @self: a #ClutterActor
1403  *
1404  * Calls clutter_actor_show() on all children of an actor (if any).
1405  *
1406  * Since: 0.2
1407  *
1408  * Deprecated: 1.10: Actors are visible by default
1409  */
1410 void
1411 clutter_actor_show_all (ClutterActor *self)
1412 {
1413   ClutterActorClass *klass;
1414
1415   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1416
1417   klass = CLUTTER_ACTOR_GET_CLASS (self);
1418   if (klass->show_all)
1419     klass->show_all (self);
1420 }
1421
1422 static void
1423 clutter_actor_real_hide (ClutterActor *self)
1424 {
1425   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1426     {
1427       ClutterActorPrivate *priv = self->priv;
1428
1429       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1430
1431       /* we notify on the "visible" flag in the clutter_actor_hide()
1432        * wrapper so the entire hide signal emission completes first
1433        * (?)
1434        */
1435       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1436
1437       /* we queue a relayout unless the actor is inside a
1438        * container that explicitly told us not to
1439        */
1440       if (priv->parent != NULL &&
1441           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1442         clutter_actor_queue_relayout (priv->parent);
1443     }
1444 }
1445
1446 /**
1447  * clutter_actor_hide:
1448  * @self: A #ClutterActor
1449  *
1450  * Flags an actor to be hidden. A hidden actor will not be
1451  * rendered on the stage.
1452  *
1453  * Actors are visible by default.
1454  *
1455  * If this function is called on an actor without a parent, the
1456  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1457  * as a side-effect.
1458  */
1459 void
1460 clutter_actor_hide (ClutterActor *self)
1461 {
1462   ClutterActorPrivate *priv;
1463
1464   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1465
1466   /* simple optimization */
1467   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1468     {
1469       /* we still need to set the :show-on-set-parent property, in
1470        * case hide() is called on an unparented actor
1471        */
1472       set_show_on_set_parent (self, FALSE);
1473       return;
1474     }
1475
1476 #ifdef CLUTTER_ENABLE_DEBUG
1477   clutter_actor_verify_map_state (self);
1478 #endif
1479
1480   priv = self->priv;
1481
1482   g_object_freeze_notify (G_OBJECT (self));
1483
1484   set_show_on_set_parent (self, FALSE);
1485
1486   g_signal_emit (self, actor_signals[HIDE], 0);
1487   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1488
1489   if (priv->parent != NULL)
1490     clutter_actor_queue_redraw (priv->parent);
1491
1492   g_object_thaw_notify (G_OBJECT (self));
1493 }
1494
1495 /**
1496  * clutter_actor_hide_all:
1497  * @self: a #ClutterActor
1498  *
1499  * Calls clutter_actor_hide() on all child actors (if any).
1500  *
1501  * Since: 0.2
1502  *
1503  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1504  *   prevent its children from being painted as well.
1505  */
1506 void
1507 clutter_actor_hide_all (ClutterActor *self)
1508 {
1509   ClutterActorClass *klass;
1510
1511   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1512
1513   klass = CLUTTER_ACTOR_GET_CLASS (self);
1514   if (klass->hide_all)
1515     klass->hide_all (self);
1516 }
1517
1518 /**
1519  * clutter_actor_realize:
1520  * @self: A #ClutterActor
1521  *
1522  * Realization informs the actor that it is attached to a stage. It
1523  * can use this to allocate resources if it wanted to delay allocation
1524  * until it would be rendered. However it is perfectly acceptable for
1525  * an actor to create resources before being realized because Clutter
1526  * only ever has a single rendering context so that actor is free to
1527  * be moved from one stage to another.
1528  *
1529  * This function does nothing if the actor is already realized.
1530  *
1531  * Because a realized actor must have realized parent actors, calling
1532  * clutter_actor_realize() will also realize all parents of the actor.
1533  *
1534  * This function does not realize child actors, except in the special
1535  * case that realizing the stage, when the stage is visible, will
1536  * suddenly map (and thus realize) the children of the stage.
1537  **/
1538 void
1539 clutter_actor_realize (ClutterActor *self)
1540 {
1541   ClutterActorPrivate *priv;
1542
1543   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1544
1545   priv = self->priv;
1546
1547 #ifdef CLUTTER_ENABLE_DEBUG
1548   clutter_actor_verify_map_state (self);
1549 #endif
1550
1551   if (CLUTTER_ACTOR_IS_REALIZED (self))
1552     return;
1553
1554   /* To be realized, our parent actors must be realized first.
1555    * This will only succeed if we're inside a toplevel.
1556    */
1557   if (priv->parent != NULL)
1558     clutter_actor_realize (priv->parent);
1559
1560   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1561     {
1562       /* toplevels can be realized at any time */
1563     }
1564   else
1565     {
1566       /* "Fail" the realization if parent is missing or unrealized;
1567        * this should really be a g_warning() not some kind of runtime
1568        * failure; how can an app possibly recover? Instead it's a bug
1569        * in the app and the app should get an explanatory warning so
1570        * someone can fix it. But for now it's too hard to fix this
1571        * because e.g. ClutterTexture needs reworking.
1572        */
1573       if (priv->parent == NULL ||
1574           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1575         return;
1576     }
1577
1578   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1579
1580   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1581   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1582
1583   g_signal_emit (self, actor_signals[REALIZE], 0);
1584
1585   /* Stage actor is allowed to unset the realized flag again in its
1586    * default signal handler, though that is a pathological situation.
1587    */
1588
1589   /* If realization "failed" we'll have to update child state. */
1590   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1591 }
1592
1593 static void
1594 clutter_actor_real_unrealize (ClutterActor *self)
1595 {
1596   /* we must be unmapped (implying our children are also unmapped) */
1597   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1598 }
1599
1600 /**
1601  * clutter_actor_unrealize:
1602  * @self: A #ClutterActor
1603  *
1604  * Unrealization informs the actor that it may be being destroyed or
1605  * moved to another stage. The actor may want to destroy any
1606  * underlying graphics resources at this point. However it is
1607  * perfectly acceptable for it to retain the resources until the actor
1608  * is destroyed because Clutter only ever uses a single rendering
1609  * context and all of the graphics resources are valid on any stage.
1610  *
1611  * Because mapped actors must be realized, actors may not be
1612  * unrealized if they are mapped. This function hides the actor to be
1613  * sure it isn't mapped, an application-visible side effect that you
1614  * may not be expecting.
1615  *
1616  * This function should not be called by application code.
1617  */
1618 void
1619 clutter_actor_unrealize (ClutterActor *self)
1620 {
1621   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1622   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1623
1624 /* This function should not really be in the public API, because
1625  * there isn't a good reason to call it. ClutterActor will already
1626  * unrealize things for you when it's important to do so.
1627  *
1628  * If you were using clutter_actor_unrealize() in a dispose
1629  * implementation, then don't, just chain up to ClutterActor's
1630  * dispose.
1631  *
1632  * If you were using clutter_actor_unrealize() to implement
1633  * unrealizing children of your container, then don't, ClutterActor
1634  * will already take care of that.
1635  *
1636  * If you were using clutter_actor_unrealize() to re-realize to
1637  * create your resources in a different way, then use
1638  * _clutter_actor_rerealize() (inside Clutter) or just call your
1639  * code that recreates your resources directly (outside Clutter).
1640  */
1641
1642 #ifdef CLUTTER_ENABLE_DEBUG
1643   clutter_actor_verify_map_state (self);
1644 #endif
1645
1646   clutter_actor_hide (self);
1647
1648   clutter_actor_unrealize_not_hiding (self);
1649 }
1650
1651 static ClutterActorTraverseVisitFlags
1652 unrealize_actor_before_children_cb (ClutterActor *self,
1653                                     int depth,
1654                                     void *user_data)
1655 {
1656   /* If an actor is already unrealized we know its children have also
1657    * already been unrealized... */
1658   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1659     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1660
1661   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1662
1663   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1664 }
1665
1666 static ClutterActorTraverseVisitFlags
1667 unrealize_actor_after_children_cb (ClutterActor *self,
1668                                    int depth,
1669                                    void *user_data)
1670 {
1671   /* We want to unset the realized flag only _after_
1672    * child actors are unrealized, to maintain invariants.
1673    */
1674   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1675   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1676   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1677 }
1678
1679 /*
1680  * clutter_actor_unrealize_not_hiding:
1681  * @self: A #ClutterActor
1682  *
1683  * Unrealization informs the actor that it may be being destroyed or
1684  * moved to another stage. The actor may want to destroy any
1685  * underlying graphics resources at this point. However it is
1686  * perfectly acceptable for it to retain the resources until the actor
1687  * is destroyed because Clutter only ever uses a single rendering
1688  * context and all of the graphics resources are valid on any stage.
1689  *
1690  * Because mapped actors must be realized, actors may not be
1691  * unrealized if they are mapped. You must hide the actor or one of
1692  * its parents before attempting to unrealize.
1693  *
1694  * This function is separate from clutter_actor_unrealize() because it
1695  * does not automatically hide the actor.
1696  * Actors need not be hidden to be unrealized, they just need to
1697  * be unmapped. In fact we don't want to mess up the application's
1698  * setting of the "visible" flag, so hiding is very undesirable.
1699  *
1700  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1701  * backward compatibility.
1702  */
1703 static void
1704 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1705 {
1706   _clutter_actor_traverse (self,
1707                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1708                            unrealize_actor_before_children_cb,
1709                            unrealize_actor_after_children_cb,
1710                            NULL);
1711 }
1712
1713 /*
1714  * _clutter_actor_rerealize:
1715  * @self: A #ClutterActor
1716  * @callback: Function to call while unrealized
1717  * @data: data for callback
1718  *
1719  * If an actor is already unrealized, this just calls the callback.
1720  *
1721  * If it is realized, it unrealizes temporarily, calls the callback,
1722  * and then re-realizes the actor.
1723  *
1724  * As a side effect, leaves all children of the actor unrealized if
1725  * the actor was realized but not showing.  This is because when we
1726  * unrealize the actor temporarily we must unrealize its children
1727  * (e.g. children of a stage can't be realized if stage window is
1728  * gone). And we aren't clever enough to save the realization state of
1729  * all children. In most cases this should not matter, because
1730  * the children will automatically realize when they next become mapped.
1731  */
1732 void
1733 _clutter_actor_rerealize (ClutterActor    *self,
1734                           ClutterCallback  callback,
1735                           void            *data)
1736 {
1737   gboolean was_mapped;
1738   gboolean was_showing;
1739   gboolean was_realized;
1740
1741   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1742
1743 #ifdef CLUTTER_ENABLE_DEBUG
1744   clutter_actor_verify_map_state (self);
1745 #endif
1746
1747   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1748   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1749   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1750
1751   /* Must be unmapped to unrealize. Note we only have to hide this
1752    * actor if it was mapped (if all parents were showing).  If actor
1753    * is merely visible (but not mapped), then that's fine, we can
1754    * leave it visible.
1755    */
1756   if (was_mapped)
1757     clutter_actor_hide (self);
1758
1759   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1760
1761   /* unrealize self and all children */
1762   clutter_actor_unrealize_not_hiding (self);
1763
1764   if (callback != NULL)
1765     {
1766       (* callback) (self, data);
1767     }
1768
1769   if (was_showing)
1770     clutter_actor_show (self); /* will realize only if mapping implies it */
1771   else if (was_realized)
1772     clutter_actor_realize (self); /* realize self and all parents */
1773 }
1774
1775 static void
1776 clutter_actor_real_pick (ClutterActor       *self,
1777                          const ClutterColor *color)
1778 {
1779   /* the default implementation is just to paint a rectangle
1780    * with the same size of the actor using the passed color
1781    */
1782   if (clutter_actor_should_pick_paint (self))
1783     {
1784       ClutterActorBox box = { 0, };
1785       float width, height;
1786
1787       clutter_actor_get_allocation_box (self, &box);
1788
1789       width = box.x2 - box.x1;
1790       height = box.y2 - box.y1;
1791
1792       cogl_set_source_color4ub (color->red,
1793                                 color->green,
1794                                 color->blue,
1795                                 color->alpha);
1796
1797       cogl_rectangle (0, 0, width, height);
1798     }
1799
1800   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1801    * with existing container classes that override the pick() virtual
1802    * and chain up to the default implementation - otherwise we'll end up
1803    * painting our children twice.
1804    *
1805    * this has to go away for 2.0; hopefully along the pick() itself.
1806    */
1807   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1808     {
1809       ClutterActor *iter;
1810
1811       for (iter = self->priv->first_child;
1812            iter != NULL;
1813            iter = iter->priv->next_sibling)
1814         clutter_actor_paint (iter);
1815     }
1816 }
1817
1818 /**
1819  * clutter_actor_should_pick_paint:
1820  * @self: A #ClutterActor
1821  *
1822  * Should be called inside the implementation of the
1823  * #ClutterActor::pick virtual function in order to check whether
1824  * the actor should paint itself in pick mode or not.
1825  *
1826  * This function should never be called directly by applications.
1827  *
1828  * Return value: %TRUE if the actor should paint its silhouette,
1829  *   %FALSE otherwise
1830  */
1831 gboolean
1832 clutter_actor_should_pick_paint (ClutterActor *self)
1833 {
1834   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1835
1836   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1837       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1838        CLUTTER_ACTOR_IS_REACTIVE (self)))
1839     return TRUE;
1840
1841   return FALSE;
1842 }
1843
1844 static void
1845 clutter_actor_real_get_preferred_width (ClutterActor *self,
1846                                         gfloat        for_height,
1847                                         gfloat       *min_width_p,
1848                                         gfloat       *natural_width_p)
1849 {
1850   ClutterActorPrivate *priv = self->priv;
1851
1852   if (priv->n_children != 0 &&
1853       priv->layout_manager != NULL)
1854     {
1855       ClutterContainer *container = CLUTTER_CONTAINER (self);
1856
1857       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1858                     "for the preferred width",
1859                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1860                     priv->layout_manager);
1861
1862       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1863                                                   container,
1864                                                   for_height,
1865                                                   min_width_p,
1866                                                   natural_width_p);
1867
1868       return;
1869     }
1870
1871   /* Default implementation is always 0x0, usually an actor
1872    * using this default is relying on someone to set the
1873    * request manually
1874    */
1875   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1876
1877   if (min_width_p)
1878     *min_width_p = 0;
1879
1880   if (natural_width_p)
1881     *natural_width_p = 0;
1882 }
1883
1884 static void
1885 clutter_actor_real_get_preferred_height (ClutterActor *self,
1886                                          gfloat        for_width,
1887                                          gfloat       *min_height_p,
1888                                          gfloat       *natural_height_p)
1889 {
1890   ClutterActorPrivate *priv = self->priv;
1891
1892   if (priv->n_children != 0 &&
1893       priv->layout_manager != NULL)
1894     {
1895       ClutterContainer *container = CLUTTER_CONTAINER (self);
1896
1897       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1898                     "for the preferred height",
1899                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1900                     priv->layout_manager);
1901
1902       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1903                                                    container,
1904                                                    for_width,
1905                                                    min_height_p,
1906                                                    natural_height_p);
1907
1908       return;
1909     }
1910   /* Default implementation is always 0x0, usually an actor
1911    * using this default is relying on someone to set the
1912    * request manually
1913    */
1914   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1915
1916   if (min_height_p)
1917     *min_height_p = 0;
1918
1919   if (natural_height_p)
1920     *natural_height_p = 0;
1921 }
1922
1923 static void
1924 clutter_actor_store_old_geometry (ClutterActor    *self,
1925                                   ClutterActorBox *box)
1926 {
1927   *box = self->priv->allocation;
1928 }
1929
1930 static inline void
1931 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1932                                           const ClutterActorBox *old)
1933 {
1934   ClutterActorPrivate *priv = self->priv;
1935   GObject *obj = G_OBJECT (self);
1936
1937   g_object_freeze_notify (obj);
1938
1939   /* to avoid excessive requisition or allocation cycles we
1940    * use the cached values.
1941    *
1942    * - if we don't have an allocation we assume that we need
1943    *   to notify anyway
1944    * - if we don't have a width or a height request we notify
1945    *   width and height
1946    * - if we have a valid allocation then we check the old
1947    *   bounding box with the current allocation and we notify
1948    *   the changes
1949    */
1950   if (priv->needs_allocation)
1951     {
1952       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1953       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1954       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1955       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1956     }
1957   else if (priv->needs_width_request || priv->needs_height_request)
1958     {
1959       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1960       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1961     }
1962   else
1963     {
1964       gfloat xu, yu;
1965       gfloat widthu, heightu;
1966
1967       xu = priv->allocation.x1;
1968       yu = priv->allocation.y1;
1969       widthu = priv->allocation.x2 - priv->allocation.x1;
1970       heightu = priv->allocation.y2 - priv->allocation.y1;
1971
1972       if (xu != old->x1)
1973         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1974
1975       if (yu != old->y1)
1976         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1977
1978       if (widthu != (old->x2 - old->x1))
1979         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1980
1981       if (heightu != (old->y2 - old->y1))
1982         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1983     }
1984
1985   g_object_thaw_notify (obj);
1986 }
1987
1988 /*< private >
1989  * clutter_actor_set_allocation_internal:
1990  * @self: a #ClutterActor
1991  * @box: a #ClutterActorBox
1992  * @flags: allocation flags
1993  *
1994  * Stores the allocation of @self.
1995  *
1996  * This function only performs basic storage and property notification.
1997  *
1998  * This function should be called by clutter_actor_set_allocation()
1999  * and by the default implementation of #ClutterActorClass.allocate().
2000  *
2001  * Return value: %TRUE if the allocation of the #ClutterActor has been
2002  *   changed, and %FALSE otherwise
2003  */
2004 static inline gboolean
2005 clutter_actor_set_allocation_internal (ClutterActor           *self,
2006                                        const ClutterActorBox  *box,
2007                                        ClutterAllocationFlags  flags)
2008 {
2009   ClutterActorPrivate *priv = self->priv;
2010   GObject *obj;
2011   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2012   gboolean flags_changed;
2013   gboolean retval;
2014   ClutterActorBox old_alloc = { 0, };
2015
2016   obj = G_OBJECT (self);
2017
2018   g_object_freeze_notify (obj);
2019
2020   clutter_actor_store_old_geometry (self, &old_alloc);
2021
2022   x1_changed = priv->allocation.x1 != box->x1;
2023   y1_changed = priv->allocation.y1 != box->y1;
2024   x2_changed = priv->allocation.x2 != box->x2;
2025   y2_changed = priv->allocation.y2 != box->y2;
2026
2027   flags_changed = priv->allocation_flags != flags;
2028
2029   priv->allocation = *box;
2030   priv->allocation_flags = flags;
2031
2032   /* allocation is authoritative */
2033   priv->needs_width_request = FALSE;
2034   priv->needs_height_request = FALSE;
2035   priv->needs_allocation = FALSE;
2036
2037   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2038     {
2039       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2040                     _clutter_actor_get_debug_name (self));
2041
2042       priv->transform_valid = FALSE;
2043
2044       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2045
2046       retval = TRUE;
2047     }
2048   else
2049     retval = FALSE;
2050
2051   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2052
2053   g_object_thaw_notify (obj);
2054
2055   return retval;
2056 }
2057
2058 static void clutter_actor_real_allocate (ClutterActor           *self,
2059                                          const ClutterActorBox  *box,
2060                                          ClutterAllocationFlags  flags);
2061
2062 static inline void
2063 clutter_actor_maybe_layout_children (ClutterActor           *self,
2064                                      const ClutterActorBox  *allocation,
2065                                      ClutterAllocationFlags  flags)
2066 {
2067   ClutterActorPrivate *priv = self->priv;
2068
2069   /* this is going to be a bit hard to follow, so let's put an explanation
2070    * here.
2071    *
2072    * we want ClutterActor to have a default layout manager if the actor was
2073    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2074    *
2075    * we also want any subclass of ClutterActor that does not override the
2076    * ::allocate() virtual function to delegate to a layout manager.
2077    *
2078    * finally, we want to allow people subclassing ClutterActor and overriding
2079    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2080    *
2081    * on the other hand, we want existing actor subclasses overriding the
2082    * ::allocate() virtual function and chaining up to the parent's
2083    * implementation to continue working without allocating their children
2084    * twice, or without entering an allocation loop.
2085    *
2086    * for the first two points, we check if the class of the actor is
2087    * overridding the ::allocate() virtual function; if it isn't, then we
2088    * follow through with checking whether we have children and a layout
2089    * manager, and eventually calling clutter_layout_manager_allocate().
2090    *
2091    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2092    * allocation flags that we got passed, and if it is present, we continue
2093    * with the check above.
2094    *
2095    * if neither of these two checks yields a positive result, we just
2096    * assume that the ::allocate() virtual function that resulted in this
2097    * function being called will also allocate the children of the actor.
2098    */
2099
2100   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2101     goto check_layout;
2102
2103   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2104     goto check_layout;
2105
2106   return;
2107
2108 check_layout:
2109   if (priv->n_children != 0 &&
2110       priv->layout_manager != NULL)
2111     {
2112       ClutterContainer *container = CLUTTER_CONTAINER (self);
2113       ClutterAllocationFlags children_flags;
2114       ClutterActorBox children_box;
2115
2116       /* normalize the box passed to the layout manager */
2117       children_box.x1 = children_box.y1 = 0.f;
2118       children_box.x2 = (allocation->x2 - allocation->x1);
2119       children_box.y2 = (allocation->y2 - allocation->y1);
2120
2121       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2122        * the actor's children, since it refers only to the current
2123        * actor's allocation.
2124        */
2125       children_flags = flags;
2126       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2127
2128       CLUTTER_NOTE (LAYOUT,
2129                     "Allocating %d children of %s "
2130                     "at { %.2f, %.2f - %.2f x %.2f } "
2131                     "using %s",
2132                     priv->n_children,
2133                     _clutter_actor_get_debug_name (self),
2134                     allocation->x1,
2135                     allocation->y1,
2136                     (allocation->x2 - allocation->x1),
2137                     (allocation->y2 - allocation->y1),
2138                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2139
2140       clutter_layout_manager_allocate (priv->layout_manager,
2141                                        container,
2142                                        &children_box,
2143                                        children_flags);
2144     }
2145 }
2146
2147 static void
2148 clutter_actor_real_allocate (ClutterActor           *self,
2149                              const ClutterActorBox  *box,
2150                              ClutterAllocationFlags  flags)
2151 {
2152   ClutterActorPrivate *priv = self->priv;
2153   gboolean changed;
2154
2155   g_object_freeze_notify (G_OBJECT (self));
2156
2157   changed = clutter_actor_set_allocation_internal (self, box, flags);
2158
2159   /* we allocate our children before we notify changes in our geometry,
2160    * so that people connecting to properties will be able to get valid
2161    * data out of the sub-tree of the scene graph that has this actor at
2162    * the root.
2163    */
2164   clutter_actor_maybe_layout_children (self, box, flags);
2165
2166   if (changed)
2167     {
2168       ClutterActorBox signal_box = priv->allocation;
2169       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2170
2171       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2172                      &signal_box,
2173                      signal_flags);
2174     }
2175
2176   g_object_thaw_notify (G_OBJECT (self));
2177 }
2178
2179 static void
2180 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2181                                     ClutterActor *origin)
2182 {
2183   /* no point in queuing a redraw on a destroyed actor */
2184   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2185     return;
2186
2187   /* NB: We can't bail out early here if the actor is hidden in case
2188    * the actor bas been cloned. In this case the clone will need to
2189    * receive the signal so it can queue its own redraw.
2190    */
2191
2192   /* calls klass->queue_redraw in default handler */
2193   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2194 }
2195
2196 static void
2197 clutter_actor_real_queue_redraw (ClutterActor *self,
2198                                  ClutterActor *origin)
2199 {
2200   ClutterActor *parent;
2201
2202   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2203                 _clutter_actor_get_debug_name (self),
2204                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2205                                : "same actor");
2206
2207   /* no point in queuing a redraw on a destroyed actor */
2208   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2209     return;
2210
2211   /* If the queue redraw is coming from a child then the actor has
2212      become dirty and any queued effect is no longer valid */
2213   if (self != origin)
2214     {
2215       self->priv->is_dirty = TRUE;
2216       self->priv->effect_to_redraw = NULL;
2217     }
2218
2219   /* If the actor isn't visible, we still had to emit the signal
2220    * to allow for a ClutterClone, but the appearance of the parent
2221    * won't change so we don't have to propagate up the hierarchy.
2222    */
2223   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2224     return;
2225
2226   /* Although we could determine here that a full stage redraw
2227    * has already been queued and immediately bail out, we actually
2228    * guarantee that we will propagate a queue-redraw signal to our
2229    * parent at least once so that it's possible to implement a
2230    * container that tracks which of its children have queued a
2231    * redraw.
2232    */
2233   if (self->priv->propagated_one_redraw)
2234     {
2235       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2236       if (stage != NULL &&
2237           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2238         return;
2239     }
2240
2241   self->priv->propagated_one_redraw = TRUE;
2242
2243   /* notify parents, if they are all visible eventually we'll
2244    * queue redraw on the stage, which queues the redraw idle.
2245    */
2246   parent = clutter_actor_get_parent (self);
2247   if (parent != NULL)
2248     {
2249       /* this will go up recursively */
2250       _clutter_actor_signal_queue_redraw (parent, origin);
2251     }
2252 }
2253
2254 static void
2255 clutter_actor_real_queue_relayout (ClutterActor *self)
2256 {
2257   ClutterActorPrivate *priv = self->priv;
2258
2259   /* no point in queueing a redraw on a destroyed actor */
2260   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2261     return;
2262
2263   priv->needs_width_request  = TRUE;
2264   priv->needs_height_request = TRUE;
2265   priv->needs_allocation     = TRUE;
2266
2267   /* reset the cached size requests */
2268   memset (priv->width_requests, 0,
2269           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2270   memset (priv->height_requests, 0,
2271           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2272
2273   /* We need to go all the way up the hierarchy */
2274   if (priv->parent != NULL)
2275     _clutter_actor_queue_only_relayout (priv->parent);
2276 }
2277
2278 /**
2279  * clutter_actor_apply_relative_transform_to_point:
2280  * @self: A #ClutterActor
2281  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2282  *   default #ClutterStage
2283  * @point: A point as #ClutterVertex
2284  * @vertex: (out caller-allocates): The translated #ClutterVertex
2285  *
2286  * Transforms @point in coordinates relative to the actor into
2287  * ancestor-relative coordinates using the relevant transform
2288  * stack (i.e. scale, rotation, etc).
2289  *
2290  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2291  * this case, the coordinates returned will be the coordinates on
2292  * the stage before the projection is applied. This is different from
2293  * the behaviour of clutter_actor_apply_transform_to_point().
2294  *
2295  * Since: 0.6
2296  */
2297 void
2298 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2299                                                  ClutterActor        *ancestor,
2300                                                  const ClutterVertex *point,
2301                                                  ClutterVertex       *vertex)
2302 {
2303   gfloat w;
2304   CoglMatrix matrix;
2305
2306   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2307   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2308   g_return_if_fail (point != NULL);
2309   g_return_if_fail (vertex != NULL);
2310
2311   *vertex = *point;
2312   w = 1.0;
2313
2314   if (ancestor == NULL)
2315     ancestor = _clutter_actor_get_stage_internal (self);
2316
2317   if (ancestor == NULL)
2318     {
2319       *vertex = *point;
2320       return;
2321     }
2322
2323   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2324   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2325 }
2326
2327 static gboolean
2328 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2329                                          const ClutterVertex *vertices_in,
2330                                          ClutterVertex *vertices_out,
2331                                          int n_vertices)
2332 {
2333   ClutterActor *stage;
2334   CoglMatrix modelview;
2335   CoglMatrix projection;
2336   float viewport[4];
2337
2338   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2339
2340   stage = _clutter_actor_get_stage_internal (self);
2341
2342   /* We really can't do anything meaningful in this case so don't try
2343    * to do any transform */
2344   if (stage == NULL)
2345     return FALSE;
2346
2347   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2348    * that gets us to stage coordinates, we want to go all the way to eye
2349    * coordinates */
2350   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2351
2352   /* Fetch the projection and viewport */
2353   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2354   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2355                                &viewport[0],
2356                                &viewport[1],
2357                                &viewport[2],
2358                                &viewport[3]);
2359
2360   _clutter_util_fully_transform_vertices (&modelview,
2361                                           &projection,
2362                                           viewport,
2363                                           vertices_in,
2364                                           vertices_out,
2365                                           n_vertices);
2366
2367   return TRUE;
2368 }
2369
2370 /**
2371  * clutter_actor_apply_transform_to_point:
2372  * @self: A #ClutterActor
2373  * @point: A point as #ClutterVertex
2374  * @vertex: (out caller-allocates): The translated #ClutterVertex
2375  *
2376  * Transforms @point in coordinates relative to the actor
2377  * into screen-relative coordinates with the current actor
2378  * transformation (i.e. scale, rotation, etc)
2379  *
2380  * Since: 0.4
2381  **/
2382 void
2383 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2384                                         const ClutterVertex *point,
2385                                         ClutterVertex       *vertex)
2386 {
2387   g_return_if_fail (point != NULL);
2388   g_return_if_fail (vertex != NULL);
2389   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2390 }
2391
2392 /*
2393  * _clutter_actor_get_relative_transformation_matrix:
2394  * @self: The actor whose coordinate space you want to transform from.
2395  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2396  *            or %NULL if you want to transform all the way to eye coordinates.
2397  * @matrix: A #CoglMatrix to store the transformation
2398  *
2399  * This gets a transformation @matrix that will transform coordinates from the
2400  * coordinate space of @self into the coordinate space of @ancestor.
2401  *
2402  * For example if you need a matrix that can transform the local actor
2403  * coordinates of @self into stage coordinates you would pass the actor's stage
2404  * pointer as the @ancestor.
2405  *
2406  * If you pass %NULL then the transformation will take you all the way through
2407  * to eye coordinates. This can be useful if you want to extract the entire
2408  * modelview transform that Clutter applies before applying the projection
2409  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2410  * using cogl_set_modelview_matrix() for example then you would want a matrix
2411  * that transforms into eye coordinates.
2412  *
2413  * <note><para>This function explicitly initializes the given @matrix. If you just
2414  * want clutter to multiply a relative transformation with an existing matrix
2415  * you can use clutter_actor_apply_relative_transformation_matrix()
2416  * instead.</para></note>
2417  *
2418  */
2419 /* XXX: We should consider caching the stage relative modelview along with
2420  * the actor itself */
2421 static void
2422 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2423                                                    ClutterActor *ancestor,
2424                                                    CoglMatrix *matrix)
2425 {
2426   cogl_matrix_init_identity (matrix);
2427
2428   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2429 }
2430
2431 /* Project the given @box into stage window coordinates, writing the
2432  * transformed vertices to @verts[]. */
2433 static gboolean
2434 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2435                                           const ClutterActorBox *box,
2436                                           ClutterVertex          verts[])
2437 {
2438   ClutterVertex box_vertices[4];
2439
2440   box_vertices[0].x = box->x1;
2441   box_vertices[0].y = box->y1;
2442   box_vertices[0].z = 0;
2443   box_vertices[1].x = box->x2;
2444   box_vertices[1].y = box->y1;
2445   box_vertices[1].z = 0;
2446   box_vertices[2].x = box->x1;
2447   box_vertices[2].y = box->y2;
2448   box_vertices[2].z = 0;
2449   box_vertices[3].x = box->x2;
2450   box_vertices[3].y = box->y2;
2451   box_vertices[3].z = 0;
2452
2453   return
2454     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2455 }
2456
2457 /**
2458  * clutter_actor_get_allocation_vertices:
2459  * @self: A #ClutterActor
2460  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2461  *   against, or %NULL to use the #ClutterStage
2462  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2463  *   location for an array of 4 #ClutterVertex in which to store the result
2464  *
2465  * Calculates the transformed coordinates of the four corners of the
2466  * actor in the plane of @ancestor. The returned vertices relate to
2467  * the #ClutterActorBox coordinates as follows:
2468  * <itemizedlist>
2469  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2470  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2471  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2472  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2473  * </itemizedlist>
2474  *
2475  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2476  * this case, the coordinates returned will be the coordinates on
2477  * the stage before the projection is applied. This is different from
2478  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2479  *
2480  * Since: 0.6
2481  */
2482 void
2483 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2484                                        ClutterActor  *ancestor,
2485                                        ClutterVertex  verts[])
2486 {
2487   ClutterActorPrivate *priv;
2488   ClutterActorBox box;
2489   ClutterVertex vertices[4];
2490   CoglMatrix modelview;
2491
2492   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2493   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2494
2495   if (ancestor == NULL)
2496     ancestor = _clutter_actor_get_stage_internal (self);
2497
2498   /* Fallback to a NOP transform if the actor isn't parented under a
2499    * stage. */
2500   if (ancestor == NULL)
2501     ancestor = self;
2502
2503   priv = self->priv;
2504
2505   /* if the actor needs to be allocated we force a relayout, so that
2506    * we will have valid values to use in the transformations */
2507   if (priv->needs_allocation)
2508     {
2509       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2510       if (stage)
2511         _clutter_stage_maybe_relayout (stage);
2512       else
2513         {
2514           box.x1 = box.y1 = 0;
2515           /* The result isn't really meaningful in this case but at
2516            * least try to do something *vaguely* reasonable... */
2517           clutter_actor_get_size (self, &box.x2, &box.y2);
2518         }
2519     }
2520
2521   clutter_actor_get_allocation_box (self, &box);
2522
2523   vertices[0].x = box.x1;
2524   vertices[0].y = box.y1;
2525   vertices[0].z = 0;
2526   vertices[1].x = box.x2;
2527   vertices[1].y = box.y1;
2528   vertices[1].z = 0;
2529   vertices[2].x = box.x1;
2530   vertices[2].y = box.y2;
2531   vertices[2].z = 0;
2532   vertices[3].x = box.x2;
2533   vertices[3].y = box.y2;
2534   vertices[3].z = 0;
2535
2536   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2537                                                      &modelview);
2538
2539   cogl_matrix_transform_points (&modelview,
2540                                 3,
2541                                 sizeof (ClutterVertex),
2542                                 vertices,
2543                                 sizeof (ClutterVertex),
2544                                 vertices,
2545                                 4);
2546 }
2547
2548 /**
2549  * clutter_actor_get_abs_allocation_vertices:
2550  * @self: A #ClutterActor
2551  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2552  *   of 4 #ClutterVertex where to store the result.
2553  *
2554  * Calculates the transformed screen coordinates of the four corners of
2555  * the actor; the returned vertices relate to the #ClutterActorBox
2556  * coordinates  as follows:
2557  * <itemizedlist>
2558  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2559  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2560  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2561  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2562  * </itemizedlist>
2563  *
2564  * Since: 0.4
2565  */
2566 void
2567 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2568                                            ClutterVertex  verts[])
2569 {
2570   ClutterActorPrivate *priv;
2571   ClutterActorBox actor_space_allocation;
2572
2573   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2574
2575   priv = self->priv;
2576
2577   /* if the actor needs to be allocated we force a relayout, so that
2578    * the actor allocation box will be valid for
2579    * _clutter_actor_transform_and_project_box()
2580    */
2581   if (priv->needs_allocation)
2582     {
2583       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2584       /* There's nothing meaningful we can do now */
2585       if (!stage)
2586         return;
2587
2588       _clutter_stage_maybe_relayout (stage);
2589     }
2590
2591   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2592    * own coordinate space... */
2593   actor_space_allocation.x1 = 0;
2594   actor_space_allocation.y1 = 0;
2595   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2596   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2597   _clutter_actor_transform_and_project_box (self,
2598                                             &actor_space_allocation,
2599                                             verts);
2600 }
2601
2602 static void
2603 clutter_actor_real_apply_transform (ClutterActor *self,
2604                                     CoglMatrix   *matrix)
2605 {
2606   ClutterActorPrivate *priv = self->priv;
2607
2608   if (!priv->transform_valid)
2609     {
2610       CoglMatrix *transform = &priv->transform;
2611       const ClutterTransformInfo *info;
2612
2613       info = _clutter_actor_get_transform_info_or_defaults (self);
2614
2615       cogl_matrix_init_identity (transform);
2616
2617       cogl_matrix_translate (transform,
2618                              priv->allocation.x1,
2619                              priv->allocation.y1,
2620                              0.0);
2621
2622       if (info->depth)
2623         cogl_matrix_translate (transform, 0, 0, info->depth);
2624
2625       /*
2626        * because the rotation involves translations, we must scale
2627        * before applying the rotations (if we apply the scale after
2628        * the rotations, the translations included in the rotation are
2629        * not scaled and so the entire object will move on the screen
2630        * as a result of rotating it).
2631        */
2632       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2633         {
2634           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2635                                         &info->scale_center,
2636                                         cogl_matrix_scale (transform,
2637                                                            info->scale_x,
2638                                                            info->scale_y,
2639                                                            1.0));
2640         }
2641
2642       if (info->rz_angle)
2643         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2644                                       &info->rz_center,
2645                                       cogl_matrix_rotate (transform,
2646                                                           info->rz_angle,
2647                                                           0, 0, 1.0));
2648
2649       if (info->ry_angle)
2650         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2651                                       &info->ry_center,
2652                                       cogl_matrix_rotate (transform,
2653                                                           info->ry_angle,
2654                                                           0, 1.0, 0));
2655
2656       if (info->rx_angle)
2657         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2658                                       &info->rx_center,
2659                                       cogl_matrix_rotate (transform,
2660                                                           info->rx_angle,
2661                                                           1.0, 0, 0));
2662
2663       if (!clutter_anchor_coord_is_zero (&info->anchor))
2664         {
2665           gfloat x, y, z;
2666
2667           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2668           cogl_matrix_translate (transform, -x, -y, -z);
2669         }
2670
2671       priv->transform_valid = TRUE;
2672     }
2673
2674   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2675 }
2676
2677 /* Applies the transforms associated with this actor to the given
2678  * matrix. */
2679 void
2680 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2681                                           CoglMatrix *matrix)
2682 {
2683   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2684 }
2685
2686 /*
2687  * clutter_actor_apply_relative_transformation_matrix:
2688  * @self: The actor whose coordinate space you want to transform from.
2689  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2690  *            or %NULL if you want to transform all the way to eye coordinates.
2691  * @matrix: A #CoglMatrix to apply the transformation too.
2692  *
2693  * This multiplies a transform with @matrix that will transform coordinates
2694  * from the coordinate space of @self into the coordinate space of @ancestor.
2695  *
2696  * For example if you need a matrix that can transform the local actor
2697  * coordinates of @self into stage coordinates you would pass the actor's stage
2698  * pointer as the @ancestor.
2699  *
2700  * If you pass %NULL then the transformation will take you all the way through
2701  * to eye coordinates. This can be useful if you want to extract the entire
2702  * modelview transform that Clutter applies before applying the projection
2703  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2704  * using cogl_set_modelview_matrix() for example then you would want a matrix
2705  * that transforms into eye coordinates.
2706  *
2707  * <note>This function doesn't initialize the given @matrix, it simply
2708  * multiplies the requested transformation matrix with the existing contents of
2709  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2710  * before calling this function, or you can use
2711  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2712  */
2713 void
2714 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2715                                                      ClutterActor *ancestor,
2716                                                      CoglMatrix *matrix)
2717 {
2718   ClutterActor *parent;
2719
2720   /* Note we terminate before ever calling stage->apply_transform()
2721    * since that would conceptually be relative to the underlying
2722    * window OpenGL coordinates so we'd need a special @ancestor
2723    * value to represent the fake parent of the stage. */
2724   if (self == ancestor)
2725     return;
2726
2727   parent = clutter_actor_get_parent (self);
2728
2729   if (parent != NULL)
2730     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2731                                                          matrix);
2732
2733   _clutter_actor_apply_modelview_transform (self, matrix);
2734 }
2735
2736 static void
2737 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2738                                        ClutterPaintVolume *pv,
2739                                        const char *label,
2740                                        const CoglColor *color)
2741 {
2742   static CoglPipeline *outline = NULL;
2743   CoglPrimitive *prim;
2744   ClutterVertex line_ends[12 * 2];
2745   int n_vertices;
2746   CoglContext *ctx =
2747     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2748   /* XXX: at some point we'll query this from the stage but we can't
2749    * do that until the osx backend uses Cogl natively. */
2750   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2751
2752   if (outline == NULL)
2753     outline = cogl_pipeline_new (ctx);
2754
2755   _clutter_paint_volume_complete (pv);
2756
2757   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2758
2759   /* Front face */
2760   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2761   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2762   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2763   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2764
2765   if (!pv->is_2d)
2766     {
2767       /* Back face */
2768       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2769       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2770       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2771       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2772
2773       /* Lines connecting front face to back face */
2774       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2775       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2776       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2777       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2778     }
2779
2780   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2781                                 n_vertices,
2782                                 (CoglVertexP3 *)line_ends);
2783
2784   cogl_pipeline_set_color (outline, color);
2785   cogl_framebuffer_draw_primitive (fb, outline, prim);
2786   cogl_object_unref (prim);
2787
2788   if (label)
2789     {
2790       PangoLayout *layout;
2791       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2792       pango_layout_set_text (layout, label, -1);
2793       cogl_pango_render_layout (layout,
2794                                 pv->vertices[0].x,
2795                                 pv->vertices[0].y,
2796                                 color,
2797                                 0);
2798       g_object_unref (layout);
2799     }
2800 }
2801
2802 static void
2803 _clutter_actor_draw_paint_volume (ClutterActor *self)
2804 {
2805   ClutterPaintVolume *pv;
2806   CoglColor color;
2807
2808   pv = _clutter_actor_get_paint_volume_mutable (self);
2809   if (!pv)
2810     {
2811       gfloat width, height;
2812       ClutterPaintVolume fake_pv;
2813
2814       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2815       _clutter_paint_volume_init_static (&fake_pv, stage);
2816
2817       clutter_actor_get_size (self, &width, &height);
2818       clutter_paint_volume_set_width (&fake_pv, width);
2819       clutter_paint_volume_set_height (&fake_pv, height);
2820
2821       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2822       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2823                                              _clutter_actor_get_debug_name (self),
2824                                              &color);
2825
2826       clutter_paint_volume_free (&fake_pv);
2827     }
2828   else
2829     {
2830       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2831       _clutter_actor_draw_paint_volume_full (self, pv,
2832                                              _clutter_actor_get_debug_name (self),
2833                                              &color);
2834     }
2835 }
2836
2837 static void
2838 _clutter_actor_paint_cull_result (ClutterActor *self,
2839                                   gboolean success,
2840                                   ClutterCullResult result)
2841 {
2842   ClutterPaintVolume *pv;
2843   CoglColor color;
2844
2845   if (success)
2846     {
2847       if (result == CLUTTER_CULL_RESULT_IN)
2848         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2849       else if (result == CLUTTER_CULL_RESULT_OUT)
2850         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2851       else
2852         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2853     }
2854   else
2855     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2856
2857   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2858     _clutter_actor_draw_paint_volume_full (self, pv,
2859                                            _clutter_actor_get_debug_name (self),
2860                                            &color);
2861   else
2862     {
2863       PangoLayout *layout;
2864       char *label =
2865         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2866       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2867       cogl_set_source_color (&color);
2868
2869       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2870       pango_layout_set_text (layout, label, -1);
2871       cogl_pango_render_layout (layout,
2872                                 0,
2873                                 0,
2874                                 &color,
2875                                 0);
2876       g_free (label);
2877       g_object_unref (layout);
2878     }
2879 }
2880
2881 static int clone_paint_level = 0;
2882
2883 void
2884 _clutter_actor_push_clone_paint (void)
2885 {
2886   clone_paint_level++;
2887 }
2888
2889 void
2890 _clutter_actor_pop_clone_paint (void)
2891 {
2892   clone_paint_level--;
2893 }
2894
2895 static gboolean
2896 in_clone_paint (void)
2897 {
2898   return clone_paint_level > 0;
2899 }
2900
2901 /* Returns TRUE if the actor can be ignored */
2902 /* FIXME: we should return a ClutterCullResult, and
2903  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2904  * means there's no point in trying to cull descendants of the current
2905  * node. */
2906 static gboolean
2907 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2908 {
2909   ClutterActorPrivate *priv = self->priv;
2910   ClutterActor *stage;
2911   const ClutterPlane *stage_clip;
2912
2913   if (!priv->last_paint_volume_valid)
2914     {
2915       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2916                     "->last_paint_volume_valid == FALSE",
2917                     _clutter_actor_get_debug_name (self));
2918       return FALSE;
2919     }
2920
2921   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2922     return FALSE;
2923
2924   stage = _clutter_actor_get_stage_internal (self);
2925   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2926   if (G_UNLIKELY (!stage_clip))
2927     {
2928       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2929                     "No stage clip set",
2930                     _clutter_actor_get_debug_name (self));
2931       return FALSE;
2932     }
2933
2934   if (cogl_get_draw_framebuffer () !=
2935       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2936     {
2937       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2938                     "Current framebuffer doesn't correspond to stage",
2939                     _clutter_actor_get_debug_name (self));
2940       return FALSE;
2941     }
2942
2943   *result_out =
2944     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2945   return TRUE;
2946 }
2947
2948 static void
2949 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2950 {
2951   ClutterActorPrivate *priv = self->priv;
2952   const ClutterPaintVolume *pv;
2953
2954   if (priv->last_paint_volume_valid)
2955     {
2956       clutter_paint_volume_free (&priv->last_paint_volume);
2957       priv->last_paint_volume_valid = FALSE;
2958     }
2959
2960   pv = clutter_actor_get_paint_volume (self);
2961   if (!pv)
2962     {
2963       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2964                     "Actor failed to report a paint volume",
2965                     _clutter_actor_get_debug_name (self));
2966       return;
2967     }
2968
2969   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2970
2971   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2972                                             NULL); /* eye coordinates */
2973
2974   priv->last_paint_volume_valid = TRUE;
2975 }
2976
2977 static inline gboolean
2978 actor_has_shader_data (ClutterActor *self)
2979 {
2980   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2981 }
2982
2983 guint32
2984 _clutter_actor_get_pick_id (ClutterActor *self)
2985 {
2986   if (self->priv->pick_id < 0)
2987     return 0;
2988
2989   return self->priv->pick_id;
2990 }
2991
2992 /* This is the same as clutter_actor_add_effect except that it doesn't
2993    queue a redraw and it doesn't notify on the effect property */
2994 static void
2995 _clutter_actor_add_effect_internal (ClutterActor  *self,
2996                                     ClutterEffect *effect)
2997 {
2998   ClutterActorPrivate *priv = self->priv;
2999
3000   if (priv->effects == NULL)
3001     {
3002       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3003       priv->effects->actor = self;
3004     }
3005
3006   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3007 }
3008
3009 /* This is the same as clutter_actor_remove_effect except that it doesn't
3010    queue a redraw and it doesn't notify on the effect property */
3011 static void
3012 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3013                                        ClutterEffect *effect)
3014 {
3015   ClutterActorPrivate *priv = self->priv;
3016
3017   if (priv->effects == NULL)
3018     return;
3019
3020   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3021 }
3022
3023 static gboolean
3024 needs_flatten_effect (ClutterActor *self)
3025 {
3026   ClutterActorPrivate *priv = self->priv;
3027
3028   if (G_UNLIKELY (clutter_paint_debug_flags &
3029                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3030     return FALSE;
3031
3032   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3033     return TRUE;
3034   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3035     {
3036       if (clutter_actor_get_paint_opacity (self) < 255 &&
3037           clutter_actor_has_overlaps (self))
3038         return TRUE;
3039     }
3040
3041   return FALSE;
3042 }
3043
3044 static void
3045 add_or_remove_flatten_effect (ClutterActor *self)
3046 {
3047   ClutterActorPrivate *priv = self->priv;
3048
3049   /* Add or remove the flatten effect depending on the
3050      offscreen-redirect property. */
3051   if (needs_flatten_effect (self))
3052     {
3053       if (priv->flatten_effect == NULL)
3054         {
3055           ClutterActorMeta *actor_meta;
3056           gint priority;
3057
3058           priv->flatten_effect = _clutter_flatten_effect_new ();
3059           /* Keep a reference to the effect so that we can queue
3060              redraws from it */
3061           g_object_ref_sink (priv->flatten_effect);
3062
3063           /* Set the priority of the effect to high so that it will
3064              always be applied to the actor first. It uses an internal
3065              priority so that it won't be visible to applications */
3066           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3067           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3068           _clutter_actor_meta_set_priority (actor_meta, priority);
3069
3070           /* This will add the effect without queueing a redraw */
3071           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3072         }
3073     }
3074   else
3075     {
3076       if (priv->flatten_effect != NULL)
3077         {
3078           /* Destroy the effect so that it will lose its fbo cache of
3079              the actor */
3080           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3081           g_object_unref (priv->flatten_effect);
3082           priv->flatten_effect = NULL;
3083         }
3084     }
3085 }
3086
3087 static void
3088 clutter_actor_real_paint (ClutterActor *actor)
3089 {
3090   ClutterActorPrivate *priv = actor->priv;
3091   ClutterActor *iter;
3092
3093   /* paint the background color, if set */
3094   if (priv->bg_color_set)
3095     {
3096       float width, height;
3097       guint8 real_alpha;
3098
3099       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3100
3101       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3102                  * priv->bg_color.alpha
3103                  / 255;
3104
3105       cogl_set_source_color4ub (priv->bg_color.red,
3106                                 priv->bg_color.green,
3107                                 priv->bg_color.blue,
3108                                 real_alpha);
3109
3110       cogl_rectangle (0, 0, width, height);
3111     }
3112
3113   for (iter = priv->first_child;
3114        iter != NULL;
3115        iter = iter->priv->next_sibling)
3116     {
3117       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3118                     _clutter_actor_get_debug_name (iter),
3119                     _clutter_actor_get_debug_name (actor),
3120                     iter->priv->allocation.x1,
3121                     iter->priv->allocation.y1,
3122                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3123                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3124
3125       clutter_actor_paint (iter);
3126     }
3127 }
3128
3129 /**
3130  * clutter_actor_paint:
3131  * @self: A #ClutterActor
3132  *
3133  * Renders the actor to display.
3134  *
3135  * This function should not be called directly by applications.
3136  * Call clutter_actor_queue_redraw() to queue paints, instead.
3137  *
3138  * This function is context-aware, and will either cause a
3139  * regular paint or a pick paint.
3140  *
3141  * This function will emit the #ClutterActor::paint signal or
3142  * the #ClutterActor::pick signal, depending on the context.
3143  *
3144  * This function does not paint the actor if the actor is set to 0,
3145  * unless it is performing a pick paint.
3146  */
3147 void
3148 clutter_actor_paint (ClutterActor *self)
3149 {
3150   ClutterActorPrivate *priv;
3151   ClutterPickMode pick_mode;
3152   gboolean clip_set = FALSE;
3153   gboolean shader_applied = FALSE;
3154
3155   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3156                           "Actor real-paint counter",
3157                           "Increments each time any actor is painted",
3158                           0 /* no application private data */);
3159   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3160                           "Actor pick-paint counter",
3161                           "Increments each time any actor is painted "
3162                           "for picking",
3163                           0 /* no application private data */);
3164
3165   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3166
3167   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3168     return;
3169
3170   priv = self->priv;
3171
3172   pick_mode = _clutter_context_get_pick_mode ();
3173
3174   if (pick_mode == CLUTTER_PICK_NONE)
3175     priv->propagated_one_redraw = FALSE;
3176
3177   /* It's an important optimization that we consider painting of
3178    * actors with 0 opacity to be a NOP... */
3179   if (pick_mode == CLUTTER_PICK_NONE &&
3180       /* ignore top-levels, since they might be transparent */
3181       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3182       /* Use the override opacity if its been set */
3183       ((priv->opacity_override >= 0) ?
3184        priv->opacity_override : priv->opacity) == 0)
3185     return;
3186
3187   /* if we aren't paintable (not in a toplevel with all
3188    * parents paintable) then do nothing.
3189    */
3190   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3191     return;
3192
3193   /* mark that we are in the paint process */
3194   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3195
3196   cogl_push_matrix();
3197
3198   if (priv->enable_model_view_transform)
3199     {
3200       CoglMatrix matrix;
3201
3202       /* XXX: It could be better to cache the modelview with the actor
3203        * instead of progressively building up the transformations on
3204        * the matrix stack every time we paint. */
3205       cogl_get_modelview_matrix (&matrix);
3206       _clutter_actor_apply_modelview_transform (self, &matrix);
3207
3208 #ifdef CLUTTER_ENABLE_DEBUG
3209       /* Catch when out-of-band transforms have been made by actors not as part
3210        * of an apply_transform vfunc... */
3211       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3212         {
3213           CoglMatrix expected_matrix;
3214
3215           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3216                                                              &expected_matrix);
3217
3218           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3219             {
3220               GString *buf = g_string_sized_new (1024);
3221               ClutterActor *parent;
3222
3223               parent = self;
3224               while (parent != NULL)
3225                 {
3226                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3227
3228                   if (parent->priv->parent != NULL)
3229                     g_string_append (buf, "->");
3230
3231                   parent = parent->priv->parent;
3232                 }
3233
3234               g_warning ("Unexpected transform found when painting actor "
3235                          "\"%s\". This will be caused by one of the actor's "
3236                          "ancestors (%s) using the Cogl API directly to transform "
3237                          "children instead of using ::apply_transform().",
3238                          _clutter_actor_get_debug_name (self),
3239                          buf->str);
3240
3241               g_string_free (buf, TRUE);
3242             }
3243         }
3244 #endif /* CLUTTER_ENABLE_DEBUG */
3245
3246       cogl_set_modelview_matrix (&matrix);
3247     }
3248
3249   if (priv->has_clip)
3250     {
3251       cogl_clip_push_rectangle (priv->clip.x,
3252                                 priv->clip.y,
3253                                 priv->clip.x + priv->clip.width,
3254                                 priv->clip.y + priv->clip.height);
3255       clip_set = TRUE;
3256     }
3257   else if (priv->clip_to_allocation)
3258     {
3259       gfloat width, height;
3260
3261       width  = priv->allocation.x2 - priv->allocation.x1;
3262       height = priv->allocation.y2 - priv->allocation.y1;
3263
3264       cogl_clip_push_rectangle (0, 0, width, height);
3265       clip_set = TRUE;
3266     }
3267
3268   if (pick_mode == CLUTTER_PICK_NONE)
3269     {
3270       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3271
3272       /* We check whether we need to add the flatten effect before
3273          each paint so that we can avoid having a mechanism for
3274          applications to notify when the value of the
3275          has_overlaps virtual changes. */
3276       add_or_remove_flatten_effect (self);
3277     }
3278   else
3279     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3280
3281   /* We save the current paint volume so that the next time the
3282    * actor queues a redraw we can constrain the redraw to just
3283    * cover the union of the new bounding box and the old.
3284    *
3285    * We also fetch the current paint volume to perform culling so
3286    * we can avoid painting actors outside the current clip region.
3287    *
3288    * If we are painting inside a clone, we should neither update
3289    * the paint volume or use it to cull painting, since the paint
3290    * box represents the location of the source actor on the
3291    * screen.
3292    *
3293    * XXX: We are starting to do a lot of vertex transforms on
3294    * the CPU in a typical paint, so at some point we should
3295    * audit these and consider caching some things.
3296    *
3297    * NB: We don't perform culling while picking at this point because
3298    * clutter-stage.c doesn't setup the clipping planes appropriately.
3299    *
3300    * NB: We don't want to update the last-paint-volume during picking
3301    * because the last-paint-volume is used to determine the old screen
3302    * space location of an actor that has moved so we can know the
3303    * minimal region to redraw to clear an old view of the actor. If we
3304    * update this during picking then by the time we come around to
3305    * paint then the last-paint-volume would likely represent the new
3306    * actor position not the old.
3307    */
3308   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3309     {
3310       gboolean success;
3311       /* annoyingly gcc warns if uninitialized even though
3312        * the initialization is redundant :-( */
3313       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3314
3315       if (G_LIKELY ((clutter_paint_debug_flags &
3316                      (CLUTTER_DEBUG_DISABLE_CULLING |
3317                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3318                     (CLUTTER_DEBUG_DISABLE_CULLING |
3319                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3320         _clutter_actor_update_last_paint_volume (self);
3321
3322       success = cull_actor (self, &result);
3323
3324       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3325         _clutter_actor_paint_cull_result (self, success, result);
3326       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3327         goto done;
3328     }
3329
3330   if (priv->effects == NULL)
3331     {
3332       if (pick_mode == CLUTTER_PICK_NONE &&
3333           actor_has_shader_data (self))
3334         {
3335           _clutter_actor_shader_pre_paint (self, FALSE);
3336           shader_applied = TRUE;
3337         }
3338
3339       priv->next_effect_to_paint = NULL;
3340     }
3341   else
3342     priv->next_effect_to_paint =
3343       _clutter_meta_group_peek_metas (priv->effects);
3344
3345   clutter_actor_continue_paint (self);
3346
3347   if (shader_applied)
3348     _clutter_actor_shader_post_paint (self);
3349
3350   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3351                   pick_mode == CLUTTER_PICK_NONE))
3352     _clutter_actor_draw_paint_volume (self);
3353
3354 done:
3355   /* If we make it here then the actor has run through a complete
3356      paint run including all the effects so it's no longer dirty */
3357   if (pick_mode == CLUTTER_PICK_NONE)
3358     priv->is_dirty = FALSE;
3359
3360   if (clip_set)
3361     cogl_clip_pop();
3362
3363   cogl_pop_matrix();
3364
3365   /* paint sequence complete */
3366   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3367 }
3368
3369 /**
3370  * clutter_actor_continue_paint:
3371  * @self: A #ClutterActor
3372  *
3373  * Run the next stage of the paint sequence. This function should only
3374  * be called within the implementation of the ‘run’ virtual of a
3375  * #ClutterEffect. It will cause the run method of the next effect to
3376  * be applied, or it will paint the actual actor if the current effect
3377  * is the last effect in the chain.
3378  *
3379  * Since: 1.8
3380  */
3381 void
3382 clutter_actor_continue_paint (ClutterActor *self)
3383 {
3384   ClutterActorPrivate *priv;
3385
3386   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3387   /* This should only be called from with in the ‘run’ implementation
3388      of a ClutterEffect */
3389   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3390
3391   priv = self->priv;
3392
3393   /* Skip any effects that are disabled */
3394   while (priv->next_effect_to_paint &&
3395          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3396     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3397
3398   /* If this has come from the last effect then we'll just paint the
3399      actual actor */
3400   if (priv->next_effect_to_paint == NULL)
3401     {
3402       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3403         {
3404           g_signal_emit (self, actor_signals[PAINT], 0);
3405         }
3406       else
3407         {
3408           ClutterColor col = { 0, };
3409
3410           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3411
3412           /* Actor will then paint silhouette of itself in supplied
3413            * color.  See clutter_stage_get_actor_at_pos() for where
3414            * picking is enabled.
3415            */
3416           g_signal_emit (self, actor_signals[PICK], 0, &col);
3417         }
3418     }
3419   else
3420     {
3421       ClutterEffect *old_current_effect;
3422       ClutterEffectPaintFlags run_flags = 0;
3423
3424       /* Cache the current effect so that we can put it back before
3425          returning */
3426       old_current_effect = priv->current_effect;
3427
3428       priv->current_effect = priv->next_effect_to_paint->data;
3429       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3430
3431       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3432         {
3433           if (priv->is_dirty)
3434             {
3435               /* If there's an effect queued with this redraw then all
3436                  effects up to that one will be considered dirty. It
3437                  is expected the queued effect will paint the cached
3438                  image and not call clutter_actor_continue_paint again
3439                  (although it should work ok if it does) */
3440               if (priv->effect_to_redraw == NULL ||
3441                   priv->current_effect != priv->effect_to_redraw)
3442                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3443             }
3444
3445           _clutter_effect_paint (priv->current_effect, run_flags);
3446         }
3447       else
3448         {
3449           /* We can't determine when an actor has been modified since
3450              its last pick so lets just assume it has always been
3451              modified */
3452           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3453
3454           _clutter_effect_pick (priv->current_effect, run_flags);
3455         }
3456
3457       priv->current_effect = old_current_effect;
3458     }
3459 }
3460
3461 static ClutterActorTraverseVisitFlags
3462 invalidate_queue_redraw_entry (ClutterActor *self,
3463                                int           depth,
3464                                gpointer      user_data)
3465 {
3466   ClutterActorPrivate *priv = self->priv;
3467
3468   if (priv->queue_redraw_entry != NULL)
3469     {
3470       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3471       priv->queue_redraw_entry = NULL;
3472     }
3473
3474   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3475 }
3476
3477 static inline void
3478 remove_child (ClutterActor *self,
3479               ClutterActor *child)
3480 {
3481   ClutterActor *prev_sibling, *next_sibling;
3482
3483   prev_sibling = child->priv->prev_sibling;
3484   next_sibling = child->priv->next_sibling;
3485
3486   if (prev_sibling != NULL)
3487     prev_sibling->priv->next_sibling = next_sibling;
3488
3489   if (next_sibling != NULL)
3490     next_sibling->priv->prev_sibling = prev_sibling;
3491
3492   if (self->priv->first_child == child)
3493     self->priv->first_child = next_sibling;
3494
3495   if (self->priv->last_child == child)
3496     self->priv->last_child = prev_sibling;
3497
3498   child->priv->parent = NULL;
3499   child->priv->prev_sibling = NULL;
3500   child->priv->next_sibling = NULL;
3501 }
3502
3503 typedef enum {
3504   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3505   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3506   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3507   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3508   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3509   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3510
3511   /* default flags for public API */
3512   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3513                                     REMOVE_CHILD_EMIT_PARENT_SET |
3514                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3515                                     REMOVE_CHILD_CHECK_STATE |
3516                                     REMOVE_CHILD_FLUSH_QUEUE |
3517                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3518
3519   /* flags for legacy/deprecated API */
3520   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3521                                     REMOVE_CHILD_FLUSH_QUEUE |
3522                                     REMOVE_CHILD_EMIT_PARENT_SET |
3523                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3524 } ClutterActorRemoveChildFlags;
3525
3526 /*< private >
3527  * clutter_actor_remove_child_internal:
3528  * @self: a #ClutterActor
3529  * @child: the child of @self that has to be removed
3530  * @flags: control the removal operations
3531  *
3532  * Removes @child from the list of children of @self.
3533  */
3534 static void
3535 clutter_actor_remove_child_internal (ClutterActor                 *self,
3536                                      ClutterActor                 *child,
3537                                      ClutterActorRemoveChildFlags  flags)
3538 {
3539   ClutterActor *old_first, *old_last;
3540   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3541   gboolean flush_queue;
3542   gboolean notify_first_last;
3543   gboolean was_mapped;
3544
3545   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3546   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3547   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3548   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3549   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3550   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3551
3552   g_object_freeze_notify (G_OBJECT (self));
3553
3554   if (destroy_meta)
3555     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3556
3557   if (check_state)
3558     {
3559       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3560
3561       /* we need to unrealize *before* we set parent_actor to NULL,
3562        * because in an unrealize method actors are dissociating from the
3563        * stage, which means they need to be able to
3564        * clutter_actor_get_stage().
3565        *
3566        * yhis should unmap and unrealize, unless we're reparenting.
3567        */
3568       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3569     }
3570   else
3571     was_mapped = FALSE;
3572
3573   if (flush_queue)
3574     {
3575       /* We take this opportunity to invalidate any queue redraw entry
3576        * associated with the actor and descendants since we won't be able to
3577        * determine the appropriate stage after this.
3578        *
3579        * we do this after we updated the mapped state because actors might
3580        * end up queueing redraws inside their mapped/unmapped virtual
3581        * functions, and if we invalidate the redraw entry we could end up
3582        * with an inconsistent state and weird memory corruption. see
3583        * bugs:
3584        *
3585        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3586        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3587        */
3588       _clutter_actor_traverse (child,
3589                                0,
3590                                invalidate_queue_redraw_entry,
3591                                NULL,
3592                                NULL);
3593     }
3594
3595   old_first = self->priv->first_child;
3596   old_last = self->priv->last_child;
3597
3598   remove_child (self, child);
3599
3600   self->priv->n_children -= 1;
3601
3602   self->priv->age += 1;
3603
3604   /* clutter_actor_reparent() will emit ::parent-set for us */
3605   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3606     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3607
3608   /* if the child was mapped then we need to relayout ourselves to account
3609    * for the removed child
3610    */
3611   if (was_mapped)
3612     clutter_actor_queue_relayout (self);
3613
3614   /* we need to emit the signal before dropping the reference */
3615   if (emit_actor_removed)
3616     g_signal_emit_by_name (self, "actor-removed", child);
3617
3618   if (notify_first_last)
3619     {
3620       if (old_first != self->priv->first_child)
3621         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3622
3623       if (old_last != self->priv->last_child)
3624         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3625     }
3626
3627   g_object_thaw_notify (G_OBJECT (self));
3628
3629   /* remove the reference we acquired in clutter_actor_add_child() */
3630   g_object_unref (child);
3631 }
3632
3633 static const ClutterTransformInfo default_transform_info = {
3634   0.0, { 0, },          /* rotation-x */
3635   0.0, { 0, },          /* rotation-y */
3636   0.0, { 0, },          /* rotation-z */
3637
3638   1.0, 1.0, { 0, },     /* scale */
3639
3640   { 0, },               /* anchor */
3641
3642   0.0,                  /* depth */
3643 };
3644
3645 /*< private >
3646  * _clutter_actor_get_transform_info_or_defaults:
3647  * @self: a #ClutterActor
3648  *
3649  * Retrieves the ClutterTransformInfo structure associated to an actor.
3650  *
3651  * If the actor does not have a ClutterTransformInfo structure associated
3652  * to it, then the default structure will be returned.
3653  *
3654  * This function should only be used for getters.
3655  *
3656  * Return value: a const pointer to the ClutterTransformInfo structure
3657  */
3658 const ClutterTransformInfo *
3659 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3660 {
3661   ClutterTransformInfo *info;
3662
3663   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3664   if (info != NULL)
3665     return info;
3666
3667   return &default_transform_info;
3668 }
3669
3670 static void
3671 clutter_transform_info_free (gpointer data)
3672 {
3673   if (data != NULL)
3674     g_slice_free (ClutterTransformInfo, data);
3675 }
3676
3677 /*< private >
3678  * _clutter_actor_get_transform_info:
3679  * @self: a #ClutterActor
3680  *
3681  * Retrieves a pointer to the ClutterTransformInfo structure.
3682  *
3683  * If the actor does not have a ClutterTransformInfo associated to it, one
3684  * will be created and initialized to the default values.
3685  *
3686  * This function should be used for setters.
3687  *
3688  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3689  * instead.
3690  *
3691  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3692  *   structure
3693  */
3694 ClutterTransformInfo *
3695 _clutter_actor_get_transform_info (ClutterActor *self)
3696 {
3697   ClutterTransformInfo *info;
3698
3699   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3700   if (info == NULL)
3701     {
3702       info = g_slice_new (ClutterTransformInfo);
3703
3704       *info = default_transform_info;
3705
3706       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3707                                info,
3708                                clutter_transform_info_free);
3709     }
3710
3711   return info;
3712 }
3713
3714 /*< private >
3715  * clutter_actor_set_rotation_angle_internal:
3716  * @self: a #ClutterActor
3717  * @axis: the axis of the angle to change
3718  * @angle: the angle of rotation
3719  *
3720  * Sets the rotation angle on the given axis without affecting the
3721  * rotation center point.
3722  */
3723 static inline void
3724 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3725                                            ClutterRotateAxis  axis,
3726                                            gdouble            angle)
3727 {
3728   GObject *obj = G_OBJECT (self);
3729   ClutterTransformInfo *info;
3730
3731   info = _clutter_actor_get_transform_info (self);
3732
3733   g_object_freeze_notify (obj);
3734
3735   switch (axis)
3736     {
3737     case CLUTTER_X_AXIS:
3738       info->rx_angle = angle;
3739       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3740       break;
3741
3742     case CLUTTER_Y_AXIS:
3743       info->ry_angle = angle;
3744       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3745       break;
3746
3747     case CLUTTER_Z_AXIS:
3748       info->rz_angle = angle;
3749       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3750       break;
3751     }
3752
3753   self->priv->transform_valid = FALSE;
3754
3755   g_object_thaw_notify (obj);
3756
3757   clutter_actor_queue_redraw (self);
3758 }
3759
3760 static inline void
3761 clutter_actor_set_rotation_angle (ClutterActor      *self,
3762                                   ClutterRotateAxis  axis,
3763                                   gdouble            angle)
3764 {
3765   ClutterTransformInfo *info;
3766
3767   info = _clutter_actor_get_transform_info (self);
3768
3769   if (clutter_actor_get_easing_duration (self) != 0)
3770     {
3771       ClutterTransition *transition;
3772       GParamSpec *pspec = NULL;
3773       double *cur_angle_p = NULL;
3774
3775       switch (axis)
3776         {
3777         case CLUTTER_X_AXIS:
3778           cur_angle_p = &info->rx_angle;
3779           pspec = obj_props[PROP_ROTATION_ANGLE_X];
3780           break;
3781
3782         case CLUTTER_Y_AXIS:
3783           cur_angle_p = &info->ry_angle;
3784           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3785           break;
3786
3787         case CLUTTER_Z_AXIS:
3788           cur_angle_p = &info->rz_angle;
3789           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3790           break;
3791         }
3792
3793       g_assert (pspec != NULL);
3794       g_assert (cur_angle_p != NULL);
3795
3796       transition = _clutter_actor_get_transition (self, pspec);
3797       if (transition == NULL)
3798         {
3799           transition = _clutter_actor_create_transition (self, pspec,
3800                                                          *cur_angle_p,
3801                                                          angle);
3802           clutter_timeline_start (CLUTTER_TIMELINE (transition));
3803         }
3804       else
3805         _clutter_actor_update_transition (self, pspec, angle);
3806
3807       self->priv->transform_valid = FALSE;
3808       clutter_actor_queue_redraw (self);
3809     }
3810   else
3811     clutter_actor_set_rotation_angle_internal (self, axis, angle);
3812 }
3813
3814 /*< private >
3815  * clutter_actor_set_rotation_center_internal:
3816  * @self: a #ClutterActor
3817  * @axis: the axis of the center to change
3818  * @center: the coordinates of the rotation center
3819  *
3820  * Sets the rotation center on the given axis without affecting the
3821  * rotation angle.
3822  */
3823 static inline void
3824 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3825                                             ClutterRotateAxis    axis,
3826                                             const ClutterVertex *center)
3827 {
3828   GObject *obj = G_OBJECT (self);
3829   ClutterTransformInfo *info;
3830   ClutterVertex v = { 0, 0, 0 };
3831
3832   info = _clutter_actor_get_transform_info (self);
3833
3834   if (center != NULL)
3835     v = *center;
3836
3837   g_object_freeze_notify (obj);
3838
3839   switch (axis)
3840     {
3841     case CLUTTER_X_AXIS:
3842       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3843       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3844       break;
3845
3846     case CLUTTER_Y_AXIS:
3847       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3848       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3849       break;
3850
3851     case CLUTTER_Z_AXIS:
3852       /* if the previously set rotation center was fractional, then
3853        * setting explicit coordinates will have to notify the
3854        * :rotation-center-z-gravity property as well
3855        */
3856       if (info->rz_center.is_fractional)
3857         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3858
3859       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3860       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3861       break;
3862     }
3863
3864   self->priv->transform_valid = FALSE;
3865
3866   g_object_thaw_notify (obj);
3867
3868   clutter_actor_queue_redraw (self);
3869 }
3870
3871 static void
3872 clutter_actor_animate_scale_factor (ClutterActor *self,
3873                                     double        old_factor,
3874                                     double        new_factor,
3875                                     GParamSpec   *pspec)
3876 {
3877   ClutterTransition *transition;
3878
3879   transition = _clutter_actor_get_transition (self, pspec);
3880   if (transition == NULL)
3881     {
3882       transition = _clutter_actor_create_transition (self, pspec,
3883                                                      old_factor,
3884                                                      new_factor);
3885       clutter_timeline_start (CLUTTER_TIMELINE (transition));
3886     }
3887   else
3888     _clutter_actor_update_transition (self, pspec, new_factor);
3889
3890
3891   self->priv->transform_valid = FALSE;
3892   clutter_actor_queue_redraw (self);
3893 }
3894
3895 static void
3896 clutter_actor_set_scale_factor_internal (ClutterActor *self,
3897                                          double factor,
3898                                          GParamSpec *pspec)
3899 {
3900   GObject *obj = G_OBJECT (self);
3901   ClutterTransformInfo *info;
3902
3903   info = _clutter_actor_get_transform_info (self);
3904
3905   if (pspec == obj_props[PROP_SCALE_X])
3906     info->scale_x = factor;
3907   else
3908     info->scale_y = factor;
3909
3910   self->priv->transform_valid = FALSE;
3911   clutter_actor_queue_redraw (self);
3912   g_object_notify_by_pspec (obj, pspec);
3913 }
3914
3915 static inline void
3916 clutter_actor_set_scale_factor (ClutterActor      *self,
3917                                 ClutterRotateAxis  axis,
3918                                 gdouble            factor)
3919 {
3920   GObject *obj = G_OBJECT (self);
3921   ClutterTransformInfo *info;
3922   GParamSpec *pspec;
3923
3924   info = _clutter_actor_get_transform_info (self);
3925
3926   g_object_freeze_notify (obj);
3927
3928   switch (axis)
3929     {
3930     case CLUTTER_X_AXIS:
3931       pspec = obj_props[PROP_SCALE_X];
3932
3933       if (clutter_actor_get_easing_duration (self) != 0)
3934         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
3935       else
3936         clutter_actor_set_scale_factor_internal (self, factor, pspec);
3937       break;
3938
3939     case CLUTTER_Y_AXIS:
3940       pspec = obj_props[PROP_SCALE_Y];
3941
3942       if (clutter_actor_get_easing_duration (self) != 0)
3943         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
3944       else
3945         clutter_actor_set_scale_factor_internal (self, factor, pspec);
3946       break;
3947
3948     default:
3949       g_assert_not_reached ();
3950     }
3951
3952   g_object_thaw_notify (obj);
3953 }
3954
3955 static inline void
3956 clutter_actor_set_scale_center (ClutterActor      *self,
3957                                 ClutterRotateAxis  axis,
3958                                 gfloat             coord)
3959 {
3960   GObject *obj = G_OBJECT (self);
3961   ClutterTransformInfo *info;
3962   gfloat center_x, center_y;
3963
3964   info = _clutter_actor_get_transform_info (self);
3965
3966   g_object_freeze_notify (obj);
3967
3968   /* get the current scale center coordinates */
3969   clutter_anchor_coord_get_units (self, &info->scale_center,
3970                                   &center_x,
3971                                   &center_y,
3972                                   NULL);
3973
3974   /* we need to notify this too, because setting explicit coordinates will
3975    * change the gravity as a side effect
3976    */
3977   if (info->scale_center.is_fractional)
3978     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3979
3980   switch (axis)
3981     {
3982     case CLUTTER_X_AXIS:
3983       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3984       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3985       break;
3986
3987     case CLUTTER_Y_AXIS:
3988       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3989       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3990       break;
3991
3992     default:
3993       g_assert_not_reached ();
3994     }
3995
3996   self->priv->transform_valid = FALSE;
3997
3998   clutter_actor_queue_redraw (self);
3999
4000   g_object_thaw_notify (obj);
4001 }
4002
4003 static inline void
4004 clutter_actor_set_anchor_coord (ClutterActor      *self,
4005                                 ClutterRotateAxis  axis,
4006                                 gfloat             coord)
4007 {
4008   GObject *obj = G_OBJECT (self);
4009   ClutterTransformInfo *info;
4010   gfloat anchor_x, anchor_y;
4011
4012   info = _clutter_actor_get_transform_info (self);
4013
4014   g_object_freeze_notify (obj);
4015
4016   clutter_anchor_coord_get_units (self, &info->anchor,
4017                                   &anchor_x,
4018                                   &anchor_y,
4019                                   NULL);
4020
4021   if (info->anchor.is_fractional)
4022     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4023
4024   switch (axis)
4025     {
4026     case CLUTTER_X_AXIS:
4027       clutter_anchor_coord_set_units (&info->anchor,
4028                                       coord,
4029                                       anchor_y,
4030                                       0.0);
4031       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4032       break;
4033
4034     case CLUTTER_Y_AXIS:
4035       clutter_anchor_coord_set_units (&info->anchor,
4036                                       anchor_x,
4037                                       coord,
4038                                       0.0);
4039       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4040       break;
4041
4042     default:
4043       g_assert_not_reached ();
4044     }
4045
4046   self->priv->transform_valid = FALSE;
4047
4048   clutter_actor_queue_redraw (self);
4049
4050   g_object_thaw_notify (obj);
4051 }
4052
4053 static void
4054 clutter_actor_set_property (GObject      *object,
4055                             guint         prop_id,
4056                             const GValue *value,
4057                             GParamSpec   *pspec)
4058 {
4059   ClutterActor *actor = CLUTTER_ACTOR (object);
4060   ClutterActorPrivate *priv = actor->priv;
4061
4062   switch (prop_id)
4063     {
4064     case PROP_X:
4065       clutter_actor_set_x (actor, g_value_get_float (value));
4066       break;
4067
4068     case PROP_Y:
4069       clutter_actor_set_y (actor, g_value_get_float (value));
4070       break;
4071
4072     case PROP_WIDTH:
4073       clutter_actor_set_width (actor, g_value_get_float (value));
4074       break;
4075
4076     case PROP_HEIGHT:
4077       clutter_actor_set_height (actor, g_value_get_float (value));
4078       break;
4079
4080     case PROP_FIXED_X:
4081       clutter_actor_set_x (actor, g_value_get_float (value));
4082       break;
4083
4084     case PROP_FIXED_Y:
4085       clutter_actor_set_y (actor, g_value_get_float (value));
4086       break;
4087
4088     case PROP_FIXED_POSITION_SET:
4089       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4090       break;
4091
4092     case PROP_MIN_WIDTH:
4093       clutter_actor_set_min_width (actor, g_value_get_float (value));
4094       break;
4095
4096     case PROP_MIN_HEIGHT:
4097       clutter_actor_set_min_height (actor, g_value_get_float (value));
4098       break;
4099
4100     case PROP_NATURAL_WIDTH:
4101       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4102       break;
4103
4104     case PROP_NATURAL_HEIGHT:
4105       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4106       break;
4107
4108     case PROP_MIN_WIDTH_SET:
4109       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4110       break;
4111
4112     case PROP_MIN_HEIGHT_SET:
4113       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4114       break;
4115
4116     case PROP_NATURAL_WIDTH_SET:
4117       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4118       break;
4119
4120     case PROP_NATURAL_HEIGHT_SET:
4121       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4122       break;
4123
4124     case PROP_REQUEST_MODE:
4125       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4126       break;
4127
4128     case PROP_DEPTH:
4129       clutter_actor_set_depth (actor, g_value_get_float (value));
4130       break;
4131
4132     case PROP_OPACITY:
4133       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4134       break;
4135
4136     case PROP_OFFSCREEN_REDIRECT:
4137       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4138       break;
4139
4140     case PROP_NAME:
4141       clutter_actor_set_name (actor, g_value_get_string (value));
4142       break;
4143
4144     case PROP_VISIBLE:
4145       if (g_value_get_boolean (value) == TRUE)
4146         clutter_actor_show (actor);
4147       else
4148         clutter_actor_hide (actor);
4149       break;
4150
4151     case PROP_SCALE_X:
4152       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4153                                       g_value_get_double (value));
4154       break;
4155
4156     case PROP_SCALE_Y:
4157       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4158                                       g_value_get_double (value));
4159       break;
4160
4161     case PROP_SCALE_CENTER_X:
4162       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4163                                       g_value_get_float (value));
4164       break;
4165
4166     case PROP_SCALE_CENTER_Y:
4167       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4168                                       g_value_get_float (value));
4169       break;
4170
4171     case PROP_SCALE_GRAVITY:
4172       {
4173         const ClutterTransformInfo *info;
4174         ClutterGravity gravity;
4175
4176         info = _clutter_actor_get_transform_info_or_defaults (actor);
4177         gravity = g_value_get_enum (value);
4178
4179         clutter_actor_set_scale_with_gravity (actor,
4180                                               info->scale_x,
4181                                               info->scale_y,
4182                                               gravity);
4183       }
4184       break;
4185
4186     case PROP_CLIP:
4187       {
4188         const ClutterGeometry *geom = g_value_get_boxed (value);
4189
4190         clutter_actor_set_clip (actor,
4191                                 geom->x, geom->y,
4192                                 geom->width, geom->height);
4193       }
4194       break;
4195
4196     case PROP_CLIP_TO_ALLOCATION:
4197       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4198       break;
4199
4200     case PROP_REACTIVE:
4201       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4202       break;
4203
4204     case PROP_ROTATION_ANGLE_X:
4205       clutter_actor_set_rotation_angle (actor,
4206                                         CLUTTER_X_AXIS,
4207                                         g_value_get_double (value));
4208       break;
4209
4210     case PROP_ROTATION_ANGLE_Y:
4211       clutter_actor_set_rotation_angle (actor,
4212                                         CLUTTER_Y_AXIS,
4213                                         g_value_get_double (value));
4214       break;
4215
4216     case PROP_ROTATION_ANGLE_Z:
4217       clutter_actor_set_rotation_angle (actor,
4218                                         CLUTTER_Z_AXIS,
4219                                         g_value_get_double (value));
4220       break;
4221
4222     case PROP_ROTATION_CENTER_X:
4223       clutter_actor_set_rotation_center_internal (actor,
4224                                                   CLUTTER_X_AXIS,
4225                                                   g_value_get_boxed (value));
4226       break;
4227
4228     case PROP_ROTATION_CENTER_Y:
4229       clutter_actor_set_rotation_center_internal (actor,
4230                                                   CLUTTER_Y_AXIS,
4231                                                   g_value_get_boxed (value));
4232       break;
4233
4234     case PROP_ROTATION_CENTER_Z:
4235       clutter_actor_set_rotation_center_internal (actor,
4236                                                   CLUTTER_Z_AXIS,
4237                                                   g_value_get_boxed (value));
4238       break;
4239
4240     case PROP_ROTATION_CENTER_Z_GRAVITY:
4241       {
4242         const ClutterTransformInfo *info;
4243
4244         info = _clutter_actor_get_transform_info_or_defaults (actor);
4245         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4246                                                    g_value_get_enum (value));
4247       }
4248       break;
4249
4250     case PROP_ANCHOR_X:
4251       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4252                                       g_value_get_float (value));
4253       break;
4254
4255     case PROP_ANCHOR_Y:
4256       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4257                                       g_value_get_float (value));
4258       break;
4259
4260     case PROP_ANCHOR_GRAVITY:
4261       clutter_actor_set_anchor_point_from_gravity (actor,
4262                                                    g_value_get_enum (value));
4263       break;
4264
4265     case PROP_SHOW_ON_SET_PARENT:
4266       priv->show_on_set_parent = g_value_get_boolean (value);
4267       break;
4268
4269     case PROP_TEXT_DIRECTION:
4270       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4271       break;
4272
4273     case PROP_ACTIONS:
4274       clutter_actor_add_action (actor, g_value_get_object (value));
4275       break;
4276
4277     case PROP_CONSTRAINTS:
4278       clutter_actor_add_constraint (actor, g_value_get_object (value));
4279       break;
4280
4281     case PROP_EFFECT:
4282       clutter_actor_add_effect (actor, g_value_get_object (value));
4283       break;
4284
4285     case PROP_LAYOUT_MANAGER:
4286       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4287       break;
4288
4289     case PROP_X_ALIGN:
4290       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4291       break;
4292
4293     case PROP_Y_ALIGN:
4294       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4295       break;
4296
4297     case PROP_MARGIN_TOP:
4298       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4299       break;
4300
4301     case PROP_MARGIN_BOTTOM:
4302       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4303       break;
4304
4305     case PROP_MARGIN_LEFT:
4306       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4307       break;
4308
4309     case PROP_MARGIN_RIGHT:
4310       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4311       break;
4312
4313     case PROP_BACKGROUND_COLOR:
4314       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4315       break;
4316
4317     default:
4318       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4319       break;
4320     }
4321 }
4322
4323 static void
4324 clutter_actor_get_property (GObject    *object,
4325                             guint       prop_id,
4326                             GValue     *value,
4327                             GParamSpec *pspec)
4328 {
4329   ClutterActor *actor = CLUTTER_ACTOR (object);
4330   ClutterActorPrivate *priv = actor->priv;
4331
4332   switch (prop_id)
4333     {
4334     case PROP_X:
4335       g_value_set_float (value, clutter_actor_get_x (actor));
4336       break;
4337
4338     case PROP_Y:
4339       g_value_set_float (value, clutter_actor_get_y (actor));
4340       break;
4341
4342     case PROP_WIDTH:
4343       g_value_set_float (value, clutter_actor_get_width (actor));
4344       break;
4345
4346     case PROP_HEIGHT:
4347       g_value_set_float (value, clutter_actor_get_height (actor));
4348       break;
4349
4350     case PROP_FIXED_X:
4351       {
4352         const ClutterLayoutInfo *info;
4353
4354         info = _clutter_actor_get_layout_info_or_defaults (actor);
4355         g_value_set_float (value, info->fixed_x);
4356       }
4357       break;
4358
4359     case PROP_FIXED_Y:
4360       {
4361         const ClutterLayoutInfo *info;
4362
4363         info = _clutter_actor_get_layout_info_or_defaults (actor);
4364         g_value_set_float (value, info->fixed_y);
4365       }
4366       break;
4367
4368     case PROP_FIXED_POSITION_SET:
4369       g_value_set_boolean (value, priv->position_set);
4370       break;
4371
4372     case PROP_MIN_WIDTH:
4373       {
4374         const ClutterLayoutInfo *info;
4375
4376         info = _clutter_actor_get_layout_info_or_defaults (actor);
4377         g_value_set_float (value, info->min_width);
4378       }
4379       break;
4380
4381     case PROP_MIN_HEIGHT:
4382       {
4383         const ClutterLayoutInfo *info;
4384
4385         info = _clutter_actor_get_layout_info_or_defaults (actor);
4386         g_value_set_float (value, info->min_height);
4387       }
4388       break;
4389
4390     case PROP_NATURAL_WIDTH:
4391       {
4392         const ClutterLayoutInfo *info;
4393
4394         info = _clutter_actor_get_layout_info_or_defaults (actor);
4395         g_value_set_float (value, info->natural_width);
4396       }
4397       break;
4398
4399     case PROP_NATURAL_HEIGHT:
4400       {
4401         const ClutterLayoutInfo *info;
4402
4403         info = _clutter_actor_get_layout_info_or_defaults (actor);
4404         g_value_set_float (value, info->natural_height);
4405       }
4406       break;
4407
4408     case PROP_MIN_WIDTH_SET:
4409       g_value_set_boolean (value, priv->min_width_set);
4410       break;
4411
4412     case PROP_MIN_HEIGHT_SET:
4413       g_value_set_boolean (value, priv->min_height_set);
4414       break;
4415
4416     case PROP_NATURAL_WIDTH_SET:
4417       g_value_set_boolean (value, priv->natural_width_set);
4418       break;
4419
4420     case PROP_NATURAL_HEIGHT_SET:
4421       g_value_set_boolean (value, priv->natural_height_set);
4422       break;
4423
4424     case PROP_REQUEST_MODE:
4425       g_value_set_enum (value, priv->request_mode);
4426       break;
4427
4428     case PROP_ALLOCATION:
4429       g_value_set_boxed (value, &priv->allocation);
4430       break;
4431
4432     case PROP_DEPTH:
4433       g_value_set_float (value, clutter_actor_get_depth (actor));
4434       break;
4435
4436     case PROP_OPACITY:
4437       g_value_set_uint (value, priv->opacity);
4438       break;
4439
4440     case PROP_OFFSCREEN_REDIRECT:
4441       g_value_set_enum (value, priv->offscreen_redirect);
4442       break;
4443
4444     case PROP_NAME:
4445       g_value_set_string (value, priv->name);
4446       break;
4447
4448     case PROP_VISIBLE:
4449       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4450       break;
4451
4452     case PROP_MAPPED:
4453       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4454       break;
4455
4456     case PROP_REALIZED:
4457       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4458       break;
4459
4460     case PROP_HAS_CLIP:
4461       g_value_set_boolean (value, priv->has_clip);
4462       break;
4463
4464     case PROP_CLIP:
4465       {
4466         ClutterGeometry clip;
4467
4468         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4469         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4470         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4471         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4472
4473         g_value_set_boxed (value, &clip);
4474       }
4475       break;
4476
4477     case PROP_CLIP_TO_ALLOCATION:
4478       g_value_set_boolean (value, priv->clip_to_allocation);
4479       break;
4480
4481     case PROP_SCALE_X:
4482       {
4483         const ClutterTransformInfo *info;
4484
4485         info = _clutter_actor_get_transform_info_or_defaults (actor);
4486         g_value_set_double (value, info->scale_x);
4487       }
4488       break;
4489
4490     case PROP_SCALE_Y:
4491       {
4492         const ClutterTransformInfo *info;
4493
4494         info = _clutter_actor_get_transform_info_or_defaults (actor);
4495         g_value_set_double (value, info->scale_y);
4496       }
4497       break;
4498
4499     case PROP_SCALE_CENTER_X:
4500       {
4501         gfloat center;
4502
4503         clutter_actor_get_scale_center (actor, &center, NULL);
4504
4505         g_value_set_float (value, center);
4506       }
4507       break;
4508
4509     case PROP_SCALE_CENTER_Y:
4510       {
4511         gfloat center;
4512
4513         clutter_actor_get_scale_center (actor, NULL, &center);
4514
4515         g_value_set_float (value, center);
4516       }
4517       break;
4518
4519     case PROP_SCALE_GRAVITY:
4520       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4521       break;
4522
4523     case PROP_REACTIVE:
4524       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4525       break;
4526
4527     case PROP_ROTATION_ANGLE_X:
4528       {
4529         const ClutterTransformInfo *info;
4530
4531         info = _clutter_actor_get_transform_info_or_defaults (actor);
4532         g_value_set_double (value, info->rx_angle);
4533       }
4534       break;
4535
4536     case PROP_ROTATION_ANGLE_Y:
4537       {
4538         const ClutterTransformInfo *info;
4539
4540         info = _clutter_actor_get_transform_info_or_defaults (actor);
4541         g_value_set_double (value, info->ry_angle);
4542       }
4543       break;
4544
4545     case PROP_ROTATION_ANGLE_Z:
4546       {
4547         const ClutterTransformInfo *info;
4548
4549         info = _clutter_actor_get_transform_info_or_defaults (actor);
4550         g_value_set_double (value, info->rz_angle);
4551       }
4552       break;
4553
4554     case PROP_ROTATION_CENTER_X:
4555       {
4556         ClutterVertex center;
4557
4558         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4559                                     &center.x,
4560                                     &center.y,
4561                                     &center.z);
4562
4563         g_value_set_boxed (value, &center);
4564       }
4565       break;
4566
4567     case PROP_ROTATION_CENTER_Y:
4568       {
4569         ClutterVertex center;
4570
4571         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4572                                     &center.x,
4573                                     &center.y,
4574                                     &center.z);
4575
4576         g_value_set_boxed (value, &center);
4577       }
4578       break;
4579
4580     case PROP_ROTATION_CENTER_Z:
4581       {
4582         ClutterVertex center;
4583
4584         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4585                                     &center.x,
4586                                     &center.y,
4587                                     &center.z);
4588
4589         g_value_set_boxed (value, &center);
4590       }
4591       break;
4592
4593     case PROP_ROTATION_CENTER_Z_GRAVITY:
4594       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4595       break;
4596
4597     case PROP_ANCHOR_X:
4598       {
4599         const ClutterTransformInfo *info;
4600         gfloat anchor_x;
4601
4602         info = _clutter_actor_get_transform_info_or_defaults (actor);
4603         clutter_anchor_coord_get_units (actor, &info->anchor,
4604                                         &anchor_x,
4605                                         NULL,
4606                                         NULL);
4607         g_value_set_float (value, anchor_x);
4608       }
4609       break;
4610
4611     case PROP_ANCHOR_Y:
4612       {
4613         const ClutterTransformInfo *info;
4614         gfloat anchor_y;
4615
4616         info = _clutter_actor_get_transform_info_or_defaults (actor);
4617         clutter_anchor_coord_get_units (actor, &info->anchor,
4618                                         NULL,
4619                                         &anchor_y,
4620                                         NULL);
4621         g_value_set_float (value, anchor_y);
4622       }
4623       break;
4624
4625     case PROP_ANCHOR_GRAVITY:
4626       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4627       break;
4628
4629     case PROP_SHOW_ON_SET_PARENT:
4630       g_value_set_boolean (value, priv->show_on_set_parent);
4631       break;
4632
4633     case PROP_TEXT_DIRECTION:
4634       g_value_set_enum (value, priv->text_direction);
4635       break;
4636
4637     case PROP_HAS_POINTER:
4638       g_value_set_boolean (value, priv->has_pointer);
4639       break;
4640
4641     case PROP_LAYOUT_MANAGER:
4642       g_value_set_object (value, priv->layout_manager);
4643       break;
4644
4645     case PROP_X_ALIGN:
4646       {
4647         const ClutterLayoutInfo *info;
4648
4649         info = _clutter_actor_get_layout_info_or_defaults (actor);
4650         g_value_set_enum (value, info->x_align);
4651       }
4652       break;
4653
4654     case PROP_Y_ALIGN:
4655       {
4656         const ClutterLayoutInfo *info;
4657
4658         info = _clutter_actor_get_layout_info_or_defaults (actor);
4659         g_value_set_enum (value, info->y_align);
4660       }
4661       break;
4662
4663     case PROP_MARGIN_TOP:
4664       {
4665         const ClutterLayoutInfo *info;
4666
4667         info = _clutter_actor_get_layout_info_or_defaults (actor);
4668         g_value_set_float (value, info->margin.top);
4669       }
4670       break;
4671
4672     case PROP_MARGIN_BOTTOM:
4673       {
4674         const ClutterLayoutInfo *info;
4675
4676         info = _clutter_actor_get_layout_info_or_defaults (actor);
4677         g_value_set_float (value, info->margin.bottom);
4678       }
4679       break;
4680
4681     case PROP_MARGIN_LEFT:
4682       {
4683         const ClutterLayoutInfo *info;
4684
4685         info = _clutter_actor_get_layout_info_or_defaults (actor);
4686         g_value_set_float (value, info->margin.left);
4687       }
4688       break;
4689
4690     case PROP_MARGIN_RIGHT:
4691       {
4692         const ClutterLayoutInfo *info;
4693
4694         info = _clutter_actor_get_layout_info_or_defaults (actor);
4695         g_value_set_float (value, info->margin.right);
4696       }
4697       break;
4698
4699     case PROP_BACKGROUND_COLOR_SET:
4700       g_value_set_boolean (value, priv->bg_color_set);
4701       break;
4702
4703     case PROP_BACKGROUND_COLOR:
4704       g_value_set_boxed (value, &priv->bg_color);
4705       break;
4706
4707     case PROP_FIRST_CHILD:
4708       g_value_set_object (value, priv->first_child);
4709       break;
4710
4711     case PROP_LAST_CHILD:
4712       g_value_set_object (value, priv->last_child);
4713       break;
4714
4715     default:
4716       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4717       break;
4718     }
4719 }
4720
4721 static void
4722 clutter_actor_dispose (GObject *object)
4723 {
4724   ClutterActor *self = CLUTTER_ACTOR (object);
4725   ClutterActorPrivate *priv = self->priv;
4726
4727   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4728                 priv->id,
4729                 g_type_name (G_OBJECT_TYPE (self)),
4730                 object->ref_count);
4731
4732   g_signal_emit (self, actor_signals[DESTROY], 0);
4733
4734   /* avoid recursing when called from clutter_actor_destroy() */
4735   if (priv->parent != NULL)
4736     {
4737       ClutterActor *parent = priv->parent;
4738
4739       /* go through the Container implementation unless this
4740        * is an internal child and has been marked as such.
4741        *
4742        * removing the actor from its parent will reset the
4743        * realized and mapped states.
4744        */
4745       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4746         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4747       else
4748         clutter_actor_remove_child_internal (parent, self,
4749                                              REMOVE_CHILD_LEGACY_FLAGS);
4750     }
4751
4752   /* parent must be gone at this point */
4753   g_assert (priv->parent == NULL);
4754
4755   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4756     {
4757       /* can't be mapped or realized with no parent */
4758       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4759       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4760     }
4761
4762   g_clear_object (&priv->pango_context);
4763   g_clear_object (&priv->actions);
4764   g_clear_object (&priv->constraints);
4765   g_clear_object (&priv->effects);
4766   g_clear_object (&priv->flatten_effect);
4767
4768   if (priv->layout_manager != NULL)
4769     {
4770       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4771       g_object_unref (priv->layout_manager);
4772       priv->layout_manager = NULL;
4773     }
4774
4775   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4776 }
4777
4778 static void
4779 clutter_actor_finalize (GObject *object)
4780 {
4781   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4782
4783   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4784                 priv->name != NULL ? priv->name : "<none>",
4785                 priv->id,
4786                 g_type_name (G_OBJECT_TYPE (object)));
4787
4788   _clutter_context_release_id (priv->id);
4789
4790   g_free (priv->name);
4791
4792   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4793 }
4794
4795
4796 /**
4797  * clutter_actor_get_accessible:
4798  * @self: a #ClutterActor
4799  *
4800  * Returns the accessible object that describes the actor to an
4801  * assistive technology.
4802  *
4803  * If no class-specific #AtkObject implementation is available for the
4804  * actor instance in question, it will inherit an #AtkObject
4805  * implementation from the first ancestor class for which such an
4806  * implementation is defined.
4807  *
4808  * The documentation of the <ulink
4809  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4810  * library contains more information about accessible objects and
4811  * their uses.
4812  *
4813  * Returns: (transfer none): the #AtkObject associated with @actor
4814  */
4815 AtkObject *
4816 clutter_actor_get_accessible (ClutterActor *self)
4817 {
4818   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4819
4820   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4821 }
4822
4823 static AtkObject *
4824 clutter_actor_real_get_accessible (ClutterActor *actor)
4825 {
4826   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4827 }
4828
4829 static AtkObject *
4830 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4831 {
4832   AtkObject *accessible;
4833
4834   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4835   if (accessible != NULL)
4836     g_object_ref (accessible);
4837
4838   return accessible;
4839 }
4840
4841 static void
4842 atk_implementor_iface_init (AtkImplementorIface *iface)
4843 {
4844   iface->ref_accessible = _clutter_actor_ref_accessible;
4845 }
4846
4847 static gboolean
4848 clutter_actor_update_default_paint_volume (ClutterActor       *self,
4849                                            ClutterPaintVolume *volume)
4850 {
4851   ClutterActorPrivate *priv = self->priv;
4852   gboolean res = FALSE;
4853
4854   /* we start from the allocation */
4855   clutter_paint_volume_set_width (volume,
4856                                   priv->allocation.x2 - priv->allocation.x1);
4857   clutter_paint_volume_set_height (volume,
4858                                    priv->allocation.y2 - priv->allocation.y1);
4859
4860   /* if the actor has a clip set then we have a pretty definite
4861    * size for the paint volume: the actor cannot possibly paint
4862    * outside the clip region.
4863    */
4864   if (priv->clip_to_allocation)
4865     {
4866       /* the allocation has already been set, so we just flip the
4867        * return value
4868        */
4869       res = TRUE;
4870     }
4871   else
4872     {
4873       ClutterActor *child;
4874
4875       if (priv->has_clip &&
4876           priv->clip.width >= 0 &&
4877           priv->clip.height >= 0)
4878         {
4879           ClutterVertex origin;
4880
4881           origin.x = priv->clip.x;
4882           origin.y = priv->clip.y;
4883           origin.z = 0;
4884
4885           clutter_paint_volume_set_origin (volume, &origin);
4886           clutter_paint_volume_set_width (volume, priv->clip.width);
4887           clutter_paint_volume_set_height (volume, priv->clip.height);
4888
4889           res = TRUE;
4890         }
4891
4892       /* if we don't have children we just bail out here... */
4893       if (priv->n_children == 0)
4894         return res;
4895
4896       /* ...but if we have children then we ask for their paint volume in
4897        * our coordinates. if any of our children replies that it doesn't
4898        * have a paint volume, we bail out
4899        */
4900       for (child = priv->first_child;
4901            child != NULL;
4902            child = child->priv->next_sibling)
4903         {
4904           const ClutterPaintVolume *child_volume;
4905
4906           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4907           if (child_volume == NULL)
4908             {
4909               res = FALSE;
4910               break;
4911             }
4912
4913           clutter_paint_volume_union (volume, child_volume);
4914           res = TRUE;
4915         }
4916     }
4917
4918   return res;
4919
4920 }
4921
4922 static gboolean
4923 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4924                                      ClutterPaintVolume *volume)
4925 {
4926   ClutterActorClass *klass;
4927   gboolean res;
4928
4929   klass = CLUTTER_ACTOR_GET_CLASS (self);
4930
4931   /* XXX - this thoroughly sucks, but we don't want to penalize users
4932    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4933    * redraw. This should go away in 2.0.
4934    */
4935   if (klass->paint == clutter_actor_real_paint &&
4936       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4937     {
4938       res = TRUE;
4939     }
4940   else
4941     {
4942       /* this is the default return value: we cannot know if a class
4943        * is going to paint outside its allocation, so we take the
4944        * conservative approach.
4945        */
4946       res = FALSE;
4947     }
4948
4949   if (clutter_actor_update_default_paint_volume (self, volume))
4950     return res;
4951
4952   return FALSE;
4953 }
4954
4955 /**
4956  * clutter_actor_get_default_paint_volume:
4957  * @self: a #ClutterActor
4958  *
4959  * Retrieves the default paint volume for @self.
4960  *
4961  * This function provides the same #ClutterPaintVolume that would be
4962  * computed by the default implementation inside #ClutterActor of the
4963  * #ClutterActorClass.get_paint_volume() virtual function.
4964  *
4965  * This function should only be used by #ClutterActor subclasses that
4966  * cannot chain up to the parent implementation when computing their
4967  * paint volume.
4968  *
4969  * Return value: (transfer none): a pointer to the default
4970  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
4971  *   the actor could not compute a valid paint volume. The returned value
4972  *   is not guaranteed to be stable across multiple frames, so if you
4973  *   want to retain it, you will need to copy it using
4974  *   clutter_paint_volume_copy().
4975  *
4976  * Since: 1.10
4977  */
4978 const ClutterPaintVolume *
4979 clutter_actor_get_default_paint_volume (ClutterActor *self)
4980 {
4981   ClutterPaintVolume volume;
4982   ClutterPaintVolume *res;
4983
4984   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4985
4986   res = NULL;
4987   _clutter_paint_volume_init_static (&volume, self);
4988   if (clutter_actor_update_default_paint_volume (self, &volume))
4989     {
4990       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
4991
4992       if (stage != NULL)
4993         {
4994           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
4995           _clutter_paint_volume_copy_static (&volume, res);
4996         }
4997     }
4998
4999   clutter_paint_volume_free (&volume);
5000
5001   return res;
5002 }
5003
5004 static gboolean
5005 clutter_actor_real_has_overlaps (ClutterActor *self)
5006 {
5007   /* By default we'll assume that all actors need an offscreen redirect to get
5008    * the correct opacity. Actors such as ClutterTexture that would never need
5009    * an offscreen redirect can override this to return FALSE. */
5010   return TRUE;
5011 }
5012
5013 static void
5014 clutter_actor_real_destroy (ClutterActor *actor)
5015 {
5016   ClutterActorIter iter;
5017
5018   clutter_actor_iter_init (&iter, actor);
5019   while (clutter_actor_iter_next (&iter, NULL))
5020     clutter_actor_iter_destroy (&iter);
5021 }
5022
5023 static GObject *
5024 clutter_actor_constructor (GType gtype,
5025                            guint n_props,
5026                            GObjectConstructParam *props)
5027 {
5028   GObjectClass *gobject_class;
5029   ClutterActor *self;
5030   GObject *retval;
5031
5032   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5033   retval = gobject_class->constructor (gtype, n_props, props);
5034   self = CLUTTER_ACTOR (retval);
5035
5036   if (self->priv->layout_manager == NULL)
5037     {
5038       ClutterLayoutManager *default_layout;
5039
5040       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5041
5042       default_layout = clutter_fixed_layout_new ();
5043       clutter_actor_set_layout_manager (self, default_layout);
5044     }
5045
5046   return retval;
5047 }
5048
5049 static void
5050 clutter_actor_class_init (ClutterActorClass *klass)
5051 {
5052   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5053
5054   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5055   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5056   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5057   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5058
5059   object_class->constructor = clutter_actor_constructor;
5060   object_class->set_property = clutter_actor_set_property;
5061   object_class->get_property = clutter_actor_get_property;
5062   object_class->dispose = clutter_actor_dispose;
5063   object_class->finalize = clutter_actor_finalize;
5064
5065   klass->show = clutter_actor_real_show;
5066   klass->show_all = clutter_actor_show;
5067   klass->hide = clutter_actor_real_hide;
5068   klass->hide_all = clutter_actor_hide;
5069   klass->map = clutter_actor_real_map;
5070   klass->unmap = clutter_actor_real_unmap;
5071   klass->unrealize = clutter_actor_real_unrealize;
5072   klass->pick = clutter_actor_real_pick;
5073   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5074   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5075   klass->allocate = clutter_actor_real_allocate;
5076   klass->queue_redraw = clutter_actor_real_queue_redraw;
5077   klass->queue_relayout = clutter_actor_real_queue_relayout;
5078   klass->apply_transform = clutter_actor_real_apply_transform;
5079   klass->get_accessible = clutter_actor_real_get_accessible;
5080   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5081   klass->has_overlaps = clutter_actor_real_has_overlaps;
5082   klass->paint = clutter_actor_real_paint;
5083   klass->destroy = clutter_actor_real_destroy;
5084
5085   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5086
5087   /**
5088    * ClutterActor:x:
5089    *
5090    * X coordinate of the actor in pixels. If written, forces a fixed
5091    * position for the actor. If read, returns the fixed position if any,
5092    * otherwise the allocation if available, otherwise 0.
5093    *
5094    * The #ClutterActor:x property is animatable.
5095    */
5096   obj_props[PROP_X] =
5097     g_param_spec_float ("x",
5098                         P_("X coordinate"),
5099                         P_("X coordinate of the actor"),
5100                         -G_MAXFLOAT, G_MAXFLOAT,
5101                         0.0,
5102                         G_PARAM_READWRITE |
5103                         G_PARAM_STATIC_STRINGS |
5104                         CLUTTER_PARAM_ANIMATABLE);
5105
5106   /**
5107    * ClutterActor:y:
5108    *
5109    * Y coordinate of the actor in pixels. If written, forces a fixed
5110    * position for the actor.  If read, returns the fixed position if
5111    * any, otherwise the allocation if available, otherwise 0.
5112    *
5113    * The #ClutterActor:y property is animatable.
5114    */
5115   obj_props[PROP_Y] =
5116     g_param_spec_float ("y",
5117                         P_("Y coordinate"),
5118                         P_("Y coordinate of the actor"),
5119                         -G_MAXFLOAT, G_MAXFLOAT,
5120                         0.0,
5121                         G_PARAM_READWRITE |
5122                         G_PARAM_STATIC_STRINGS |
5123                         CLUTTER_PARAM_ANIMATABLE);
5124
5125   /**
5126    * ClutterActor:width:
5127    *
5128    * Width of the actor (in pixels). If written, forces the minimum and
5129    * natural size request of the actor to the given width. If read, returns
5130    * the allocated width if available, otherwise the width request.
5131    *
5132    * The #ClutterActor:width property is animatable.
5133    */
5134   obj_props[PROP_WIDTH] =
5135     g_param_spec_float ("width",
5136                         P_("Width"),
5137                         P_("Width of the actor"),
5138                         0.0, G_MAXFLOAT,
5139                         0.0,
5140                         G_PARAM_READWRITE |
5141                         G_PARAM_STATIC_STRINGS |
5142                         CLUTTER_PARAM_ANIMATABLE);
5143
5144   /**
5145    * ClutterActor:height:
5146    *
5147    * Height of the actor (in pixels).  If written, forces the minimum and
5148    * natural size request of the actor to the given height. If read, returns
5149    * the allocated height if available, otherwise the height request.
5150    *
5151    * The #ClutterActor:height property is animatable.
5152    */
5153   obj_props[PROP_HEIGHT] =
5154     g_param_spec_float ("height",
5155                         P_("Height"),
5156                         P_("Height of the actor"),
5157                         0.0, G_MAXFLOAT,
5158                         0.0,
5159                         G_PARAM_READWRITE |
5160                         G_PARAM_STATIC_STRINGS |
5161                         CLUTTER_PARAM_ANIMATABLE);
5162
5163   /**
5164    * ClutterActor:fixed-x:
5165    *
5166    * The fixed X position of the actor in pixels.
5167    *
5168    * Writing this property sets #ClutterActor:fixed-position-set
5169    * property as well, as a side effect
5170    *
5171    * Since: 0.8
5172    */
5173   obj_props[PROP_FIXED_X] =
5174     g_param_spec_float ("fixed-x",
5175                         P_("Fixed X"),
5176                         P_("Forced X position of the actor"),
5177                         -G_MAXFLOAT, G_MAXFLOAT,
5178                         0.0,
5179                         CLUTTER_PARAM_READWRITE);
5180
5181   /**
5182    * ClutterActor:fixed-y:
5183    *
5184    * The fixed Y position of the actor in pixels.
5185    *
5186    * Writing this property sets the #ClutterActor:fixed-position-set
5187    * property as well, as a side effect
5188    *
5189    * Since: 0.8
5190    */
5191   obj_props[PROP_FIXED_Y] =
5192     g_param_spec_float ("fixed-y",
5193                         P_("Fixed Y"),
5194                         P_("Forced Y position of the actor"),
5195                         -G_MAXFLOAT, G_MAXFLOAT,
5196                         0,
5197                         CLUTTER_PARAM_READWRITE);
5198
5199   /**
5200    * ClutterActor:fixed-position-set:
5201    *
5202    * This flag controls whether the #ClutterActor:fixed-x and
5203    * #ClutterActor:fixed-y properties are used
5204    *
5205    * Since: 0.8
5206    */
5207   obj_props[PROP_FIXED_POSITION_SET] =
5208     g_param_spec_boolean ("fixed-position-set",
5209                           P_("Fixed position set"),
5210                           P_("Whether to use fixed positioning for the actor"),
5211                           FALSE,
5212                           CLUTTER_PARAM_READWRITE);
5213
5214   /**
5215    * ClutterActor:min-width:
5216    *
5217    * A forced minimum width request for the actor, in pixels
5218    *
5219    * Writing this property sets the #ClutterActor:min-width-set property
5220    * as well, as a side effect.
5221    *
5222    *This property overrides the usual width request of the actor.
5223    *
5224    * Since: 0.8
5225    */
5226   obj_props[PROP_MIN_WIDTH] =
5227     g_param_spec_float ("min-width",
5228                         P_("Min Width"),
5229                         P_("Forced minimum width request for the actor"),
5230                         0.0, G_MAXFLOAT,
5231                         0.0,
5232                         CLUTTER_PARAM_READWRITE);
5233
5234   /**
5235    * ClutterActor:min-height:
5236    *
5237    * A forced minimum height request for the actor, in pixels
5238    *
5239    * Writing this property sets the #ClutterActor:min-height-set property
5240    * as well, as a side effect. This property overrides the usual height
5241    * request of the actor.
5242    *
5243    * Since: 0.8
5244    */
5245   obj_props[PROP_MIN_HEIGHT] =
5246     g_param_spec_float ("min-height",
5247                         P_("Min Height"),
5248                         P_("Forced minimum height request for the actor"),
5249                         0.0, G_MAXFLOAT,
5250                         0.0,
5251                         CLUTTER_PARAM_READWRITE);
5252
5253   /**
5254    * ClutterActor:natural-width:
5255    *
5256    * A forced natural width request for the actor, in pixels
5257    *
5258    * Writing this property sets the #ClutterActor:natural-width-set
5259    * property as well, as a side effect. This property overrides the
5260    * usual width request of the actor
5261    *
5262    * Since: 0.8
5263    */
5264   obj_props[PROP_NATURAL_WIDTH] =
5265     g_param_spec_float ("natural-width",
5266                         P_("Natural Width"),
5267                         P_("Forced natural width request for the actor"),
5268                         0.0, G_MAXFLOAT,
5269                         0.0,
5270                         CLUTTER_PARAM_READWRITE);
5271
5272   /**
5273    * ClutterActor:natural-height:
5274    *
5275    * A forced natural height request for the actor, in pixels
5276    *
5277    * Writing this property sets the #ClutterActor:natural-height-set
5278    * property as well, as a side effect. This property overrides the
5279    * usual height request of the actor
5280    *
5281    * Since: 0.8
5282    */
5283   obj_props[PROP_NATURAL_HEIGHT] =
5284     g_param_spec_float ("natural-height",
5285                         P_("Natural Height"),
5286                         P_("Forced natural height request for the actor"),
5287                         0.0, G_MAXFLOAT,
5288                         0.0,
5289                         CLUTTER_PARAM_READWRITE);
5290
5291   /**
5292    * ClutterActor:min-width-set:
5293    *
5294    * This flag controls whether the #ClutterActor:min-width property
5295    * is used
5296    *
5297    * Since: 0.8
5298    */
5299   obj_props[PROP_MIN_WIDTH_SET] =
5300     g_param_spec_boolean ("min-width-set",
5301                           P_("Minimum width set"),
5302                           P_("Whether to use the min-width property"),
5303                           FALSE,
5304                           CLUTTER_PARAM_READWRITE);
5305
5306   /**
5307    * ClutterActor:min-height-set:
5308    *
5309    * This flag controls whether the #ClutterActor:min-height property
5310    * is used
5311    *
5312    * Since: 0.8
5313    */
5314   obj_props[PROP_MIN_HEIGHT_SET] =
5315     g_param_spec_boolean ("min-height-set",
5316                           P_("Minimum height set"),
5317                           P_("Whether to use the min-height property"),
5318                           FALSE,
5319                           CLUTTER_PARAM_READWRITE);
5320
5321   /**
5322    * ClutterActor:natural-width-set:
5323    *
5324    * This flag controls whether the #ClutterActor:natural-width property
5325    * is used
5326    *
5327    * Since: 0.8
5328    */
5329   obj_props[PROP_NATURAL_WIDTH_SET] =
5330     g_param_spec_boolean ("natural-width-set",
5331                           P_("Natural width set"),
5332                           P_("Whether to use the natural-width property"),
5333                           FALSE,
5334                           CLUTTER_PARAM_READWRITE);
5335
5336   /**
5337    * ClutterActor:natural-height-set:
5338    *
5339    * This flag controls whether the #ClutterActor:natural-height property
5340    * is used
5341    *
5342    * Since: 0.8
5343    */
5344   obj_props[PROP_NATURAL_HEIGHT_SET] =
5345     g_param_spec_boolean ("natural-height-set",
5346                           P_("Natural height set"),
5347                           P_("Whether to use the natural-height property"),
5348                           FALSE,
5349                           CLUTTER_PARAM_READWRITE);
5350
5351   /**
5352    * ClutterActor:allocation:
5353    *
5354    * The allocation for the actor, in pixels
5355    *
5356    * This is property is read-only, but you might monitor it to know when an
5357    * actor moves or resizes
5358    *
5359    * Since: 0.8
5360    */
5361   obj_props[PROP_ALLOCATION] =
5362     g_param_spec_boxed ("allocation",
5363                         P_("Allocation"),
5364                         P_("The actor's allocation"),
5365                         CLUTTER_TYPE_ACTOR_BOX,
5366                         CLUTTER_PARAM_READABLE);
5367
5368   /**
5369    * ClutterActor:request-mode:
5370    *
5371    * Request mode for the #ClutterActor. The request mode determines the
5372    * type of geometry management used by the actor, either height for width
5373    * (the default) or width for height.
5374    *
5375    * For actors implementing height for width, the parent container should get
5376    * the preferred width first, and then the preferred height for that width.
5377    *
5378    * For actors implementing width for height, the parent container should get
5379    * the preferred height first, and then the preferred width for that height.
5380    *
5381    * For instance:
5382    *
5383    * |[
5384    *   ClutterRequestMode mode;
5385    *   gfloat natural_width, min_width;
5386    *   gfloat natural_height, min_height;
5387    *
5388    *   mode = clutter_actor_get_request_mode (child);
5389    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5390    *     {
5391    *       clutter_actor_get_preferred_width (child, -1,
5392    *                                          &amp;min_width,
5393    *                                          &amp;natural_width);
5394    *       clutter_actor_get_preferred_height (child, natural_width,
5395    *                                           &amp;min_height,
5396    *                                           &amp;natural_height);
5397    *     }
5398    *   else
5399    *     {
5400    *       clutter_actor_get_preferred_height (child, -1,
5401    *                                           &amp;min_height,
5402    *                                           &amp;natural_height);
5403    *       clutter_actor_get_preferred_width (child, natural_height,
5404    *                                          &amp;min_width,
5405    *                                          &amp;natural_width);
5406    *     }
5407    * ]|
5408    *
5409    * will retrieve the minimum and natural width and height depending on the
5410    * preferred request mode of the #ClutterActor "child".
5411    *
5412    * The clutter_actor_get_preferred_size() function will implement this
5413    * check for you.
5414    *
5415    * Since: 0.8
5416    */
5417   obj_props[PROP_REQUEST_MODE] =
5418     g_param_spec_enum ("request-mode",
5419                        P_("Request Mode"),
5420                        P_("The actor's request mode"),
5421                        CLUTTER_TYPE_REQUEST_MODE,
5422                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5423                        CLUTTER_PARAM_READWRITE);
5424
5425   /**
5426    * ClutterActor:depth:
5427    *
5428    * The position of the actor on the Z axis.
5429    *
5430    * The #ClutterActor:depth property is relative to the parent's
5431    * modelview matrix.
5432    *
5433    * The #ClutterActor:depth property is animatable.
5434    *
5435    * Since: 0.6
5436    */
5437   obj_props[PROP_DEPTH] =
5438     g_param_spec_float ("depth",
5439                         P_("Depth"),
5440                         P_("Position on the Z axis"),
5441                         -G_MAXFLOAT, G_MAXFLOAT,
5442                         0.0,
5443                         G_PARAM_READWRITE |
5444                         G_PARAM_STATIC_STRINGS |
5445                         CLUTTER_PARAM_ANIMATABLE);
5446
5447   /**
5448    * ClutterActor:opacity:
5449    *
5450    * Opacity of an actor, between 0 (fully transparent) and
5451    * 255 (fully opaque)
5452    *
5453    * The #ClutterActor:opacity property is animatable.
5454    */
5455   obj_props[PROP_OPACITY] =
5456     g_param_spec_uint ("opacity",
5457                        P_("Opacity"),
5458                        P_("Opacity of an actor"),
5459                        0, 255,
5460                        255,
5461                        G_PARAM_READWRITE |
5462                        G_PARAM_STATIC_STRINGS |
5463                        CLUTTER_PARAM_ANIMATABLE);
5464
5465   /**
5466    * ClutterActor:offscreen-redirect:
5467    *
5468    * Determines the conditions in which the actor will be redirected
5469    * to an offscreen framebuffer while being painted. For example this
5470    * can be used to cache an actor in a framebuffer or for improved
5471    * handling of transparent actors. See
5472    * clutter_actor_set_offscreen_redirect() for details.
5473    *
5474    * Since: 1.8
5475    */
5476   obj_props[PROP_OFFSCREEN_REDIRECT] =
5477     g_param_spec_flags ("offscreen-redirect",
5478                         P_("Offscreen redirect"),
5479                         P_("Flags controlling when to flatten the actor into a single image"),
5480                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5481                         0,
5482                         CLUTTER_PARAM_READWRITE);
5483
5484   /**
5485    * ClutterActor:visible:
5486    *
5487    * Whether the actor is set to be visible or not
5488    *
5489    * See also #ClutterActor:mapped
5490    */
5491   obj_props[PROP_VISIBLE] =
5492     g_param_spec_boolean ("visible",
5493                           P_("Visible"),
5494                           P_("Whether the actor is visible or not"),
5495                           FALSE,
5496                           CLUTTER_PARAM_READWRITE);
5497
5498   /**
5499    * ClutterActor:mapped:
5500    *
5501    * Whether the actor is mapped (will be painted when the stage
5502    * to which it belongs is mapped)
5503    *
5504    * Since: 1.0
5505    */
5506   obj_props[PROP_MAPPED] =
5507     g_param_spec_boolean ("mapped",
5508                           P_("Mapped"),
5509                           P_("Whether the actor will be painted"),
5510                           FALSE,
5511                           CLUTTER_PARAM_READABLE);
5512
5513   /**
5514    * ClutterActor:realized:
5515    *
5516    * Whether the actor has been realized
5517    *
5518    * Since: 1.0
5519    */
5520   obj_props[PROP_REALIZED] =
5521     g_param_spec_boolean ("realized",
5522                           P_("Realized"),
5523                           P_("Whether the actor has been realized"),
5524                           FALSE,
5525                           CLUTTER_PARAM_READABLE);
5526
5527   /**
5528    * ClutterActor:reactive:
5529    *
5530    * Whether the actor is reactive to events or not
5531    *
5532    * Only reactive actors will emit event-related signals
5533    *
5534    * Since: 0.6
5535    */
5536   obj_props[PROP_REACTIVE] =
5537     g_param_spec_boolean ("reactive",
5538                           P_("Reactive"),
5539                           P_("Whether the actor is reactive to events"),
5540                           FALSE,
5541                           CLUTTER_PARAM_READWRITE);
5542
5543   /**
5544    * ClutterActor:has-clip:
5545    *
5546    * Whether the actor has the #ClutterActor:clip property set or not
5547    */
5548   obj_props[PROP_HAS_CLIP] =
5549     g_param_spec_boolean ("has-clip",
5550                           P_("Has Clip"),
5551                           P_("Whether the actor has a clip set"),
5552                           FALSE,
5553                           CLUTTER_PARAM_READABLE);
5554
5555   /**
5556    * ClutterActor:clip:
5557    *
5558    * The clip region for the actor, in actor-relative coordinates
5559    *
5560    * Every part of the actor outside the clip region will not be
5561    * painted
5562    */
5563   obj_props[PROP_CLIP] =
5564     g_param_spec_boxed ("clip",
5565                         P_("Clip"),
5566                         P_("The clip region for the actor"),
5567                         CLUTTER_TYPE_GEOMETRY,
5568                         CLUTTER_PARAM_READWRITE);
5569
5570   /**
5571    * ClutterActor:name:
5572    *
5573    * The name of the actor
5574    *
5575    * Since: 0.2
5576    */
5577   obj_props[PROP_NAME] =
5578     g_param_spec_string ("name",
5579                          P_("Name"),
5580                          P_("Name of the actor"),
5581                          NULL,
5582                          CLUTTER_PARAM_READWRITE);
5583
5584   /**
5585    * ClutterActor:scale-x:
5586    *
5587    * The horizontal scale of the actor.
5588    *
5589    * The #ClutterActor:scale-x property is animatable.
5590    *
5591    * Since: 0.6
5592    */
5593   obj_props[PROP_SCALE_X] =
5594     g_param_spec_double ("scale-x",
5595                          P_("Scale X"),
5596                          P_("Scale factor on the X axis"),
5597                          0.0, G_MAXDOUBLE,
5598                          1.0,
5599                          G_PARAM_READWRITE |
5600                          G_PARAM_STATIC_STRINGS |
5601                          CLUTTER_PARAM_ANIMATABLE);
5602
5603   /**
5604    * ClutterActor:scale-y:
5605    *
5606    * The vertical scale of the actor.
5607    *
5608    * The #ClutterActor:scale-y property is animatable.
5609    *
5610    * Since: 0.6
5611    */
5612   obj_props[PROP_SCALE_Y] =
5613     g_param_spec_double ("scale-y",
5614                          P_("Scale Y"),
5615                          P_("Scale factor on the Y axis"),
5616                          0.0, G_MAXDOUBLE,
5617                          1.0,
5618                          G_PARAM_READWRITE |
5619                          G_PARAM_STATIC_STRINGS |
5620                          CLUTTER_PARAM_ANIMATABLE);
5621
5622   /**
5623    * ClutterActor:scale-center-x:
5624    *
5625    * The horizontal center point for scaling
5626    *
5627    * Since: 1.0
5628    */
5629   obj_props[PROP_SCALE_CENTER_X] =
5630     g_param_spec_float ("scale-center-x",
5631                         P_("Scale Center X"),
5632                         P_("Horizontal scale center"),
5633                         -G_MAXFLOAT, G_MAXFLOAT,
5634                         0.0,
5635                         CLUTTER_PARAM_READWRITE);
5636
5637   /**
5638    * ClutterActor:scale-center-y:
5639    *
5640    * The vertical center point for scaling
5641    *
5642    * Since: 1.0
5643    */
5644   obj_props[PROP_SCALE_CENTER_Y] =
5645     g_param_spec_float ("scale-center-y",
5646                         P_("Scale Center Y"),
5647                         P_("Vertical scale center"),
5648                         -G_MAXFLOAT, G_MAXFLOAT,
5649                         0.0,
5650                         CLUTTER_PARAM_READWRITE);
5651
5652   /**
5653    * ClutterActor:scale-gravity:
5654    *
5655    * The center point for scaling expressed as a #ClutterGravity
5656    *
5657    * Since: 1.0
5658    */
5659   obj_props[PROP_SCALE_GRAVITY] =
5660     g_param_spec_enum ("scale-gravity",
5661                        P_("Scale Gravity"),
5662                        P_("The center of scaling"),
5663                        CLUTTER_TYPE_GRAVITY,
5664                        CLUTTER_GRAVITY_NONE,
5665                        CLUTTER_PARAM_READWRITE);
5666
5667   /**
5668    * ClutterActor:rotation-angle-x:
5669    *
5670    * The rotation angle on the X axis.
5671    *
5672    * The #ClutterActor:rotation-angle-x property is animatable.
5673    *
5674    * Since: 0.6
5675    */
5676   obj_props[PROP_ROTATION_ANGLE_X] =
5677     g_param_spec_double ("rotation-angle-x",
5678                          P_("Rotation Angle X"),
5679                          P_("The rotation angle on the X axis"),
5680                          -G_MAXDOUBLE, G_MAXDOUBLE,
5681                          0.0,
5682                          G_PARAM_READWRITE |
5683                          G_PARAM_STATIC_STRINGS |
5684                          CLUTTER_PARAM_ANIMATABLE);
5685
5686   /**
5687    * ClutterActor:rotation-angle-y:
5688    *
5689    * The rotation angle on the Y axis
5690    *
5691    * The #ClutterActor:rotation-angle-y property is animatable.
5692    *
5693    * Since: 0.6
5694    */
5695   obj_props[PROP_ROTATION_ANGLE_Y] =
5696     g_param_spec_double ("rotation-angle-y",
5697                          P_("Rotation Angle Y"),
5698                          P_("The rotation angle on the Y axis"),
5699                          -G_MAXDOUBLE, G_MAXDOUBLE,
5700                          0.0,
5701                          G_PARAM_READWRITE |
5702                          G_PARAM_STATIC_STRINGS |
5703                          CLUTTER_PARAM_ANIMATABLE);
5704
5705   /**
5706    * ClutterActor:rotation-angle-z:
5707    *
5708    * The rotation angle on the Z axis
5709    *
5710    * The #ClutterActor:rotation-angle-z property is animatable.
5711    *
5712    * Since: 0.6
5713    */
5714   obj_props[PROP_ROTATION_ANGLE_Z] =
5715     g_param_spec_double ("rotation-angle-z",
5716                          P_("Rotation Angle Z"),
5717                          P_("The rotation angle on the Z axis"),
5718                          -G_MAXDOUBLE, G_MAXDOUBLE,
5719                          0.0,
5720                          G_PARAM_READWRITE |
5721                          G_PARAM_STATIC_STRINGS |
5722                          CLUTTER_PARAM_ANIMATABLE);
5723
5724   /**
5725    * ClutterActor:rotation-center-x:
5726    *
5727    * The rotation center on the X axis.
5728    *
5729    * Since: 0.6
5730    */
5731   obj_props[PROP_ROTATION_CENTER_X] =
5732     g_param_spec_boxed ("rotation-center-x",
5733                         P_("Rotation Center X"),
5734                         P_("The rotation center on the X axis"),
5735                         CLUTTER_TYPE_VERTEX,
5736                         CLUTTER_PARAM_READWRITE);
5737
5738   /**
5739    * ClutterActor:rotation-center-y:
5740    *
5741    * The rotation center on the Y axis.
5742    *
5743    * Since: 0.6
5744    */
5745   obj_props[PROP_ROTATION_CENTER_Y] =
5746     g_param_spec_boxed ("rotation-center-y",
5747                         P_("Rotation Center Y"),
5748                         P_("The rotation center on the Y axis"),
5749                         CLUTTER_TYPE_VERTEX,
5750                         CLUTTER_PARAM_READWRITE);
5751
5752   /**
5753    * ClutterActor:rotation-center-z:
5754    *
5755    * The rotation center on the Z axis.
5756    *
5757    * Since: 0.6
5758    */
5759   obj_props[PROP_ROTATION_CENTER_Z] =
5760     g_param_spec_boxed ("rotation-center-z",
5761                         P_("Rotation Center Z"),
5762                         P_("The rotation center on the Z axis"),
5763                         CLUTTER_TYPE_VERTEX,
5764                         CLUTTER_PARAM_READWRITE);
5765
5766   /**
5767    * ClutterActor:rotation-center-z-gravity:
5768    *
5769    * The rotation center on the Z axis expressed as a #ClutterGravity.
5770    *
5771    * Since: 1.0
5772    */
5773   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5774     g_param_spec_enum ("rotation-center-z-gravity",
5775                        P_("Rotation Center Z Gravity"),
5776                        P_("Center point for rotation around the Z axis"),
5777                        CLUTTER_TYPE_GRAVITY,
5778                        CLUTTER_GRAVITY_NONE,
5779                        CLUTTER_PARAM_READWRITE);
5780
5781   /**
5782    * ClutterActor:anchor-x:
5783    *
5784    * The X coordinate of an actor's anchor point, relative to
5785    * the actor coordinate space, in pixels
5786    *
5787    * Since: 0.8
5788    */
5789   obj_props[PROP_ANCHOR_X] =
5790     g_param_spec_float ("anchor-x",
5791                         P_("Anchor X"),
5792                         P_("X coordinate of the anchor point"),
5793                         -G_MAXFLOAT, G_MAXFLOAT,
5794                         0,
5795                         CLUTTER_PARAM_READWRITE);
5796
5797   /**
5798    * ClutterActor:anchor-y:
5799    *
5800    * The Y coordinate of an actor's anchor point, relative to
5801    * the actor coordinate space, in pixels
5802    *
5803    * Since: 0.8
5804    */
5805   obj_props[PROP_ANCHOR_Y] =
5806     g_param_spec_float ("anchor-y",
5807                         P_("Anchor Y"),
5808                         P_("Y coordinate of the anchor point"),
5809                         -G_MAXFLOAT, G_MAXFLOAT,
5810                         0,
5811                         CLUTTER_PARAM_READWRITE);
5812
5813   /**
5814    * ClutterActor:anchor-gravity:
5815    *
5816    * The anchor point expressed as a #ClutterGravity
5817    *
5818    * Since: 1.0
5819    */
5820   obj_props[PROP_ANCHOR_GRAVITY] =
5821     g_param_spec_enum ("anchor-gravity",
5822                        P_("Anchor Gravity"),
5823                        P_("The anchor point as a ClutterGravity"),
5824                        CLUTTER_TYPE_GRAVITY,
5825                        CLUTTER_GRAVITY_NONE,
5826                        CLUTTER_PARAM_READWRITE);
5827
5828   /**
5829    * ClutterActor:show-on-set-parent:
5830    *
5831    * If %TRUE, the actor is automatically shown when parented.
5832    *
5833    * Calling clutter_actor_hide() on an actor which has not been
5834    * parented will set this property to %FALSE as a side effect.
5835    *
5836    * Since: 0.8
5837    */
5838   obj_props[PROP_SHOW_ON_SET_PARENT] =
5839     g_param_spec_boolean ("show-on-set-parent",
5840                           P_("Show on set parent"),
5841                           P_("Whether the actor is shown when parented"),
5842                           TRUE,
5843                           CLUTTER_PARAM_READWRITE);
5844
5845   /**
5846    * ClutterActor:clip-to-allocation:
5847    *
5848    * Whether the clip region should track the allocated area
5849    * of the actor.
5850    *
5851    * This property is ignored if a clip area has been explicitly
5852    * set using clutter_actor_set_clip().
5853    *
5854    * Since: 1.0
5855    */
5856   obj_props[PROP_CLIP_TO_ALLOCATION] =
5857     g_param_spec_boolean ("clip-to-allocation",
5858                           P_("Clip to Allocation"),
5859                           P_("Sets the clip region to track the actor's allocation"),
5860                           FALSE,
5861                           CLUTTER_PARAM_READWRITE);
5862
5863   /**
5864    * ClutterActor:text-direction:
5865    *
5866    * The direction of the text inside a #ClutterActor.
5867    *
5868    * Since: 1.0
5869    */
5870   obj_props[PROP_TEXT_DIRECTION] =
5871     g_param_spec_enum ("text-direction",
5872                        P_("Text Direction"),
5873                        P_("Direction of the text"),
5874                        CLUTTER_TYPE_TEXT_DIRECTION,
5875                        CLUTTER_TEXT_DIRECTION_LTR,
5876                        CLUTTER_PARAM_READWRITE);
5877
5878   /**
5879    * ClutterActor:has-pointer:
5880    *
5881    * Whether the actor contains the pointer of a #ClutterInputDevice
5882    * or not.
5883    *
5884    * Since: 1.2
5885    */
5886   obj_props[PROP_HAS_POINTER] =
5887     g_param_spec_boolean ("has-pointer",
5888                           P_("Has Pointer"),
5889                           P_("Whether the actor contains the pointer of an input device"),
5890                           FALSE,
5891                           CLUTTER_PARAM_READABLE);
5892
5893   /**
5894    * ClutterActor:actions:
5895    *
5896    * Adds a #ClutterAction to the actor
5897    *
5898    * Since: 1.4
5899    */
5900   obj_props[PROP_ACTIONS] =
5901     g_param_spec_object ("actions",
5902                          P_("Actions"),
5903                          P_("Adds an action to the actor"),
5904                          CLUTTER_TYPE_ACTION,
5905                          CLUTTER_PARAM_WRITABLE);
5906
5907   /**
5908    * ClutterActor:constraints:
5909    *
5910    * Adds a #ClutterConstraint to the actor
5911    *
5912    * Since: 1.4
5913    */
5914   obj_props[PROP_CONSTRAINTS] =
5915     g_param_spec_object ("constraints",
5916                          P_("Constraints"),
5917                          P_("Adds a constraint to the actor"),
5918                          CLUTTER_TYPE_CONSTRAINT,
5919                          CLUTTER_PARAM_WRITABLE);
5920
5921   /**
5922    * ClutterActor:effect:
5923    *
5924    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5925    *
5926    * Since: 1.4
5927    */
5928   obj_props[PROP_EFFECT] =
5929     g_param_spec_object ("effect",
5930                          P_("Effect"),
5931                          P_("Add an effect to be applied on the actor"),
5932                          CLUTTER_TYPE_EFFECT,
5933                          CLUTTER_PARAM_WRITABLE);
5934
5935   /**
5936    * ClutterActor:layout-manager:
5937    *
5938    * A delegate object for controlling the layout of the children of
5939    * an actor.
5940    *
5941    * Since: 1.10
5942    */
5943   obj_props[PROP_LAYOUT_MANAGER] =
5944     g_param_spec_object ("layout-manager",
5945                          P_("Layout Manager"),
5946                          P_("The object controlling the layout of an actor's children"),
5947                          CLUTTER_TYPE_LAYOUT_MANAGER,
5948                          CLUTTER_PARAM_READWRITE);
5949
5950
5951   /**
5952    * ClutterActor:x-align:
5953    *
5954    * The alignment of an actor on the X axis, if the actor has been given
5955    * extra space for its allocation.
5956    *
5957    * Since: 1.10
5958    */
5959   obj_props[PROP_X_ALIGN] =
5960     g_param_spec_enum ("x-align",
5961                        P_("X Alignment"),
5962                        P_("The alignment of the actor on the X axis within its allocation"),
5963                        CLUTTER_TYPE_ACTOR_ALIGN,
5964                        CLUTTER_ACTOR_ALIGN_FILL,
5965                        CLUTTER_PARAM_READWRITE);
5966
5967   /**
5968    * ClutterActor:y-align:
5969    *
5970    * The alignment of an actor on the Y axis, if the actor has been given
5971    * extra space for its allocation.
5972    *
5973    * Since: 1.10
5974    */
5975   obj_props[PROP_Y_ALIGN] =
5976     g_param_spec_enum ("y-align",
5977                        P_("Y Alignment"),
5978                        P_("The alignment of the actor on the Y axis within its allocation"),
5979                        CLUTTER_TYPE_ACTOR_ALIGN,
5980                        CLUTTER_ACTOR_ALIGN_FILL,
5981                        CLUTTER_PARAM_READWRITE);
5982
5983   /**
5984    * ClutterActor:margin-top:
5985    *
5986    * The margin (in pixels) from the top of the actor.
5987    *
5988    * This property adds a margin to the actor's preferred size; the margin
5989    * will be automatically taken into account when allocating the actor.
5990    *
5991    * Since: 1.10
5992    */
5993   obj_props[PROP_MARGIN_TOP] =
5994     g_param_spec_float ("margin-top",
5995                         P_("Margin Top"),
5996                         P_("Extra space at the top"),
5997                         0.0, G_MAXFLOAT,
5998                         0.0,
5999                         CLUTTER_PARAM_READWRITE);
6000
6001   /**
6002    * ClutterActor:margin-bottom:
6003    *
6004    * The margin (in pixels) from the bottom of the actor.
6005    *
6006    * This property adds a margin to the actor's preferred size; the margin
6007    * will be automatically taken into account when allocating the actor.
6008    *
6009    * Since: 1.10
6010    */
6011   obj_props[PROP_MARGIN_BOTTOM] =
6012     g_param_spec_float ("margin-bottom",
6013                         P_("Margin Bottom"),
6014                         P_("Extra space at the bottom"),
6015                         0.0, G_MAXFLOAT,
6016                         0.0,
6017                         CLUTTER_PARAM_READWRITE);
6018
6019   /**
6020    * ClutterActor:margin-left:
6021    *
6022    * The margin (in pixels) from the left of the actor.
6023    *
6024    * This property adds a margin to the actor's preferred size; the margin
6025    * will be automatically taken into account when allocating the actor.
6026    *
6027    * Since: 1.10
6028    */
6029   obj_props[PROP_MARGIN_LEFT] =
6030     g_param_spec_float ("margin-left",
6031                         P_("Margin Left"),
6032                         P_("Extra space at the left"),
6033                         0.0, G_MAXFLOAT,
6034                         0.0,
6035                         CLUTTER_PARAM_READWRITE);
6036
6037   /**
6038    * ClutterActor:margin-right:
6039    *
6040    * The margin (in pixels) from the right of the actor.
6041    *
6042    * This property adds a margin to the actor's preferred size; the margin
6043    * will be automatically taken into account when allocating the actor.
6044    *
6045    * Since: 1.10
6046    */
6047   obj_props[PROP_MARGIN_RIGHT] =
6048     g_param_spec_float ("margin-right",
6049                         P_("Margin Right"),
6050                         P_("Extra space at the right"),
6051                         0.0, G_MAXFLOAT,
6052                         0.0,
6053                         CLUTTER_PARAM_READWRITE);
6054
6055   /**
6056    * ClutterActor:background-color-set:
6057    *
6058    * Whether the #ClutterActor:background-color property has been set.
6059    *
6060    * Since: 1.10
6061    */
6062   obj_props[PROP_BACKGROUND_COLOR_SET] =
6063     g_param_spec_boolean ("background-color-set",
6064                           P_("Background Color Set"),
6065                           P_("Whether the background color is set"),
6066                           FALSE,
6067                           CLUTTER_PARAM_READABLE);
6068
6069   /**
6070    * ClutterActor:background-color:
6071    *
6072    * Paints a solid fill of the actor's allocation using the specified
6073    * color.
6074    *
6075    * The #ClutterActor:background-color property is animatable.
6076    *
6077    * Since: 1.10
6078    */
6079   obj_props[PROP_BACKGROUND_COLOR] =
6080     clutter_param_spec_color ("background-color",
6081                               P_("Background color"),
6082                               P_("The actor's background color"),
6083                               CLUTTER_COLOR_Transparent,
6084                               G_PARAM_READWRITE |
6085                               G_PARAM_STATIC_STRINGS |
6086                               CLUTTER_PARAM_ANIMATABLE);
6087
6088   /**
6089    * ClutterActor:first-child:
6090    *
6091    * The actor's first child.
6092    *
6093    * Since: 1.10
6094    */
6095   obj_props[PROP_FIRST_CHILD] =
6096     g_param_spec_object ("first-child",
6097                          P_("First Child"),
6098                          P_("The actor's first child"),
6099                          CLUTTER_TYPE_ACTOR,
6100                          CLUTTER_PARAM_READABLE);
6101
6102   /**
6103    * ClutterActor:last-child:
6104    *
6105    * The actor's last child.
6106    *
6107    * Since: 1.10
6108    */
6109   obj_props[PROP_LAST_CHILD] =
6110     g_param_spec_object ("last-child",
6111                          P_("Last Child"),
6112                          P_("The actor's last child"),
6113                          CLUTTER_TYPE_ACTOR,
6114                          CLUTTER_PARAM_READABLE);
6115
6116   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6117
6118   /**
6119    * ClutterActor::destroy:
6120    * @actor: the #ClutterActor which emitted the signal
6121    *
6122    * The ::destroy signal notifies that all references held on the
6123    * actor which emitted it should be released.
6124    *
6125    * The ::destroy signal should be used by all holders of a reference
6126    * on @actor.
6127    *
6128    * This signal might result in the finalization of the #ClutterActor
6129    * if all references are released.
6130    *
6131    * Composite actors and actors implementing the #ClutterContainer
6132    * interface should override the default implementation of the
6133    * class handler of this signal and call clutter_actor_destroy() on
6134    * their children. When overriding the default class handler, it is
6135    * required to chain up to the parent's implementation.
6136    *
6137    * Since: 0.2
6138    */
6139   actor_signals[DESTROY] =
6140     g_signal_new (I_("destroy"),
6141                   G_TYPE_FROM_CLASS (object_class),
6142                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6143                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6144                   NULL, NULL,
6145                   _clutter_marshal_VOID__VOID,
6146                   G_TYPE_NONE, 0);
6147   /**
6148    * ClutterActor::show:
6149    * @actor: the object which received the signal
6150    *
6151    * The ::show signal is emitted when an actor is visible and
6152    * rendered on the stage.
6153    *
6154    * Since: 0.2
6155    */
6156   actor_signals[SHOW] =
6157     g_signal_new (I_("show"),
6158                   G_TYPE_FROM_CLASS (object_class),
6159                   G_SIGNAL_RUN_FIRST,
6160                   G_STRUCT_OFFSET (ClutterActorClass, show),
6161                   NULL, NULL,
6162                   _clutter_marshal_VOID__VOID,
6163                   G_TYPE_NONE, 0);
6164   /**
6165    * ClutterActor::hide:
6166    * @actor: the object which received the signal
6167    *
6168    * The ::hide signal is emitted when an actor is no longer rendered
6169    * on the stage.
6170    *
6171    * Since: 0.2
6172    */
6173   actor_signals[HIDE] =
6174     g_signal_new (I_("hide"),
6175                   G_TYPE_FROM_CLASS (object_class),
6176                   G_SIGNAL_RUN_FIRST,
6177                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6178                   NULL, NULL,
6179                   _clutter_marshal_VOID__VOID,
6180                   G_TYPE_NONE, 0);
6181   /**
6182    * ClutterActor::parent-set:
6183    * @actor: the object which received the signal
6184    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6185    *
6186    * This signal is emitted when the parent of the actor changes.
6187    *
6188    * Since: 0.2
6189    */
6190   actor_signals[PARENT_SET] =
6191     g_signal_new (I_("parent-set"),
6192                   G_TYPE_FROM_CLASS (object_class),
6193                   G_SIGNAL_RUN_LAST,
6194                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6195                   NULL, NULL,
6196                   _clutter_marshal_VOID__OBJECT,
6197                   G_TYPE_NONE, 1,
6198                   CLUTTER_TYPE_ACTOR);
6199
6200   /**
6201    * ClutterActor::queue-redraw:
6202    * @actor: the actor we're bubbling the redraw request through
6203    * @origin: the actor which initiated the redraw request
6204    *
6205    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6206    * is called on @origin.
6207    *
6208    * The default implementation for #ClutterActor chains up to the
6209    * parent actor and queues a redraw on the parent, thus "bubbling"
6210    * the redraw queue up through the actor graph. The default
6211    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6212    * in a main loop idle handler.
6213    *
6214    * Note that the @origin actor may be the stage, or a container; it
6215    * does not have to be a leaf node in the actor graph.
6216    *
6217    * Toolkits embedding a #ClutterStage which require a redraw and
6218    * relayout cycle can stop the emission of this signal using the
6219    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6220    * themselves, like:
6221    *
6222    * |[
6223    *   static void
6224    *   on_redraw_complete (gpointer data)
6225    *   {
6226    *     ClutterStage *stage = data;
6227    *
6228    *     /&ast; execute the Clutter drawing pipeline &ast;/
6229    *     clutter_stage_ensure_redraw (stage);
6230    *   }
6231    *
6232    *   static void
6233    *   on_stage_queue_redraw (ClutterStage *stage)
6234    *   {
6235    *     /&ast; this prevents the default handler to run &ast;/
6236    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6237    *
6238    *     /&ast; queue a redraw with the host toolkit and call
6239    *      &ast; a function when the redraw has been completed
6240    *      &ast;/
6241    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6242    *   }
6243    * ]|
6244    *
6245    * <note><para>This signal is emitted before the Clutter paint
6246    * pipeline is executed. If you want to know when the pipeline has
6247    * been completed you should connect to the ::paint signal on the
6248    * Stage with g_signal_connect_after().</para></note>
6249    *
6250    * Since: 1.0
6251    */
6252   actor_signals[QUEUE_REDRAW] =
6253     g_signal_new (I_("queue-redraw"),
6254                   G_TYPE_FROM_CLASS (object_class),
6255                   G_SIGNAL_RUN_LAST |
6256                   G_SIGNAL_NO_RECURSE |
6257                   G_SIGNAL_NO_HOOKS,
6258                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6259                   NULL, NULL,
6260                   _clutter_marshal_VOID__OBJECT,
6261                   G_TYPE_NONE, 1,
6262                   CLUTTER_TYPE_ACTOR);
6263
6264   /**
6265    * ClutterActor::queue-relayout
6266    * @actor: the actor being queued for relayout
6267    *
6268    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6269    * is called on an actor.
6270    *
6271    * The default implementation for #ClutterActor chains up to the
6272    * parent actor and queues a relayout on the parent, thus "bubbling"
6273    * the relayout queue up through the actor graph.
6274    *
6275    * The main purpose of this signal is to allow relayout to be propagated
6276    * properly in the procense of #ClutterClone actors. Applications will
6277    * not normally need to connect to this signal.
6278    *
6279    * Since: 1.2
6280    */
6281   actor_signals[QUEUE_RELAYOUT] =
6282     g_signal_new (I_("queue-relayout"),
6283                   G_TYPE_FROM_CLASS (object_class),
6284                   G_SIGNAL_RUN_LAST |
6285                   G_SIGNAL_NO_RECURSE |
6286                   G_SIGNAL_NO_HOOKS,
6287                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6288                   NULL, NULL,
6289                   _clutter_marshal_VOID__VOID,
6290                   G_TYPE_NONE, 0);
6291
6292   /**
6293    * ClutterActor::event:
6294    * @actor: the actor which received the event
6295    * @event: a #ClutterEvent
6296    *
6297    * The ::event signal is emitted each time an event is received
6298    * by the @actor. This signal will be emitted on every actor,
6299    * following the hierarchy chain, until it reaches the top-level
6300    * container (the #ClutterStage).
6301    *
6302    * Return value: %TRUE if the event has been handled by the actor,
6303    *   or %FALSE to continue the emission.
6304    *
6305    * Since: 0.6
6306    */
6307   actor_signals[EVENT] =
6308     g_signal_new (I_("event"),
6309                   G_TYPE_FROM_CLASS (object_class),
6310                   G_SIGNAL_RUN_LAST,
6311                   G_STRUCT_OFFSET (ClutterActorClass, event),
6312                   _clutter_boolean_handled_accumulator, NULL,
6313                   _clutter_marshal_BOOLEAN__BOXED,
6314                   G_TYPE_BOOLEAN, 1,
6315                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6316   /**
6317    * ClutterActor::button-press-event:
6318    * @actor: the actor which received the event
6319    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6320    *
6321    * The ::button-press-event signal is emitted each time a mouse button
6322    * is pressed on @actor.
6323    *
6324    * Return value: %TRUE if the event has been handled by the actor,
6325    *   or %FALSE to continue the emission.
6326    *
6327    * Since: 0.6
6328    */
6329   actor_signals[BUTTON_PRESS_EVENT] =
6330     g_signal_new (I_("button-press-event"),
6331                   G_TYPE_FROM_CLASS (object_class),
6332                   G_SIGNAL_RUN_LAST,
6333                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6334                   _clutter_boolean_handled_accumulator, NULL,
6335                   _clutter_marshal_BOOLEAN__BOXED,
6336                   G_TYPE_BOOLEAN, 1,
6337                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6338   /**
6339    * ClutterActor::button-release-event:
6340    * @actor: the actor which received the event
6341    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6342    *
6343    * The ::button-release-event signal is emitted each time a mouse button
6344    * is released on @actor.
6345    *
6346    * Return value: %TRUE if the event has been handled by the actor,
6347    *   or %FALSE to continue the emission.
6348    *
6349    * Since: 0.6
6350    */
6351   actor_signals[BUTTON_RELEASE_EVENT] =
6352     g_signal_new (I_("button-release-event"),
6353                   G_TYPE_FROM_CLASS (object_class),
6354                   G_SIGNAL_RUN_LAST,
6355                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6356                   _clutter_boolean_handled_accumulator, NULL,
6357                   _clutter_marshal_BOOLEAN__BOXED,
6358                   G_TYPE_BOOLEAN, 1,
6359                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6360   /**
6361    * ClutterActor::scroll-event:
6362    * @actor: the actor which received the event
6363    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6364    *
6365    * The ::scroll-event signal is emitted each time the mouse is
6366    * scrolled on @actor
6367    *
6368    * Return value: %TRUE if the event has been handled by the actor,
6369    *   or %FALSE to continue the emission.
6370    *
6371    * Since: 0.6
6372    */
6373   actor_signals[SCROLL_EVENT] =
6374     g_signal_new (I_("scroll-event"),
6375                   G_TYPE_FROM_CLASS (object_class),
6376                   G_SIGNAL_RUN_LAST,
6377                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6378                   _clutter_boolean_handled_accumulator, NULL,
6379                   _clutter_marshal_BOOLEAN__BOXED,
6380                   G_TYPE_BOOLEAN, 1,
6381                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6382   /**
6383    * ClutterActor::key-press-event:
6384    * @actor: the actor which received the event
6385    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6386    *
6387    * The ::key-press-event signal is emitted each time a keyboard button
6388    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6389    *
6390    * Return value: %TRUE if the event has been handled by the actor,
6391    *   or %FALSE to continue the emission.
6392    *
6393    * Since: 0.6
6394    */
6395   actor_signals[KEY_PRESS_EVENT] =
6396     g_signal_new (I_("key-press-event"),
6397                   G_TYPE_FROM_CLASS (object_class),
6398                   G_SIGNAL_RUN_LAST,
6399                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6400                   _clutter_boolean_handled_accumulator, NULL,
6401                   _clutter_marshal_BOOLEAN__BOXED,
6402                   G_TYPE_BOOLEAN, 1,
6403                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6404   /**
6405    * ClutterActor::key-release-event:
6406    * @actor: the actor which received the event
6407    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6408    *
6409    * The ::key-release-event signal is emitted each time a keyboard button
6410    * is released while @actor has key focus (see
6411    * clutter_stage_set_key_focus()).
6412    *
6413    * Return value: %TRUE if the event has been handled by the actor,
6414    *   or %FALSE to continue the emission.
6415    *
6416    * Since: 0.6
6417    */
6418   actor_signals[KEY_RELEASE_EVENT] =
6419     g_signal_new (I_("key-release-event"),
6420                   G_TYPE_FROM_CLASS (object_class),
6421                   G_SIGNAL_RUN_LAST,
6422                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6423                   _clutter_boolean_handled_accumulator, NULL,
6424                   _clutter_marshal_BOOLEAN__BOXED,
6425                   G_TYPE_BOOLEAN, 1,
6426                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6427   /**
6428    * ClutterActor::motion-event:
6429    * @actor: the actor which received the event
6430    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6431    *
6432    * The ::motion-event signal is emitted each time the mouse pointer is
6433    * moved over @actor.
6434    *
6435    * Return value: %TRUE if the event has been handled by the actor,
6436    *   or %FALSE to continue the emission.
6437    *
6438    * Since: 0.6
6439    */
6440   actor_signals[MOTION_EVENT] =
6441     g_signal_new (I_("motion-event"),
6442                   G_TYPE_FROM_CLASS (object_class),
6443                   G_SIGNAL_RUN_LAST,
6444                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6445                   _clutter_boolean_handled_accumulator, NULL,
6446                   _clutter_marshal_BOOLEAN__BOXED,
6447                   G_TYPE_BOOLEAN, 1,
6448                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6449
6450   /**
6451    * ClutterActor::key-focus-in:
6452    * @actor: the actor which now has key focus
6453    *
6454    * The ::key-focus-in signal is emitted when @actor receives key focus.
6455    *
6456    * Since: 0.6
6457    */
6458   actor_signals[KEY_FOCUS_IN] =
6459     g_signal_new (I_("key-focus-in"),
6460                   G_TYPE_FROM_CLASS (object_class),
6461                   G_SIGNAL_RUN_LAST,
6462                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6463                   NULL, NULL,
6464                   _clutter_marshal_VOID__VOID,
6465                   G_TYPE_NONE, 0);
6466
6467   /**
6468    * ClutterActor::key-focus-out:
6469    * @actor: the actor which now has key focus
6470    *
6471    * The ::key-focus-out signal is emitted when @actor loses key focus.
6472    *
6473    * Since: 0.6
6474    */
6475   actor_signals[KEY_FOCUS_OUT] =
6476     g_signal_new (I_("key-focus-out"),
6477                   G_TYPE_FROM_CLASS (object_class),
6478                   G_SIGNAL_RUN_LAST,
6479                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6480                   NULL, NULL,
6481                   _clutter_marshal_VOID__VOID,
6482                   G_TYPE_NONE, 0);
6483
6484   /**
6485    * ClutterActor::enter-event:
6486    * @actor: the actor which the pointer has entered.
6487    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6488    *
6489    * The ::enter-event signal is emitted when the pointer enters the @actor
6490    *
6491    * Return value: %TRUE if the event has been handled by the actor,
6492    *   or %FALSE to continue the emission.
6493    *
6494    * Since: 0.6
6495    */
6496   actor_signals[ENTER_EVENT] =
6497     g_signal_new (I_("enter-event"),
6498                   G_TYPE_FROM_CLASS (object_class),
6499                   G_SIGNAL_RUN_LAST,
6500                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6501                   _clutter_boolean_handled_accumulator, NULL,
6502                   _clutter_marshal_BOOLEAN__BOXED,
6503                   G_TYPE_BOOLEAN, 1,
6504                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6505
6506   /**
6507    * ClutterActor::leave-event:
6508    * @actor: the actor which the pointer has left
6509    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6510    *
6511    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6512    *
6513    * Return value: %TRUE if the event has been handled by the actor,
6514    *   or %FALSE to continue the emission.
6515    *
6516    * Since: 0.6
6517    */
6518   actor_signals[LEAVE_EVENT] =
6519     g_signal_new (I_("leave-event"),
6520                   G_TYPE_FROM_CLASS (object_class),
6521                   G_SIGNAL_RUN_LAST,
6522                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6523                   _clutter_boolean_handled_accumulator, NULL,
6524                   _clutter_marshal_BOOLEAN__BOXED,
6525                   G_TYPE_BOOLEAN, 1,
6526                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6527
6528   /**
6529    * ClutterActor::captured-event:
6530    * @actor: the actor which received the signal
6531    * @event: a #ClutterEvent
6532    *
6533    * The ::captured-event signal is emitted when an event is captured
6534    * by Clutter. This signal will be emitted starting from the top-level
6535    * container (the #ClutterStage) to the actor which received the event
6536    * going down the hierarchy. This signal can be used to intercept every
6537    * event before the specialized events (like
6538    * ClutterActor::button-press-event or ::key-released-event) are
6539    * emitted.
6540    *
6541    * Return value: %TRUE if the event has been handled by the actor,
6542    *   or %FALSE to continue the emission.
6543    *
6544    * Since: 0.6
6545    */
6546   actor_signals[CAPTURED_EVENT] =
6547     g_signal_new (I_("captured-event"),
6548                   G_TYPE_FROM_CLASS (object_class),
6549                   G_SIGNAL_RUN_LAST,
6550                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6551                   _clutter_boolean_handled_accumulator, NULL,
6552                   _clutter_marshal_BOOLEAN__BOXED,
6553                   G_TYPE_BOOLEAN, 1,
6554                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6555
6556   /**
6557    * ClutterActor::paint:
6558    * @actor: the #ClutterActor that received the signal
6559    *
6560    * The ::paint signal is emitted each time an actor is being painted.
6561    *
6562    * Subclasses of #ClutterActor should override the class signal handler
6563    * and paint themselves in that function.
6564    *
6565    * It is possible to connect a handler to the ::paint signal in order
6566    * to set up some custom aspect of a paint.
6567    *
6568    * Since: 0.8
6569    */
6570   actor_signals[PAINT] =
6571     g_signal_new (I_("paint"),
6572                   G_TYPE_FROM_CLASS (object_class),
6573                   G_SIGNAL_RUN_LAST |
6574                   G_SIGNAL_NO_RECURSE |
6575                   G_SIGNAL_NO_HOOKS,
6576                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6577                   NULL, NULL,
6578                   _clutter_marshal_VOID__VOID,
6579                   G_TYPE_NONE, 0);
6580   /**
6581    * ClutterActor::realize:
6582    * @actor: the #ClutterActor that received the signal
6583    *
6584    * The ::realize signal is emitted each time an actor is being
6585    * realized.
6586    *
6587    * Since: 0.8
6588    */
6589   actor_signals[REALIZE] =
6590     g_signal_new (I_("realize"),
6591                   G_TYPE_FROM_CLASS (object_class),
6592                   G_SIGNAL_RUN_LAST,
6593                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6594                   NULL, NULL,
6595                   _clutter_marshal_VOID__VOID,
6596                   G_TYPE_NONE, 0);
6597   /**
6598    * ClutterActor::unrealize:
6599    * @actor: the #ClutterActor that received the signal
6600    *
6601    * The ::unrealize signal is emitted each time an actor is being
6602    * unrealized.
6603    *
6604    * Since: 0.8
6605    */
6606   actor_signals[UNREALIZE] =
6607     g_signal_new (I_("unrealize"),
6608                   G_TYPE_FROM_CLASS (object_class),
6609                   G_SIGNAL_RUN_LAST,
6610                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6611                   NULL, NULL,
6612                   _clutter_marshal_VOID__VOID,
6613                   G_TYPE_NONE, 0);
6614
6615   /**
6616    * ClutterActor::pick:
6617    * @actor: the #ClutterActor that received the signal
6618    * @color: the #ClutterColor to be used when picking
6619    *
6620    * The ::pick signal is emitted each time an actor is being painted
6621    * in "pick mode". The pick mode is used to identify the actor during
6622    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6623    * The actor should paint its shape using the passed @pick_color.
6624    *
6625    * Subclasses of #ClutterActor should override the class signal handler
6626    * and paint themselves in that function.
6627    *
6628    * It is possible to connect a handler to the ::pick signal in order
6629    * to set up some custom aspect of a paint in pick mode.
6630    *
6631    * Since: 1.0
6632    */
6633   actor_signals[PICK] =
6634     g_signal_new (I_("pick"),
6635                   G_TYPE_FROM_CLASS (object_class),
6636                   G_SIGNAL_RUN_LAST,
6637                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6638                   NULL, NULL,
6639                   _clutter_marshal_VOID__BOXED,
6640                   G_TYPE_NONE, 1,
6641                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6642
6643   /**
6644    * ClutterActor::allocation-changed:
6645    * @actor: the #ClutterActor that emitted the signal
6646    * @box: a #ClutterActorBox with the new allocation
6647    * @flags: #ClutterAllocationFlags for the allocation
6648    *
6649    * The ::allocation-changed signal is emitted when the
6650    * #ClutterActor:allocation property changes. Usually, application
6651    * code should just use the notifications for the :allocation property
6652    * but if you want to track the allocation flags as well, for instance
6653    * to know whether the absolute origin of @actor changed, then you might
6654    * want use this signal instead.
6655    *
6656    * Since: 1.0
6657    */
6658   actor_signals[ALLOCATION_CHANGED] =
6659     g_signal_new (I_("allocation-changed"),
6660                   G_TYPE_FROM_CLASS (object_class),
6661                   G_SIGNAL_RUN_LAST,
6662                   0,
6663                   NULL, NULL,
6664                   _clutter_marshal_VOID__BOXED_FLAGS,
6665                   G_TYPE_NONE, 2,
6666                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6667                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6668 }
6669
6670 static void
6671 clutter_actor_init (ClutterActor *self)
6672 {
6673   ClutterActorPrivate *priv;
6674
6675   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6676
6677   priv->id = _clutter_context_acquire_id (self);
6678   priv->pick_id = -1;
6679
6680   priv->opacity = 0xff;
6681   priv->show_on_set_parent = TRUE;
6682
6683   priv->needs_width_request = TRUE;
6684   priv->needs_height_request = TRUE;
6685   priv->needs_allocation = TRUE;
6686
6687   priv->cached_width_age = 1;
6688   priv->cached_height_age = 1;
6689
6690   priv->opacity_override = -1;
6691   priv->enable_model_view_transform = TRUE;
6692
6693   /* Initialize an empty paint volume to start with */
6694   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6695   priv->last_paint_volume_valid = TRUE;
6696
6697   priv->transform_valid = FALSE;
6698 }
6699
6700 /**
6701  * clutter_actor_new:
6702  *
6703  * Creates a new #ClutterActor.
6704  *
6705  * A newly created actor has a floating reference, which will be sunk
6706  * when it is added to another actor.
6707  *
6708  * Return value: (transfer full): the newly created #ClutterActor
6709  *
6710  * Since: 1.10
6711  */
6712 ClutterActor *
6713 clutter_actor_new (void)
6714 {
6715   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6716 }
6717
6718 /**
6719  * clutter_actor_destroy:
6720  * @self: a #ClutterActor
6721  *
6722  * Destroys an actor.  When an actor is destroyed, it will break any
6723  * references it holds to other objects.  If the actor is inside a
6724  * container, the actor will be removed.
6725  *
6726  * When you destroy a container, its children will be destroyed as well.
6727  *
6728  * Note: you cannot destroy the #ClutterStage returned by
6729  * clutter_stage_get_default().
6730  */
6731 void
6732 clutter_actor_destroy (ClutterActor *self)
6733 {
6734   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6735
6736   g_object_ref (self);
6737
6738   /* avoid recursion while destroying */
6739   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6740     {
6741       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6742
6743       g_object_run_dispose (G_OBJECT (self));
6744
6745       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6746     }
6747
6748   g_object_unref (self);
6749 }
6750
6751 void
6752 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6753                                     ClutterPaintVolume *clip)
6754 {
6755   ClutterActorPrivate *priv = self->priv;
6756   ClutterPaintVolume *pv;
6757   gboolean clipped;
6758
6759   /* Remove queue entry early in the process, otherwise a new
6760      queue_redraw() during signal handling could put back this
6761      object in the stage redraw list (but the entry is freed as
6762      soon as we return from this function, causing a segfault
6763      later)
6764   */
6765   priv->queue_redraw_entry = NULL;
6766
6767   /* If we've been explicitly passed a clip volume then there's
6768    * nothing more to calculate, but otherwise the only thing we know
6769    * is that the change is constrained to the given actor.
6770    *
6771    * The idea is that if we know the paint volume for where the actor
6772    * was last drawn (in eye coordinates) and we also have the paint
6773    * volume for where it will be drawn next (in actor coordinates)
6774    * then if we queue a redraw for both these volumes that will cover
6775    * everything that needs to be redrawn to clear the old view and
6776    * show the latest view of the actor.
6777    *
6778    * Don't clip this redraw if we don't know what position we had for
6779    * the previous redraw since we don't know where to set the clip so
6780    * it will clear the actor as it is currently.
6781    */
6782   if (clip)
6783     {
6784       _clutter_actor_set_queue_redraw_clip (self, clip);
6785       clipped = TRUE;
6786     }
6787   else if (G_LIKELY (priv->last_paint_volume_valid))
6788     {
6789       pv = _clutter_actor_get_paint_volume_mutable (self);
6790       if (pv)
6791         {
6792           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6793
6794           /* make sure we redraw the actors old position... */
6795           _clutter_actor_set_queue_redraw_clip (stage,
6796                                                 &priv->last_paint_volume);
6797           _clutter_actor_signal_queue_redraw (stage, stage);
6798           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6799
6800           /* XXX: Ideally the redraw signal would take a clip volume
6801            * argument, but that would be an ABI break. Until we can
6802            * break the ABI we pass the argument out-of-band
6803            */
6804
6805           /* setup the clip for the actors new position... */
6806           _clutter_actor_set_queue_redraw_clip (self, pv);
6807           clipped = TRUE;
6808         }
6809       else
6810         clipped = FALSE;
6811     }
6812   else
6813     clipped = FALSE;
6814
6815   _clutter_actor_signal_queue_redraw (self, self);
6816
6817   /* Just in case anyone is manually firing redraw signals without
6818    * using the public queue_redraw() API we are careful to ensure that
6819    * our out-of-band clip member is cleared before returning...
6820    *
6821    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6822    */
6823   if (G_LIKELY (clipped))
6824     _clutter_actor_set_queue_redraw_clip (self, NULL);
6825 }
6826
6827 static void
6828 _clutter_actor_get_allocation_clip (ClutterActor *self,
6829                                     ClutterActorBox *clip)
6830 {
6831   ClutterActorBox allocation;
6832
6833   /* XXX: we don't care if we get an out of date allocation here
6834    * because clutter_actor_queue_redraw_with_clip knows to ignore
6835    * the clip if the actor's allocation is invalid.
6836    *
6837    * This is noted because clutter_actor_get_allocation_box does some
6838    * unnecessary work to support buggy code with a comment suggesting
6839    * that it could be changed later which would be good for this use
6840    * case!
6841    */
6842   clutter_actor_get_allocation_box (self, &allocation);
6843
6844   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6845    * actor's own coordinate space but the allocation is in parent
6846    * coordinates */
6847   clip->x1 = 0;
6848   clip->y1 = 0;
6849   clip->x2 = allocation.x2 - allocation.x1;
6850   clip->y2 = allocation.y2 - allocation.y1;
6851 }
6852
6853 void
6854 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6855                                   ClutterRedrawFlags  flags,
6856                                   ClutterPaintVolume *volume,
6857                                   ClutterEffect      *effect)
6858 {
6859   ClutterActorPrivate *priv = self->priv;
6860   ClutterPaintVolume allocation_pv;
6861   ClutterPaintVolume *pv;
6862   gboolean should_free_pv;
6863   ClutterActor *stage;
6864
6865   /* Here's an outline of the actor queue redraw mechanism:
6866    *
6867    * The process starts in one of the following two functions which
6868    * are wrappers for this function:
6869    * clutter_actor_queue_redraw
6870    * _clutter_actor_queue_redraw_with_clip
6871    *
6872    * additionally, an effect can queue a redraw by wrapping this
6873    * function in clutter_effect_queue_rerun
6874    *
6875    * This functions queues an entry in a list associated with the
6876    * stage which is a list of actors that queued a redraw while
6877    * updating the timelines, performing layouting and processing other
6878    * mainloop sources before the next paint starts.
6879    *
6880    * We aim to minimize the processing done at this point because
6881    * there is a good chance other events will happen while updating
6882    * the scenegraph that would invalidate any expensive work we might
6883    * otherwise try to do here. For example we don't try and resolve
6884    * the screen space bounding box of an actor at this stage so as to
6885    * minimize how much of the screen redraw because it's possible
6886    * something else will happen which will force a full redraw anyway.
6887    *
6888    * When all updates are complete and we come to paint the stage then
6889    * we iterate this list and actually emit the "queue-redraw" signals
6890    * for each of the listed actors which will bubble up to the stage
6891    * for each actor and at that point we will transform the actors
6892    * paint volume into screen coordinates to determine the clip region
6893    * for what needs to be redrawn in the next paint.
6894    *
6895    * Besides minimizing redundant work another reason for this
6896    * deferred design is that it's more likely we will be able to
6897    * determine the paint volume of an actor once we've finished
6898    * updating the scenegraph because its allocation should be up to
6899    * date. NB: If we can't determine an actors paint volume then we
6900    * can't automatically queue a clipped redraw which can make a big
6901    * difference to performance.
6902    *
6903    * So the control flow goes like this:
6904    * One of clutter_actor_queue_redraw,
6905    *        _clutter_actor_queue_redraw_with_clip
6906    *     or clutter_effect_queue_rerun
6907    *
6908    * then control moves to:
6909    *   _clutter_stage_queue_actor_redraw
6910    *
6911    * later during _clutter_stage_do_update, once relayouting is done
6912    * and the scenegraph has been updated we will call:
6913    * _clutter_stage_finish_queue_redraws
6914    *
6915    * _clutter_stage_finish_queue_redraws will call
6916    * _clutter_actor_finish_queue_redraw for each listed actor.
6917    * Note: actors *are* allowed to queue further redraws during this
6918    * process (considering clone actors or texture_new_from_actor which
6919    * respond to their source queueing a redraw by queuing a redraw
6920    * themselves). We repeat the process until the list is empty.
6921    *
6922    * This will result in the "queue-redraw" signal being fired for
6923    * each actor which will pass control to the default signal handler:
6924    * clutter_actor_real_queue_redraw
6925    *
6926    * This will bubble up to the stages handler:
6927    * clutter_stage_real_queue_redraw
6928    *
6929    * clutter_stage_real_queue_redraw will transform the actors paint
6930    * volume into screen space and add it as a clip region for the next
6931    * paint.
6932    */
6933
6934   /* ignore queueing a redraw for actors being destroyed */
6935   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6936     return;
6937
6938   stage = _clutter_actor_get_stage_internal (self);
6939
6940   /* Ignore queueing a redraw for actors not descended from a stage */
6941   if (stage == NULL)
6942     return;
6943
6944   /* ignore queueing a redraw on stages that are being destroyed */
6945   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6946     return;
6947
6948   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6949     {
6950       ClutterActorBox allocation_clip;
6951       ClutterVertex origin;
6952
6953       /* If the actor doesn't have a valid allocation then we will
6954        * queue a full stage redraw. */
6955       if (priv->needs_allocation)
6956         {
6957           /* NB: NULL denotes an undefined clip which will result in a
6958            * full redraw... */
6959           _clutter_actor_set_queue_redraw_clip (self, NULL);
6960           _clutter_actor_signal_queue_redraw (self, self);
6961           return;
6962         }
6963
6964       _clutter_paint_volume_init_static (&allocation_pv, self);
6965       pv = &allocation_pv;
6966
6967       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6968
6969       origin.x = allocation_clip.x1;
6970       origin.y = allocation_clip.y1;
6971       origin.z = 0;
6972       clutter_paint_volume_set_origin (pv, &origin);
6973       clutter_paint_volume_set_width (pv,
6974                                       allocation_clip.x2 - allocation_clip.x1);
6975       clutter_paint_volume_set_height (pv,
6976                                        allocation_clip.y2 -
6977                                        allocation_clip.y1);
6978       should_free_pv = TRUE;
6979     }
6980   else
6981     {
6982       pv = volume;
6983       should_free_pv = FALSE;
6984     }
6985
6986   self->priv->queue_redraw_entry =
6987     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6988                                        priv->queue_redraw_entry,
6989                                        self,
6990                                        pv);
6991
6992   if (should_free_pv)
6993     clutter_paint_volume_free (pv);
6994
6995   /* If this is the first redraw queued then we can directly use the
6996      effect parameter */
6997   if (!priv->is_dirty)
6998     priv->effect_to_redraw = effect;
6999   /* Otherwise we need to merge it with the existing effect parameter */
7000   else if (effect != NULL)
7001     {
7002       /* If there's already an effect then we need to use whichever is
7003          later in the chain of actors. Otherwise a full redraw has
7004          already been queued on the actor so we need to ignore the
7005          effect parameter */
7006       if (priv->effect_to_redraw != NULL)
7007         {
7008           if (priv->effects == NULL)
7009             g_warning ("Redraw queued with an effect that is "
7010                        "not applied to the actor");
7011           else
7012             {
7013               const GList *l;
7014
7015               for (l = _clutter_meta_group_peek_metas (priv->effects);
7016                    l != NULL;
7017                    l = l->next)
7018                 {
7019                   if (l->data == priv->effect_to_redraw ||
7020                       l->data == effect)
7021                     priv->effect_to_redraw = l->data;
7022                 }
7023             }
7024         }
7025     }
7026   else
7027     {
7028       /* If no effect is specified then we need to redraw the whole
7029          actor */
7030       priv->effect_to_redraw = NULL;
7031     }
7032
7033   priv->is_dirty = TRUE;
7034 }
7035
7036 /**
7037  * clutter_actor_queue_redraw:
7038  * @self: A #ClutterActor
7039  *
7040  * Queues up a redraw of an actor and any children. The redraw occurs
7041  * once the main loop becomes idle (after the current batch of events
7042  * has been processed, roughly).
7043  *
7044  * Applications rarely need to call this, as redraws are handled
7045  * automatically by modification functions.
7046  *
7047  * This function will not do anything if @self is not visible, or
7048  * if the actor is inside an invisible part of the scenegraph.
7049  *
7050  * Also be aware that painting is a NOP for actors with an opacity of
7051  * 0
7052  *
7053  * When you are implementing a custom actor you must queue a redraw
7054  * whenever some private state changes that will affect painting or
7055  * picking of your actor.
7056  */
7057 void
7058 clutter_actor_queue_redraw (ClutterActor *self)
7059 {
7060   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7061
7062   _clutter_actor_queue_redraw_full (self,
7063                                     0, /* flags */
7064                                     NULL, /* clip volume */
7065                                     NULL /* effect */);
7066 }
7067
7068 /*< private >
7069  * _clutter_actor_queue_redraw_with_clip:
7070  * @self: A #ClutterActor
7071  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7072  *   this queue redraw.
7073  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7074  *   redrawn or %NULL if you are just using a @flag to state your
7075  *   desired clipping.
7076  *
7077  * Queues up a clipped redraw of an actor and any children. The redraw
7078  * occurs once the main loop becomes idle (after the current batch of
7079  * events has been processed, roughly).
7080  *
7081  * If no flags are given the clip volume is defined by @volume
7082  * specified in actor coordinates and tells Clutter that only content
7083  * within this volume has been changed so Clutter can optionally
7084  * optimize the redraw.
7085  *
7086  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7087  * should be %NULL and this tells Clutter to use the actor's current
7088  * allocation as a clip box. This flag can only be used for 2D actors,
7089  * because any actor with depth may be projected outside its
7090  * allocation.
7091  *
7092  * Applications rarely need to call this, as redraws are handled
7093  * automatically by modification functions.
7094  *
7095  * This function will not do anything if @self is not visible, or if
7096  * the actor is inside an invisible part of the scenegraph.
7097  *
7098  * Also be aware that painting is a NOP for actors with an opacity of
7099  * 0
7100  *
7101  * When you are implementing a custom actor you must queue a redraw
7102  * whenever some private state changes that will affect painting or
7103  * picking of your actor.
7104  */
7105 void
7106 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7107                                        ClutterRedrawFlags  flags,
7108                                        ClutterPaintVolume *volume)
7109 {
7110   _clutter_actor_queue_redraw_full (self,
7111                                     flags, /* flags */
7112                                     volume, /* clip volume */
7113                                     NULL /* effect */);
7114 }
7115
7116 static void
7117 _clutter_actor_queue_only_relayout (ClutterActor *self)
7118 {
7119   ClutterActorPrivate *priv = self->priv;
7120
7121   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7122     return;
7123
7124   if (priv->needs_width_request &&
7125       priv->needs_height_request &&
7126       priv->needs_allocation)
7127     return; /* save some cpu cycles */
7128
7129 #if CLUTTER_ENABLE_DEBUG
7130   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7131     {
7132       g_warning ("The actor '%s' is currently inside an allocation "
7133                  "cycle; calling clutter_actor_queue_relayout() is "
7134                  "not recommended",
7135                  _clutter_actor_get_debug_name (self));
7136     }
7137 #endif /* CLUTTER_ENABLE_DEBUG */
7138
7139   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7140 }
7141
7142 /**
7143  * clutter_actor_queue_redraw_with_clip:
7144  * @self: a #ClutterActor
7145  * @clip: (allow-none): a rectangular clip region, or %NULL
7146  *
7147  * Queues a redraw on @self limited to a specific, actor-relative
7148  * rectangular area.
7149  *
7150  * If @clip is %NULL this function is equivalent to
7151  * clutter_actor_queue_redraw().
7152  *
7153  * Since: 1.10
7154  */
7155 void
7156 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7157                                       const cairo_rectangle_int_t *clip)
7158 {
7159   ClutterPaintVolume volume;
7160   ClutterVertex origin;
7161
7162   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7163
7164   if (clip == NULL)
7165     {
7166       clutter_actor_queue_redraw (self);
7167       return;
7168     }
7169
7170   _clutter_paint_volume_init_static (&volume, self);
7171
7172   origin.x = clip->x;
7173   origin.y = clip->y;
7174   origin.z = 0.0f;
7175
7176   clutter_paint_volume_set_origin (&volume, &origin);
7177   clutter_paint_volume_set_width (&volume, clip->width);
7178   clutter_paint_volume_set_height (&volume, clip->height);
7179
7180   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7181
7182   clutter_paint_volume_free (&volume);
7183 }
7184
7185 /**
7186  * clutter_actor_queue_relayout:
7187  * @self: A #ClutterActor
7188  *
7189  * Indicates that the actor's size request or other layout-affecting
7190  * properties may have changed. This function is used inside #ClutterActor
7191  * subclass implementations, not by applications directly.
7192  *
7193  * Queueing a new layout automatically queues a redraw as well.
7194  *
7195  * Since: 0.8
7196  */
7197 void
7198 clutter_actor_queue_relayout (ClutterActor *self)
7199 {
7200   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7201
7202   _clutter_actor_queue_only_relayout (self);
7203   clutter_actor_queue_redraw (self);
7204 }
7205
7206 /**
7207  * clutter_actor_get_preferred_size:
7208  * @self: a #ClutterActor
7209  * @min_width_p: (out) (allow-none): return location for the minimum
7210  *   width, or %NULL
7211  * @min_height_p: (out) (allow-none): return location for the minimum
7212  *   height, or %NULL
7213  * @natural_width_p: (out) (allow-none): return location for the natural
7214  *   width, or %NULL
7215  * @natural_height_p: (out) (allow-none): return location for the natural
7216  *   height, or %NULL
7217  *
7218  * Computes the preferred minimum and natural size of an actor, taking into
7219  * account the actor's geometry management (either height-for-width
7220  * or width-for-height).
7221  *
7222  * The width and height used to compute the preferred height and preferred
7223  * width are the actor's natural ones.
7224  *
7225  * If you need to control the height for the preferred width, or the width for
7226  * the preferred height, you should use clutter_actor_get_preferred_width()
7227  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7228  * geometry management using the #ClutterActor:request-mode property.
7229  *
7230  * Since: 0.8
7231  */
7232 void
7233 clutter_actor_get_preferred_size (ClutterActor *self,
7234                                   gfloat       *min_width_p,
7235                                   gfloat       *min_height_p,
7236                                   gfloat       *natural_width_p,
7237                                   gfloat       *natural_height_p)
7238 {
7239   ClutterActorPrivate *priv;
7240   gfloat min_width, min_height;
7241   gfloat natural_width, natural_height;
7242
7243   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7244
7245   priv = self->priv;
7246
7247   min_width = min_height = 0;
7248   natural_width = natural_height = 0;
7249
7250   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7251     {
7252       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7253       clutter_actor_get_preferred_width (self, -1,
7254                                          &min_width,
7255                                          &natural_width);
7256       clutter_actor_get_preferred_height (self, natural_width,
7257                                           &min_height,
7258                                           &natural_height);
7259     }
7260   else
7261     {
7262       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7263       clutter_actor_get_preferred_height (self, -1,
7264                                           &min_height,
7265                                           &natural_height);
7266       clutter_actor_get_preferred_width (self, natural_height,
7267                                          &min_width,
7268                                          &natural_width);
7269     }
7270
7271   if (min_width_p)
7272     *min_width_p = min_width;
7273
7274   if (min_height_p)
7275     *min_height_p = min_height;
7276
7277   if (natural_width_p)
7278     *natural_width_p = natural_width;
7279
7280   if (natural_height_p)
7281     *natural_height_p = natural_height;
7282 }
7283
7284 /*< private >
7285  * effective_align:
7286  * @align: a #ClutterActorAlign
7287  * @direction: a #ClutterTextDirection
7288  *
7289  * Retrieves the correct alignment depending on the text direction
7290  *
7291  * Return value: the effective alignment
7292  */
7293 static ClutterActorAlign
7294 effective_align (ClutterActorAlign    align,
7295                  ClutterTextDirection direction)
7296 {
7297   ClutterActorAlign res;
7298
7299   switch (align)
7300     {
7301     case CLUTTER_ACTOR_ALIGN_START:
7302       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7303           ? CLUTTER_ACTOR_ALIGN_END
7304           : CLUTTER_ACTOR_ALIGN_START;
7305       break;
7306
7307     case CLUTTER_ACTOR_ALIGN_END:
7308       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7309           ? CLUTTER_ACTOR_ALIGN_START
7310           : CLUTTER_ACTOR_ALIGN_END;
7311       break;
7312
7313     default:
7314       res = align;
7315       break;
7316     }
7317
7318   return res;
7319 }
7320
7321 static inline void
7322 adjust_for_margin (float  margin_start,
7323                    float  margin_end,
7324                    float *minimum_size,
7325                    float *natural_size,
7326                    float *allocated_start,
7327                    float *allocated_end)
7328 {
7329   *minimum_size -= (margin_start + margin_end);
7330   *natural_size -= (margin_start + margin_end);
7331   *allocated_start += margin_start;
7332   *allocated_end -= margin_end;
7333 }
7334
7335 static inline void
7336 adjust_for_alignment (ClutterActorAlign  alignment,
7337                       float              natural_size,
7338                       float             *allocated_start,
7339                       float             *allocated_end)
7340 {
7341   float allocated_size = *allocated_end - *allocated_start;
7342
7343   switch (alignment)
7344     {
7345     case CLUTTER_ACTOR_ALIGN_FILL:
7346       /* do nothing */
7347       break;
7348
7349     case CLUTTER_ACTOR_ALIGN_START:
7350       /* keep start */
7351       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7352       break;
7353
7354     case CLUTTER_ACTOR_ALIGN_END:
7355       if (allocated_size > natural_size)
7356         {
7357           *allocated_start += (allocated_size - natural_size);
7358           *allocated_end = *allocated_start + natural_size;
7359         }
7360       break;
7361
7362     case CLUTTER_ACTOR_ALIGN_CENTER:
7363       if (allocated_size > natural_size)
7364         {
7365           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7366           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7367         }
7368       break;
7369     }
7370 }
7371
7372 /*< private >
7373  * clutter_actor_adjust_width:
7374  * @self: a #ClutterActor
7375  * @minimum_width: (inout): the actor's preferred minimum width, which
7376  *   will be adjusted depending on the margin
7377  * @natural_width: (inout): the actor's preferred natural width, which
7378  *   will be adjusted depending on the margin
7379  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7380  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7381  *
7382  * Adjusts the preferred and allocated position and size of an actor,
7383  * depending on the margin and alignment properties.
7384  */
7385 static void
7386 clutter_actor_adjust_width (ClutterActor *self,
7387                             gfloat       *minimum_width,
7388                             gfloat       *natural_width,
7389                             gfloat       *adjusted_x1,
7390                             gfloat       *adjusted_x2)
7391 {
7392   ClutterTextDirection text_dir;
7393   const ClutterLayoutInfo *info;
7394
7395   info = _clutter_actor_get_layout_info_or_defaults (self);
7396   text_dir = clutter_actor_get_text_direction (self);
7397
7398   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7399
7400   /* this will tweak natural_width to remove the margin, so that
7401    * adjust_for_alignment() will use the correct size
7402    */
7403   adjust_for_margin (info->margin.left, info->margin.right,
7404                      minimum_width, natural_width,
7405                      adjusted_x1, adjusted_x2);
7406
7407   adjust_for_alignment (effective_align (info->x_align, text_dir),
7408                         *natural_width,
7409                         adjusted_x1, adjusted_x2);
7410 }
7411
7412 /*< private >
7413  * clutter_actor_adjust_height:
7414  * @self: a #ClutterActor
7415  * @minimum_height: (inout): the actor's preferred minimum height, which
7416  *   will be adjusted depending on the margin
7417  * @natural_height: (inout): the actor's preferred natural height, which
7418  *   will be adjusted depending on the margin
7419  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7420  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7421  *
7422  * Adjusts the preferred and allocated position and size of an actor,
7423  * depending on the margin and alignment properties.
7424  */
7425 static void
7426 clutter_actor_adjust_height (ClutterActor *self,
7427                              gfloat       *minimum_height,
7428                              gfloat       *natural_height,
7429                              gfloat       *adjusted_y1,
7430                              gfloat       *adjusted_y2)
7431 {
7432   const ClutterLayoutInfo *info;
7433
7434   info = _clutter_actor_get_layout_info_or_defaults (self);
7435
7436   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7437
7438   /* this will tweak natural_height to remove the margin, so that
7439    * adjust_for_alignment() will use the correct size
7440    */
7441   adjust_for_margin (info->margin.top, info->margin.bottom,
7442                      minimum_height, natural_height,
7443                      adjusted_y1,
7444                      adjusted_y2);
7445
7446   /* we don't use effective_align() here, because text direction
7447    * only affects the horizontal axis
7448    */
7449   adjust_for_alignment (info->y_align,
7450                         *natural_height,
7451                         adjusted_y1,
7452                         adjusted_y2);
7453
7454 }
7455
7456 /* looks for a cached size request for this for_size. If not
7457  * found, returns the oldest entry so it can be overwritten */
7458 static gboolean
7459 _clutter_actor_get_cached_size_request (gfloat         for_size,
7460                                         SizeRequest   *cached_size_requests,
7461                                         SizeRequest  **result)
7462 {
7463   guint i;
7464
7465   *result = &cached_size_requests[0];
7466
7467   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7468     {
7469       SizeRequest *sr;
7470
7471       sr = &cached_size_requests[i];
7472
7473       if (sr->age > 0 &&
7474           sr->for_size == for_size)
7475         {
7476           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7477           *result = sr;
7478           return TRUE;
7479         }
7480       else if (sr->age < (*result)->age)
7481         {
7482           *result = sr;
7483         }
7484     }
7485
7486   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7487
7488   return FALSE;
7489 }
7490
7491 /**
7492  * clutter_actor_get_preferred_width:
7493  * @self: A #ClutterActor
7494  * @for_height: available height when computing the preferred width,
7495  *   or a negative value to indicate that no height is defined
7496  * @min_width_p: (out) (allow-none): return location for minimum width,
7497  *   or %NULL
7498  * @natural_width_p: (out) (allow-none): return location for the natural
7499  *   width, or %NULL
7500  *
7501  * Computes the requested minimum and natural widths for an actor,
7502  * optionally depending on the specified height, or if they are
7503  * already computed, returns the cached values.
7504  *
7505  * An actor may not get its request - depending on the layout
7506  * manager that's in effect.
7507  *
7508  * A request should not incorporate the actor's scale or anchor point;
7509  * those transformations do not affect layout, only rendering.
7510  *
7511  * Since: 0.8
7512  */
7513 void
7514 clutter_actor_get_preferred_width (ClutterActor *self,
7515                                    gfloat        for_height,
7516                                    gfloat       *min_width_p,
7517                                    gfloat       *natural_width_p)
7518 {
7519   float request_min_width, request_natural_width;
7520   SizeRequest *cached_size_request;
7521   const ClutterLayoutInfo *info;
7522   ClutterActorPrivate *priv;
7523   gboolean found_in_cache;
7524
7525   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7526
7527   priv = self->priv;
7528
7529   info = _clutter_actor_get_layout_info_or_defaults (self);
7530
7531   /* we shortcircuit the case of a fixed size set using set_width() */
7532   if (priv->min_width_set && priv->natural_width_set)
7533     {
7534       if (min_width_p != NULL)
7535         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7536
7537       if (natural_width_p != NULL)
7538         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7539
7540       return;
7541     }
7542
7543   /* the remaining cases are:
7544    *
7545    *   - either min_width or natural_width have been set
7546    *   - neither min_width or natural_width have been set
7547    *
7548    * in both cases, we go through the cache (and through the actor in case
7549    * of cache misses) and determine the authoritative value depending on
7550    * the *_set flags.
7551    */
7552
7553   if (!priv->needs_width_request)
7554     {
7555       found_in_cache =
7556         _clutter_actor_get_cached_size_request (for_height,
7557                                                 priv->width_requests,
7558                                                 &cached_size_request);
7559     }
7560   else
7561     {
7562       /* if the actor needs a width request we use the first slot */
7563       found_in_cache = FALSE;
7564       cached_size_request = &priv->width_requests[0];
7565     }
7566
7567   if (!found_in_cache)
7568     {
7569       gfloat minimum_width, natural_width;
7570       ClutterActorClass *klass;
7571
7572       minimum_width = natural_width = 0;
7573
7574       /* adjust for the margin */
7575       if (for_height >= 0)
7576         {
7577           for_height -= (info->margin.top + info->margin.bottom);
7578           if (for_height < 0)
7579             for_height = 0;
7580         }
7581
7582       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7583
7584       klass = CLUTTER_ACTOR_GET_CLASS (self);
7585       klass->get_preferred_width (self, for_height,
7586                                   &minimum_width,
7587                                   &natural_width);
7588
7589       /* adjust for the margin */
7590       minimum_width += (info->margin.left + info->margin.right);
7591       natural_width += (info->margin.left + info->margin.right);
7592
7593       /* Due to accumulated float errors, it's better not to warn
7594        * on this, but just fix it.
7595        */
7596       if (natural_width < minimum_width)
7597         natural_width = minimum_width;
7598
7599       cached_size_request->min_size = minimum_width;
7600       cached_size_request->natural_size = natural_width;
7601       cached_size_request->for_size = for_height;
7602       cached_size_request->age = priv->cached_width_age;
7603
7604       priv->cached_width_age += 1;
7605       priv->needs_width_request = FALSE;
7606     }
7607
7608   if (!priv->min_width_set)
7609     request_min_width = cached_size_request->min_size;
7610   else
7611     request_min_width = info->min_width;
7612
7613   if (!priv->natural_width_set)
7614     request_natural_width = cached_size_request->natural_size;
7615   else
7616     request_natural_width = info->natural_width;
7617
7618   if (min_width_p)
7619     *min_width_p = request_min_width;
7620
7621   if (natural_width_p)
7622     *natural_width_p = request_natural_width;
7623 }
7624
7625 /**
7626  * clutter_actor_get_preferred_height:
7627  * @self: A #ClutterActor
7628  * @for_width: available width to assume in computing desired height,
7629  *   or a negative value to indicate that no width is defined
7630  * @min_height_p: (out) (allow-none): return location for minimum height,
7631  *   or %NULL
7632  * @natural_height_p: (out) (allow-none): return location for natural
7633  *   height, or %NULL
7634  *
7635  * Computes the requested minimum and natural heights for an actor,
7636  * or if they are already computed, returns the cached values.
7637  *
7638  * An actor may not get its request - depending on the layout
7639  * manager that's in effect.
7640  *
7641  * A request should not incorporate the actor's scale or anchor point;
7642  * those transformations do not affect layout, only rendering.
7643  *
7644  * Since: 0.8
7645  */
7646 void
7647 clutter_actor_get_preferred_height (ClutterActor *self,
7648                                     gfloat        for_width,
7649                                     gfloat       *min_height_p,
7650                                     gfloat       *natural_height_p)
7651 {
7652   float request_min_height, request_natural_height;
7653   SizeRequest *cached_size_request;
7654   const ClutterLayoutInfo *info;
7655   ClutterActorPrivate *priv;
7656   gboolean found_in_cache;
7657
7658   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7659
7660   priv = self->priv;
7661
7662   info = _clutter_actor_get_layout_info_or_defaults (self);
7663
7664   /* we shortcircuit the case of a fixed size set using set_height() */
7665   if (priv->min_height_set && priv->natural_height_set)
7666     {
7667       if (min_height_p != NULL)
7668         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7669
7670       if (natural_height_p != NULL)
7671         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7672
7673       return;
7674     }
7675
7676   /* the remaining cases are:
7677    *
7678    *   - either min_height or natural_height have been set
7679    *   - neither min_height or natural_height have been set
7680    *
7681    * in both cases, we go through the cache (and through the actor in case
7682    * of cache misses) and determine the authoritative value depending on
7683    * the *_set flags.
7684    */
7685
7686   if (!priv->needs_height_request)
7687     {
7688       found_in_cache =
7689         _clutter_actor_get_cached_size_request (for_width,
7690                                                 priv->height_requests,
7691                                                 &cached_size_request);
7692     }
7693   else
7694     {
7695       found_in_cache = FALSE;
7696       cached_size_request = &priv->height_requests[0];
7697     }
7698
7699   if (!found_in_cache)
7700     {
7701       gfloat minimum_height, natural_height;
7702       ClutterActorClass *klass;
7703
7704       minimum_height = natural_height = 0;
7705
7706       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7707
7708       /* adjust for margin */
7709       if (for_width >= 0)
7710         {
7711           for_width -= (info->margin.left + info->margin.right);
7712           if (for_width < 0)
7713             for_width = 0;
7714         }
7715
7716       klass = CLUTTER_ACTOR_GET_CLASS (self);
7717       klass->get_preferred_height (self, for_width,
7718                                    &minimum_height,
7719                                    &natural_height);
7720
7721       /* adjust for margin */
7722       minimum_height += (info->margin.top + info->margin.bottom);
7723       natural_height += (info->margin.top + info->margin.bottom);
7724
7725       /* Due to accumulated float errors, it's better not to warn
7726        * on this, but just fix it.
7727        */
7728       if (natural_height < minimum_height)
7729         natural_height = minimum_height;
7730
7731       cached_size_request->min_size = minimum_height;
7732       cached_size_request->natural_size = natural_height;
7733       cached_size_request->for_size = for_width;
7734       cached_size_request->age = priv->cached_height_age;
7735
7736       priv->cached_height_age += 1;
7737       priv->needs_height_request = FALSE;
7738     }
7739
7740   if (!priv->min_height_set)
7741     request_min_height = cached_size_request->min_size;
7742   else
7743     request_min_height = info->min_height;
7744
7745   if (!priv->natural_height_set)
7746     request_natural_height = cached_size_request->natural_size;
7747   else
7748     request_natural_height = info->natural_height;
7749
7750   if (min_height_p)
7751     *min_height_p = request_min_height;
7752
7753   if (natural_height_p)
7754     *natural_height_p = request_natural_height;
7755 }
7756
7757 /**
7758  * clutter_actor_get_allocation_box:
7759  * @self: A #ClutterActor
7760  * @box: (out): the function fills this in with the actor's allocation
7761  *
7762  * Gets the layout box an actor has been assigned. The allocation can
7763  * only be assumed valid inside a paint() method; anywhere else, it
7764  * may be out-of-date.
7765  *
7766  * An allocation does not incorporate the actor's scale or anchor point;
7767  * those transformations do not affect layout, only rendering.
7768  *
7769  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7770  * of functions inside the implementation of the get_preferred_width()
7771  * or get_preferred_height() virtual functions.</note>
7772  *
7773  * Since: 0.8
7774  */
7775 void
7776 clutter_actor_get_allocation_box (ClutterActor    *self,
7777                                   ClutterActorBox *box)
7778 {
7779   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7780
7781   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7782    * which limits calling get_allocation to inside paint() basically; or
7783    * we can 2) force a layout, which could be expensive if someone calls
7784    * get_allocation somewhere silly; or we can 3) just return the latest
7785    * value, allowing it to be out-of-date, and assume people know what
7786    * they are doing.
7787    *
7788    * The least-surprises approach that keeps existing code working is
7789    * likely to be 2). People can end up doing some inefficient things,
7790    * though, and in general code that requires 2) is probably broken.
7791    */
7792
7793   /* this implements 2) */
7794   if (G_UNLIKELY (self->priv->needs_allocation))
7795     {
7796       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7797
7798       /* do not queue a relayout on an unparented actor */
7799       if (stage)
7800         _clutter_stage_maybe_relayout (stage);
7801     }
7802
7803   /* commenting out the code above and just keeping this assigment
7804    * implements 3)
7805    */
7806   *box = self->priv->allocation;
7807 }
7808
7809 /**
7810  * clutter_actor_get_allocation_geometry:
7811  * @self: A #ClutterActor
7812  * @geom: (out): allocation geometry in pixels
7813  *
7814  * Gets the layout box an actor has been assigned.  The allocation can
7815  * only be assumed valid inside a paint() method; anywhere else, it
7816  * may be out-of-date.
7817  *
7818  * An allocation does not incorporate the actor's scale or anchor point;
7819  * those transformations do not affect layout, only rendering.
7820  *
7821  * The returned rectangle is in pixels.
7822  *
7823  * Since: 0.8
7824  */
7825 void
7826 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7827                                        ClutterGeometry *geom)
7828 {
7829   ClutterActorBox box;
7830
7831   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7832   g_return_if_fail (geom != NULL);
7833
7834   clutter_actor_get_allocation_box (self, &box);
7835
7836   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7837   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7838   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7839   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7840 }
7841
7842 static void
7843 clutter_actor_update_constraints (ClutterActor    *self,
7844                                   ClutterActorBox *allocation)
7845 {
7846   ClutterActorPrivate *priv = self->priv;
7847   const GList *constraints, *l;
7848
7849   if (priv->constraints == NULL)
7850     return;
7851
7852   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7853   for (l = constraints; l != NULL; l = l->next)
7854     {
7855       ClutterConstraint *constraint = l->data;
7856       ClutterActorMeta *meta = l->data;
7857
7858       if (clutter_actor_meta_get_enabled (meta))
7859         {
7860           _clutter_constraint_update_allocation (constraint,
7861                                                  self,
7862                                                  allocation);
7863         }
7864     }
7865 }
7866
7867 /*< private >
7868  * clutter_actor_adjust_allocation:
7869  * @self: a #ClutterActor
7870  * @allocation: (inout): the allocation to adjust
7871  *
7872  * Adjusts the passed allocation box taking into account the actor's
7873  * layout information, like alignment, expansion, and margin.
7874  */
7875 static void
7876 clutter_actor_adjust_allocation (ClutterActor    *self,
7877                                  ClutterActorBox *allocation)
7878 {
7879   ClutterActorBox adj_allocation;
7880   float alloc_width, alloc_height;
7881   float min_width, min_height;
7882   float nat_width, nat_height;
7883   ClutterRequestMode req_mode;
7884
7885   adj_allocation = *allocation;
7886
7887   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7888
7889   /* we want to hit the cache, so we use the public API */
7890   req_mode = clutter_actor_get_request_mode (self);
7891
7892   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7893     {
7894       clutter_actor_get_preferred_width (self, -1,
7895                                          &min_width,
7896                                          &nat_width);
7897       clutter_actor_get_preferred_height (self, alloc_width,
7898                                           &min_height,
7899                                           &nat_height);
7900     }
7901   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7902     {
7903       clutter_actor_get_preferred_height (self, -1,
7904                                           &min_height,
7905                                           &nat_height);
7906       clutter_actor_get_preferred_height (self, alloc_height,
7907                                           &min_width,
7908                                           &nat_width);
7909     }
7910
7911 #ifdef CLUTTER_ENABLE_DEBUG
7912   /* warn about underallocations */
7913   if (_clutter_diagnostic_enabled () &&
7914       (floorf (min_width - alloc_width) > 0 ||
7915        floorf (min_height - alloc_height) > 0))
7916     {
7917       ClutterActor *parent = clutter_actor_get_parent (self);
7918
7919       /* the only actors that are allowed to be underallocated are the Stage,
7920        * as it doesn't have an implicit size, and Actors that specifically
7921        * told us that they want to opt-out from layout control mechanisms
7922        * through the NO_LAYOUT escape hatch.
7923        */
7924       if (parent != NULL &&
7925           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7926         {
7927           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7928                      "of %.2f x %.2f from its parent actor '%s', but its "
7929                      "requested minimum size is of %.2f x %.2f",
7930                      _clutter_actor_get_debug_name (self),
7931                      alloc_width, alloc_height,
7932                      _clutter_actor_get_debug_name (parent),
7933                      min_width, min_height);
7934         }
7935     }
7936 #endif
7937
7938   clutter_actor_adjust_width (self,
7939                               &min_width,
7940                               &nat_width,
7941                               &adj_allocation.x1,
7942                               &adj_allocation.x2);
7943
7944   clutter_actor_adjust_height (self,
7945                                &min_height,
7946                                &nat_height,
7947                                &adj_allocation.y1,
7948                                &adj_allocation.y2);
7949
7950   /* we maintain the invariant that an allocation cannot be adjusted
7951    * to be outside the parent-given box
7952    */
7953   if (adj_allocation.x1 < allocation->x1 ||
7954       adj_allocation.y1 < allocation->y1 ||
7955       adj_allocation.x2 > allocation->x2 ||
7956       adj_allocation.y2 > allocation->y2)
7957     {
7958       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7959                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7960                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7961                  _clutter_actor_get_debug_name (self),
7962                  adj_allocation.x1, adj_allocation.y1,
7963                  adj_allocation.x2 - adj_allocation.x1,
7964                  adj_allocation.y2 - adj_allocation.y1,
7965                  allocation->x1, allocation->y1,
7966                  allocation->x2 - allocation->x1,
7967                  allocation->y2 - allocation->y1);
7968       return;
7969     }
7970
7971   *allocation = adj_allocation;
7972 }
7973
7974 /**
7975  * clutter_actor_allocate:
7976  * @self: A #ClutterActor
7977  * @box: new allocation of the actor, in parent-relative coordinates
7978  * @flags: flags that control the allocation
7979  *
7980  * Called by the parent of an actor to assign the actor its size.
7981  * Should never be called by applications (except when implementing
7982  * a container or layout manager).
7983  *
7984  * Actors can know from their allocation box whether they have moved
7985  * with respect to their parent actor. The @flags parameter describes
7986  * additional information about the allocation, for instance whether
7987  * the parent has moved with respect to the stage, for example because
7988  * a grandparent's origin has moved.
7989  *
7990  * Since: 0.8
7991  */
7992 void
7993 clutter_actor_allocate (ClutterActor           *self,
7994                         const ClutterActorBox  *box,
7995                         ClutterAllocationFlags  flags)
7996 {
7997   ClutterActorPrivate *priv;
7998   ClutterActorClass *klass;
7999   ClutterActorBox old_allocation, real_allocation;
8000   gboolean origin_changed, child_moved, size_changed;
8001   gboolean stage_allocation_changed;
8002
8003   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8004   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8005     {
8006       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8007                  "which isn't a descendent of the stage!\n",
8008                  self, _clutter_actor_get_debug_name (self));
8009       return;
8010     }
8011
8012   priv = self->priv;
8013
8014   old_allocation = priv->allocation;
8015   real_allocation = *box;
8016
8017   /* constraints are allowed to modify the allocation only here; we do
8018    * this prior to all the other checks so that we can bail out if the
8019    * allocation did not change
8020    */
8021   clutter_actor_update_constraints (self, &real_allocation);
8022
8023   /* adjust the allocation depending on the align/margin properties */
8024   clutter_actor_adjust_allocation (self, &real_allocation);
8025
8026   if (real_allocation.x2 < real_allocation.x1 ||
8027       real_allocation.y2 < real_allocation.y1)
8028     {
8029       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8030                  _clutter_actor_get_debug_name (self),
8031                  real_allocation.x2 - real_allocation.x1,
8032                  real_allocation.y2 - real_allocation.y1);
8033     }
8034
8035   /* we allow 0-sized actors, but not negative-sized ones */
8036   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8037   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8038
8039   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8040
8041   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8042                  real_allocation.y1 != old_allocation.y1);
8043
8044   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8045                   real_allocation.y2 != old_allocation.y2);
8046
8047   if (origin_changed || child_moved || size_changed)
8048     stage_allocation_changed = TRUE;
8049   else
8050     stage_allocation_changed = FALSE;
8051
8052   /* If we get an allocation "out of the blue"
8053    * (we did not queue relayout), then we want to
8054    * ignore it. But if we have needs_allocation set,
8055    * we want to guarantee that allocate() virtual
8056    * method is always called, i.e. that queue_relayout()
8057    * always results in an allocate() invocation on
8058    * an actor.
8059    *
8060    * The optimization here is to avoid re-allocating
8061    * actors that did not queue relayout and were
8062    * not moved.
8063    */
8064   if (!priv->needs_allocation && !stage_allocation_changed)
8065     {
8066       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8067       return;
8068     }
8069
8070   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8071    * clutter_actor_allocate(), it indicates whether the parent has its
8072    * absolute origin moved; when passed in to ClutterActor::allocate()
8073    * virtual method though, it indicates whether the child has its
8074    * absolute origin moved.  So we set it when child_moved is TRUE
8075    */
8076   if (child_moved)
8077     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8078
8079   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8080
8081   klass = CLUTTER_ACTOR_GET_CLASS (self);
8082   klass->allocate (self, &real_allocation, flags);
8083
8084   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8085
8086   if (stage_allocation_changed)
8087     clutter_actor_queue_redraw (self);
8088 }
8089
8090 /**
8091  * clutter_actor_set_allocation:
8092  * @self: a #ClutterActor
8093  * @box: a #ClutterActorBox
8094  * @flags: allocation flags
8095  *
8096  * Stores the allocation of @self as defined by @box.
8097  *
8098  * This function can only be called from within the implementation of
8099  * the #ClutterActorClass.allocate() virtual function.
8100  *
8101  * The allocation should have been adjusted to take into account constraints,
8102  * alignment, and margin properties. If you are implementing a #ClutterActor
8103  * subclass that provides its own layout management policy for its children
8104  * instead of using a #ClutterLayoutManager delegate, you should not call
8105  * this function on the children of @self; instead, you should call
8106  * clutter_actor_allocate(), which will adjust the allocation box for
8107  * you.
8108  *
8109  * This function should only be used by subclasses of #ClutterActor
8110  * that wish to store their allocation but cannot chain up to the
8111  * parent's implementation; the default implementation of the
8112  * #ClutterActorClass.allocate() virtual function will call this
8113  * function.
8114  *
8115  * It is important to note that, while chaining up was the recommended
8116  * behaviour for #ClutterActor subclasses prior to the introduction of
8117  * this function, it is recommended to call clutter_actor_set_allocation()
8118  * instead.
8119  *
8120  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8121  * to handle the allocation of its children, this function will call
8122  * the clutter_layout_manager_allocate() function only if the
8123  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8124  * expected that the subclass will call clutter_layout_manager_allocate()
8125  * by itself. For instance, the following code:
8126  *
8127  * |[
8128  * static void
8129  * my_actor_allocate (ClutterActor *actor,
8130  *                    const ClutterActorBox *allocation,
8131  *                    ClutterAllocationFlags flags)
8132  * {
8133  *   ClutterActorBox new_alloc;
8134  *   ClutterAllocationFlags new_flags;
8135  *
8136  *   adjust_allocation (allocation, &amp;new_alloc);
8137  *
8138  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8139  *
8140  *   /&ast; this will use the layout manager set on the actor &ast;/
8141  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8142  * }
8143  * ]|
8144  *
8145  * is equivalent to this:
8146  *
8147  * |[
8148  * static void
8149  * my_actor_allocate (ClutterActor *actor,
8150  *                    const ClutterActorBox *allocation,
8151  *                    ClutterAllocationFlags flags)
8152  * {
8153  *   ClutterLayoutManager *layout;
8154  *   ClutterActorBox new_alloc;
8155  *
8156  *   adjust_allocation (allocation, &amp;new_alloc);
8157  *
8158  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8159  *
8160  *   layout = clutter_actor_get_layout_manager (actor);
8161  *   clutter_layout_manager_allocate (layout,
8162  *                                    CLUTTER_CONTAINER (actor),
8163  *                                    &amp;new_alloc,
8164  *                                    flags);
8165  * }
8166  * ]|
8167  *
8168  * Since: 1.10
8169  */
8170 void
8171 clutter_actor_set_allocation (ClutterActor           *self,
8172                               const ClutterActorBox  *box,
8173                               ClutterAllocationFlags  flags)
8174 {
8175   ClutterActorPrivate *priv;
8176   gboolean changed;
8177
8178   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8179   g_return_if_fail (box != NULL);
8180
8181   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8182     {
8183       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8184                   "can only be called from within the implementation of "
8185                   "the ClutterActor::allocate() virtual function.");
8186       return;
8187     }
8188
8189   priv = self->priv;
8190
8191   g_object_freeze_notify (G_OBJECT (self));
8192
8193   changed = clutter_actor_set_allocation_internal (self, box, flags);
8194
8195   /* we allocate our children before we notify changes in our geometry,
8196    * so that people connecting to properties will be able to get valid
8197    * data out of the sub-tree of the scene graph that has this actor at
8198    * the root.
8199    */
8200   clutter_actor_maybe_layout_children (self, box, flags);
8201
8202   if (changed)
8203     {
8204       ClutterActorBox signal_box = priv->allocation;
8205       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8206
8207       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8208                      &signal_box,
8209                      signal_flags);
8210     }
8211
8212   g_object_thaw_notify (G_OBJECT (self));
8213 }
8214
8215 /**
8216  * clutter_actor_set_geometry:
8217  * @self: A #ClutterActor
8218  * @geometry: A #ClutterGeometry
8219  *
8220  * Sets the actor's fixed position and forces its minimum and natural
8221  * size, in pixels. This means the untransformed actor will have the
8222  * given geometry. This is the same as calling clutter_actor_set_position()
8223  * and clutter_actor_set_size().
8224  *
8225  * Deprecated: 1.10: Use clutter_actor_set_position() and
8226  *   clutter_actor_set_size() instead.
8227  */
8228 void
8229 clutter_actor_set_geometry (ClutterActor          *self,
8230                             const ClutterGeometry *geometry)
8231 {
8232   g_object_freeze_notify (G_OBJECT (self));
8233
8234   clutter_actor_set_position (self, geometry->x, geometry->y);
8235   clutter_actor_set_size (self, geometry->width, geometry->height);
8236
8237   g_object_thaw_notify (G_OBJECT (self));
8238 }
8239
8240 /**
8241  * clutter_actor_get_geometry:
8242  * @self: A #ClutterActor
8243  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8244  *
8245  * Gets the size and position of an actor relative to its parent
8246  * actor. This is the same as calling clutter_actor_get_position() and
8247  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8248  * requested size and position if the actor's allocation is invalid.
8249  *
8250  * Deprecated: 1.10: Use clutter_actor_get_position() and
8251  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8252  *   instead.
8253  */
8254 void
8255 clutter_actor_get_geometry (ClutterActor    *self,
8256                             ClutterGeometry *geometry)
8257 {
8258   gfloat x, y, width, height;
8259
8260   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8261   g_return_if_fail (geometry != NULL);
8262
8263   clutter_actor_get_position (self, &x, &y);
8264   clutter_actor_get_size (self, &width, &height);
8265
8266   geometry->x = (int) x;
8267   geometry->y = (int) y;
8268   geometry->width = (int) width;
8269   geometry->height = (int) height;
8270 }
8271
8272 /**
8273  * clutter_actor_set_position:
8274  * @self: A #ClutterActor
8275  * @x: New left position of actor in pixels.
8276  * @y: New top position of actor in pixels.
8277  *
8278  * Sets the actor's fixed position in pixels relative to any parent
8279  * actor.
8280  *
8281  * If a layout manager is in use, this position will override the
8282  * layout manager and force a fixed position.
8283  */
8284 void
8285 clutter_actor_set_position (ClutterActor *self,
8286                             gfloat        x,
8287                             gfloat        y)
8288 {
8289   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8290
8291   g_object_freeze_notify (G_OBJECT (self));
8292
8293   clutter_actor_set_x (self, x);
8294   clutter_actor_set_y (self, y);
8295
8296   g_object_thaw_notify (G_OBJECT (self));
8297 }
8298
8299 /**
8300  * clutter_actor_get_fixed_position_set:
8301  * @self: A #ClutterActor
8302  *
8303  * Checks whether an actor has a fixed position set (and will thus be
8304  * unaffected by any layout manager).
8305  *
8306  * Return value: %TRUE if the fixed position is set on the actor
8307  *
8308  * Since: 0.8
8309  */
8310 gboolean
8311 clutter_actor_get_fixed_position_set (ClutterActor *self)
8312 {
8313   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8314
8315   return self->priv->position_set;
8316 }
8317
8318 /**
8319  * clutter_actor_set_fixed_position_set:
8320  * @self: A #ClutterActor
8321  * @is_set: whether to use fixed position
8322  *
8323  * Sets whether an actor has a fixed position set (and will thus be
8324  * unaffected by any layout manager).
8325  *
8326  * Since: 0.8
8327  */
8328 void
8329 clutter_actor_set_fixed_position_set (ClutterActor *self,
8330                                       gboolean      is_set)
8331 {
8332   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8333
8334   if (self->priv->position_set == (is_set != FALSE))
8335     return;
8336
8337   self->priv->position_set = is_set != FALSE;
8338   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8339
8340   clutter_actor_queue_relayout (self);
8341 }
8342
8343 /**
8344  * clutter_actor_move_by:
8345  * @self: A #ClutterActor
8346  * @dx: Distance to move Actor on X axis.
8347  * @dy: Distance to move Actor on Y axis.
8348  *
8349  * Moves an actor by the specified distance relative to its current
8350  * position in pixels.
8351  *
8352  * This function modifies the fixed position of an actor and thus removes
8353  * it from any layout management. Another way to move an actor is with an
8354  * anchor point, see clutter_actor_set_anchor_point().
8355  *
8356  * Since: 0.2
8357  */
8358 void
8359 clutter_actor_move_by (ClutterActor *self,
8360                        gfloat        dx,
8361                        gfloat        dy)
8362 {
8363   const ClutterLayoutInfo *info;
8364   gfloat x, y;
8365
8366   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8367
8368   info = _clutter_actor_get_layout_info_or_defaults (self);
8369   x = info->fixed_x;
8370   y = info->fixed_y;
8371
8372   clutter_actor_set_position (self, x + dx, y + dy);
8373 }
8374
8375 static void
8376 clutter_actor_set_min_width (ClutterActor *self,
8377                              gfloat        min_width)
8378 {
8379   ClutterActorPrivate *priv = self->priv;
8380   ClutterActorBox old = { 0, };
8381   ClutterLayoutInfo *info;
8382
8383   /* if we are setting the size on a top-level actor and the
8384    * backend only supports static top-levels (e.g. framebuffers)
8385    * then we ignore the passed value and we override it with
8386    * the stage implementation's preferred size.
8387    */
8388   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8389       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8390     return;
8391
8392   info = _clutter_actor_get_layout_info (self);
8393
8394   if (priv->min_width_set && min_width == info->min_width)
8395     return;
8396
8397   g_object_freeze_notify (G_OBJECT (self));
8398
8399   clutter_actor_store_old_geometry (self, &old);
8400
8401   info->min_width = min_width;
8402   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8403   clutter_actor_set_min_width_set (self, TRUE);
8404
8405   clutter_actor_notify_if_geometry_changed (self, &old);
8406
8407   g_object_thaw_notify (G_OBJECT (self));
8408
8409   clutter_actor_queue_relayout (self);
8410 }
8411
8412 static void
8413 clutter_actor_set_min_height (ClutterActor *self,
8414                               gfloat        min_height)
8415
8416 {
8417   ClutterActorPrivate *priv = self->priv;
8418   ClutterActorBox old = { 0, };
8419   ClutterLayoutInfo *info;
8420
8421   /* if we are setting the size on a top-level actor and the
8422    * backend only supports static top-levels (e.g. framebuffers)
8423    * then we ignore the passed value and we override it with
8424    * the stage implementation's preferred size.
8425    */
8426   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8427       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8428     return;
8429
8430   info = _clutter_actor_get_layout_info (self);
8431
8432   if (priv->min_height_set && min_height == info->min_height)
8433     return;
8434
8435   g_object_freeze_notify (G_OBJECT (self));
8436
8437   clutter_actor_store_old_geometry (self, &old);
8438
8439   info->min_height = min_height;
8440   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8441   clutter_actor_set_min_height_set (self, TRUE);
8442
8443   clutter_actor_notify_if_geometry_changed (self, &old);
8444
8445   g_object_thaw_notify (G_OBJECT (self));
8446
8447   clutter_actor_queue_relayout (self);
8448 }
8449
8450 static void
8451 clutter_actor_set_natural_width (ClutterActor *self,
8452                                  gfloat        natural_width)
8453 {
8454   ClutterActorPrivate *priv = self->priv;
8455   ClutterActorBox old = { 0, };
8456   ClutterLayoutInfo *info;
8457
8458   /* if we are setting the size on a top-level actor and the
8459    * backend only supports static top-levels (e.g. framebuffers)
8460    * then we ignore the passed value and we override it with
8461    * the stage implementation's preferred size.
8462    */
8463   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8464       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8465     return;
8466
8467   info = _clutter_actor_get_layout_info (self);
8468
8469   if (priv->natural_width_set && natural_width == info->natural_width)
8470     return;
8471
8472   g_object_freeze_notify (G_OBJECT (self));
8473
8474   clutter_actor_store_old_geometry (self, &old);
8475
8476   info->natural_width = natural_width;
8477   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8478   clutter_actor_set_natural_width_set (self, TRUE);
8479
8480   clutter_actor_notify_if_geometry_changed (self, &old);
8481
8482   g_object_thaw_notify (G_OBJECT (self));
8483
8484   clutter_actor_queue_relayout (self);
8485 }
8486
8487 static void
8488 clutter_actor_set_natural_height (ClutterActor *self,
8489                                   gfloat        natural_height)
8490 {
8491   ClutterActorPrivate *priv = self->priv;
8492   ClutterActorBox old = { 0, };
8493   ClutterLayoutInfo *info;
8494
8495   /* if we are setting the size on a top-level actor and the
8496    * backend only supports static top-levels (e.g. framebuffers)
8497    * then we ignore the passed value and we override it with
8498    * the stage implementation's preferred size.
8499    */
8500   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8501       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8502     return;
8503
8504   info = _clutter_actor_get_layout_info (self);
8505
8506   if (priv->natural_height_set && natural_height == info->natural_height)
8507     return;
8508
8509   g_object_freeze_notify (G_OBJECT (self));
8510
8511   clutter_actor_store_old_geometry (self, &old);
8512
8513   info->natural_height = natural_height;
8514   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8515   clutter_actor_set_natural_height_set (self, TRUE);
8516
8517   clutter_actor_notify_if_geometry_changed (self, &old);
8518
8519   g_object_thaw_notify (G_OBJECT (self));
8520
8521   clutter_actor_queue_relayout (self);
8522 }
8523
8524 static void
8525 clutter_actor_set_min_width_set (ClutterActor *self,
8526                                  gboolean      use_min_width)
8527 {
8528   ClutterActorPrivate *priv = self->priv;
8529   ClutterActorBox old = { 0, };
8530
8531   if (priv->min_width_set == (use_min_width != FALSE))
8532     return;
8533
8534   clutter_actor_store_old_geometry (self, &old);
8535
8536   priv->min_width_set = use_min_width != FALSE;
8537   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8538
8539   clutter_actor_notify_if_geometry_changed (self, &old);
8540
8541   clutter_actor_queue_relayout (self);
8542 }
8543
8544 static void
8545 clutter_actor_set_min_height_set (ClutterActor *self,
8546                                   gboolean      use_min_height)
8547 {
8548   ClutterActorPrivate *priv = self->priv;
8549   ClutterActorBox old = { 0, };
8550
8551   if (priv->min_height_set == (use_min_height != FALSE))
8552     return;
8553
8554   clutter_actor_store_old_geometry (self, &old);
8555
8556   priv->min_height_set = use_min_height != FALSE;
8557   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8558
8559   clutter_actor_notify_if_geometry_changed (self, &old);
8560
8561   clutter_actor_queue_relayout (self);
8562 }
8563
8564 static void
8565 clutter_actor_set_natural_width_set (ClutterActor *self,
8566                                      gboolean      use_natural_width)
8567 {
8568   ClutterActorPrivate *priv = self->priv;
8569   ClutterActorBox old = { 0, };
8570
8571   if (priv->natural_width_set == (use_natural_width != FALSE))
8572     return;
8573
8574   clutter_actor_store_old_geometry (self, &old);
8575
8576   priv->natural_width_set = use_natural_width != FALSE;
8577   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8578
8579   clutter_actor_notify_if_geometry_changed (self, &old);
8580
8581   clutter_actor_queue_relayout (self);
8582 }
8583
8584 static void
8585 clutter_actor_set_natural_height_set (ClutterActor *self,
8586                                       gboolean      use_natural_height)
8587 {
8588   ClutterActorPrivate *priv = self->priv;
8589   ClutterActorBox old = { 0, };
8590
8591   if (priv->natural_height_set == (use_natural_height != FALSE))
8592     return;
8593
8594   clutter_actor_store_old_geometry (self, &old);
8595
8596   priv->natural_height_set = use_natural_height != FALSE;
8597   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8598
8599   clutter_actor_notify_if_geometry_changed (self, &old);
8600
8601   clutter_actor_queue_relayout (self);
8602 }
8603
8604 /**
8605  * clutter_actor_set_request_mode:
8606  * @self: a #ClutterActor
8607  * @mode: the request mode
8608  *
8609  * Sets the geometry request mode of @self.
8610  *
8611  * The @mode determines the order for invoking
8612  * clutter_actor_get_preferred_width() and
8613  * clutter_actor_get_preferred_height()
8614  *
8615  * Since: 1.2
8616  */
8617 void
8618 clutter_actor_set_request_mode (ClutterActor       *self,
8619                                 ClutterRequestMode  mode)
8620 {
8621   ClutterActorPrivate *priv;
8622
8623   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8624
8625   priv = self->priv;
8626
8627   if (priv->request_mode == mode)
8628     return;
8629
8630   priv->request_mode = mode;
8631
8632   priv->needs_width_request = TRUE;
8633   priv->needs_height_request = TRUE;
8634
8635   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8636
8637   clutter_actor_queue_relayout (self);
8638 }
8639
8640 /**
8641  * clutter_actor_get_request_mode:
8642  * @self: a #ClutterActor
8643  *
8644  * Retrieves the geometry request mode of @self
8645  *
8646  * Return value: the request mode for the actor
8647  *
8648  * Since: 1.2
8649  */
8650 ClutterRequestMode
8651 clutter_actor_get_request_mode (ClutterActor *self)
8652 {
8653   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8654                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8655
8656   return self->priv->request_mode;
8657 }
8658
8659 /* variant of set_width() without checks and without notification
8660  * freeze+thaw, for internal usage only
8661  */
8662 static inline void
8663 clutter_actor_set_width_internal (ClutterActor *self,
8664                                   gfloat        width)
8665 {
8666   if (width >= 0)
8667     {
8668       /* the Stage will use the :min-width to control the minimum
8669        * width to be resized to, so we should not be setting it
8670        * along with the :natural-width
8671        */
8672       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8673         clutter_actor_set_min_width (self, width);
8674
8675       clutter_actor_set_natural_width (self, width);
8676     }
8677   else
8678     {
8679       /* we only unset the :natural-width for the Stage */
8680       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8681         clutter_actor_set_min_width_set (self, FALSE);
8682
8683       clutter_actor_set_natural_width_set (self, FALSE);
8684     }
8685 }
8686
8687 /* variant of set_height() without checks and without notification
8688  * freeze+thaw, for internal usage only
8689  */
8690 static inline void
8691 clutter_actor_set_height_internal (ClutterActor *self,
8692                                    gfloat        height)
8693 {
8694   if (height >= 0)
8695     {
8696       /* see the comment above in set_width_internal() */
8697       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8698         clutter_actor_set_min_height (self, height);
8699
8700       clutter_actor_set_natural_height (self, height);
8701     }
8702   else
8703     {
8704       /* see the comment above in set_width_internal() */
8705       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8706         clutter_actor_set_min_height_set (self, FALSE);
8707
8708       clutter_actor_set_natural_height_set (self, FALSE);
8709     }
8710 }
8711
8712 /**
8713  * clutter_actor_set_size:
8714  * @self: A #ClutterActor
8715  * @width: New width of actor in pixels, or -1
8716  * @height: New height of actor in pixels, or -1
8717  *
8718  * Sets the actor's size request in pixels. This overrides any
8719  * "normal" size request the actor would have. For example
8720  * a text actor might normally request the size of the text;
8721  * this function would force a specific size instead.
8722  *
8723  * If @width and/or @height are -1 the actor will use its
8724  * "normal" size request instead of overriding it, i.e.
8725  * you can "unset" the size with -1.
8726  *
8727  * This function sets or unsets both the minimum and natural size.
8728  */
8729 void
8730 clutter_actor_set_size (ClutterActor *self,
8731                         gfloat        width,
8732                         gfloat        height)
8733 {
8734   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8735
8736   g_object_freeze_notify (G_OBJECT (self));
8737
8738   clutter_actor_set_width (self, width);
8739   clutter_actor_set_height (self, height);
8740
8741   g_object_thaw_notify (G_OBJECT (self));
8742 }
8743
8744 /**
8745  * clutter_actor_get_size:
8746  * @self: A #ClutterActor
8747  * @width: (out) (allow-none): return location for the width, or %NULL.
8748  * @height: (out) (allow-none): return location for the height, or %NULL.
8749  *
8750  * This function tries to "do what you mean" and return
8751  * the size an actor will have. If the actor has a valid
8752  * allocation, the allocation will be returned; otherwise,
8753  * the actors natural size request will be returned.
8754  *
8755  * If you care whether you get the request vs. the allocation, you
8756  * should probably call a different function like
8757  * clutter_actor_get_allocation_box() or
8758  * clutter_actor_get_preferred_width().
8759  *
8760  * Since: 0.2
8761  */
8762 void
8763 clutter_actor_get_size (ClutterActor *self,
8764                         gfloat       *width,
8765                         gfloat       *height)
8766 {
8767   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8768
8769   if (width)
8770     *width = clutter_actor_get_width (self);
8771
8772   if (height)
8773     *height = clutter_actor_get_height (self);
8774 }
8775
8776 /**
8777  * clutter_actor_get_position:
8778  * @self: a #ClutterActor
8779  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8780  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8781  *
8782  * This function tries to "do what you mean" and tell you where the
8783  * actor is, prior to any transformations. Retrieves the fixed
8784  * position of an actor in pixels, if one has been set; otherwise, if
8785  * the allocation is valid, returns the actor's allocated position;
8786  * otherwise, returns 0,0.
8787  *
8788  * The returned position is in pixels.
8789  *
8790  * Since: 0.6
8791  */
8792 void
8793 clutter_actor_get_position (ClutterActor *self,
8794                             gfloat       *x,
8795                             gfloat       *y)
8796 {
8797   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8798
8799   if (x)
8800     *x = clutter_actor_get_x (self);
8801
8802   if (y)
8803     *y = clutter_actor_get_y (self);
8804 }
8805
8806 /**
8807  * clutter_actor_get_transformed_position:
8808  * @self: A #ClutterActor
8809  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8810  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8811  *
8812  * Gets the absolute position of an actor, in pixels relative to the stage.
8813  *
8814  * Since: 0.8
8815  */
8816 void
8817 clutter_actor_get_transformed_position (ClutterActor *self,
8818                                         gfloat       *x,
8819                                         gfloat       *y)
8820 {
8821   ClutterVertex v1;
8822   ClutterVertex v2;
8823
8824   v1.x = v1.y = v1.z = 0;
8825   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8826
8827   if (x)
8828     *x = v2.x;
8829
8830   if (y)
8831     *y = v2.y;
8832 }
8833
8834 /**
8835  * clutter_actor_get_transformed_size:
8836  * @self: A #ClutterActor
8837  * @width: (out) (allow-none): return location for the width, or %NULL
8838  * @height: (out) (allow-none): return location for the height, or %NULL
8839  *
8840  * Gets the absolute size of an actor in pixels, taking into account the
8841  * scaling factors.
8842  *
8843  * If the actor has a valid allocation, the allocated size will be used.
8844  * If the actor has not a valid allocation then the preferred size will
8845  * be transformed and returned.
8846  *
8847  * If you want the transformed allocation, see
8848  * clutter_actor_get_abs_allocation_vertices() instead.
8849  *
8850  * <note>When the actor (or one of its ancestors) is rotated around the
8851  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8852  * as a generic quadrangle; in that case this function returns the size
8853  * of the smallest rectangle that encapsulates the entire quad. Please
8854  * note that in this case no assumptions can be made about the relative
8855  * position of this envelope to the absolute position of the actor, as
8856  * returned by clutter_actor_get_transformed_position(); if you need this
8857  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8858  * to get the coords of the actual quadrangle.</note>
8859  *
8860  * Since: 0.8
8861  */
8862 void
8863 clutter_actor_get_transformed_size (ClutterActor *self,
8864                                     gfloat       *width,
8865                                     gfloat       *height)
8866 {
8867   ClutterActorPrivate *priv;
8868   ClutterVertex v[4];
8869   gfloat x_min, x_max, y_min, y_max;
8870   gint i;
8871
8872   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8873
8874   priv = self->priv;
8875
8876   /* if the actor hasn't been allocated yet, get the preferred
8877    * size and transform that
8878    */
8879   if (priv->needs_allocation)
8880     {
8881       gfloat natural_width, natural_height;
8882       ClutterActorBox box;
8883
8884       /* Make a fake allocation to transform.
8885        *
8886        * NB: _clutter_actor_transform_and_project_box expects a box in
8887        * the actor's coordinate space... */
8888
8889       box.x1 = 0;
8890       box.y1 = 0;
8891
8892       natural_width = natural_height = 0;
8893       clutter_actor_get_preferred_size (self, NULL, NULL,
8894                                         &natural_width,
8895                                         &natural_height);
8896
8897       box.x2 = natural_width;
8898       box.y2 = natural_height;
8899
8900       _clutter_actor_transform_and_project_box (self, &box, v);
8901     }
8902   else
8903     clutter_actor_get_abs_allocation_vertices (self, v);
8904
8905   x_min = x_max = v[0].x;
8906   y_min = y_max = v[0].y;
8907
8908   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8909     {
8910       if (v[i].x < x_min)
8911         x_min = v[i].x;
8912
8913       if (v[i].x > x_max)
8914         x_max = v[i].x;
8915
8916       if (v[i].y < y_min)
8917         y_min = v[i].y;
8918
8919       if (v[i].y > y_max)
8920         y_max = v[i].y;
8921     }
8922
8923   if (width)
8924     *width  = x_max - x_min;
8925
8926   if (height)
8927     *height = y_max - y_min;
8928 }
8929
8930 /**
8931  * clutter_actor_get_width:
8932  * @self: A #ClutterActor
8933  *
8934  * Retrieves the width of a #ClutterActor.
8935  *
8936  * If the actor has a valid allocation, this function will return the
8937  * width of the allocated area given to the actor.
8938  *
8939  * If the actor does not have a valid allocation, this function will
8940  * return the actor's natural width, that is the preferred width of
8941  * the actor.
8942  *
8943  * If you care whether you get the preferred width or the width that
8944  * has been assigned to the actor, you should probably call a different
8945  * function like clutter_actor_get_allocation_box() to retrieve the
8946  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8947  * preferred width.
8948  *
8949  * If an actor has a fixed width, for instance a width that has been
8950  * assigned using clutter_actor_set_width(), the width returned will
8951  * be the same value.
8952  *
8953  * Return value: the width of the actor, in pixels
8954  */
8955 gfloat
8956 clutter_actor_get_width (ClutterActor *self)
8957 {
8958   ClutterActorPrivate *priv;
8959
8960   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8961
8962   priv = self->priv;
8963
8964   if (priv->needs_allocation)
8965     {
8966       gfloat natural_width = 0;
8967
8968       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8969         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8970       else
8971         {
8972           gfloat natural_height = 0;
8973
8974           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8975           clutter_actor_get_preferred_width (self, natural_height,
8976                                              NULL,
8977                                              &natural_width);
8978         }
8979
8980       return natural_width;
8981     }
8982   else
8983     return priv->allocation.x2 - priv->allocation.x1;
8984 }
8985
8986 /**
8987  * clutter_actor_get_height:
8988  * @self: A #ClutterActor
8989  *
8990  * Retrieves the height of a #ClutterActor.
8991  *
8992  * If the actor has a valid allocation, this function will return the
8993  * height of the allocated area given to the actor.
8994  *
8995  * If the actor does not have a valid allocation, this function will
8996  * return the actor's natural height, that is the preferred height of
8997  * the actor.
8998  *
8999  * If you care whether you get the preferred height or the height that
9000  * has been assigned to the actor, you should probably call a different
9001  * function like clutter_actor_get_allocation_box() to retrieve the
9002  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9003  * preferred height.
9004  *
9005  * If an actor has a fixed height, for instance a height that has been
9006  * assigned using clutter_actor_set_height(), the height returned will
9007  * be the same value.
9008  *
9009  * Return value: the height of the actor, in pixels
9010  */
9011 gfloat
9012 clutter_actor_get_height (ClutterActor *self)
9013 {
9014   ClutterActorPrivate *priv;
9015
9016   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9017
9018   priv = self->priv;
9019
9020   if (priv->needs_allocation)
9021     {
9022       gfloat natural_height = 0;
9023
9024       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9025         {
9026           gfloat natural_width = 0;
9027
9028           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9029           clutter_actor_get_preferred_height (self, natural_width,
9030                                               NULL, &natural_height);
9031         }
9032       else
9033         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9034
9035       return natural_height;
9036     }
9037   else
9038     return priv->allocation.y2 - priv->allocation.y1;
9039 }
9040
9041 /**
9042  * clutter_actor_set_width:
9043  * @self: A #ClutterActor
9044  * @width: Requested new width for the actor, in pixels, or -1
9045  *
9046  * Forces a width on an actor, causing the actor's preferred width
9047  * and height (if any) to be ignored.
9048  *
9049  * If @width is -1 the actor will use its preferred width request
9050  * instead of overriding it, i.e. you can "unset" the width with -1.
9051  *
9052  * This function sets both the minimum and natural size of the actor.
9053  *
9054  * since: 0.2
9055  */
9056 void
9057 clutter_actor_set_width (ClutterActor *self,
9058                          gfloat        width)
9059 {
9060   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9061
9062   if (clutter_actor_get_easing_duration (self) != 0)
9063     {
9064       ClutterTransition *transition;
9065
9066       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9067       if (transition == NULL)
9068         {
9069           float old_width = clutter_actor_get_width (self);
9070
9071           transition = _clutter_actor_create_transition (self,
9072                                                          obj_props[PROP_WIDTH],
9073                                                          old_width,
9074                                                          width);
9075           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9076         }
9077       else
9078         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9079
9080       clutter_actor_queue_relayout (self);
9081     }
9082   else
9083     {
9084       g_object_freeze_notify (G_OBJECT (self));
9085
9086       clutter_actor_set_width_internal (self, width);
9087
9088       g_object_thaw_notify (G_OBJECT (self));
9089     }
9090 }
9091
9092 /**
9093  * clutter_actor_set_height:
9094  * @self: A #ClutterActor
9095  * @height: Requested new height for the actor, in pixels, or -1
9096  *
9097  * Forces a height on an actor, causing the actor's preferred width
9098  * and height (if any) to be ignored.
9099  *
9100  * If @height is -1 the actor will use its preferred height instead of
9101  * overriding it, i.e. you can "unset" the height with -1.
9102  *
9103  * This function sets both the minimum and natural size of the actor.
9104  *
9105  * since: 0.2
9106  */
9107 void
9108 clutter_actor_set_height (ClutterActor *self,
9109                           gfloat        height)
9110 {
9111   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9112
9113   if (clutter_actor_get_easing_duration (self) != 0)
9114     {
9115       ClutterTransition *transition;
9116
9117       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9118       if (transition ==  NULL)
9119         {
9120           float old_height = clutter_actor_get_height (self);
9121
9122           transition = _clutter_actor_create_transition (self,
9123                                                          obj_props[PROP_HEIGHT],
9124                                                          old_height,
9125                                                          height);
9126           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9127         }
9128       else
9129         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9130
9131       clutter_actor_queue_relayout (self);
9132     }
9133   else
9134     {
9135       g_object_freeze_notify (G_OBJECT (self));
9136
9137       clutter_actor_set_height_internal (self, height);
9138
9139       g_object_thaw_notify (G_OBJECT (self));
9140     }
9141 }
9142
9143 static inline void
9144 clutter_actor_set_x_internal (ClutterActor *self,
9145                               float         x)
9146 {
9147   ClutterActorPrivate *priv = self->priv;
9148   ClutterLayoutInfo *linfo;
9149   ClutterActorBox old = { 0, };
9150
9151   linfo = _clutter_actor_get_layout_info (self);
9152
9153   if (priv->position_set && linfo->fixed_x == x)
9154     return;
9155
9156   clutter_actor_store_old_geometry (self, &old);
9157
9158   linfo->fixed_x = x;
9159   clutter_actor_set_fixed_position_set (self, TRUE);
9160
9161   clutter_actor_notify_if_geometry_changed (self, &old);
9162
9163   clutter_actor_queue_relayout (self);
9164 }
9165
9166 static inline void
9167 clutter_actor_set_y_internal (ClutterActor *self,
9168                               float         y)
9169 {
9170   ClutterActorPrivate *priv = self->priv;
9171   ClutterLayoutInfo *linfo;
9172   ClutterActorBox old = { 0, };
9173
9174   linfo = _clutter_actor_get_layout_info (self);
9175
9176   if (priv->position_set && linfo->fixed_y == y)
9177     return;
9178
9179   clutter_actor_store_old_geometry (self, &old);
9180
9181   linfo->fixed_y = y;
9182   clutter_actor_set_fixed_position_set (self, TRUE);
9183
9184   clutter_actor_notify_if_geometry_changed (self, &old);
9185 }
9186
9187 /**
9188  * clutter_actor_set_x:
9189  * @self: a #ClutterActor
9190  * @x: the actor's position on the X axis
9191  *
9192  * Sets the actor's X coordinate, relative to its parent, in pixels.
9193  *
9194  * Overrides any layout manager and forces a fixed position for
9195  * the actor.
9196  *
9197  * The #ClutterActor:x property is animatable.
9198  *
9199  * Since: 0.6
9200  */
9201 void
9202 clutter_actor_set_x (ClutterActor *self,
9203                      gfloat        x)
9204 {
9205   const ClutterLayoutInfo *linfo;
9206
9207   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9208
9209   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9210
9211   if (clutter_actor_get_easing_duration (self) != 0)
9212     {
9213       ClutterTransition *transition;
9214
9215       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9216       if (transition == NULL)
9217         {
9218           transition = _clutter_actor_create_transition (self,
9219                                                          obj_props[PROP_X],
9220                                                          linfo->fixed_x,
9221                                                          x);
9222
9223           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9224         }
9225       else
9226         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9227
9228       clutter_actor_queue_relayout (self);
9229     }
9230   else
9231     clutter_actor_set_x_internal (self, x);
9232 }
9233
9234 /**
9235  * clutter_actor_set_y:
9236  * @self: a #ClutterActor
9237  * @y: the actor's position on the Y axis
9238  *
9239  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9240  *
9241  * Overrides any layout manager and forces a fixed position for
9242  * the actor.
9243  *
9244  * The #ClutterActor:y property is animatable.
9245  *
9246  * Since: 0.6
9247  */
9248 void
9249 clutter_actor_set_y (ClutterActor *self,
9250                      gfloat        y)
9251 {
9252   const ClutterLayoutInfo *linfo;
9253
9254   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9255
9256   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9257
9258   if (clutter_actor_get_easing_duration (self) != 0)
9259     {
9260       ClutterTransition *transition;
9261
9262       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9263       if (transition == NULL)
9264         {
9265           transition = _clutter_actor_create_transition (self,
9266                                                          obj_props[PROP_Y],
9267                                                          linfo->fixed_y,
9268                                                          y);
9269
9270           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9271         }
9272       else
9273         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9274
9275       clutter_actor_queue_relayout (self);
9276     }
9277   else
9278     clutter_actor_set_y_internal (self, y);
9279
9280   clutter_actor_queue_relayout (self);
9281 }
9282
9283 /**
9284  * clutter_actor_get_x:
9285  * @self: A #ClutterActor
9286  *
9287  * Retrieves the X coordinate of a #ClutterActor.
9288  *
9289  * This function tries to "do what you mean", by returning the
9290  * correct value depending on the actor's state.
9291  *
9292  * If the actor has a valid allocation, this function will return
9293  * the X coordinate of the origin of the allocation box.
9294  *
9295  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9296  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9297  * function will return that coordinate.
9298  *
9299  * If both the allocation and a fixed position are missing, this function
9300  * will return 0.
9301  *
9302  * Return value: the X coordinate, in pixels, ignoring any
9303  *   transformation (i.e. scaling, rotation)
9304  */
9305 gfloat
9306 clutter_actor_get_x (ClutterActor *self)
9307 {
9308   ClutterActorPrivate *priv;
9309
9310   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9311
9312   priv = self->priv;
9313
9314   if (priv->needs_allocation)
9315     {
9316       if (priv->position_set)
9317         {
9318           const ClutterLayoutInfo *info;
9319
9320           info = _clutter_actor_get_layout_info_or_defaults (self);
9321
9322           return info->fixed_x;
9323         }
9324       else
9325         return 0;
9326     }
9327   else
9328     return priv->allocation.x1;
9329 }
9330
9331 /**
9332  * clutter_actor_get_y:
9333  * @self: A #ClutterActor
9334  *
9335  * Retrieves the Y coordinate of a #ClutterActor.
9336  *
9337  * This function tries to "do what you mean", by returning the
9338  * correct value depending on the actor's state.
9339  *
9340  * If the actor has a valid allocation, this function will return
9341  * the Y coordinate of the origin of the allocation box.
9342  *
9343  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9344  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9345  * function will return that coordinate.
9346  *
9347  * If both the allocation and a fixed position are missing, this function
9348  * will return 0.
9349  *
9350  * Return value: the Y coordinate, in pixels, ignoring any
9351  *   transformation (i.e. scaling, rotation)
9352  */
9353 gfloat
9354 clutter_actor_get_y (ClutterActor *self)
9355 {
9356   ClutterActorPrivate *priv;
9357
9358   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9359
9360   priv = self->priv;
9361
9362   if (priv->needs_allocation)
9363     {
9364       if (priv->position_set)
9365         {
9366           const ClutterLayoutInfo *info;
9367
9368           info = _clutter_actor_get_layout_info_or_defaults (self);
9369
9370           return info->fixed_y;
9371         }
9372       else
9373         return 0;
9374     }
9375   else
9376     return priv->allocation.y1;
9377 }
9378
9379 /**
9380  * clutter_actor_set_scale:
9381  * @self: A #ClutterActor
9382  * @scale_x: double factor to scale actor by horizontally.
9383  * @scale_y: double factor to scale actor by vertically.
9384  *
9385  * Scales an actor with the given factors. The scaling is relative to
9386  * the scale center and the anchor point. The scale center is
9387  * unchanged by this function and defaults to 0,0.
9388  *
9389  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9390  * animatable.
9391  *
9392  * Since: 0.2
9393  */
9394 void
9395 clutter_actor_set_scale (ClutterActor *self,
9396                          gdouble       scale_x,
9397                          gdouble       scale_y)
9398 {
9399   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9400
9401   g_object_freeze_notify (G_OBJECT (self));
9402
9403   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9404   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9405
9406   g_object_thaw_notify (G_OBJECT (self));
9407 }
9408
9409 /**
9410  * clutter_actor_set_scale_full:
9411  * @self: A #ClutterActor
9412  * @scale_x: double factor to scale actor by horizontally.
9413  * @scale_y: double factor to scale actor by vertically.
9414  * @center_x: X coordinate of the center of the scale.
9415  * @center_y: Y coordinate of the center of the scale
9416  *
9417  * Scales an actor with the given factors around the given center
9418  * point. The center point is specified in pixels relative to the
9419  * anchor point (usually the top left corner of the actor).
9420  *
9421  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9422  * are animatable.
9423  *
9424  * Since: 1.0
9425  */
9426 void
9427 clutter_actor_set_scale_full (ClutterActor *self,
9428                               gdouble       scale_x,
9429                               gdouble       scale_y,
9430                               gfloat        center_x,
9431                               gfloat        center_y)
9432 {
9433   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9434
9435   g_object_freeze_notify (G_OBJECT (self));
9436
9437   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9438   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9439   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9440   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9441
9442   g_object_thaw_notify (G_OBJECT (self));
9443 }
9444
9445 /**
9446  * clutter_actor_set_scale_with_gravity:
9447  * @self: A #ClutterActor
9448  * @scale_x: double factor to scale actor by horizontally.
9449  * @scale_y: double factor to scale actor by vertically.
9450  * @gravity: the location of the scale center expressed as a compass
9451  * direction.
9452  *
9453  * Scales an actor with the given factors around the given
9454  * center point. The center point is specified as one of the compass
9455  * directions in #ClutterGravity. For example, setting it to north
9456  * will cause the top of the actor to remain unchanged and the rest of
9457  * the actor to expand left, right and downwards.
9458  *
9459  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9460  * animatable.
9461  *
9462  * Since: 1.0
9463  */
9464 void
9465 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9466                                       gdouble         scale_x,
9467                                       gdouble         scale_y,
9468                                       ClutterGravity  gravity)
9469 {
9470   ClutterTransformInfo *info;
9471   GObject *obj;
9472
9473   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9474
9475   obj = G_OBJECT (self);
9476
9477   g_object_freeze_notify (obj);
9478
9479   info = _clutter_actor_get_transform_info (self);
9480   info->scale_x = scale_x;
9481   info->scale_y = scale_y;
9482
9483   if (gravity == CLUTTER_GRAVITY_NONE)
9484     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9485   else
9486     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9487
9488   self->priv->transform_valid = FALSE;
9489
9490   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9491   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9492   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9493   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9494   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9495
9496   clutter_actor_queue_redraw (self);
9497
9498   g_object_thaw_notify (obj);
9499 }
9500
9501 /**
9502  * clutter_actor_get_scale:
9503  * @self: A #ClutterActor
9504  * @scale_x: (out) (allow-none): Location to store horizonal
9505  *   scale factor, or %NULL.
9506  * @scale_y: (out) (allow-none): Location to store vertical
9507  *   scale factor, or %NULL.
9508  *
9509  * Retrieves an actors scale factors.
9510  *
9511  * Since: 0.2
9512  */
9513 void
9514 clutter_actor_get_scale (ClutterActor *self,
9515                          gdouble      *scale_x,
9516                          gdouble      *scale_y)
9517 {
9518   const ClutterTransformInfo *info;
9519
9520   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9521
9522   info = _clutter_actor_get_transform_info_or_defaults (self);
9523
9524   if (scale_x)
9525     *scale_x = info->scale_x;
9526
9527   if (scale_y)
9528     *scale_y = info->scale_y;
9529 }
9530
9531 /**
9532  * clutter_actor_get_scale_center:
9533  * @self: A #ClutterActor
9534  * @center_x: (out) (allow-none): Location to store the X position
9535  *   of the scale center, or %NULL.
9536  * @center_y: (out) (allow-none): Location to store the Y position
9537  *   of the scale center, or %NULL.
9538  *
9539  * Retrieves the scale center coordinate in pixels relative to the top
9540  * left corner of the actor. If the scale center was specified using a
9541  * #ClutterGravity this will calculate the pixel offset using the
9542  * current size of the actor.
9543  *
9544  * Since: 1.0
9545  */
9546 void
9547 clutter_actor_get_scale_center (ClutterActor *self,
9548                                 gfloat       *center_x,
9549                                 gfloat       *center_y)
9550 {
9551   const ClutterTransformInfo *info;
9552
9553   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9554
9555   info = _clutter_actor_get_transform_info_or_defaults (self);
9556
9557   clutter_anchor_coord_get_units (self, &info->scale_center,
9558                                   center_x,
9559                                   center_y,
9560                                   NULL);
9561 }
9562
9563 /**
9564  * clutter_actor_get_scale_gravity:
9565  * @self: A #ClutterActor
9566  *
9567  * Retrieves the scale center as a compass direction. If the scale
9568  * center was specified in pixels or units this will return
9569  * %CLUTTER_GRAVITY_NONE.
9570  *
9571  * Return value: the scale gravity
9572  *
9573  * Since: 1.0
9574  */
9575 ClutterGravity
9576 clutter_actor_get_scale_gravity (ClutterActor *self)
9577 {
9578   const ClutterTransformInfo *info;
9579
9580   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9581
9582   info = _clutter_actor_get_transform_info_or_defaults (self);
9583
9584   return clutter_anchor_coord_get_gravity (&info->scale_center);
9585 }
9586
9587 static inline void
9588 clutter_actor_set_opacity_internal (ClutterActor *self,
9589                                     guint8        opacity)
9590 {
9591   ClutterActorPrivate *priv = self->priv;
9592
9593   if (priv->opacity != opacity)
9594     {
9595       priv->opacity = opacity;
9596
9597       /* Queue a redraw from the flatten effect so that it can use
9598          its cached image if available instead of having to redraw the
9599          actual actor. If it doesn't end up using the FBO then the
9600          effect is still able to continue the paint anyway. If there
9601          is no flatten effect yet then this is equivalent to queueing
9602          a full redraw */
9603       _clutter_actor_queue_redraw_full (self,
9604                                         0, /* flags */
9605                                         NULL, /* clip */
9606                                         priv->flatten_effect);
9607
9608       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9609     }
9610 }
9611
9612 /**
9613  * clutter_actor_set_opacity:
9614  * @self: A #ClutterActor
9615  * @opacity: New opacity value for the actor.
9616  *
9617  * Sets the actor's opacity, with zero being completely transparent and
9618  * 255 (0xff) being fully opaque.
9619  *
9620  * The #ClutterActor:opacity property is animatable.
9621  */
9622 void
9623 clutter_actor_set_opacity (ClutterActor *self,
9624                            guint8        opacity)
9625 {
9626   ClutterActorPrivate *priv;
9627
9628   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9629
9630   priv = self->priv;
9631
9632   if (clutter_actor_get_easing_duration (self) != 0)
9633     {
9634       ClutterTransition *transition;
9635
9636       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9637       if (transition == NULL)
9638         {
9639           transition = _clutter_actor_create_transition (self,
9640                                                          obj_props[PROP_OPACITY],
9641                                                          priv->opacity,
9642                                                          opacity);
9643           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9644         }
9645       else
9646         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9647
9648       clutter_actor_queue_redraw (self);
9649     }
9650   else
9651     clutter_actor_set_opacity_internal (self, opacity);
9652 }
9653
9654 /*
9655  * clutter_actor_get_paint_opacity_internal:
9656  * @self: a #ClutterActor
9657  *
9658  * Retrieves the absolute opacity of the actor, as it appears on the stage
9659  *
9660  * This function does not do type checks
9661  *
9662  * Return value: the absolute opacity of the actor
9663  */
9664 static guint8
9665 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9666 {
9667   ClutterActorPrivate *priv = self->priv;
9668   ClutterActor *parent;
9669
9670   /* override the top-level opacity to always be 255; even in
9671    * case of ClutterStage:use-alpha being TRUE we want the rest
9672    * of the scene to be painted
9673    */
9674   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9675     return 255;
9676
9677   if (priv->opacity_override >= 0)
9678     return priv->opacity_override;
9679
9680   parent = priv->parent;
9681
9682   /* Factor in the actual actors opacity with parents */
9683   if (parent != NULL)
9684     {
9685       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9686
9687       if (opacity != 0xff)
9688         return (opacity * priv->opacity) / 0xff;
9689     }
9690
9691   return priv->opacity;
9692
9693 }
9694
9695 /**
9696  * clutter_actor_get_paint_opacity:
9697  * @self: A #ClutterActor
9698  *
9699  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9700  *
9701  * This function traverses the hierarchy chain and composites the opacity of
9702  * the actor with that of its parents.
9703  *
9704  * This function is intended for subclasses to use in the paint virtual
9705  * function, to paint themselves with the correct opacity.
9706  *
9707  * Return value: The actor opacity value.
9708  *
9709  * Since: 0.8
9710  */
9711 guint8
9712 clutter_actor_get_paint_opacity (ClutterActor *self)
9713 {
9714   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9715
9716   return clutter_actor_get_paint_opacity_internal (self);
9717 }
9718
9719 /**
9720  * clutter_actor_get_opacity:
9721  * @self: a #ClutterActor
9722  *
9723  * Retrieves the opacity value of an actor, as set by
9724  * clutter_actor_set_opacity().
9725  *
9726  * For retrieving the absolute opacity of the actor inside a paint
9727  * virtual function, see clutter_actor_get_paint_opacity().
9728  *
9729  * Return value: the opacity of the actor
9730  */
9731 guint8
9732 clutter_actor_get_opacity (ClutterActor *self)
9733 {
9734   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9735
9736   return self->priv->opacity;
9737 }
9738
9739 /**
9740  * clutter_actor_set_offscreen_redirect:
9741  * @self: A #ClutterActor
9742  * @redirect: New offscreen redirect flags for the actor.
9743  *
9744  * Defines the circumstances where the actor should be redirected into
9745  * an offscreen image. The offscreen image is used to flatten the
9746  * actor into a single image while painting for two main reasons.
9747  * Firstly, when the actor is painted a second time without any of its
9748  * contents changing it can simply repaint the cached image without
9749  * descending further down the actor hierarchy. Secondly, it will make
9750  * the opacity look correct even if there are overlapping primitives
9751  * in the actor.
9752  *
9753  * Caching the actor could in some cases be a performance win and in
9754  * some cases be a performance lose so it is important to determine
9755  * which value is right for an actor before modifying this value. For
9756  * example, there is never any reason to flatten an actor that is just
9757  * a single texture (such as a #ClutterTexture) because it is
9758  * effectively already cached in an image so the offscreen would be
9759  * redundant. Also if the actor contains primitives that are far apart
9760  * with a large transparent area in the middle (such as a large
9761  * CluterGroup with a small actor in the top left and a small actor in
9762  * the bottom right) then the cached image will contain the entire
9763  * image of the large area and the paint will waste time blending all
9764  * of the transparent pixels in the middle.
9765  *
9766  * The default method of implementing opacity on a container simply
9767  * forwards on the opacity to all of the children. If the children are
9768  * overlapping then it will appear as if they are two separate glassy
9769  * objects and there will be a break in the color where they
9770  * overlap. By redirecting to an offscreen buffer it will be as if the
9771  * two opaque objects are combined into one and then made transparent
9772  * which is usually what is expected.
9773  *
9774  * The image below demonstrates the difference between redirecting and
9775  * not. The image shows two Clutter groups, each containing a red and
9776  * a green rectangle which overlap. The opacity on the group is set to
9777  * 128 (which is 50%). When the offscreen redirect is not used, the
9778  * red rectangle can be seen through the blue rectangle as if the two
9779  * rectangles were separately transparent. When the redirect is used
9780  * the group as a whole is transparent instead so the red rectangle is
9781  * not visible where they overlap.
9782  *
9783  * <figure id="offscreen-redirect">
9784  *   <title>Sample of using an offscreen redirect for transparency</title>
9785  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9786  * </figure>
9787  *
9788  * The default value for this property is 0, so we effectively will
9789  * never redirect an actor offscreen by default. This means that there
9790  * are times that transparent actors may look glassy as described
9791  * above. The reason this is the default is because there is a
9792  * performance trade off between quality and performance here. In many
9793  * cases the default form of glassy opacity looks good enough, but if
9794  * it's not you will need to set the
9795  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9796  * redirection for opacity.
9797  *
9798  * Custom actors that don't contain any overlapping primitives are
9799  * recommended to override the has_overlaps() virtual to return %FALSE
9800  * for maximum efficiency.
9801  *
9802  * Since: 1.8
9803  */
9804 void
9805 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9806                                       ClutterOffscreenRedirect redirect)
9807 {
9808   ClutterActorPrivate *priv;
9809
9810   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9811
9812   priv = self->priv;
9813
9814   if (priv->offscreen_redirect != redirect)
9815     {
9816       priv->offscreen_redirect = redirect;
9817
9818       /* Queue a redraw from the effect so that it can use its cached
9819          image if available instead of having to redraw the actual
9820          actor. If it doesn't end up using the FBO then the effect is
9821          still able to continue the paint anyway. If there is no
9822          effect then this is equivalent to queuing a full redraw */
9823       _clutter_actor_queue_redraw_full (self,
9824                                         0, /* flags */
9825                                         NULL, /* clip */
9826                                         priv->flatten_effect);
9827
9828       g_object_notify_by_pspec (G_OBJECT (self),
9829                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9830     }
9831 }
9832
9833 /**
9834  * clutter_actor_get_offscreen_redirect:
9835  * @self: a #ClutterActor
9836  *
9837  * Retrieves whether to redirect the actor to an offscreen buffer, as
9838  * set by clutter_actor_set_offscreen_redirect().
9839  *
9840  * Return value: the value of the offscreen-redirect property of the actor
9841  *
9842  * Since: 1.8
9843  */
9844 ClutterOffscreenRedirect
9845 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9846 {
9847   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9848
9849   return self->priv->offscreen_redirect;
9850 }
9851
9852 /**
9853  * clutter_actor_set_name:
9854  * @self: A #ClutterActor
9855  * @name: Textual tag to apply to actor
9856  *
9857  * Sets the given name to @self. The name can be used to identify
9858  * a #ClutterActor.
9859  */
9860 void
9861 clutter_actor_set_name (ClutterActor *self,
9862                         const gchar  *name)
9863 {
9864   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9865
9866   g_free (self->priv->name);
9867   self->priv->name = g_strdup (name);
9868
9869   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9870 }
9871
9872 /**
9873  * clutter_actor_get_name:
9874  * @self: A #ClutterActor
9875  *
9876  * Retrieves the name of @self.
9877  *
9878  * Return value: the name of the actor, or %NULL. The returned string is
9879  *   owned by the actor and should not be modified or freed.
9880  */
9881 const gchar *
9882 clutter_actor_get_name (ClutterActor *self)
9883 {
9884   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9885
9886   return self->priv->name;
9887 }
9888
9889 /**
9890  * clutter_actor_get_gid:
9891  * @self: A #ClutterActor
9892  *
9893  * Retrieves the unique id for @self.
9894  *
9895  * Return value: Globally unique value for this object instance.
9896  *
9897  * Since: 0.6
9898  *
9899  * Deprecated: 1.8: The id is not used any longer.
9900  */
9901 guint32
9902 clutter_actor_get_gid (ClutterActor *self)
9903 {
9904   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9905
9906   return self->priv->id;
9907 }
9908
9909 static inline void
9910 clutter_actor_set_depth_internal (ClutterActor *self,
9911                                   float         depth)
9912 {
9913   ClutterTransformInfo *info;
9914
9915   info = _clutter_actor_get_transform_info (self);
9916
9917   if (info->depth != depth)
9918     {
9919       /* Sets Z value - XXX 2.0: should we invert? */
9920       info->depth = depth;
9921
9922       self->priv->transform_valid = FALSE;
9923
9924       /* FIXME - remove this crap; sadly, there are still containers
9925        * in Clutter that depend on this utter brain damage
9926        */
9927       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9928
9929       clutter_actor_queue_redraw (self);
9930
9931       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9932     }
9933 }
9934
9935 /**
9936  * clutter_actor_set_depth:
9937  * @self: a #ClutterActor
9938  * @depth: Z co-ord
9939  *
9940  * Sets the Z coordinate of @self to @depth.
9941  *
9942  * The unit used by @depth is dependant on the perspective setup. See
9943  * also clutter_stage_set_perspective().
9944  */
9945 void
9946 clutter_actor_set_depth (ClutterActor *self,
9947                          gfloat        depth)
9948 {
9949   const ClutterTransformInfo *tinfo;
9950
9951   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9952
9953   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
9954
9955   if (clutter_actor_get_easing_duration (self) != 0)
9956     {
9957       ClutterTransition *transition;
9958
9959       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
9960       if (transition == NULL)
9961         {
9962           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
9963                                                          tinfo->depth,
9964                                                          depth);
9965           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9966         }
9967       else
9968         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
9969
9970       clutter_actor_queue_redraw (self);
9971     }
9972   else
9973     clutter_actor_set_depth_internal (self, depth);
9974 }
9975
9976 /**
9977  * clutter_actor_get_depth:
9978  * @self: a #ClutterActor
9979  *
9980  * Retrieves the depth of @self.
9981  *
9982  * Return value: the depth of the actor
9983  */
9984 gfloat
9985 clutter_actor_get_depth (ClutterActor *self)
9986 {
9987   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9988
9989   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
9990 }
9991
9992 /**
9993  * clutter_actor_set_rotation:
9994  * @self: a #ClutterActor
9995  * @axis: the axis of rotation
9996  * @angle: the angle of rotation
9997  * @x: X coordinate of the rotation center
9998  * @y: Y coordinate of the rotation center
9999  * @z: Z coordinate of the rotation center
10000  *
10001  * Sets the rotation angle of @self around the given axis.
10002  *
10003  * The rotation center coordinates used depend on the value of @axis:
10004  * <itemizedlist>
10005  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10006  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10007  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10008  * </itemizedlist>
10009  *
10010  * The rotation coordinates are relative to the anchor point of the
10011  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10012  * point is set, the upper left corner is assumed as the origin.
10013  *
10014  * Since: 0.8
10015  */
10016 void
10017 clutter_actor_set_rotation (ClutterActor      *self,
10018                             ClutterRotateAxis  axis,
10019                             gdouble            angle,
10020                             gfloat             x,
10021                             gfloat             y,
10022                             gfloat             z)
10023 {
10024   ClutterVertex v;
10025
10026   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10027
10028   v.x = x;
10029   v.y = y;
10030   v.z = z;
10031
10032   g_object_freeze_notify (G_OBJECT (self));
10033
10034   clutter_actor_set_rotation_angle (self, axis, angle);
10035   clutter_actor_set_rotation_center_internal (self, axis, &v);
10036
10037   g_object_thaw_notify (G_OBJECT (self));
10038 }
10039
10040 /**
10041  * clutter_actor_set_z_rotation_from_gravity:
10042  * @self: a #ClutterActor
10043  * @angle: the angle of rotation
10044  * @gravity: the center point of the rotation
10045  *
10046  * Sets the rotation angle of @self around the Z axis using the center
10047  * point specified as a compass point. For example to rotate such that
10048  * the center of the actor remains static you can use
10049  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10050  * will move accordingly.
10051  *
10052  * Since: 1.0
10053  */
10054 void
10055 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10056                                            gdouble         angle,
10057                                            ClutterGravity  gravity)
10058 {
10059   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10060
10061   if (gravity == CLUTTER_GRAVITY_NONE)
10062     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10063   else
10064     {
10065       GObject *obj = G_OBJECT (self);
10066       ClutterTransformInfo *info;
10067
10068       info = _clutter_actor_get_transform_info (self);
10069
10070       g_object_freeze_notify (obj);
10071
10072       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10073
10074       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10075       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10076       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10077
10078       g_object_thaw_notify (obj);
10079     }
10080 }
10081
10082 /**
10083  * clutter_actor_get_rotation:
10084  * @self: a #ClutterActor
10085  * @axis: the axis of rotation
10086  * @x: (out): return value for the X coordinate of the center of rotation
10087  * @y: (out): return value for the Y coordinate of the center of rotation
10088  * @z: (out): return value for the Z coordinate of the center of rotation
10089  *
10090  * Retrieves the angle and center of rotation on the given axis,
10091  * set using clutter_actor_set_rotation().
10092  *
10093  * Return value: the angle of rotation
10094  *
10095  * Since: 0.8
10096  */
10097 gdouble
10098 clutter_actor_get_rotation (ClutterActor      *self,
10099                             ClutterRotateAxis  axis,
10100                             gfloat            *x,
10101                             gfloat            *y,
10102                             gfloat            *z)
10103 {
10104   const ClutterTransformInfo *info;
10105   const AnchorCoord *anchor_coord;
10106   gdouble retval = 0;
10107
10108   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10109
10110   info = _clutter_actor_get_transform_info_or_defaults (self);
10111
10112   switch (axis)
10113     {
10114     case CLUTTER_X_AXIS:
10115       anchor_coord = &info->rx_center;
10116       retval = info->rx_angle;
10117       break;
10118
10119     case CLUTTER_Y_AXIS:
10120       anchor_coord = &info->ry_center;
10121       retval = info->ry_angle;
10122       break;
10123
10124     case CLUTTER_Z_AXIS:
10125       anchor_coord = &info->rz_center;
10126       retval = info->rz_angle;
10127       break;
10128
10129     default:
10130       anchor_coord = NULL;
10131       retval = 0.0;
10132       break;
10133     }
10134
10135   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10136
10137   return retval;
10138 }
10139
10140 /**
10141  * clutter_actor_get_z_rotation_gravity:
10142  * @self: A #ClutterActor
10143  *
10144  * Retrieves the center for the rotation around the Z axis as a
10145  * compass direction. If the center was specified in pixels or units
10146  * this will return %CLUTTER_GRAVITY_NONE.
10147  *
10148  * Return value: the Z rotation center
10149  *
10150  * Since: 1.0
10151  */
10152 ClutterGravity
10153 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10154 {
10155   const ClutterTransformInfo *info;
10156
10157   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10158
10159   info = _clutter_actor_get_transform_info_or_defaults (self);
10160
10161   return clutter_anchor_coord_get_gravity (&info->rz_center);
10162 }
10163
10164 /**
10165  * clutter_actor_set_clip:
10166  * @self: A #ClutterActor
10167  * @xoff: X offset of the clip rectangle
10168  * @yoff: Y offset of the clip rectangle
10169  * @width: Width of the clip rectangle
10170  * @height: Height of the clip rectangle
10171  *
10172  * Sets clip area for @self. The clip area is always computed from the
10173  * upper left corner of the actor, even if the anchor point is set
10174  * otherwise.
10175  *
10176  * Since: 0.6
10177  */
10178 void
10179 clutter_actor_set_clip (ClutterActor *self,
10180                         gfloat        xoff,
10181                         gfloat        yoff,
10182                         gfloat        width,
10183                         gfloat        height)
10184 {
10185   ClutterActorPrivate *priv;
10186
10187   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10188
10189   priv = self->priv;
10190
10191   if (priv->has_clip &&
10192       priv->clip.x == xoff &&
10193       priv->clip.y == yoff &&
10194       priv->clip.width == width &&
10195       priv->clip.height == height)
10196     return;
10197
10198   priv->clip.x = xoff;
10199   priv->clip.y = yoff;
10200   priv->clip.width = width;
10201   priv->clip.height = height;
10202
10203   priv->has_clip = TRUE;
10204
10205   clutter_actor_queue_redraw (self);
10206
10207   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10208   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10209 }
10210
10211 /**
10212  * clutter_actor_remove_clip:
10213  * @self: A #ClutterActor
10214  *
10215  * Removes clip area from @self.
10216  */
10217 void
10218 clutter_actor_remove_clip (ClutterActor *self)
10219 {
10220   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10221
10222   if (!self->priv->has_clip)
10223     return;
10224
10225   self->priv->has_clip = FALSE;
10226
10227   clutter_actor_queue_redraw (self);
10228
10229   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10230 }
10231
10232 /**
10233  * clutter_actor_has_clip:
10234  * @self: a #ClutterActor
10235  *
10236  * Determines whether the actor has a clip area set or not.
10237  *
10238  * Return value: %TRUE if the actor has a clip area set.
10239  *
10240  * Since: 0.1.1
10241  */
10242 gboolean
10243 clutter_actor_has_clip (ClutterActor *self)
10244 {
10245   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10246
10247   return self->priv->has_clip;
10248 }
10249
10250 /**
10251  * clutter_actor_get_clip:
10252  * @self: a #ClutterActor
10253  * @xoff: (out) (allow-none): return location for the X offset of
10254  *   the clip rectangle, or %NULL
10255  * @yoff: (out) (allow-none): return location for the Y offset of
10256  *   the clip rectangle, or %NULL
10257  * @width: (out) (allow-none): return location for the width of
10258  *   the clip rectangle, or %NULL
10259  * @height: (out) (allow-none): return location for the height of
10260  *   the clip rectangle, or %NULL
10261  *
10262  * Gets the clip area for @self, if any is set
10263  *
10264  * Since: 0.6
10265  */
10266 void
10267 clutter_actor_get_clip (ClutterActor *self,
10268                         gfloat       *xoff,
10269                         gfloat       *yoff,
10270                         gfloat       *width,
10271                         gfloat       *height)
10272 {
10273   ClutterActorPrivate *priv;
10274
10275   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10276
10277   priv = self->priv;
10278
10279   if (!priv->has_clip)
10280     return;
10281
10282   if (xoff != NULL)
10283     *xoff = priv->clip.x;
10284
10285   if (yoff != NULL)
10286     *yoff = priv->clip.y;
10287
10288   if (width != NULL)
10289     *width = priv->clip.width;
10290
10291   if (height != NULL)
10292     *height = priv->clip.height;
10293 }
10294
10295 /**
10296  * clutter_actor_get_children:
10297  * @self: a #ClutterActor
10298  *
10299  * Retrieves the list of children of @self.
10300  *
10301  * Return value: (transfer container) (element-type ClutterActor): A newly
10302  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10303  *   done.
10304  *
10305  * Since: 1.10
10306  */
10307 GList *
10308 clutter_actor_get_children (ClutterActor *self)
10309 {
10310   ClutterActor *iter;
10311   GList *res;
10312
10313   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10314
10315   /* we walk the list backward so that we can use prepend(),
10316    * which is O(1)
10317    */
10318   for (iter = self->priv->last_child, res = NULL;
10319        iter != NULL;
10320        iter = iter->priv->prev_sibling)
10321     {
10322       res = g_list_prepend (res, iter);
10323     }
10324
10325   return res;
10326 }
10327
10328 /*< private >
10329  * insert_child_at_depth:
10330  * @self: a #ClutterActor
10331  * @child: a #ClutterActor
10332  *
10333  * Inserts @child inside the list of children held by @self, using
10334  * the depth as the insertion criteria.
10335  *
10336  * This sadly makes the insertion not O(1), but we can keep the
10337  * list sorted so that the painters algorithm we use for painting
10338  * the children will work correctly.
10339  */
10340 static void
10341 insert_child_at_depth (ClutterActor *self,
10342                        ClutterActor *child,
10343                        gpointer      dummy G_GNUC_UNUSED)
10344 {
10345   ClutterActor *iter;
10346   float child_depth;
10347
10348   child->priv->parent = self;
10349
10350   child_depth =
10351     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10352
10353   /* special-case the first child */
10354   if (self->priv->n_children == 0)
10355     {
10356       self->priv->first_child = child;
10357       self->priv->last_child = child;
10358
10359       child->priv->next_sibling = NULL;
10360       child->priv->prev_sibling = NULL;
10361
10362       return;
10363     }
10364
10365   /* Find the right place to insert the child so that it will still be
10366      sorted and the child will be after all of the actors at the same
10367      dept */
10368   for (iter = self->priv->first_child;
10369        iter != NULL;
10370        iter = iter->priv->next_sibling)
10371     {
10372       float iter_depth;
10373
10374       iter_depth =
10375         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10376
10377       if (iter_depth > child_depth)
10378         break;
10379     }
10380
10381   if (iter != NULL)
10382     {
10383       ClutterActor *tmp = iter->priv->prev_sibling;
10384
10385       if (tmp != NULL)
10386         tmp->priv->next_sibling = child;
10387
10388       /* Insert the node before the found one */
10389       child->priv->prev_sibling = iter->priv->prev_sibling;
10390       child->priv->next_sibling = iter;
10391       iter->priv->prev_sibling = child;
10392     }
10393   else
10394     {
10395       ClutterActor *tmp = self->priv->last_child;
10396
10397       if (tmp != NULL)
10398         tmp->priv->next_sibling = child;
10399
10400       /* insert the node at the end of the list */
10401       child->priv->prev_sibling = self->priv->last_child;
10402       child->priv->next_sibling = NULL;
10403     }
10404
10405   if (child->priv->prev_sibling == NULL)
10406     self->priv->first_child = child;
10407
10408   if (child->priv->next_sibling == NULL)
10409     self->priv->last_child = child;
10410 }
10411
10412 static void
10413 insert_child_at_index (ClutterActor *self,
10414                        ClutterActor *child,
10415                        gpointer      data_)
10416 {
10417   gint index_ = GPOINTER_TO_INT (data_);
10418
10419   child->priv->parent = self;
10420
10421   if (index_ == 0)
10422     {
10423       ClutterActor *tmp = self->priv->first_child;
10424
10425       if (tmp != NULL)
10426         tmp->priv->prev_sibling = child;
10427
10428       child->priv->prev_sibling = NULL;
10429       child->priv->next_sibling = tmp;
10430     }
10431   else if (index_ < 0 || index_ >= self->priv->n_children)
10432     {
10433       ClutterActor *tmp = self->priv->last_child;
10434
10435       if (tmp != NULL)
10436         tmp->priv->next_sibling = child;
10437
10438       child->priv->prev_sibling = tmp;
10439       child->priv->next_sibling = NULL;
10440     }
10441   else
10442     {
10443       ClutterActor *iter;
10444       int i;
10445
10446       for (iter = self->priv->first_child, i = 0;
10447            iter != NULL;
10448            iter = iter->priv->next_sibling, i += 1)
10449         {
10450           if (index_ == i)
10451             {
10452               ClutterActor *tmp = iter->priv->prev_sibling;
10453
10454               child->priv->prev_sibling = tmp;
10455               child->priv->next_sibling = iter;
10456
10457               iter->priv->prev_sibling = child;
10458
10459               if (tmp != NULL)
10460                 tmp->priv->next_sibling = child;
10461
10462               break;
10463             }
10464         }
10465     }
10466
10467   if (child->priv->prev_sibling == NULL)
10468     self->priv->first_child = child;
10469
10470   if (child->priv->next_sibling == NULL)
10471     self->priv->last_child = child;
10472 }
10473
10474 static void
10475 insert_child_above (ClutterActor *self,
10476                     ClutterActor *child,
10477                     gpointer      data)
10478 {
10479   ClutterActor *sibling = data;
10480
10481   child->priv->parent = self;
10482
10483   if (sibling == NULL)
10484     sibling = self->priv->last_child;
10485
10486   child->priv->prev_sibling = sibling;
10487
10488   if (sibling != NULL)
10489     {
10490       ClutterActor *tmp = sibling->priv->next_sibling;
10491
10492       child->priv->next_sibling = tmp;
10493
10494       if (tmp != NULL)
10495         tmp->priv->prev_sibling = child;
10496
10497       sibling->priv->next_sibling = child;
10498     }
10499   else
10500     child->priv->next_sibling = NULL;
10501
10502   if (child->priv->prev_sibling == NULL)
10503     self->priv->first_child = child;
10504
10505   if (child->priv->next_sibling == NULL)
10506     self->priv->last_child = child;
10507 }
10508
10509 static void
10510 insert_child_below (ClutterActor *self,
10511                     ClutterActor *child,
10512                     gpointer      data)
10513 {
10514   ClutterActor *sibling = data;
10515
10516   child->priv->parent = self;
10517
10518   if (sibling == NULL)
10519     sibling = self->priv->first_child;
10520
10521   child->priv->next_sibling = sibling;
10522
10523   if (sibling != NULL)
10524     {
10525       ClutterActor *tmp = sibling->priv->prev_sibling;
10526
10527       child->priv->prev_sibling = tmp;
10528
10529       if (tmp != NULL)
10530         tmp->priv->next_sibling = child;
10531
10532       sibling->priv->prev_sibling = child;
10533     }
10534   else
10535     child->priv->prev_sibling = NULL;
10536
10537   if (child->priv->prev_sibling == NULL)
10538     self->priv->first_child = child;
10539
10540   if (child->priv->next_sibling == NULL)
10541     self->priv->last_child = child;
10542 }
10543
10544 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10545                                            ClutterActor *child,
10546                                            gpointer      data);
10547
10548 typedef enum {
10549   ADD_CHILD_CREATE_META       = 1 << 0,
10550   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10551   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10552   ADD_CHILD_CHECK_STATE       = 1 << 3,
10553   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10554
10555   /* default flags for public API */
10556   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10557                                ADD_CHILD_EMIT_PARENT_SET |
10558                                ADD_CHILD_EMIT_ACTOR_ADDED |
10559                                ADD_CHILD_CHECK_STATE |
10560                                ADD_CHILD_NOTIFY_FIRST_LAST,
10561
10562   /* flags for legacy/deprecated API */
10563   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10564                                ADD_CHILD_CHECK_STATE |
10565                                ADD_CHILD_NOTIFY_FIRST_LAST
10566 } ClutterActorAddChildFlags;
10567
10568 /*< private >
10569  * clutter_actor_add_child_internal:
10570  * @self: a #ClutterActor
10571  * @child: a #ClutterActor
10572  * @flags: control flags for actions
10573  * @add_func: delegate function
10574  * @data: (closure): data to pass to @add_func
10575  *
10576  * Adds @child to the list of children of @self.
10577  *
10578  * The actual insertion inside the list is delegated to @add_func: this
10579  * function will just set up the state, perform basic checks, and emit
10580  * signals.
10581  *
10582  * The @flags argument is used to perform additional operations.
10583  */
10584 static inline void
10585 clutter_actor_add_child_internal (ClutterActor              *self,
10586                                   ClutterActor              *child,
10587                                   ClutterActorAddChildFlags  flags,
10588                                   ClutterActorAddChildFunc   add_func,
10589                                   gpointer                   data)
10590 {
10591   ClutterTextDirection text_dir;
10592   gboolean create_meta;
10593   gboolean emit_parent_set, emit_actor_added;
10594   gboolean check_state;
10595   gboolean notify_first_last;
10596   ClutterActor *old_first_child, *old_last_child;
10597
10598   if (child->priv->parent != NULL)
10599     {
10600       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10601                  "use clutter_actor_remove_child() first.",
10602                  _clutter_actor_get_debug_name (child),
10603                  _clutter_actor_get_debug_name (child->priv->parent));
10604       return;
10605     }
10606
10607   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10608     {
10609       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10610                  "a child of another actor.",
10611                  _clutter_actor_get_debug_name (child));
10612       return;
10613     }
10614
10615 #if 0
10616   /* XXX - this check disallows calling methods that change the stacking
10617    * order within the destruction sequence, by triggering a critical
10618    * warning first, and leaving the actor in an undefined state, which
10619    * then ends up being caught by an assertion.
10620    *
10621    * the reproducible sequence is:
10622    *
10623    *   - actor gets destroyed;
10624    *   - another actor, linked to the first, will try to change the
10625    *     stacking order of the first actor;
10626    *   - changing the stacking order is a composite operation composed
10627    *     by the following steps:
10628    *     1. ref() the child;
10629    *     2. remove_child_internal(), which removes the reference;
10630    *     3. add_child_internal(), which adds a reference;
10631    *   - the state of the actor is not changed between (2) and (3), as
10632    *     it could be an expensive recomputation;
10633    *   - if (3) bails out, then the actor is in an undefined state, but
10634    *     still alive;
10635    *   - the destruction sequence terminates, but the actor is unparented
10636    *     while its state indicates being parented instead.
10637    *   - assertion failure.
10638    *
10639    * the obvious fix would be to decompose each set_child_*_sibling()
10640    * method into proper remove_child()/add_child(), with state validation;
10641    * this may cause excessive work, though, and trigger a cascade of other
10642    * bugs in code that assumes that a change in the stacking order is an
10643    * atomic operation.
10644    *
10645    * another potential fix is to just remove this check here, and let
10646    * code doing stacking order changes inside the destruction sequence
10647    * of an actor continue doing the work.
10648    *
10649    * the third fix is to silently bail out early from every
10650    * set_child_*_sibling() and set_child_at_index() method, and avoid
10651    * doing work.
10652    *
10653    * I have a preference for the second solution, since it involves the
10654    * least amount of work, and the least amount of code duplication.
10655    *
10656    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10657    */
10658   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10659     {
10660       g_warning ("The actor '%s' is currently being destroyed, and "
10661                  "cannot be added as a child of another actor.",
10662                  _clutter_actor_get_debug_name (child));
10663       return;
10664     }
10665 #endif
10666
10667   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10668   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10669   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10670   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10671   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10672
10673   old_first_child = self->priv->first_child;
10674   old_last_child = self->priv->last_child;
10675
10676   g_object_freeze_notify (G_OBJECT (self));
10677
10678   if (create_meta)
10679     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10680
10681   g_object_ref_sink (child);
10682   child->priv->parent = NULL;
10683   child->priv->next_sibling = NULL;
10684   child->priv->prev_sibling = NULL;
10685
10686   /* delegate the actual insertion */
10687   add_func (self, child, data);
10688
10689   g_assert (child->priv->parent == self);
10690
10691   self->priv->n_children += 1;
10692
10693   self->priv->age += 1;
10694
10695   /* if push_internal() has been called then we automatically set
10696    * the flag on the actor
10697    */
10698   if (self->priv->internal_child)
10699     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10700
10701   /* clutter_actor_reparent() will emit ::parent-set for us */
10702   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10703     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10704
10705   if (check_state)
10706     {
10707       /* If parent is mapped or realized, we need to also be mapped or
10708        * realized once we're inside the parent.
10709        */
10710       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10711
10712       /* propagate the parent's text direction to the child */
10713       text_dir = clutter_actor_get_text_direction (self);
10714       clutter_actor_set_text_direction (child, text_dir);
10715     }
10716
10717   if (child->priv->show_on_set_parent)
10718     clutter_actor_show (child);
10719
10720   if (CLUTTER_ACTOR_IS_MAPPED (child))
10721     clutter_actor_queue_redraw (child);
10722
10723   /* maintain the invariant that if an actor needs layout,
10724    * its parents do as well
10725    */
10726   if (child->priv->needs_width_request ||
10727       child->priv->needs_height_request ||
10728       child->priv->needs_allocation)
10729     {
10730       /* we work around the short-circuiting we do
10731        * in clutter_actor_queue_relayout() since we
10732        * want to force a relayout
10733        */
10734       child->priv->needs_width_request = TRUE;
10735       child->priv->needs_height_request = TRUE;
10736       child->priv->needs_allocation = TRUE;
10737
10738       clutter_actor_queue_relayout (child->priv->parent);
10739     }
10740
10741   if (emit_actor_added)
10742     g_signal_emit_by_name (self, "actor-added", child);
10743
10744   if (notify_first_last)
10745     {
10746       if (old_first_child != self->priv->first_child)
10747         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10748
10749       if (old_last_child != self->priv->last_child)
10750         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10751     }
10752
10753   g_object_thaw_notify (G_OBJECT (self));
10754 }
10755
10756 /**
10757  * clutter_actor_add_child:
10758  * @self: a #ClutterActor
10759  * @child: a #ClutterActor
10760  *
10761  * Adds @child to the children of @self.
10762  *
10763  * This function will acquire a reference on @child that will only
10764  * be released when calling clutter_actor_remove_child().
10765  *
10766  * This function will take into consideration the #ClutterActor:depth
10767  * of @child, and will keep the list of children sorted.
10768  *
10769  * This function will emit the #ClutterContainer::actor-added signal
10770  * on @self.
10771  *
10772  * Since: 1.10
10773  */
10774 void
10775 clutter_actor_add_child (ClutterActor *self,
10776                          ClutterActor *child)
10777 {
10778   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10779   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10780   g_return_if_fail (self != child);
10781   g_return_if_fail (child->priv->parent == NULL);
10782
10783   clutter_actor_add_child_internal (self, child,
10784                                     ADD_CHILD_DEFAULT_FLAGS,
10785                                     insert_child_at_depth,
10786                                     NULL);
10787 }
10788
10789 /**
10790  * clutter_actor_insert_child_at_index:
10791  * @self: a #ClutterActor
10792  * @child: a #ClutterActor
10793  * @index_: the index
10794  *
10795  * Inserts @child into the list of children of @self, using the
10796  * given @index_. If @index_ is greater than the number of children
10797  * in @self, or is less than 0, then the new child is added at the end.
10798  *
10799  * This function will acquire a reference on @child that will only
10800  * be released when calling clutter_actor_remove_child().
10801  *
10802  * This function will not take into consideration the #ClutterActor:depth
10803  * of @child.
10804  *
10805  * This function will emit the #ClutterContainer::actor-added signal
10806  * on @self.
10807  *
10808  * Since: 1.10
10809  */
10810 void
10811 clutter_actor_insert_child_at_index (ClutterActor *self,
10812                                      ClutterActor *child,
10813                                      gint          index_)
10814 {
10815   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10816   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10817   g_return_if_fail (self != child);
10818   g_return_if_fail (child->priv->parent == NULL);
10819
10820   clutter_actor_add_child_internal (self, child,
10821                                     ADD_CHILD_DEFAULT_FLAGS,
10822                                     insert_child_at_index,
10823                                     GINT_TO_POINTER (index_));
10824 }
10825
10826 /**
10827  * clutter_actor_insert_child_above:
10828  * @self: a #ClutterActor
10829  * @child: a #ClutterActor
10830  * @sibling: (allow-none): a child of @self, or %NULL
10831  *
10832  * Inserts @child into the list of children of @self, above another
10833  * child of @self or, if @sibling is %NULL, above all the children
10834  * of @self.
10835  *
10836  * This function will acquire a reference on @child that will only
10837  * be released when calling clutter_actor_remove_child().
10838  *
10839  * This function will not take into consideration the #ClutterActor:depth
10840  * of @child.
10841  *
10842  * This function will emit the #ClutterContainer::actor-added signal
10843  * on @self.
10844  *
10845  * Since: 1.10
10846  */
10847 void
10848 clutter_actor_insert_child_above (ClutterActor *self,
10849                                   ClutterActor *child,
10850                                   ClutterActor *sibling)
10851 {
10852   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10853   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10854   g_return_if_fail (self != child);
10855   g_return_if_fail (child != sibling);
10856   g_return_if_fail (child->priv->parent == NULL);
10857   g_return_if_fail (sibling == NULL ||
10858                     (CLUTTER_IS_ACTOR (sibling) &&
10859                      sibling->priv->parent == self));
10860
10861   clutter_actor_add_child_internal (self, child,
10862                                     ADD_CHILD_DEFAULT_FLAGS,
10863                                     insert_child_above,
10864                                     sibling);
10865 }
10866
10867 /**
10868  * clutter_actor_insert_child_below:
10869  * @self: a #ClutterActor
10870  * @child: a #ClutterActor
10871  * @sibling: (allow-none): a child of @self, or %NULL
10872  *
10873  * Inserts @child into the list of children of @self, below another
10874  * child of @self or, if @sibling is %NULL, below all the children
10875  * of @self.
10876  *
10877  * This function will acquire a reference on @child that will only
10878  * be released when calling clutter_actor_remove_child().
10879  *
10880  * This function will not take into consideration the #ClutterActor:depth
10881  * of @child.
10882  *
10883  * This function will emit the #ClutterContainer::actor-added signal
10884  * on @self.
10885  *
10886  * Since: 1.10
10887  */
10888 void
10889 clutter_actor_insert_child_below (ClutterActor *self,
10890                                   ClutterActor *child,
10891                                   ClutterActor *sibling)
10892 {
10893   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10894   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10895   g_return_if_fail (self != child);
10896   g_return_if_fail (child != sibling);
10897   g_return_if_fail (child->priv->parent == NULL);
10898   g_return_if_fail (sibling == NULL ||
10899                     (CLUTTER_IS_ACTOR (sibling) &&
10900                      sibling->priv->parent == self));
10901
10902   clutter_actor_add_child_internal (self, child,
10903                                     ADD_CHILD_DEFAULT_FLAGS,
10904                                     insert_child_below,
10905                                     sibling);
10906 }
10907
10908 /**
10909  * clutter_actor_set_parent:
10910  * @self: A #ClutterActor
10911  * @parent: A new #ClutterActor parent
10912  *
10913  * Sets the parent of @self to @parent.
10914  *
10915  * This function will result in @parent acquiring a reference on @self,
10916  * eventually by sinking its floating reference first. The reference
10917  * will be released by clutter_actor_unparent().
10918  *
10919  * This function should only be called by legacy #ClutterActor<!-- -->s
10920  * implementing the #ClutterContainer interface.
10921  *
10922  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10923  */
10924 void
10925 clutter_actor_set_parent (ClutterActor *self,
10926                           ClutterActor *parent)
10927 {
10928   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10929   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10930   g_return_if_fail (self != parent);
10931   g_return_if_fail (self->priv->parent == NULL);
10932
10933   /* as this function will be called inside ClutterContainer::add
10934    * implementations or when building up a composite actor, we have
10935    * to preserve the old behaviour, and not create child meta or
10936    * emit the ::actor-added signal, to avoid recursion or double
10937    * emissions
10938    */
10939   clutter_actor_add_child_internal (parent, self,
10940                                     ADD_CHILD_LEGACY_FLAGS,
10941                                     insert_child_at_depth,
10942                                     NULL);
10943 }
10944
10945 /**
10946  * clutter_actor_get_parent:
10947  * @self: A #ClutterActor
10948  *
10949  * Retrieves the parent of @self.
10950  *
10951  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10952  *  if no parent is set
10953  */
10954 ClutterActor *
10955 clutter_actor_get_parent (ClutterActor *self)
10956 {
10957   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10958
10959   return self->priv->parent;
10960 }
10961
10962 /**
10963  * clutter_actor_get_paint_visibility:
10964  * @self: A #ClutterActor
10965  *
10966  * Retrieves the 'paint' visibility of an actor recursively checking for non
10967  * visible parents.
10968  *
10969  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10970  *
10971  * Return Value: %TRUE if the actor is visibile and will be painted.
10972  *
10973  * Since: 0.8.4
10974  */
10975 gboolean
10976 clutter_actor_get_paint_visibility (ClutterActor *actor)
10977 {
10978   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10979
10980   return CLUTTER_ACTOR_IS_MAPPED (actor);
10981 }
10982
10983 /**
10984  * clutter_actor_remove_child:
10985  * @self: a #ClutterActor
10986  * @child: a #ClutterActor
10987  *
10988  * Removes @child from the children of @self.
10989  *
10990  * This function will release the reference added by
10991  * clutter_actor_add_child(), so if you want to keep using @child
10992  * you will have to acquire a referenced on it before calling this
10993  * function.
10994  *
10995  * This function will emit the #ClutterContainer::actor-removed
10996  * signal on @self.
10997  *
10998  * Since: 1.10
10999  */
11000 void
11001 clutter_actor_remove_child (ClutterActor *self,
11002                             ClutterActor *child)
11003 {
11004   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11005   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11006   g_return_if_fail (self != child);
11007   g_return_if_fail (child->priv->parent != NULL);
11008   g_return_if_fail (child->priv->parent == self);
11009
11010   clutter_actor_remove_child_internal (self, child,
11011                                        REMOVE_CHILD_DEFAULT_FLAGS);
11012 }
11013
11014 /**
11015  * clutter_actor_remove_all_children:
11016  * @self: a #ClutterActor
11017  *
11018  * Removes all children of @self.
11019  *
11020  * This function releases the reference added by inserting a child actor
11021  * in the list of children of @self.
11022  *
11023  * If the reference count of a child drops to zero, the child will be
11024  * destroyed. If you want to ensure the destruction of all the children
11025  * of @self, use clutter_actor_destroy_all_children().
11026  *
11027  * Since: 1.10
11028  */
11029 void
11030 clutter_actor_remove_all_children (ClutterActor *self)
11031 {
11032   ClutterActorIter iter;
11033
11034   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11035
11036   if (self->priv->n_children == 0)
11037     return;
11038
11039   g_object_freeze_notify (G_OBJECT (self));
11040
11041   clutter_actor_iter_init (&iter, self);
11042   while (clutter_actor_iter_next (&iter, NULL))
11043     clutter_actor_iter_remove (&iter);
11044
11045   g_object_thaw_notify (G_OBJECT (self));
11046
11047   /* sanity check */
11048   g_assert (self->priv->first_child == NULL);
11049   g_assert (self->priv->last_child == NULL);
11050   g_assert (self->priv->n_children == 0);
11051 }
11052
11053 /**
11054  * clutter_actor_destroy_all_children:
11055  * @self: a #ClutterActor
11056  *
11057  * Destroys all children of @self.
11058  *
11059  * This function releases the reference added by inserting a child
11060  * actor in the list of children of @self, and ensures that the
11061  * #ClutterActor::destroy signal is emitted on each child of the
11062  * actor.
11063  *
11064  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11065  * when its reference count drops to 0; the default handler of the
11066  * #ClutterActor::destroy signal will destroy all the children of an
11067  * actor. This function ensures that all children are destroyed, instead
11068  * of just removed from @self, unlike clutter_actor_remove_all_children()
11069  * which will merely release the reference and remove each child.
11070  *
11071  * Unless you acquired an additional reference on each child of @self
11072  * prior to calling clutter_actor_remove_all_children() and want to reuse
11073  * the actors, you should use clutter_actor_destroy_all_children() in
11074  * order to make sure that children are destroyed and signal handlers
11075  * are disconnected even in cases where circular references prevent this
11076  * from automatically happening through reference counting alone.
11077  *
11078  * Since: 1.10
11079  */
11080 void
11081 clutter_actor_destroy_all_children (ClutterActor *self)
11082 {
11083   ClutterActorIter iter;
11084
11085   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11086
11087   if (self->priv->n_children == 0)
11088     return;
11089
11090   g_object_freeze_notify (G_OBJECT (self));
11091
11092   clutter_actor_iter_init (&iter, self);
11093   while (clutter_actor_iter_next (&iter, NULL))
11094     clutter_actor_iter_destroy (&iter);
11095
11096   g_object_thaw_notify (G_OBJECT (self));
11097
11098   /* sanity check */
11099   g_assert (self->priv->first_child == NULL);
11100   g_assert (self->priv->last_child == NULL);
11101   g_assert (self->priv->n_children == 0);
11102 }
11103
11104 typedef struct _InsertBetweenData {
11105   ClutterActor *prev_sibling;
11106   ClutterActor *next_sibling;
11107 } InsertBetweenData;
11108
11109 static void
11110 insert_child_between (ClutterActor *self,
11111                       ClutterActor *child,
11112                       gpointer      data_)
11113 {
11114   InsertBetweenData *data = data_;
11115   ClutterActor *prev_sibling = data->prev_sibling;
11116   ClutterActor *next_sibling = data->next_sibling;
11117
11118   child->priv->parent = self;
11119   child->priv->prev_sibling = prev_sibling;
11120   child->priv->next_sibling = next_sibling;
11121
11122   if (prev_sibling != NULL)
11123     prev_sibling->priv->next_sibling = child;
11124
11125   if (next_sibling != NULL)
11126     next_sibling->priv->prev_sibling = child;
11127
11128   if (child->priv->prev_sibling == NULL)
11129     self->priv->first_child = child;
11130
11131   if (child->priv->next_sibling == NULL)
11132     self->priv->last_child = child;
11133 }
11134
11135 /**
11136  * clutter_actor_replace_child:
11137  * @self: a #ClutterActor
11138  * @old_child: the child of @self to replace
11139  * @new_child: the #ClutterActor to replace @old_child
11140  *
11141  * Replaces @old_child with @new_child in the list of children of @self.
11142  *
11143  * Since: 1.10
11144  */
11145 void
11146 clutter_actor_replace_child (ClutterActor *self,
11147                              ClutterActor *old_child,
11148                              ClutterActor *new_child)
11149 {
11150   ClutterActor *prev_sibling, *next_sibling;
11151   InsertBetweenData clos;
11152
11153   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11154   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11155   g_return_if_fail (old_child->priv->parent == self);
11156   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11157   g_return_if_fail (old_child != new_child);
11158   g_return_if_fail (new_child != self);
11159   g_return_if_fail (new_child->priv->parent == NULL);
11160
11161   prev_sibling = old_child->priv->prev_sibling;
11162   next_sibling = old_child->priv->next_sibling;
11163   clutter_actor_remove_child_internal (self, old_child,
11164                                        REMOVE_CHILD_DEFAULT_FLAGS);
11165
11166   clos.prev_sibling = prev_sibling;
11167   clos.next_sibling = next_sibling;
11168   clutter_actor_add_child_internal (self, new_child,
11169                                     ADD_CHILD_DEFAULT_FLAGS,
11170                                     insert_child_between,
11171                                     &clos);
11172 }
11173
11174 /**
11175  * clutter_actor_unparent:
11176  * @self: a #ClutterActor
11177  *
11178  * Removes the parent of @self.
11179  *
11180  * This will cause the parent of @self to release the reference
11181  * acquired when calling clutter_actor_set_parent(), so if you
11182  * want to keep @self you will have to acquire a reference of
11183  * your own, through g_object_ref().
11184  *
11185  * This function should only be called by legacy #ClutterActor<!-- -->s
11186  * implementing the #ClutterContainer interface.
11187  *
11188  * Since: 0.1.1
11189  *
11190  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11191  */
11192 void
11193 clutter_actor_unparent (ClutterActor *self)
11194 {
11195   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11196
11197   if (self->priv->parent == NULL)
11198     return;
11199
11200   clutter_actor_remove_child_internal (self->priv->parent, self,
11201                                        REMOVE_CHILD_LEGACY_FLAGS);
11202 }
11203
11204 /**
11205  * clutter_actor_reparent:
11206  * @self: a #ClutterActor
11207  * @new_parent: the new #ClutterActor parent
11208  *
11209  * Resets the parent actor of @self.
11210  *
11211  * This function is logically equivalent to calling clutter_actor_unparent()
11212  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11213  * ensures the child is not finalized when unparented, and emits the
11214  * #ClutterActor::parent-set signal only once.
11215  *
11216  * In reality, calling this function is less useful than it sounds, as some
11217  * application code may rely on changes in the intermediate state between
11218  * removal and addition of the actor from its old parent to the @new_parent.
11219  * Thus, it is strongly encouraged to avoid using this function in application
11220  * code.
11221  *
11222  * Since: 0.2
11223  *
11224  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11225  *   clutter_actor_add_child() instead; remember to take a reference on
11226  *   the actor being removed before calling clutter_actor_remove_child()
11227  *   to avoid the reference count dropping to zero and the actor being
11228  *   destroyed.
11229  */
11230 void
11231 clutter_actor_reparent (ClutterActor *self,
11232                         ClutterActor *new_parent)
11233 {
11234   ClutterActorPrivate *priv;
11235
11236   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11237   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11238   g_return_if_fail (self != new_parent);
11239
11240   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11241     {
11242       g_warning ("Cannot set a parent on a toplevel actor");
11243       return;
11244     }
11245
11246   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11247     {
11248       g_warning ("Cannot set a parent currently being destroyed");
11249       return;
11250     }
11251
11252   priv = self->priv;
11253
11254   if (priv->parent != new_parent)
11255     {
11256       ClutterActor *old_parent;
11257
11258       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11259
11260       old_parent = priv->parent;
11261
11262       g_object_ref (self);
11263
11264       if (old_parent != NULL)
11265         {
11266          /* go through the Container implementation if this is a regular
11267           * child and not an internal one
11268           */
11269          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11270            {
11271              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11272
11273              /* this will have to call unparent() */
11274              clutter_container_remove_actor (parent, self);
11275            }
11276          else
11277            clutter_actor_remove_child_internal (old_parent, self,
11278                                                 REMOVE_CHILD_LEGACY_FLAGS);
11279         }
11280
11281       /* Note, will call set_parent() */
11282       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11283         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11284       else
11285         clutter_actor_add_child_internal (new_parent, self,
11286                                           ADD_CHILD_LEGACY_FLAGS,
11287                                           insert_child_at_depth,
11288                                           NULL);
11289
11290       /* we emit the ::parent-set signal once */
11291       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11292
11293       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11294
11295       /* the IN_REPARENT flag suspends state updates */
11296       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11297
11298       g_object_unref (self);
11299    }
11300 }
11301
11302 /**
11303  * clutter_actor_contains:
11304  * @self: A #ClutterActor
11305  * @descendant: A #ClutterActor, possibly contained in @self
11306  *
11307  * Determines if @descendant is contained inside @self (either as an
11308  * immediate child, or as a deeper descendant). If @self and
11309  * @descendant point to the same actor then it will also return %TRUE.
11310  *
11311  * Return value: whether @descendent is contained within @self
11312  *
11313  * Since: 1.4
11314  */
11315 gboolean
11316 clutter_actor_contains (ClutterActor *self,
11317                         ClutterActor *descendant)
11318 {
11319   ClutterActor *actor;
11320
11321   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11322   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11323
11324   for (actor = descendant; actor; actor = actor->priv->parent)
11325     if (actor == self)
11326       return TRUE;
11327
11328   return FALSE;
11329 }
11330
11331 /**
11332  * clutter_actor_set_child_above_sibling:
11333  * @self: a #ClutterActor
11334  * @child: a #ClutterActor child of @self
11335  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11336  *
11337  * Sets @child to be above @sibling in the list of children of @self.
11338  *
11339  * If @sibling is %NULL, @child will be the new last child of @self.
11340  *
11341  * This function is logically equivalent to removing @child and using
11342  * clutter_actor_insert_child_above(), but it will not emit signals
11343  * or change state on @child.
11344  *
11345  * Since: 1.10
11346  */
11347 void
11348 clutter_actor_set_child_above_sibling (ClutterActor *self,
11349                                        ClutterActor *child,
11350                                        ClutterActor *sibling)
11351 {
11352   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11353   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11354   g_return_if_fail (child->priv->parent == self);
11355   g_return_if_fail (child != sibling);
11356   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11357
11358   if (sibling != NULL)
11359     g_return_if_fail (sibling->priv->parent == self);
11360
11361   /* we don't want to change the state of child, or emit signals, or
11362    * regenerate ChildMeta instances here, but we still want to follow
11363    * the correct sequence of steps encoded in remove_child() and
11364    * add_child(), so that correctness is ensured, and we only go
11365    * through one known code path.
11366    */
11367   g_object_ref (child);
11368   clutter_actor_remove_child_internal (self, child, 0);
11369   clutter_actor_add_child_internal (self, child,
11370                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11371                                     insert_child_above,
11372                                     sibling);
11373
11374   clutter_actor_queue_relayout (self);
11375 }
11376
11377 /**
11378  * clutter_actor_set_child_below_sibling:
11379  * @self: a #ClutterActor
11380  * @child: a #ClutterActor child of @self
11381  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11382  *
11383  * Sets @child to be below @sibling in the list of children of @self.
11384  *
11385  * If @sibling is %NULL, @child will be the new first child of @self.
11386  *
11387  * This function is logically equivalent to removing @self and using
11388  * clutter_actor_insert_child_below(), but it will not emit signals
11389  * or change state on @child.
11390  *
11391  * Since: 1.10
11392  */
11393 void
11394 clutter_actor_set_child_below_sibling (ClutterActor *self,
11395                                        ClutterActor *child,
11396                                        ClutterActor *sibling)
11397 {
11398   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11399   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11400   g_return_if_fail (child->priv->parent == self);
11401   g_return_if_fail (child != sibling);
11402   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11403
11404   if (sibling != NULL)
11405     g_return_if_fail (sibling->priv->parent == self);
11406
11407   /* see the comment in set_child_above_sibling() */
11408   g_object_ref (child);
11409   clutter_actor_remove_child_internal (self, child, 0);
11410   clutter_actor_add_child_internal (self, child,
11411                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11412                                     insert_child_below,
11413                                     sibling);
11414
11415   clutter_actor_queue_relayout (self);
11416 }
11417
11418 /**
11419  * clutter_actor_set_child_at_index:
11420  * @self: a #ClutterActor
11421  * @child: a #ClutterActor child of @self
11422  * @index_: the new index for @child
11423  *
11424  * Changes the index of @child in the list of children of @self.
11425  *
11426  * This function is logically equivalent to removing @child and
11427  * calling clutter_actor_insert_child_at_index(), but it will not
11428  * emit signals or change state on @child.
11429  *
11430  * Since: 1.10
11431  */
11432 void
11433 clutter_actor_set_child_at_index (ClutterActor *self,
11434                                   ClutterActor *child,
11435                                   gint          index_)
11436 {
11437   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11438   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11439   g_return_if_fail (child->priv->parent == self);
11440   g_return_if_fail (index_ <= self->priv->n_children);
11441
11442   g_object_ref (child);
11443   clutter_actor_remove_child_internal (self, child, 0);
11444   clutter_actor_add_child_internal (self, child,
11445                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11446                                     insert_child_at_index,
11447                                     GINT_TO_POINTER (index_));
11448
11449   clutter_actor_queue_relayout (self);
11450 }
11451
11452 /**
11453  * clutter_actor_raise:
11454  * @self: A #ClutterActor
11455  * @below: (allow-none): A #ClutterActor to raise above.
11456  *
11457  * Puts @self above @below.
11458  *
11459  * Both actors must have the same parent, and the parent must implement
11460  * the #ClutterContainer interface
11461  *
11462  * This function calls clutter_container_raise_child() internally.
11463  *
11464  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11465  */
11466 void
11467 clutter_actor_raise (ClutterActor *self,
11468                      ClutterActor *below)
11469 {
11470   ClutterActor *parent;
11471
11472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11473
11474   parent = clutter_actor_get_parent (self);
11475   if (parent == NULL)
11476     {
11477       g_warning ("%s: Actor '%s' is not inside a container",
11478                  G_STRFUNC,
11479                  _clutter_actor_get_debug_name (self));
11480       return;
11481     }
11482
11483   if (below != NULL)
11484     {
11485       if (parent != clutter_actor_get_parent (below))
11486         {
11487           g_warning ("%s Actor '%s' is not in the same container as "
11488                      "actor '%s'",
11489                      G_STRFUNC,
11490                      _clutter_actor_get_debug_name (self),
11491                      _clutter_actor_get_debug_name (below));
11492           return;
11493         }
11494     }
11495
11496   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11497 }
11498
11499 /**
11500  * clutter_actor_lower:
11501  * @self: A #ClutterActor
11502  * @above: (allow-none): A #ClutterActor to lower below
11503  *
11504  * Puts @self below @above.
11505  *
11506  * Both actors must have the same parent, and the parent must implement
11507  * the #ClutterContainer interface.
11508  *
11509  * This function calls clutter_container_lower_child() internally.
11510  *
11511  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11512  */
11513 void
11514 clutter_actor_lower (ClutterActor *self,
11515                      ClutterActor *above)
11516 {
11517   ClutterActor *parent;
11518
11519   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11520
11521   parent = clutter_actor_get_parent (self);
11522   if (parent == NULL)
11523     {
11524       g_warning ("%s: Actor of type %s is not inside a container",
11525                  G_STRFUNC,
11526                  _clutter_actor_get_debug_name (self));
11527       return;
11528     }
11529
11530   if (above)
11531     {
11532       if (parent != clutter_actor_get_parent (above))
11533         {
11534           g_warning ("%s: Actor '%s' is not in the same container as "
11535                      "actor '%s'",
11536                      G_STRFUNC,
11537                      _clutter_actor_get_debug_name (self),
11538                      _clutter_actor_get_debug_name (above));
11539           return;
11540         }
11541     }
11542
11543   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11544 }
11545
11546 /**
11547  * clutter_actor_raise_top:
11548  * @self: A #ClutterActor
11549  *
11550  * Raises @self to the top.
11551  *
11552  * This function calls clutter_actor_raise() internally.
11553  *
11554  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11555  *   a %NULL sibling, instead.
11556  */
11557 void
11558 clutter_actor_raise_top (ClutterActor *self)
11559 {
11560   clutter_actor_raise (self, NULL);
11561 }
11562
11563 /**
11564  * clutter_actor_lower_bottom:
11565  * @self: A #ClutterActor
11566  *
11567  * Lowers @self to the bottom.
11568  *
11569  * This function calls clutter_actor_lower() internally.
11570  *
11571  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11572  *   a %NULL sibling, instead.
11573  */
11574 void
11575 clutter_actor_lower_bottom (ClutterActor *self)
11576 {
11577   clutter_actor_lower (self, NULL);
11578 }
11579
11580 /*
11581  * Event handling
11582  */
11583
11584 /**
11585  * clutter_actor_event:
11586  * @actor: a #ClutterActor
11587  * @event: a #ClutterEvent
11588  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11589  *
11590  * This function is used to emit an event on the main stage.
11591  * You should rarely need to use this function, except for
11592  * synthetising events.
11593  *
11594  * Return value: the return value from the signal emission: %TRUE
11595  *   if the actor handled the event, or %FALSE if the event was
11596  *   not handled
11597  *
11598  * Since: 0.6
11599  */
11600 gboolean
11601 clutter_actor_event (ClutterActor *actor,
11602                      ClutterEvent *event,
11603                      gboolean      capture)
11604 {
11605   gboolean retval = FALSE;
11606   gint signal_num = -1;
11607
11608   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11609   g_return_val_if_fail (event != NULL, FALSE);
11610
11611   g_object_ref (actor);
11612
11613   if (capture)
11614     {
11615       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11616                      event,
11617                      &retval);
11618       goto out;
11619     }
11620
11621   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11622
11623   if (!retval)
11624     {
11625       switch (event->type)
11626         {
11627         case CLUTTER_NOTHING:
11628           break;
11629         case CLUTTER_BUTTON_PRESS:
11630           signal_num = BUTTON_PRESS_EVENT;
11631           break;
11632         case CLUTTER_BUTTON_RELEASE:
11633           signal_num = BUTTON_RELEASE_EVENT;
11634           break;
11635         case CLUTTER_SCROLL:
11636           signal_num = SCROLL_EVENT;
11637           break;
11638         case CLUTTER_KEY_PRESS:
11639           signal_num = KEY_PRESS_EVENT;
11640           break;
11641         case CLUTTER_KEY_RELEASE:
11642           signal_num = KEY_RELEASE_EVENT;
11643           break;
11644         case CLUTTER_MOTION:
11645           signal_num = MOTION_EVENT;
11646           break;
11647         case CLUTTER_ENTER:
11648           signal_num = ENTER_EVENT;
11649           break;
11650         case CLUTTER_LEAVE:
11651           signal_num = LEAVE_EVENT;
11652           break;
11653         case CLUTTER_DELETE:
11654         case CLUTTER_DESTROY_NOTIFY:
11655         case CLUTTER_CLIENT_MESSAGE:
11656         default:
11657           signal_num = -1;
11658           break;
11659         }
11660
11661       if (signal_num != -1)
11662         g_signal_emit (actor, actor_signals[signal_num], 0,
11663                        event, &retval);
11664     }
11665
11666 out:
11667   g_object_unref (actor);
11668
11669   return retval;
11670 }
11671
11672 /**
11673  * clutter_actor_set_reactive:
11674  * @actor: a #ClutterActor
11675  * @reactive: whether the actor should be reactive to events
11676  *
11677  * Sets @actor as reactive. Reactive actors will receive events.
11678  *
11679  * Since: 0.6
11680  */
11681 void
11682 clutter_actor_set_reactive (ClutterActor *actor,
11683                             gboolean      reactive)
11684 {
11685   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11686
11687   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11688     return;
11689
11690   if (reactive)
11691     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11692   else
11693     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11694
11695   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11696 }
11697
11698 /**
11699  * clutter_actor_get_reactive:
11700  * @actor: a #ClutterActor
11701  *
11702  * Checks whether @actor is marked as reactive.
11703  *
11704  * Return value: %TRUE if the actor is reactive
11705  *
11706  * Since: 0.6
11707  */
11708 gboolean
11709 clutter_actor_get_reactive (ClutterActor *actor)
11710 {
11711   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11712
11713   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11714 }
11715
11716 /**
11717  * clutter_actor_get_anchor_point:
11718  * @self: a #ClutterActor
11719  * @anchor_x: (out): return location for the X coordinate of the anchor point
11720  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11721  *
11722  * Gets the current anchor point of the @actor in pixels.
11723  *
11724  * Since: 0.6
11725  */
11726 void
11727 clutter_actor_get_anchor_point (ClutterActor *self,
11728                                 gfloat       *anchor_x,
11729                                 gfloat       *anchor_y)
11730 {
11731   const ClutterTransformInfo *info;
11732
11733   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11734
11735   info = _clutter_actor_get_transform_info_or_defaults (self);
11736   clutter_anchor_coord_get_units (self, &info->anchor,
11737                                   anchor_x,
11738                                   anchor_y,
11739                                   NULL);
11740 }
11741
11742 /**
11743  * clutter_actor_set_anchor_point:
11744  * @self: a #ClutterActor
11745  * @anchor_x: X coordinate of the anchor point
11746  * @anchor_y: Y coordinate of the anchor point
11747  *
11748  * Sets an anchor point for @self. The anchor point is a point in the
11749  * coordinate space of an actor to which the actor position within its
11750  * parent is relative; the default is (0, 0), i.e. the top-left corner
11751  * of the actor.
11752  *
11753  * Since: 0.6
11754  */
11755 void
11756 clutter_actor_set_anchor_point (ClutterActor *self,
11757                                 gfloat        anchor_x,
11758                                 gfloat        anchor_y)
11759 {
11760   ClutterTransformInfo *info;
11761   ClutterActorPrivate *priv;
11762   gboolean changed = FALSE;
11763   gfloat old_anchor_x, old_anchor_y;
11764   GObject *obj;
11765
11766   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11767
11768   obj = G_OBJECT (self);
11769   priv = self->priv;
11770   info = _clutter_actor_get_transform_info (self);
11771
11772   g_object_freeze_notify (obj);
11773
11774   clutter_anchor_coord_get_units (self, &info->anchor,
11775                                   &old_anchor_x,
11776                                   &old_anchor_y,
11777                                   NULL);
11778
11779   if (info->anchor.is_fractional)
11780     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11781
11782   if (old_anchor_x != anchor_x)
11783     {
11784       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11785       changed = TRUE;
11786     }
11787
11788   if (old_anchor_y != anchor_y)
11789     {
11790       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11791       changed = TRUE;
11792     }
11793
11794   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11795
11796   if (changed)
11797     {
11798       priv->transform_valid = FALSE;
11799       clutter_actor_queue_redraw (self);
11800     }
11801
11802   g_object_thaw_notify (obj);
11803 }
11804
11805 /**
11806  * clutter_actor_get_anchor_point_gravity:
11807  * @self: a #ClutterActor
11808  *
11809  * Retrieves the anchor position expressed as a #ClutterGravity. If
11810  * the anchor point was specified using pixels or units this will
11811  * return %CLUTTER_GRAVITY_NONE.
11812  *
11813  * Return value: the #ClutterGravity used by the anchor point
11814  *
11815  * Since: 1.0
11816  */
11817 ClutterGravity
11818 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11819 {
11820   const ClutterTransformInfo *info;
11821
11822   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11823
11824   info = _clutter_actor_get_transform_info_or_defaults (self);
11825
11826   return clutter_anchor_coord_get_gravity (&info->anchor);
11827 }
11828
11829 /**
11830  * clutter_actor_move_anchor_point:
11831  * @self: a #ClutterActor
11832  * @anchor_x: X coordinate of the anchor point
11833  * @anchor_y: Y coordinate of the anchor point
11834  *
11835  * Sets an anchor point for the actor, and adjusts the actor postion so that
11836  * the relative position of the actor toward its parent remains the same.
11837  *
11838  * Since: 0.6
11839  */
11840 void
11841 clutter_actor_move_anchor_point (ClutterActor *self,
11842                                  gfloat        anchor_x,
11843                                  gfloat        anchor_y)
11844 {
11845   gfloat old_anchor_x, old_anchor_y;
11846   const ClutterTransformInfo *info;
11847
11848   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11849
11850   info = _clutter_actor_get_transform_info (self);
11851   clutter_anchor_coord_get_units (self, &info->anchor,
11852                                   &old_anchor_x,
11853                                   &old_anchor_y,
11854                                   NULL);
11855
11856   g_object_freeze_notify (G_OBJECT (self));
11857
11858   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11859
11860   if (self->priv->position_set)
11861     clutter_actor_move_by (self,
11862                            anchor_x - old_anchor_x,
11863                            anchor_y - old_anchor_y);
11864
11865   g_object_thaw_notify (G_OBJECT (self));
11866 }
11867
11868 /**
11869  * clutter_actor_move_anchor_point_from_gravity:
11870  * @self: a #ClutterActor
11871  * @gravity: #ClutterGravity.
11872  *
11873  * Sets an anchor point on the actor based on the given gravity, adjusting the
11874  * actor postion so that its relative position within its parent remains
11875  * unchanged.
11876  *
11877  * Since version 1.0 the anchor point will be stored as a gravity so
11878  * that if the actor changes size then the anchor point will move. For
11879  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11880  * and later double the size of the actor, the anchor point will move
11881  * to the bottom right.
11882  *
11883  * Since: 0.6
11884  */
11885 void
11886 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11887                                               ClutterGravity  gravity)
11888 {
11889   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11890   const ClutterTransformInfo *info;
11891   ClutterActorPrivate *priv;
11892
11893   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11894
11895   priv = self->priv;
11896   info = _clutter_actor_get_transform_info (self);
11897
11898   g_object_freeze_notify (G_OBJECT (self));
11899
11900   clutter_anchor_coord_get_units (self, &info->anchor,
11901                                   &old_anchor_x,
11902                                   &old_anchor_y,
11903                                   NULL);
11904   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11905   clutter_anchor_coord_get_units (self, &info->anchor,
11906                                   &new_anchor_x,
11907                                   &new_anchor_y,
11908                                   NULL);
11909
11910   if (priv->position_set)
11911     clutter_actor_move_by (self,
11912                            new_anchor_x - old_anchor_x,
11913                            new_anchor_y - old_anchor_y);
11914
11915   g_object_thaw_notify (G_OBJECT (self));
11916 }
11917
11918 /**
11919  * clutter_actor_set_anchor_point_from_gravity:
11920  * @self: a #ClutterActor
11921  * @gravity: #ClutterGravity.
11922  *
11923  * Sets an anchor point on the actor, based on the given gravity (this is a
11924  * convenience function wrapping clutter_actor_set_anchor_point()).
11925  *
11926  * Since version 1.0 the anchor point will be stored as a gravity so
11927  * that if the actor changes size then the anchor point will move. For
11928  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11929  * and later double the size of the actor, the anchor point will move
11930  * to the bottom right.
11931  *
11932  * Since: 0.6
11933  */
11934 void
11935 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11936                                              ClutterGravity  gravity)
11937 {
11938   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11939
11940   if (gravity == CLUTTER_GRAVITY_NONE)
11941     clutter_actor_set_anchor_point (self, 0, 0);
11942   else
11943     {
11944       GObject *obj = G_OBJECT (self);
11945       ClutterTransformInfo *info;
11946
11947       g_object_freeze_notify (obj);
11948
11949       info = _clutter_actor_get_transform_info (self);
11950       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11951
11952       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11953       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11954       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11955
11956       self->priv->transform_valid = FALSE;
11957
11958       clutter_actor_queue_redraw (self);
11959
11960       g_object_thaw_notify (obj);
11961     }
11962 }
11963
11964 static void
11965 clutter_container_iface_init (ClutterContainerIface *iface)
11966 {
11967   /* we don't override anything, as ClutterContainer already has a default
11968    * implementation that we can use, and which calls into our own API.
11969    */
11970 }
11971
11972 typedef enum
11973 {
11974   PARSE_X,
11975   PARSE_Y,
11976   PARSE_WIDTH,
11977   PARSE_HEIGHT,
11978   PARSE_ANCHOR_X,
11979   PARSE_ANCHOR_Y
11980 } ParseDimension;
11981
11982 static gfloat
11983 parse_units (ClutterActor   *self,
11984              ParseDimension  dimension,
11985              JsonNode       *node)
11986 {
11987   GValue value = { 0, };
11988   gfloat retval = 0;
11989
11990   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11991     return 0;
11992
11993   json_node_get_value (node, &value);
11994
11995   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11996     {
11997       retval = (gfloat) g_value_get_int64 (&value);
11998     }
11999   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12000     {
12001       retval = g_value_get_double (&value);
12002     }
12003   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12004     {
12005       ClutterUnits units;
12006       gboolean res;
12007
12008       res = clutter_units_from_string (&units, g_value_get_string (&value));
12009       if (res)
12010         retval = clutter_units_to_pixels (&units);
12011       else
12012         {
12013           g_warning ("Invalid value '%s': integers, strings or floating point "
12014                      "values can be used for the x, y, width and height "
12015                      "properties. Valid modifiers for strings are 'px', 'mm', "
12016                      "'pt' and 'em'.",
12017                      g_value_get_string (&value));
12018           retval = 0;
12019         }
12020     }
12021   else
12022     {
12023       g_warning ("Invalid value of type '%s': integers, strings of floating "
12024                  "point values can be used for the x, y, width, height "
12025                  "anchor-x and anchor-y properties.",
12026                  g_type_name (G_VALUE_TYPE (&value)));
12027     }
12028
12029   g_value_unset (&value);
12030
12031   return retval;
12032 }
12033
12034 typedef struct {
12035   ClutterRotateAxis axis;
12036
12037   gdouble angle;
12038
12039   gfloat center_x;
12040   gfloat center_y;
12041   gfloat center_z;
12042 } RotationInfo;
12043
12044 static inline gboolean
12045 parse_rotation_array (ClutterActor *actor,
12046                       JsonArray    *array,
12047                       RotationInfo *info)
12048 {
12049   JsonNode *element;
12050
12051   if (json_array_get_length (array) != 2)
12052     return FALSE;
12053
12054   /* angle */
12055   element = json_array_get_element (array, 0);
12056   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12057     info->angle = json_node_get_double (element);
12058   else
12059     return FALSE;
12060
12061   /* center */
12062   element = json_array_get_element (array, 1);
12063   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12064     {
12065       JsonArray *center = json_node_get_array (element);
12066
12067       if (json_array_get_length (center) != 2)
12068         return FALSE;
12069
12070       switch (info->axis)
12071         {
12072         case CLUTTER_X_AXIS:
12073           info->center_y = parse_units (actor, PARSE_Y,
12074                                         json_array_get_element (center, 0));
12075           info->center_z = parse_units (actor, PARSE_Y,
12076                                         json_array_get_element (center, 1));
12077           return TRUE;
12078
12079         case CLUTTER_Y_AXIS:
12080           info->center_x = parse_units (actor, PARSE_X,
12081                                         json_array_get_element (center, 0));
12082           info->center_z = parse_units (actor, PARSE_X,
12083                                         json_array_get_element (center, 1));
12084           return TRUE;
12085
12086         case CLUTTER_Z_AXIS:
12087           info->center_x = parse_units (actor, PARSE_X,
12088                                         json_array_get_element (center, 0));
12089           info->center_y = parse_units (actor, PARSE_Y,
12090                                         json_array_get_element (center, 1));
12091           return TRUE;
12092         }
12093     }
12094
12095   return FALSE;
12096 }
12097
12098 static gboolean
12099 parse_rotation (ClutterActor *actor,
12100                 JsonNode     *node,
12101                 RotationInfo *info)
12102 {
12103   JsonArray *array;
12104   guint len, i;
12105   gboolean retval = FALSE;
12106
12107   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12108     {
12109       g_warning ("Invalid node of type '%s' found, expecting an array",
12110                  json_node_type_name (node));
12111       return FALSE;
12112     }
12113
12114   array = json_node_get_array (node);
12115   len = json_array_get_length (array);
12116
12117   for (i = 0; i < len; i++)
12118     {
12119       JsonNode *element = json_array_get_element (array, i);
12120       JsonObject *object;
12121       JsonNode *member;
12122
12123       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12124         {
12125           g_warning ("Invalid node of type '%s' found, expecting an object",
12126                      json_node_type_name (element));
12127           return FALSE;
12128         }
12129
12130       object = json_node_get_object (element);
12131
12132       if (json_object_has_member (object, "x-axis"))
12133         {
12134           member = json_object_get_member (object, "x-axis");
12135
12136           info->axis = CLUTTER_X_AXIS;
12137
12138           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12139             {
12140               info->angle = json_node_get_double (member);
12141               retval = TRUE;
12142             }
12143           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12144             retval = parse_rotation_array (actor,
12145                                            json_node_get_array (member),
12146                                            info);
12147           else
12148             retval = FALSE;
12149         }
12150       else if (json_object_has_member (object, "y-axis"))
12151         {
12152           member = json_object_get_member (object, "y-axis");
12153
12154           info->axis = CLUTTER_Y_AXIS;
12155
12156           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12157             {
12158               info->angle = json_node_get_double (member);
12159               retval = TRUE;
12160             }
12161           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12162             retval = parse_rotation_array (actor,
12163                                            json_node_get_array (member),
12164                                            info);
12165           else
12166             retval = FALSE;
12167         }
12168       else if (json_object_has_member (object, "z-axis"))
12169         {
12170           member = json_object_get_member (object, "z-axis");
12171
12172           info->axis = CLUTTER_Z_AXIS;
12173
12174           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12175             {
12176               info->angle = json_node_get_double (member);
12177               retval = TRUE;
12178             }
12179           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12180             retval = parse_rotation_array (actor,
12181                                            json_node_get_array (member),
12182                                            info);
12183           else
12184             retval = FALSE;
12185         }
12186     }
12187
12188   return retval;
12189 }
12190
12191 static GSList *
12192 parse_actor_metas (ClutterScript *script,
12193                    ClutterActor  *actor,
12194                    JsonNode      *node)
12195 {
12196   GList *elements, *l;
12197   GSList *retval = NULL;
12198
12199   if (!JSON_NODE_HOLDS_ARRAY (node))
12200     return NULL;
12201
12202   elements = json_array_get_elements (json_node_get_array (node));
12203
12204   for (l = elements; l != NULL; l = l->next)
12205     {
12206       JsonNode *element = l->data;
12207       const gchar *id_ = _clutter_script_get_id_from_node (element);
12208       GObject *meta;
12209
12210       if (id_ == NULL || *id_ == '\0')
12211         continue;
12212
12213       meta = clutter_script_get_object (script, id_);
12214       if (meta == NULL)
12215         continue;
12216
12217       retval = g_slist_prepend (retval, meta);
12218     }
12219
12220   g_list_free (elements);
12221
12222   return g_slist_reverse (retval);
12223 }
12224
12225 static GSList *
12226 parse_behaviours (ClutterScript *script,
12227                   ClutterActor  *actor,
12228                   JsonNode      *node)
12229 {
12230   GList *elements, *l;
12231   GSList *retval = NULL;
12232
12233   if (!JSON_NODE_HOLDS_ARRAY (node))
12234     return NULL;
12235
12236   elements = json_array_get_elements (json_node_get_array (node));
12237
12238   for (l = elements; l != NULL; l = l->next)
12239     {
12240       JsonNode *element = l->data;
12241       const gchar *id_ = _clutter_script_get_id_from_node (element);
12242       GObject *behaviour;
12243
12244       if (id_ == NULL || *id_ == '\0')
12245         continue;
12246
12247       behaviour = clutter_script_get_object (script, id_);
12248       if (behaviour == NULL)
12249         continue;
12250
12251       retval = g_slist_prepend (retval, behaviour);
12252     }
12253
12254   g_list_free (elements);
12255
12256   return g_slist_reverse (retval);
12257 }
12258
12259 static gboolean
12260 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12261                                  ClutterScript     *script,
12262                                  GValue            *value,
12263                                  const gchar       *name,
12264                                  JsonNode          *node)
12265 {
12266   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12267   gboolean retval = FALSE;
12268
12269   if ((name[0] == 'x' && name[1] == '\0') ||
12270       (name[0] == 'y' && name[1] == '\0') ||
12271       (strcmp (name, "width") == 0) ||
12272       (strcmp (name, "height") == 0) ||
12273       (strcmp (name, "anchor_x") == 0) ||
12274       (strcmp (name, "anchor_y") == 0))
12275     {
12276       ParseDimension dimension;
12277       gfloat units;
12278
12279       if (name[0] == 'x')
12280         dimension = PARSE_X;
12281       else if (name[0] == 'y')
12282         dimension = PARSE_Y;
12283       else if (name[0] == 'w')
12284         dimension = PARSE_WIDTH;
12285       else if (name[0] == 'h')
12286         dimension = PARSE_HEIGHT;
12287       else if (name[0] == 'a' && name[7] == 'x')
12288         dimension = PARSE_ANCHOR_X;
12289       else if (name[0] == 'a' && name[7] == 'y')
12290         dimension = PARSE_ANCHOR_Y;
12291       else
12292         return FALSE;
12293
12294       units = parse_units (actor, dimension, node);
12295
12296       /* convert back to pixels: all properties are pixel-based */
12297       g_value_init (value, G_TYPE_FLOAT);
12298       g_value_set_float (value, units);
12299
12300       retval = TRUE;
12301     }
12302   else if (strcmp (name, "rotation") == 0)
12303     {
12304       RotationInfo *info;
12305
12306       info = g_slice_new0 (RotationInfo);
12307       retval = parse_rotation (actor, node, info);
12308
12309       if (retval)
12310         {
12311           g_value_init (value, G_TYPE_POINTER);
12312           g_value_set_pointer (value, info);
12313         }
12314       else
12315         g_slice_free (RotationInfo, info);
12316     }
12317   else if (strcmp (name, "behaviours") == 0)
12318     {
12319       GSList *l;
12320
12321 #ifdef CLUTTER_ENABLE_DEBUG
12322       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12323         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12324                                      "and it should not be used in newly "
12325                                      "written ClutterScript definitions.");
12326 #endif
12327
12328       l = parse_behaviours (script, actor, node);
12329
12330       g_value_init (value, G_TYPE_POINTER);
12331       g_value_set_pointer (value, l);
12332
12333       retval = TRUE;
12334     }
12335   else if (strcmp (name, "actions") == 0 ||
12336            strcmp (name, "constraints") == 0 ||
12337            strcmp (name, "effects") == 0)
12338     {
12339       GSList *l;
12340
12341       l = parse_actor_metas (script, actor, node);
12342
12343       g_value_init (value, G_TYPE_POINTER);
12344       g_value_set_pointer (value, l);
12345
12346       retval = TRUE;
12347     }
12348
12349   return retval;
12350 }
12351
12352 static void
12353 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12354                                    ClutterScript     *script,
12355                                    const gchar       *name,
12356                                    const GValue      *value)
12357 {
12358   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12359
12360 #ifdef CLUTTER_ENABLE_DEBUG
12361   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12362     {
12363       gchar *tmp = g_strdup_value_contents (value);
12364
12365       CLUTTER_NOTE (SCRIPT,
12366                     "in ClutterActor::set_custom_property('%s') = %s",
12367                     name,
12368                     tmp);
12369
12370       g_free (tmp);
12371     }
12372 #endif /* CLUTTER_ENABLE_DEBUG */
12373
12374   if (strcmp (name, "rotation") == 0)
12375     {
12376       RotationInfo *info;
12377
12378       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12379         return;
12380
12381       info = g_value_get_pointer (value);
12382
12383       clutter_actor_set_rotation (actor,
12384                                   info->axis, info->angle,
12385                                   info->center_x,
12386                                   info->center_y,
12387                                   info->center_z);
12388
12389       g_slice_free (RotationInfo, info);
12390
12391       return;
12392     }
12393
12394   if (strcmp (name, "behaviours") == 0)
12395     {
12396       GSList *behaviours, *l;
12397
12398       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12399         return;
12400
12401       behaviours = g_value_get_pointer (value);
12402       for (l = behaviours; l != NULL; l = l->next)
12403         {
12404           ClutterBehaviour *behaviour = l->data;
12405
12406           clutter_behaviour_apply (behaviour, actor);
12407         }
12408
12409       g_slist_free (behaviours);
12410
12411       return;
12412     }
12413
12414   if (strcmp (name, "actions") == 0 ||
12415       strcmp (name, "constraints") == 0 ||
12416       strcmp (name, "effects") == 0)
12417     {
12418       GSList *metas, *l;
12419
12420       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12421         return;
12422
12423       metas = g_value_get_pointer (value);
12424       for (l = metas; l != NULL; l = l->next)
12425         {
12426           if (name[0] == 'a')
12427             clutter_actor_add_action (actor, l->data);
12428
12429           if (name[0] == 'c')
12430             clutter_actor_add_constraint (actor, l->data);
12431
12432           if (name[0] == 'e')
12433             clutter_actor_add_effect (actor, l->data);
12434         }
12435
12436       g_slist_free (metas);
12437
12438       return;
12439     }
12440
12441   g_object_set_property (G_OBJECT (scriptable), name, value);
12442 }
12443
12444 static void
12445 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12446 {
12447   iface->parse_custom_node = clutter_actor_parse_custom_node;
12448   iface->set_custom_property = clutter_actor_set_custom_property;
12449 }
12450
12451 static ClutterActorMeta *
12452 get_meta_from_animation_property (ClutterActor  *actor,
12453                                   const gchar   *name,
12454                                   gchar        **name_p)
12455 {
12456   ClutterActorPrivate *priv = actor->priv;
12457   ClutterActorMeta *meta = NULL;
12458   gchar **tokens;
12459
12460   /* if this is not a special property, fall through */
12461   if (name[0] != '@')
12462     return NULL;
12463
12464   /* detect the properties named using the following spec:
12465    *
12466    *   @<section>.<meta-name>.<property-name>
12467    *
12468    * where <section> can be one of the following:
12469    *
12470    *   - actions
12471    *   - constraints
12472    *   - effects
12473    *
12474    * and <meta-name> is the name set on a specific ActorMeta
12475    */
12476
12477   tokens = g_strsplit (name + 1, ".", -1);
12478   if (tokens == NULL || g_strv_length (tokens) != 3)
12479     {
12480       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12481                     name + 1);
12482       g_strfreev (tokens);
12483       return NULL;
12484     }
12485
12486   if (strcmp (tokens[0], "actions") == 0)
12487     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12488
12489   if (strcmp (tokens[0], "constraints") == 0)
12490     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12491
12492   if (strcmp (tokens[0], "effects") == 0)
12493     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12494
12495   if (name_p != NULL)
12496     *name_p = g_strdup (tokens[2]);
12497
12498   CLUTTER_NOTE (ANIMATION,
12499                 "Looking for property '%s' of object '%s' in section '%s'",
12500                 tokens[2],
12501                 tokens[1],
12502                 tokens[0]);
12503
12504   g_strfreev (tokens);
12505
12506   return meta;
12507 }
12508
12509 static GParamSpec *
12510 clutter_actor_find_property (ClutterAnimatable *animatable,
12511                              const gchar       *property_name)
12512 {
12513   ClutterActorMeta *meta = NULL;
12514   GObjectClass *klass = NULL;
12515   GParamSpec *pspec = NULL;
12516   gchar *p_name = NULL;
12517
12518   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12519                                            property_name,
12520                                            &p_name);
12521
12522   if (meta != NULL)
12523     {
12524       klass = G_OBJECT_GET_CLASS (meta);
12525
12526       pspec = g_object_class_find_property (klass, p_name);
12527     }
12528   else
12529     {
12530       klass = G_OBJECT_GET_CLASS (animatable);
12531
12532       pspec = g_object_class_find_property (klass, property_name);
12533     }
12534
12535   g_free (p_name);
12536
12537   return pspec;
12538 }
12539
12540 static void
12541 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12542                                  const gchar       *property_name,
12543                                  GValue            *initial)
12544 {
12545   ClutterActorMeta *meta = NULL;
12546   gchar *p_name = NULL;
12547
12548   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12549                                            property_name,
12550                                            &p_name);
12551
12552   if (meta != NULL)
12553     g_object_get_property (G_OBJECT (meta), p_name, initial);
12554   else
12555     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12556
12557   g_free (p_name);
12558 }
12559
12560 /*
12561  * clutter_actor_set_animatable_property:
12562  * @actor: a #ClutterActor
12563  * @prop_id: the paramspec id
12564  * @value: the value to set
12565  * @pspec: the paramspec
12566  *
12567  * Sets values of animatable properties.
12568  *
12569  * This is a variant of clutter_actor_set_property() that gets called
12570  * by the #ClutterAnimatable implementation of #ClutterActor for the
12571  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12572  * #GParamSpec.
12573  *
12574  * Unlike the implementation of #GObjectClass.set_property(), this
12575  * function will not update the interval if a transition involving an
12576  * animatable property is in progress - this avoids cycles with the
12577  * transition API calling the public API.
12578  */
12579 static void
12580 clutter_actor_set_animatable_property (ClutterActor *actor,
12581                                        guint         prop_id,
12582                                        const GValue *value,
12583                                        GParamSpec   *pspec)
12584 {
12585   switch (prop_id)
12586     {
12587     case PROP_X:
12588       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12589       break;
12590
12591     case PROP_Y:
12592       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12593       break;
12594
12595     case PROP_WIDTH:
12596       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12597       break;
12598
12599     case PROP_HEIGHT:
12600       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12601       break;
12602
12603     case PROP_DEPTH:
12604       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12605       break;
12606
12607     case PROP_OPACITY:
12608       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12609       break;
12610
12611     case PROP_BACKGROUND_COLOR:
12612       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12613       break;
12614
12615     case PROP_SCALE_X:
12616       clutter_actor_set_scale_factor_internal (actor,
12617                                                g_value_get_double (value),
12618                                                pspec);
12619       break;
12620
12621     case PROP_SCALE_Y:
12622       clutter_actor_set_scale_factor_internal (actor,
12623                                                g_value_get_double (value),
12624                                                pspec);
12625       break;
12626
12627     case PROP_ROTATION_ANGLE_X:
12628       clutter_actor_set_rotation_angle_internal (actor,
12629                                                  CLUTTER_X_AXIS,
12630                                                  g_value_get_double (value));
12631       break;
12632
12633     case PROP_ROTATION_ANGLE_Y:
12634       clutter_actor_set_rotation_angle_internal (actor,
12635                                                  CLUTTER_Y_AXIS,
12636                                                  g_value_get_double (value));
12637       break;
12638
12639     case PROP_ROTATION_ANGLE_Z:
12640       clutter_actor_set_rotation_angle_internal (actor,
12641                                                  CLUTTER_Z_AXIS,
12642                                                  g_value_get_double (value));
12643       break;
12644
12645     default:
12646       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12647       break;
12648     }
12649 }
12650
12651 static void
12652 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12653                                const gchar       *property_name,
12654                                const GValue      *final)
12655 {
12656   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12657   ClutterActorMeta *meta = NULL;
12658   gchar *p_name = NULL;
12659
12660   meta = get_meta_from_animation_property (actor,
12661                                            property_name,
12662                                            &p_name);
12663   if (meta != NULL)
12664     g_object_set_property (G_OBJECT (meta), p_name, final);
12665   else
12666     {
12667       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12668       GParamSpec *pspec;
12669
12670       pspec = g_object_class_find_property (obj_class, property_name);
12671
12672       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12673         {
12674           /* XXX - I'm going to the special hell for this */
12675           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12676         }
12677       else
12678         g_object_set_property (G_OBJECT (animatable), property_name, final);
12679     }
12680
12681   g_free (p_name);
12682 }
12683
12684 static void
12685 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12686 {
12687   iface->find_property = clutter_actor_find_property;
12688   iface->get_initial_state = clutter_actor_get_initial_state;
12689   iface->set_final_state = clutter_actor_set_final_state;
12690 }
12691
12692 /**
12693  * clutter_actor_transform_stage_point:
12694  * @self: A #ClutterActor
12695  * @x: (in): x screen coordinate of the point to unproject
12696  * @y: (in): y screen coordinate of the point to unproject
12697  * @x_out: (out): return location for the unprojected x coordinance
12698  * @y_out: (out): return location for the unprojected y coordinance
12699  *
12700  * This function translates screen coordinates (@x, @y) to
12701  * coordinates relative to the actor. For example, it can be used to translate
12702  * screen events from global screen coordinates into actor-local coordinates.
12703  *
12704  * The conversion can fail, notably if the transform stack results in the
12705  * actor being projected on the screen as a mere line.
12706  *
12707  * The conversion should not be expected to be pixel-perfect due to the
12708  * nature of the operation. In general the error grows when the skewing
12709  * of the actor rectangle on screen increases.
12710  *
12711  * <note><para>This function can be computationally intensive.</para></note>
12712  *
12713  * <note><para>This function only works when the allocation is up-to-date,
12714  * i.e. inside of paint().</para></note>
12715  *
12716  * Return value: %TRUE if conversion was successful.
12717  *
12718  * Since: 0.6
12719  */
12720 gboolean
12721 clutter_actor_transform_stage_point (ClutterActor *self,
12722                                      gfloat        x,
12723                                      gfloat        y,
12724                                      gfloat       *x_out,
12725                                      gfloat       *y_out)
12726 {
12727   ClutterVertex v[4];
12728   float ST[3][3];
12729   float RQ[3][3];
12730   int du, dv, xi, yi;
12731   float px, py;
12732   float xf, yf, wf, det;
12733   ClutterActorPrivate *priv;
12734
12735   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12736
12737   priv = self->priv;
12738
12739   /* This implementation is based on the quad -> quad projection algorithm
12740    * described by Paul Heckbert in:
12741    *
12742    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12743    *
12744    * and the sample implementation at:
12745    *
12746    *   http://www.cs.cmu.edu/~ph/src/texfund/
12747    *
12748    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12749    * quad to rectangle only, which significantly simplifies things; the
12750    * function calls have been unrolled, and most of the math is done in fixed
12751    * point.
12752    */
12753
12754   clutter_actor_get_abs_allocation_vertices (self, v);
12755
12756   /* Keeping these as ints simplifies the multiplication (no significant
12757    * loss of precision here).
12758    */
12759   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12760   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12761
12762   if (!du || !dv)
12763     return FALSE;
12764
12765 #define UX2FP(x)        (x)
12766 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12767
12768   /* First, find mapping from unit uv square to xy quadrilateral; this
12769    * equivalent to the pmap_square_quad() functions in the sample
12770    * implementation, which we can simplify, since our target is always
12771    * a rectangle.
12772    */
12773   px = v[0].x - v[1].x + v[3].x - v[2].x;
12774   py = v[0].y - v[1].y + v[3].y - v[2].y;
12775
12776   if (!px && !py)
12777     {
12778       /* affine transform */
12779       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12780       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12781       RQ[2][0] = UX2FP (v[0].x);
12782       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12783       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12784       RQ[2][1] = UX2FP (v[0].y);
12785       RQ[0][2] = 0;
12786       RQ[1][2] = 0;
12787       RQ[2][2] = 1.0;
12788     }
12789   else
12790     {
12791       /* projective transform */
12792       double dx1, dx2, dy1, dy2, del;
12793
12794       dx1 = UX2FP (v[1].x - v[3].x);
12795       dx2 = UX2FP (v[2].x - v[3].x);
12796       dy1 = UX2FP (v[1].y - v[3].y);
12797       dy2 = UX2FP (v[2].y - v[3].y);
12798
12799       del = DET2FP (dx1, dx2, dy1, dy2);
12800       if (!del)
12801         return FALSE;
12802
12803       /*
12804        * The division here needs to be done in floating point for
12805        * precisions reasons.
12806        */
12807       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12808       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12809       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12810       RQ[2][2] = 1.0;
12811       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12812       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12813       RQ[2][0] = UX2FP (v[0].x);
12814       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12815       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12816       RQ[2][1] = UX2FP (v[0].y);
12817     }
12818
12819   /*
12820    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12821    * square. Since our rectangle is based at 0,0 we only need to scale.
12822    */
12823   RQ[0][0] /= du;
12824   RQ[1][0] /= dv;
12825   RQ[0][1] /= du;
12826   RQ[1][1] /= dv;
12827   RQ[0][2] /= du;
12828   RQ[1][2] /= dv;
12829
12830   /*
12831    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12832    * inverse of that.
12833    */
12834   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12835   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12836   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12837   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12838   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12839   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12840   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12841   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12842   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12843
12844   /*
12845    * Check the resulting matrix is OK.
12846    */
12847   det = (RQ[0][0] * ST[0][0])
12848       + (RQ[0][1] * ST[0][1])
12849       + (RQ[0][2] * ST[0][2]);
12850   if (!det)
12851     return FALSE;
12852
12853   /*
12854    * Now transform our point with the ST matrix; the notional w
12855    * coordinate is 1, hence the last part is simply added.
12856    */
12857   xi = (int) x;
12858   yi = (int) y;
12859
12860   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12861   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12862   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12863
12864   if (x_out)
12865     *x_out = xf / wf;
12866
12867   if (y_out)
12868     *y_out = yf / wf;
12869
12870 #undef UX2FP
12871 #undef DET2FP
12872
12873   return TRUE;
12874 }
12875
12876 /*
12877  * ClutterGeometry
12878  */
12879
12880 static ClutterGeometry*
12881 clutter_geometry_copy (const ClutterGeometry *geometry)
12882 {
12883   return g_slice_dup (ClutterGeometry, geometry);
12884 }
12885
12886 static void
12887 clutter_geometry_free (ClutterGeometry *geometry)
12888 {
12889   if (G_LIKELY (geometry != NULL))
12890     g_slice_free (ClutterGeometry, geometry);
12891 }
12892
12893 /**
12894  * clutter_geometry_union:
12895  * @geometry_a: a #ClutterGeometry
12896  * @geometry_b: another #ClutterGeometry
12897  * @result: (out): location to store the result
12898  *
12899  * Find the union of two rectangles represented as #ClutterGeometry.
12900  *
12901  * Since: 1.4
12902  */
12903 void
12904 clutter_geometry_union (const ClutterGeometry *geometry_a,
12905                         const ClutterGeometry *geometry_b,
12906                         ClutterGeometry       *result)
12907 {
12908   /* We don't try to handle rectangles that can't be represented
12909    * as a signed integer box */
12910   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12911   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12912   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12913                   geometry_b->x + (gint)geometry_b->width);
12914   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12915                   geometry_b->y + (gint)geometry_b->height);
12916   result->x = x_1;
12917   result->y = y_1;
12918   result->width = x_2 - x_1;
12919   result->height = y_2 - y_1;
12920 }
12921
12922 /**
12923  * clutter_geometry_intersects:
12924  * @geometry0: The first geometry to test
12925  * @geometry1: The second geometry to test
12926  *
12927  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12928  * they do else %FALSE.
12929  *
12930  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12931  * %FALSE.
12932  *
12933  * Since: 1.4
12934  */
12935 gboolean
12936 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12937                              const ClutterGeometry *geometry1)
12938 {
12939   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12940       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12941       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12942       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12943     return FALSE;
12944   else
12945     return TRUE;
12946 }
12947
12948 static gboolean
12949 clutter_geometry_progress (const GValue *a,
12950                            const GValue *b,
12951                            gdouble       progress,
12952                            GValue       *retval)
12953 {
12954   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12955   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12956   ClutterGeometry res = { 0, };
12957   gint a_width = a_geom->width;
12958   gint b_width = b_geom->width;
12959   gint a_height = a_geom->height;
12960   gint b_height = b_geom->height;
12961
12962   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12963   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12964
12965   res.width = a_width + (b_width - a_width) * progress;
12966   res.height = a_height + (b_height - a_height) * progress;
12967
12968   g_value_set_boxed (retval, &res);
12969
12970   return TRUE;
12971 }
12972
12973 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12974                                clutter_geometry_copy,
12975                                clutter_geometry_free,
12976                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12977
12978 /*
12979  * ClutterVertices
12980  */
12981
12982 /**
12983  * clutter_vertex_new:
12984  * @x: X coordinate
12985  * @y: Y coordinate
12986  * @z: Z coordinate
12987  *
12988  * Creates a new #ClutterVertex for the point in 3D space
12989  * identified by the 3 coordinates @x, @y, @z
12990  *
12991  * Return value: the newly allocate #ClutterVertex. Use
12992  *   clutter_vertex_free() to free the resources
12993  *
12994  * Since: 1.0
12995  */
12996 ClutterVertex *
12997 clutter_vertex_new (gfloat x,
12998                     gfloat y,
12999                     gfloat z)
13000 {
13001   ClutterVertex *vertex;
13002
13003   vertex = g_slice_new (ClutterVertex);
13004   vertex->x = x;
13005   vertex->y = y;
13006   vertex->z = z;
13007
13008   return vertex;
13009 }
13010
13011 /**
13012  * clutter_vertex_copy:
13013  * @vertex: a #ClutterVertex
13014  *
13015  * Copies @vertex
13016  *
13017  * Return value: a newly allocated copy of #ClutterVertex. Use
13018  *   clutter_vertex_free() to free the allocated resources
13019  *
13020  * Since: 1.0
13021  */
13022 ClutterVertex *
13023 clutter_vertex_copy (const ClutterVertex *vertex)
13024 {
13025   if (G_LIKELY (vertex != NULL))
13026     return g_slice_dup (ClutterVertex, vertex);
13027
13028   return NULL;
13029 }
13030
13031 /**
13032  * clutter_vertex_free:
13033  * @vertex: a #ClutterVertex
13034  *
13035  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13036  *
13037  * Since: 1.0
13038  */
13039 void
13040 clutter_vertex_free (ClutterVertex *vertex)
13041 {
13042   if (G_UNLIKELY (vertex != NULL))
13043     g_slice_free (ClutterVertex, vertex);
13044 }
13045
13046 /**
13047  * clutter_vertex_equal:
13048  * @vertex_a: a #ClutterVertex
13049  * @vertex_b: a #ClutterVertex
13050  *
13051  * Compares @vertex_a and @vertex_b for equality
13052  *
13053  * Return value: %TRUE if the passed #ClutterVertex are equal
13054  *
13055  * Since: 1.0
13056  */
13057 gboolean
13058 clutter_vertex_equal (const ClutterVertex *vertex_a,
13059                       const ClutterVertex *vertex_b)
13060 {
13061   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13062
13063   if (vertex_a == vertex_b)
13064     return TRUE;
13065
13066   return vertex_a->x == vertex_b->x &&
13067          vertex_a->y == vertex_b->y &&
13068          vertex_a->z == vertex_b->z;
13069 }
13070
13071 static gboolean
13072 clutter_vertex_progress (const GValue *a,
13073                          const GValue *b,
13074                          gdouble       progress,
13075                          GValue       *retval)
13076 {
13077   const ClutterVertex *av = g_value_get_boxed (a);
13078   const ClutterVertex *bv = g_value_get_boxed (b);
13079   ClutterVertex res = { 0, };
13080
13081   res.x = av->x + (bv->x - av->x) * progress;
13082   res.y = av->y + (bv->y - av->y) * progress;
13083   res.z = av->z + (bv->z - av->z) * progress;
13084
13085   g_value_set_boxed (retval, &res);
13086
13087   return TRUE;
13088 }
13089
13090 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13091                                clutter_vertex_copy,
13092                                clutter_vertex_free,
13093                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13094
13095 /**
13096  * clutter_actor_is_rotated:
13097  * @self: a #ClutterActor
13098  *
13099  * Checks whether any rotation is applied to the actor.
13100  *
13101  * Return value: %TRUE if the actor is rotated.
13102  *
13103  * Since: 0.6
13104  */
13105 gboolean
13106 clutter_actor_is_rotated (ClutterActor *self)
13107 {
13108   const ClutterTransformInfo *info;
13109
13110   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13111
13112   info = _clutter_actor_get_transform_info_or_defaults (self);
13113
13114   if (info->rx_angle || info->ry_angle || info->rz_angle)
13115     return TRUE;
13116
13117   return FALSE;
13118 }
13119
13120 /**
13121  * clutter_actor_is_scaled:
13122  * @self: a #ClutterActor
13123  *
13124  * Checks whether the actor is scaled in either dimension.
13125  *
13126  * Return value: %TRUE if the actor is scaled.
13127  *
13128  * Since: 0.6
13129  */
13130 gboolean
13131 clutter_actor_is_scaled (ClutterActor *self)
13132 {
13133   const ClutterTransformInfo *info;
13134
13135   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13136
13137   info = _clutter_actor_get_transform_info_or_defaults (self);
13138
13139   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13140     return TRUE;
13141
13142   return FALSE;
13143 }
13144
13145 ClutterActor *
13146 _clutter_actor_get_stage_internal (ClutterActor *actor)
13147 {
13148   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13149     actor = actor->priv->parent;
13150
13151   return actor;
13152 }
13153
13154 /**
13155  * clutter_actor_get_stage:
13156  * @actor: a #ClutterActor
13157  *
13158  * Retrieves the #ClutterStage where @actor is contained.
13159  *
13160  * Return value: (transfer none) (type Clutter.Stage): the stage
13161  *   containing the actor, or %NULL
13162  *
13163  * Since: 0.8
13164  */
13165 ClutterActor *
13166 clutter_actor_get_stage (ClutterActor *actor)
13167 {
13168   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13169
13170   return _clutter_actor_get_stage_internal (actor);
13171 }
13172
13173 /**
13174  * clutter_actor_allocate_available_size:
13175  * @self: a #ClutterActor
13176  * @x: the actor's X coordinate
13177  * @y: the actor's Y coordinate
13178  * @available_width: the maximum available width, or -1 to use the
13179  *   actor's natural width
13180  * @available_height: the maximum available height, or -1 to use the
13181  *   actor's natural height
13182  * @flags: flags controlling the allocation
13183  *
13184  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13185  * preferred size, but limiting it to the maximum available width
13186  * and height provided.
13187  *
13188  * This function will do the right thing when dealing with the
13189  * actor's request mode.
13190  *
13191  * The implementation of this function is equivalent to:
13192  *
13193  * |[
13194  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13195  *     {
13196  *       clutter_actor_get_preferred_width (self, available_height,
13197  *                                          &amp;min_width,
13198  *                                          &amp;natural_width);
13199  *       width = CLAMP (natural_width, min_width, available_width);
13200  *
13201  *       clutter_actor_get_preferred_height (self, width,
13202  *                                           &amp;min_height,
13203  *                                           &amp;natural_height);
13204  *       height = CLAMP (natural_height, min_height, available_height);
13205  *     }
13206  *   else
13207  *     {
13208  *       clutter_actor_get_preferred_height (self, available_width,
13209  *                                           &amp;min_height,
13210  *                                           &amp;natural_height);
13211  *       height = CLAMP (natural_height, min_height, available_height);
13212  *
13213  *       clutter_actor_get_preferred_width (self, height,
13214  *                                          &amp;min_width,
13215  *                                          &amp;natural_width);
13216  *       width = CLAMP (natural_width, min_width, available_width);
13217  *     }
13218  *
13219  *   box.x1 = x; box.y1 = y;
13220  *   box.x2 = box.x1 + available_width;
13221  *   box.y2 = box.y1 + available_height;
13222  *   clutter_actor_allocate (self, &amp;box, flags);
13223  * ]|
13224  *
13225  * This function can be used by fluid layout managers to allocate
13226  * an actor's preferred size without making it bigger than the area
13227  * available for the container.
13228  *
13229  * Since: 1.0
13230  */
13231 void
13232 clutter_actor_allocate_available_size (ClutterActor           *self,
13233                                        gfloat                  x,
13234                                        gfloat                  y,
13235                                        gfloat                  available_width,
13236                                        gfloat                  available_height,
13237                                        ClutterAllocationFlags  flags)
13238 {
13239   ClutterActorPrivate *priv;
13240   gfloat width, height;
13241   gfloat min_width, min_height;
13242   gfloat natural_width, natural_height;
13243   ClutterActorBox box;
13244
13245   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13246
13247   priv = self->priv;
13248
13249   width = height = 0.0;
13250
13251   switch (priv->request_mode)
13252     {
13253     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13254       clutter_actor_get_preferred_width (self, available_height,
13255                                          &min_width,
13256                                          &natural_width);
13257       width  = CLAMP (natural_width, min_width, available_width);
13258
13259       clutter_actor_get_preferred_height (self, width,
13260                                           &min_height,
13261                                           &natural_height);
13262       height = CLAMP (natural_height, min_height, available_height);
13263       break;
13264
13265     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13266       clutter_actor_get_preferred_height (self, available_width,
13267                                           &min_height,
13268                                           &natural_height);
13269       height = CLAMP (natural_height, min_height, available_height);
13270
13271       clutter_actor_get_preferred_width (self, height,
13272                                          &min_width,
13273                                          &natural_width);
13274       width  = CLAMP (natural_width, min_width, available_width);
13275       break;
13276     }
13277
13278
13279   box.x1 = x;
13280   box.y1 = y;
13281   box.x2 = box.x1 + width;
13282   box.y2 = box.y1 + height;
13283   clutter_actor_allocate (self, &box, flags);
13284 }
13285
13286 /**
13287  * clutter_actor_allocate_preferred_size:
13288  * @self: a #ClutterActor
13289  * @flags: flags controlling the allocation
13290  *
13291  * Allocates the natural size of @self.
13292  *
13293  * This function is a utility call for #ClutterActor implementations
13294  * that allocates the actor's preferred natural size. It can be used
13295  * by fixed layout managers (like #ClutterGroup or so called
13296  * 'composite actors') inside the ClutterActor::allocate
13297  * implementation to give each child exactly how much space it
13298  * requires.
13299  *
13300  * This function is not meant to be used by applications. It is also
13301  * not meant to be used outside the implementation of the
13302  * ClutterActor::allocate virtual function.
13303  *
13304  * Since: 0.8
13305  */
13306 void
13307 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13308                                        ClutterAllocationFlags  flags)
13309 {
13310   gfloat actor_x, actor_y;
13311   gfloat natural_width, natural_height;
13312   ClutterActorBox actor_box;
13313
13314   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13315
13316   actor_x = clutter_actor_get_x (self);
13317   actor_y = clutter_actor_get_y (self);
13318
13319   clutter_actor_get_preferred_size (self,
13320                                     NULL, NULL,
13321                                     &natural_width,
13322                                     &natural_height);
13323
13324   actor_box.x1 = actor_x;
13325   actor_box.y1 = actor_y;
13326   actor_box.x2 = actor_box.x1 + natural_width;
13327   actor_box.y2 = actor_box.y1 + natural_height;
13328
13329   clutter_actor_allocate (self, &actor_box, flags);
13330 }
13331
13332 /**
13333  * clutter_actor_allocate_align_fill:
13334  * @self: a #ClutterActor
13335  * @box: a #ClutterActorBox, containing the available width and height
13336  * @x_align: the horizontal alignment, between 0 and 1
13337  * @y_align: the vertical alignment, between 0 and 1
13338  * @x_fill: whether the actor should fill horizontally
13339  * @y_fill: whether the actor should fill vertically
13340  * @flags: allocation flags to be passed to clutter_actor_allocate()
13341  *
13342  * Allocates @self by taking into consideration the available allocation
13343  * area; an alignment factor on either axis; and whether the actor should
13344  * fill the allocation on either axis.
13345  *
13346  * The @box should contain the available allocation width and height;
13347  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13348  * allocation will be offset by their value.
13349  *
13350  * This function takes into consideration the geometry request specified by
13351  * the #ClutterActor:request-mode property, and the text direction.
13352  *
13353  * This function is useful for fluid layout managers, like #ClutterBinLayout
13354  * or #ClutterTableLayout
13355  *
13356  * Since: 1.4
13357  */
13358 void
13359 clutter_actor_allocate_align_fill (ClutterActor           *self,
13360                                    const ClutterActorBox  *box,
13361                                    gdouble                 x_align,
13362                                    gdouble                 y_align,
13363                                    gboolean                x_fill,
13364                                    gboolean                y_fill,
13365                                    ClutterAllocationFlags  flags)
13366 {
13367   ClutterActorPrivate *priv;
13368   ClutterActorBox allocation = { 0, };
13369   gfloat x_offset, y_offset;
13370   gfloat available_width, available_height;
13371   gfloat child_width, child_height;
13372
13373   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13374   g_return_if_fail (box != NULL);
13375   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13376   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13377
13378   priv = self->priv;
13379
13380   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13381   clutter_actor_box_get_size (box, &available_width, &available_height);
13382
13383   if (available_width < 0)
13384     available_width = 0;
13385
13386   if (available_height < 0)
13387     available_height = 0;
13388
13389   if (x_fill)
13390     {
13391       allocation.x1 = x_offset;
13392       allocation.x2 = allocation.x1 + available_width;
13393     }
13394
13395   if (y_fill)
13396     {
13397       allocation.y1 = y_offset;
13398       allocation.y2 = allocation.y1 + available_height;
13399     }
13400
13401   /* if we are filling horizontally and vertically then we're done */
13402   if (x_fill && y_fill)
13403     goto out;
13404
13405   child_width = child_height = 0.0f;
13406
13407   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13408     {
13409       gfloat min_width, natural_width;
13410       gfloat min_height, natural_height;
13411
13412       clutter_actor_get_preferred_width (self, available_height,
13413                                          &min_width,
13414                                          &natural_width);
13415
13416       child_width = CLAMP (natural_width, min_width, available_width);
13417
13418       if (!y_fill)
13419         {
13420           clutter_actor_get_preferred_height (self, child_width,
13421                                               &min_height,
13422                                               &natural_height);
13423
13424           child_height = CLAMP (natural_height, min_height, available_height);
13425         }
13426     }
13427   else
13428     {
13429       gfloat min_width, natural_width;
13430       gfloat min_height, natural_height;
13431
13432       clutter_actor_get_preferred_height (self, available_width,
13433                                           &min_height,
13434                                           &natural_height);
13435
13436       child_height = CLAMP (natural_height, min_height, available_height);
13437
13438       if (!x_fill)
13439         {
13440           clutter_actor_get_preferred_width (self, child_height,
13441                                              &min_width,
13442                                              &natural_width);
13443
13444           child_width = CLAMP (natural_width, min_width, available_width);
13445         }
13446     }
13447
13448   /* invert the horizontal alignment for RTL languages */
13449   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13450     x_align = 1.0 - x_align;
13451
13452   if (!x_fill)
13453     {
13454       allocation.x1 = x_offset
13455                     + ((available_width - child_width) * x_align);
13456       allocation.x2 = allocation.x1 + child_width;
13457     }
13458
13459   if (!y_fill)
13460     {
13461       allocation.y1 = y_offset
13462                     + ((available_height - child_height) * y_align);
13463       allocation.y2 = allocation.y1 + child_height;
13464     }
13465
13466 out:
13467   clutter_actor_box_clamp_to_pixel (&allocation);
13468   clutter_actor_allocate (self, &allocation, flags);
13469 }
13470
13471 /**
13472  * clutter_actor_grab_key_focus:
13473  * @self: a #ClutterActor
13474  *
13475  * Sets the key focus of the #ClutterStage including @self
13476  * to this #ClutterActor.
13477  *
13478  * Since: 1.0
13479  */
13480 void
13481 clutter_actor_grab_key_focus (ClutterActor *self)
13482 {
13483   ClutterActor *stage;
13484
13485   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13486
13487   stage = _clutter_actor_get_stage_internal (self);
13488   if (stage != NULL)
13489     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13490 }
13491
13492 /**
13493  * clutter_actor_get_pango_context:
13494  * @self: a #ClutterActor
13495  *
13496  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13497  * is already configured using the appropriate font map, resolution
13498  * and font options.
13499  *
13500  * Unlike clutter_actor_create_pango_context(), this context is owend
13501  * by the #ClutterActor and it will be updated each time the options
13502  * stored by the #ClutterBackend change.
13503  *
13504  * You can use the returned #PangoContext to create a #PangoLayout
13505  * and render text using cogl_pango_render_layout() to reuse the
13506  * glyphs cache also used by Clutter.
13507  *
13508  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13509  *   The returned #PangoContext is owned by the actor and should not be
13510  *   unreferenced by the application code
13511  *
13512  * Since: 1.0
13513  */
13514 PangoContext *
13515 clutter_actor_get_pango_context (ClutterActor *self)
13516 {
13517   ClutterActorPrivate *priv;
13518
13519   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13520
13521   priv = self->priv;
13522
13523   if (priv->pango_context != NULL)
13524     return priv->pango_context;
13525
13526   priv->pango_context = _clutter_context_get_pango_context ();
13527   g_object_ref (priv->pango_context);
13528
13529   return priv->pango_context;
13530 }
13531
13532 /**
13533  * clutter_actor_create_pango_context:
13534  * @self: a #ClutterActor
13535  *
13536  * Creates a #PangoContext for the given actor. The #PangoContext
13537  * is already configured using the appropriate font map, resolution
13538  * and font options.
13539  *
13540  * See also clutter_actor_get_pango_context().
13541  *
13542  * Return value: (transfer full): the newly created #PangoContext.
13543  *   Use g_object_unref() on the returned value to deallocate its
13544  *   resources
13545  *
13546  * Since: 1.0
13547  */
13548 PangoContext *
13549 clutter_actor_create_pango_context (ClutterActor *self)
13550 {
13551   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13552
13553   return _clutter_context_create_pango_context ();
13554 }
13555
13556 /**
13557  * clutter_actor_create_pango_layout:
13558  * @self: a #ClutterActor
13559  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13560  *
13561  * Creates a new #PangoLayout from the same #PangoContext used
13562  * by the #ClutterActor. The #PangoLayout is already configured
13563  * with the font map, resolution and font options, and the
13564  * given @text.
13565  *
13566  * If you want to keep around a #PangoLayout created by this
13567  * function you will have to connect to the #ClutterBackend::font-changed
13568  * and #ClutterBackend::resolution-changed signals, and call
13569  * pango_layout_context_changed() in response to them.
13570  *
13571  * Return value: (transfer full): the newly created #PangoLayout.
13572  *   Use g_object_unref() when done
13573  *
13574  * Since: 1.0
13575  */
13576 PangoLayout *
13577 clutter_actor_create_pango_layout (ClutterActor *self,
13578                                    const gchar  *text)
13579 {
13580   PangoContext *context;
13581   PangoLayout *layout;
13582
13583   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13584
13585   context = clutter_actor_get_pango_context (self);
13586   layout = pango_layout_new (context);
13587
13588   if (text)
13589     pango_layout_set_text (layout, text, -1);
13590
13591   return layout;
13592 }
13593
13594 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13595  * ClutterOffscreenEffect.
13596  */
13597 void
13598 _clutter_actor_set_opacity_override (ClutterActor *self,
13599                                      gint          opacity)
13600 {
13601   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13602
13603   self->priv->opacity_override = opacity;
13604 }
13605
13606 gint
13607 _clutter_actor_get_opacity_override (ClutterActor *self)
13608 {
13609   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13610
13611   return self->priv->opacity_override;
13612 }
13613
13614 /* Allows you to disable applying the actors model view transform during
13615  * a paint. Used by ClutterClone. */
13616 void
13617 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13618                                                 gboolean      enable)
13619 {
13620   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13621
13622   self->priv->enable_model_view_transform = enable;
13623 }
13624
13625 void
13626 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13627                                           gboolean      enable)
13628 {
13629   ClutterActorPrivate *priv;
13630
13631   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13632
13633   priv = self->priv;
13634
13635   priv->enable_paint_unmapped = enable;
13636
13637   if (priv->enable_paint_unmapped)
13638     {
13639       /* Make sure that the parents of the widget are realized first;
13640        * otherwise checks in clutter_actor_update_map_state() will
13641        * fail.
13642        */
13643       clutter_actor_realize (self);
13644
13645       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13646     }
13647   else
13648     {
13649       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13650     }
13651 }
13652
13653 static void
13654 clutter_anchor_coord_get_units (ClutterActor      *self,
13655                                 const AnchorCoord *coord,
13656                                 gfloat            *x,
13657                                 gfloat            *y,
13658                                 gfloat            *z)
13659 {
13660   if (coord->is_fractional)
13661     {
13662       gfloat actor_width, actor_height;
13663
13664       clutter_actor_get_size (self, &actor_width, &actor_height);
13665
13666       if (x)
13667         *x = actor_width * coord->v.fraction.x;
13668
13669       if (y)
13670         *y = actor_height * coord->v.fraction.y;
13671
13672       if (z)
13673         *z = 0;
13674     }
13675   else
13676     {
13677       if (x)
13678         *x = coord->v.units.x;
13679
13680       if (y)
13681         *y = coord->v.units.y;
13682
13683       if (z)
13684         *z = coord->v.units.z;
13685     }
13686 }
13687
13688 static void
13689 clutter_anchor_coord_set_units (AnchorCoord *coord,
13690                                 gfloat       x,
13691                                 gfloat       y,
13692                                 gfloat       z)
13693 {
13694   coord->is_fractional = FALSE;
13695   coord->v.units.x = x;
13696   coord->v.units.y = y;
13697   coord->v.units.z = z;
13698 }
13699
13700 static ClutterGravity
13701 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13702 {
13703   if (coord->is_fractional)
13704     {
13705       if (coord->v.fraction.x == 0.0)
13706         {
13707           if (coord->v.fraction.y == 0.0)
13708             return CLUTTER_GRAVITY_NORTH_WEST;
13709           else if (coord->v.fraction.y == 0.5)
13710             return CLUTTER_GRAVITY_WEST;
13711           else if (coord->v.fraction.y == 1.0)
13712             return CLUTTER_GRAVITY_SOUTH_WEST;
13713           else
13714             return CLUTTER_GRAVITY_NONE;
13715         }
13716       else if (coord->v.fraction.x == 0.5)
13717         {
13718           if (coord->v.fraction.y == 0.0)
13719             return CLUTTER_GRAVITY_NORTH;
13720           else if (coord->v.fraction.y == 0.5)
13721             return CLUTTER_GRAVITY_CENTER;
13722           else if (coord->v.fraction.y == 1.0)
13723             return CLUTTER_GRAVITY_SOUTH;
13724           else
13725             return CLUTTER_GRAVITY_NONE;
13726         }
13727       else if (coord->v.fraction.x == 1.0)
13728         {
13729           if (coord->v.fraction.y == 0.0)
13730             return CLUTTER_GRAVITY_NORTH_EAST;
13731           else if (coord->v.fraction.y == 0.5)
13732             return CLUTTER_GRAVITY_EAST;
13733           else if (coord->v.fraction.y == 1.0)
13734             return CLUTTER_GRAVITY_SOUTH_EAST;
13735           else
13736             return CLUTTER_GRAVITY_NONE;
13737         }
13738       else
13739         return CLUTTER_GRAVITY_NONE;
13740     }
13741   else
13742     return CLUTTER_GRAVITY_NONE;
13743 }
13744
13745 static void
13746 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13747                                   ClutterGravity  gravity)
13748 {
13749   switch (gravity)
13750     {
13751     case CLUTTER_GRAVITY_NORTH:
13752       coord->v.fraction.x = 0.5;
13753       coord->v.fraction.y = 0.0;
13754       break;
13755
13756     case CLUTTER_GRAVITY_NORTH_EAST:
13757       coord->v.fraction.x = 1.0;
13758       coord->v.fraction.y = 0.0;
13759       break;
13760
13761     case CLUTTER_GRAVITY_EAST:
13762       coord->v.fraction.x = 1.0;
13763       coord->v.fraction.y = 0.5;
13764       break;
13765
13766     case CLUTTER_GRAVITY_SOUTH_EAST:
13767       coord->v.fraction.x = 1.0;
13768       coord->v.fraction.y = 1.0;
13769       break;
13770
13771     case CLUTTER_GRAVITY_SOUTH:
13772       coord->v.fraction.x = 0.5;
13773       coord->v.fraction.y = 1.0;
13774       break;
13775
13776     case CLUTTER_GRAVITY_SOUTH_WEST:
13777       coord->v.fraction.x = 0.0;
13778       coord->v.fraction.y = 1.0;
13779       break;
13780
13781     case CLUTTER_GRAVITY_WEST:
13782       coord->v.fraction.x = 0.0;
13783       coord->v.fraction.y = 0.5;
13784       break;
13785
13786     case CLUTTER_GRAVITY_NORTH_WEST:
13787       coord->v.fraction.x = 0.0;
13788       coord->v.fraction.y = 0.0;
13789       break;
13790
13791     case CLUTTER_GRAVITY_CENTER:
13792       coord->v.fraction.x = 0.5;
13793       coord->v.fraction.y = 0.5;
13794       break;
13795
13796     default:
13797       coord->v.fraction.x = 0.0;
13798       coord->v.fraction.y = 0.0;
13799       break;
13800     }
13801
13802   coord->is_fractional = TRUE;
13803 }
13804
13805 static gboolean
13806 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13807 {
13808   if (coord->is_fractional)
13809     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13810   else
13811     return (coord->v.units.x == 0.0
13812             && coord->v.units.y == 0.0
13813             && coord->v.units.z == 0.0);
13814 }
13815
13816 /**
13817  * clutter_actor_get_flags:
13818  * @self: a #ClutterActor
13819  *
13820  * Retrieves the flags set on @self
13821  *
13822  * Return value: a bitwise or of #ClutterActorFlags or 0
13823  *
13824  * Since: 1.0
13825  */
13826 ClutterActorFlags
13827 clutter_actor_get_flags (ClutterActor *self)
13828 {
13829   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13830
13831   return self->flags;
13832 }
13833
13834 /**
13835  * clutter_actor_set_flags:
13836  * @self: a #ClutterActor
13837  * @flags: the flags to set
13838  *
13839  * Sets @flags on @self
13840  *
13841  * This function will emit notifications for the changed properties
13842  *
13843  * Since: 1.0
13844  */
13845 void
13846 clutter_actor_set_flags (ClutterActor      *self,
13847                          ClutterActorFlags  flags)
13848 {
13849   ClutterActorFlags old_flags;
13850   GObject *obj;
13851   gboolean was_reactive_set, reactive_set;
13852   gboolean was_realized_set, realized_set;
13853   gboolean was_mapped_set, mapped_set;
13854   gboolean was_visible_set, visible_set;
13855
13856   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13857
13858   if (self->flags == flags)
13859     return;
13860
13861   obj = G_OBJECT (self);
13862   g_object_ref (obj);
13863   g_object_freeze_notify (obj);
13864
13865   old_flags = self->flags;
13866
13867   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13868   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13869   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13870   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13871
13872   self->flags |= flags;
13873
13874   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13875   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13876   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13877   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13878
13879   if (reactive_set != was_reactive_set)
13880     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13881
13882   if (realized_set != was_realized_set)
13883     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13884
13885   if (mapped_set != was_mapped_set)
13886     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13887
13888   if (visible_set != was_visible_set)
13889     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13890
13891   g_object_thaw_notify (obj);
13892   g_object_unref (obj);
13893 }
13894
13895 /**
13896  * clutter_actor_unset_flags:
13897  * @self: a #ClutterActor
13898  * @flags: the flags to unset
13899  *
13900  * Unsets @flags on @self
13901  *
13902  * This function will emit notifications for the changed properties
13903  *
13904  * Since: 1.0
13905  */
13906 void
13907 clutter_actor_unset_flags (ClutterActor      *self,
13908                            ClutterActorFlags  flags)
13909 {
13910   ClutterActorFlags old_flags;
13911   GObject *obj;
13912   gboolean was_reactive_set, reactive_set;
13913   gboolean was_realized_set, realized_set;
13914   gboolean was_mapped_set, mapped_set;
13915   gboolean was_visible_set, visible_set;
13916
13917   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13918
13919   obj = G_OBJECT (self);
13920   g_object_freeze_notify (obj);
13921
13922   old_flags = self->flags;
13923
13924   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13925   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13926   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13927   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13928
13929   self->flags &= ~flags;
13930
13931   if (self->flags == old_flags)
13932     return;
13933
13934   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13935   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13936   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13937   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13938
13939   if (reactive_set != was_reactive_set)
13940     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13941
13942   if (realized_set != was_realized_set)
13943     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13944
13945   if (mapped_set != was_mapped_set)
13946     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13947
13948   if (visible_set != was_visible_set)
13949     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13950
13951   g_object_thaw_notify (obj);
13952 }
13953
13954 /**
13955  * clutter_actor_get_transformation_matrix:
13956  * @self: a #ClutterActor
13957  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13958  *
13959  * Retrieves the transformations applied to @self relative to its
13960  * parent.
13961  *
13962  * Since: 1.0
13963  */
13964 void
13965 clutter_actor_get_transformation_matrix (ClutterActor *self,
13966                                          CoglMatrix   *matrix)
13967 {
13968   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13969
13970   cogl_matrix_init_identity (matrix);
13971
13972   _clutter_actor_apply_modelview_transform (self, matrix);
13973 }
13974
13975 void
13976 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13977                                    gboolean      is_in_clone_paint)
13978 {
13979   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13980   self->priv->in_clone_paint = is_in_clone_paint;
13981 }
13982
13983 /**
13984  * clutter_actor_is_in_clone_paint:
13985  * @self: a #ClutterActor
13986  *
13987  * Checks whether @self is being currently painted by a #ClutterClone
13988  *
13989  * This function is useful only inside the ::paint virtual function
13990  * implementations or within handlers for the #ClutterActor::paint
13991  * signal
13992  *
13993  * This function should not be used by applications
13994  *
13995  * Return value: %TRUE if the #ClutterActor is currently being painted
13996  *   by a #ClutterClone, and %FALSE otherwise
13997  *
13998  * Since: 1.0
13999  */
14000 gboolean
14001 clutter_actor_is_in_clone_paint (ClutterActor *self)
14002 {
14003   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14004
14005   return self->priv->in_clone_paint;
14006 }
14007
14008 static gboolean
14009 set_direction_recursive (ClutterActor *actor,
14010                          gpointer      user_data)
14011 {
14012   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14013
14014   clutter_actor_set_text_direction (actor, text_dir);
14015
14016   return TRUE;
14017 }
14018
14019 /**
14020  * clutter_actor_set_text_direction:
14021  * @self: a #ClutterActor
14022  * @text_dir: the text direction for @self
14023  *
14024  * Sets the #ClutterTextDirection for an actor
14025  *
14026  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14027  *
14028  * If @self implements #ClutterContainer then this function will recurse
14029  * inside all the children of @self (including the internal ones).
14030  *
14031  * Composite actors not implementing #ClutterContainer, or actors requiring
14032  * special handling when the text direction changes, should connect to
14033  * the #GObject::notify signal for the #ClutterActor:text-direction property
14034  *
14035  * Since: 1.2
14036  */
14037 void
14038 clutter_actor_set_text_direction (ClutterActor         *self,
14039                                   ClutterTextDirection  text_dir)
14040 {
14041   ClutterActorPrivate *priv;
14042
14043   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14044   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14045
14046   priv = self->priv;
14047
14048   if (priv->text_direction != text_dir)
14049     {
14050       priv->text_direction = text_dir;
14051
14052       /* we need to emit the notify::text-direction first, so that
14053        * the sub-classes can catch that and do specific handling of
14054        * the text direction; see clutter_text_direction_changed_cb()
14055        * inside clutter-text.c
14056        */
14057       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14058
14059       _clutter_actor_foreach_child (self, set_direction_recursive,
14060                                     GINT_TO_POINTER (text_dir));
14061
14062       clutter_actor_queue_relayout (self);
14063     }
14064 }
14065
14066 void
14067 _clutter_actor_set_has_pointer (ClutterActor *self,
14068                                 gboolean      has_pointer)
14069 {
14070   ClutterActorPrivate *priv = self->priv;
14071
14072   if (priv->has_pointer != has_pointer)
14073     {
14074       priv->has_pointer = has_pointer;
14075
14076       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14077     }
14078 }
14079
14080 /**
14081  * clutter_actor_get_text_direction:
14082  * @self: a #ClutterActor
14083  *
14084  * Retrieves the value set using clutter_actor_set_text_direction()
14085  *
14086  * If no text direction has been previously set, the default text
14087  * direction, as returned by clutter_get_default_text_direction(), will
14088  * be returned instead
14089  *
14090  * Return value: the #ClutterTextDirection for the actor
14091  *
14092  * Since: 1.2
14093  */
14094 ClutterTextDirection
14095 clutter_actor_get_text_direction (ClutterActor *self)
14096 {
14097   ClutterActorPrivate *priv;
14098
14099   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14100                         CLUTTER_TEXT_DIRECTION_LTR);
14101
14102   priv = self->priv;
14103
14104   /* if no direction has been set yet use the default */
14105   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14106     priv->text_direction = clutter_get_default_text_direction ();
14107
14108   return priv->text_direction;
14109 }
14110
14111 /**
14112  * clutter_actor_push_internal:
14113  * @self: a #ClutterActor
14114  *
14115  * Should be used by actors implementing the #ClutterContainer and with
14116  * internal children added through clutter_actor_set_parent(), for instance:
14117  *
14118  * |[
14119  *   static void
14120  *   my_actor_init (MyActor *self)
14121  *   {
14122  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14123  *
14124  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14125  *
14126  *     /&ast; calling clutter_actor_set_parent() now will result in
14127  *      &ast; the internal flag being set on a child of MyActor
14128  *      &ast;/
14129  *
14130  *     /&ast; internal child - a background texture &ast;/
14131  *     self->priv->background_tex = clutter_texture_new ();
14132  *     clutter_actor_set_parent (self->priv->background_tex,
14133  *                               CLUTTER_ACTOR (self));
14134  *
14135  *     /&ast; internal child - a label &ast;/
14136  *     self->priv->label = clutter_text_new ();
14137  *     clutter_actor_set_parent (self->priv->label,
14138  *                               CLUTTER_ACTOR (self));
14139  *
14140  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14141  *
14142  *     /&ast; calling clutter_actor_set_parent() now will not result in
14143  *      &ast; the internal flag being set on a child of MyActor
14144  *      &ast;/
14145  *   }
14146  * ]|
14147  *
14148  * This function will be used by Clutter to toggle an "internal child"
14149  * flag whenever clutter_actor_set_parent() is called; internal children
14150  * are handled differently by Clutter, specifically when destroying their
14151  * parent.
14152  *
14153  * Call clutter_actor_pop_internal() when you finished adding internal
14154  * children.
14155  *
14156  * Nested calls to clutter_actor_push_internal() are allowed, but each
14157  * one must by followed by a clutter_actor_pop_internal() call.
14158  *
14159  * Since: 1.2
14160  *
14161  * Deprecated: 1.10: All children of an actor are accessible through
14162  *   the #ClutterActor API, and #ClutterActor implements the
14163  *   #ClutterContainer interface, so this function is only useful
14164  *   for legacy containers overriding the default implementation.
14165  */
14166 void
14167 clutter_actor_push_internal (ClutterActor *self)
14168 {
14169   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14170
14171   self->priv->internal_child += 1;
14172 }
14173
14174 /**
14175  * clutter_actor_pop_internal:
14176  * @self: a #ClutterActor
14177  *
14178  * Disables the effects of clutter_actor_push_internal().
14179  *
14180  * Since: 1.2
14181  *
14182  * Deprecated: 1.10: All children of an actor are accessible through
14183  *   the #ClutterActor API. This function is only useful for legacy
14184  *   containers overriding the default implementation of the
14185  *   #ClutterContainer interface.
14186  */
14187 void
14188 clutter_actor_pop_internal (ClutterActor *self)
14189 {
14190   ClutterActorPrivate *priv;
14191
14192   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14193
14194   priv = self->priv;
14195
14196   if (priv->internal_child == 0)
14197     {
14198       g_warning ("Mismatched %s: you need to call "
14199                  "clutter_actor_push_composite() at least once before "
14200                  "calling this function", G_STRFUNC);
14201       return;
14202     }
14203
14204   priv->internal_child -= 1;
14205 }
14206
14207 /**
14208  * clutter_actor_has_pointer:
14209  * @self: a #ClutterActor
14210  *
14211  * Checks whether an actor contains the pointer of a
14212  * #ClutterInputDevice
14213  *
14214  * Return value: %TRUE if the actor contains the pointer, and
14215  *   %FALSE otherwise
14216  *
14217  * Since: 1.2
14218  */
14219 gboolean
14220 clutter_actor_has_pointer (ClutterActor *self)
14221 {
14222   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14223
14224   return self->priv->has_pointer;
14225 }
14226
14227 /* XXX: This is a workaround for not being able to break the ABI of
14228  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14229  * clutter_actor_queue_clipped_redraw() for details.
14230  */
14231 ClutterPaintVolume *
14232 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14233 {
14234   return g_object_get_data (G_OBJECT (self),
14235                             "-clutter-actor-queue-redraw-clip");
14236 }
14237
14238 void
14239 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14240                                       ClutterPaintVolume *clip)
14241 {
14242   g_object_set_data (G_OBJECT (self),
14243                      "-clutter-actor-queue-redraw-clip",
14244                      clip);
14245 }
14246
14247 /**
14248  * clutter_actor_has_allocation:
14249  * @self: a #ClutterActor
14250  *
14251  * Checks if the actor has an up-to-date allocation assigned to
14252  * it. This means that the actor should have an allocation: it's
14253  * visible and has a parent. It also means that there is no
14254  * outstanding relayout request in progress for the actor or its
14255  * children (There might be other outstanding layout requests in
14256  * progress that will cause the actor to get a new allocation
14257  * when the stage is laid out, however).
14258  *
14259  * If this function returns %FALSE, then the actor will normally
14260  * be allocated before it is next drawn on the screen.
14261  *
14262  * Return value: %TRUE if the actor has an up-to-date allocation
14263  *
14264  * Since: 1.4
14265  */
14266 gboolean
14267 clutter_actor_has_allocation (ClutterActor *self)
14268 {
14269   ClutterActorPrivate *priv;
14270
14271   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14272
14273   priv = self->priv;
14274
14275   return priv->parent != NULL &&
14276          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14277          !priv->needs_allocation;
14278 }
14279
14280 /**
14281  * clutter_actor_add_action:
14282  * @self: a #ClutterActor
14283  * @action: a #ClutterAction
14284  *
14285  * Adds @action to the list of actions applied to @self
14286  *
14287  * A #ClutterAction can only belong to one actor at a time
14288  *
14289  * The #ClutterActor will hold a reference on @action until either
14290  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14291  * is called
14292  *
14293  * Since: 1.4
14294  */
14295 void
14296 clutter_actor_add_action (ClutterActor  *self,
14297                           ClutterAction *action)
14298 {
14299   ClutterActorPrivate *priv;
14300
14301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14302   g_return_if_fail (CLUTTER_IS_ACTION (action));
14303
14304   priv = self->priv;
14305
14306   if (priv->actions == NULL)
14307     {
14308       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14309       priv->actions->actor = self;
14310     }
14311
14312   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14313
14314   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14315 }
14316
14317 /**
14318  * clutter_actor_add_action_with_name:
14319  * @self: a #ClutterActor
14320  * @name: the name to set on the action
14321  * @action: a #ClutterAction
14322  *
14323  * A convenience function for setting the name of a #ClutterAction
14324  * while adding it to the list of actions applied to @self
14325  *
14326  * This function is the logical equivalent of:
14327  *
14328  * |[
14329  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14330  *   clutter_actor_add_action (self, action);
14331  * ]|
14332  *
14333  * Since: 1.4
14334  */
14335 void
14336 clutter_actor_add_action_with_name (ClutterActor  *self,
14337                                     const gchar   *name,
14338                                     ClutterAction *action)
14339 {
14340   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14341   g_return_if_fail (name != NULL);
14342   g_return_if_fail (CLUTTER_IS_ACTION (action));
14343
14344   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14345   clutter_actor_add_action (self, action);
14346 }
14347
14348 /**
14349  * clutter_actor_remove_action:
14350  * @self: a #ClutterActor
14351  * @action: a #ClutterAction
14352  *
14353  * Removes @action from the list of actions applied to @self
14354  *
14355  * The reference held by @self on the #ClutterAction will be released
14356  *
14357  * Since: 1.4
14358  */
14359 void
14360 clutter_actor_remove_action (ClutterActor  *self,
14361                              ClutterAction *action)
14362 {
14363   ClutterActorPrivate *priv;
14364
14365   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14366   g_return_if_fail (CLUTTER_IS_ACTION (action));
14367
14368   priv = self->priv;
14369
14370   if (priv->actions == NULL)
14371     return;
14372
14373   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14374
14375   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14376 }
14377
14378 /**
14379  * clutter_actor_remove_action_by_name:
14380  * @self: a #ClutterActor
14381  * @name: the name of the action to remove
14382  *
14383  * Removes the #ClutterAction with the given name from the list
14384  * of actions applied to @self
14385  *
14386  * Since: 1.4
14387  */
14388 void
14389 clutter_actor_remove_action_by_name (ClutterActor *self,
14390                                      const gchar  *name)
14391 {
14392   ClutterActorPrivate *priv;
14393   ClutterActorMeta *meta;
14394
14395   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14396   g_return_if_fail (name != NULL);
14397
14398   priv = self->priv;
14399
14400   if (priv->actions == NULL)
14401     return;
14402
14403   meta = _clutter_meta_group_get_meta (priv->actions, name);
14404   if (meta == NULL)
14405     return;
14406
14407   _clutter_meta_group_remove_meta (priv->actions, meta);
14408
14409   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14410 }
14411
14412 /**
14413  * clutter_actor_get_actions:
14414  * @self: a #ClutterActor
14415  *
14416  * Retrieves the list of actions applied to @self
14417  *
14418  * Return value: (transfer container) (element-type Clutter.Action): a copy
14419  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14420  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14421  *   allocated by the returned #GList
14422  *
14423  * Since: 1.4
14424  */
14425 GList *
14426 clutter_actor_get_actions (ClutterActor *self)
14427 {
14428   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14429
14430   if (self->priv->actions == NULL)
14431     return NULL;
14432
14433   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14434 }
14435
14436 /**
14437  * clutter_actor_get_action:
14438  * @self: a #ClutterActor
14439  * @name: the name of the action to retrieve
14440  *
14441  * Retrieves the #ClutterAction with the given name in the list
14442  * of actions applied to @self
14443  *
14444  * Return value: (transfer none): a #ClutterAction for the given
14445  *   name, or %NULL. The returned #ClutterAction is owned by the
14446  *   actor and it should not be unreferenced directly
14447  *
14448  * Since: 1.4
14449  */
14450 ClutterAction *
14451 clutter_actor_get_action (ClutterActor *self,
14452                           const gchar  *name)
14453 {
14454   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14455   g_return_val_if_fail (name != NULL, NULL);
14456
14457   if (self->priv->actions == NULL)
14458     return NULL;
14459
14460   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14461 }
14462
14463 /**
14464  * clutter_actor_clear_actions:
14465  * @self: a #ClutterActor
14466  *
14467  * Clears the list of actions applied to @self
14468  *
14469  * Since: 1.4
14470  */
14471 void
14472 clutter_actor_clear_actions (ClutterActor *self)
14473 {
14474   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14475
14476   if (self->priv->actions == NULL)
14477     return;
14478
14479   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14480 }
14481
14482 /**
14483  * clutter_actor_add_constraint:
14484  * @self: a #ClutterActor
14485  * @constraint: a #ClutterConstraint
14486  *
14487  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14488  * to @self
14489  *
14490  * The #ClutterActor will hold a reference on the @constraint until
14491  * either clutter_actor_remove_constraint() or
14492  * clutter_actor_clear_constraints() is called.
14493  *
14494  * Since: 1.4
14495  */
14496 void
14497 clutter_actor_add_constraint (ClutterActor      *self,
14498                               ClutterConstraint *constraint)
14499 {
14500   ClutterActorPrivate *priv;
14501
14502   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14503   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14504
14505   priv = self->priv;
14506
14507   if (priv->constraints == NULL)
14508     {
14509       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14510       priv->constraints->actor = self;
14511     }
14512
14513   _clutter_meta_group_add_meta (priv->constraints,
14514                                 CLUTTER_ACTOR_META (constraint));
14515   clutter_actor_queue_relayout (self);
14516
14517   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14518 }
14519
14520 /**
14521  * clutter_actor_add_constraint_with_name:
14522  * @self: a #ClutterActor
14523  * @name: the name to set on the constraint
14524  * @constraint: a #ClutterConstraint
14525  *
14526  * A convenience function for setting the name of a #ClutterConstraint
14527  * while adding it to the list of constraints applied to @self
14528  *
14529  * This function is the logical equivalent of:
14530  *
14531  * |[
14532  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14533  *   clutter_actor_add_constraint (self, constraint);
14534  * ]|
14535  *
14536  * Since: 1.4
14537  */
14538 void
14539 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14540                                         const gchar       *name,
14541                                         ClutterConstraint *constraint)
14542 {
14543   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14544   g_return_if_fail (name != NULL);
14545   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14546
14547   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14548   clutter_actor_add_constraint (self, constraint);
14549 }
14550
14551 /**
14552  * clutter_actor_remove_constraint:
14553  * @self: a #ClutterActor
14554  * @constraint: a #ClutterConstraint
14555  *
14556  * Removes @constraint from the list of constraints applied to @self
14557  *
14558  * The reference held by @self on the #ClutterConstraint will be released
14559  *
14560  * Since: 1.4
14561  */
14562 void
14563 clutter_actor_remove_constraint (ClutterActor      *self,
14564                                  ClutterConstraint *constraint)
14565 {
14566   ClutterActorPrivate *priv;
14567
14568   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14569   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14570
14571   priv = self->priv;
14572
14573   if (priv->constraints == NULL)
14574     return;
14575
14576   _clutter_meta_group_remove_meta (priv->constraints,
14577                                    CLUTTER_ACTOR_META (constraint));
14578   clutter_actor_queue_relayout (self);
14579
14580   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14581 }
14582
14583 /**
14584  * clutter_actor_remove_constraint_by_name:
14585  * @self: a #ClutterActor
14586  * @name: the name of the constraint to remove
14587  *
14588  * Removes the #ClutterConstraint with the given name from the list
14589  * of constraints applied to @self
14590  *
14591  * Since: 1.4
14592  */
14593 void
14594 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14595                                          const gchar  *name)
14596 {
14597   ClutterActorPrivate *priv;
14598   ClutterActorMeta *meta;
14599
14600   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14601   g_return_if_fail (name != NULL);
14602
14603   priv = self->priv;
14604
14605   if (priv->constraints == NULL)
14606     return;
14607
14608   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14609   if (meta == NULL)
14610     return;
14611
14612   _clutter_meta_group_remove_meta (priv->constraints, meta);
14613   clutter_actor_queue_relayout (self);
14614 }
14615
14616 /**
14617  * clutter_actor_get_constraints:
14618  * @self: a #ClutterActor
14619  *
14620  * Retrieves the list of constraints applied to @self
14621  *
14622  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14623  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14624  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14625  *   allocated by the returned #GList
14626  *
14627  * Since: 1.4
14628  */
14629 GList *
14630 clutter_actor_get_constraints (ClutterActor *self)
14631 {
14632   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14633
14634   if (self->priv->constraints == NULL)
14635     return NULL;
14636
14637   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14638 }
14639
14640 /**
14641  * clutter_actor_get_constraint:
14642  * @self: a #ClutterActor
14643  * @name: the name of the constraint to retrieve
14644  *
14645  * Retrieves the #ClutterConstraint with the given name in the list
14646  * of constraints applied to @self
14647  *
14648  * Return value: (transfer none): a #ClutterConstraint for the given
14649  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14650  *   actor and it should not be unreferenced directly
14651  *
14652  * Since: 1.4
14653  */
14654 ClutterConstraint *
14655 clutter_actor_get_constraint (ClutterActor *self,
14656                               const gchar  *name)
14657 {
14658   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14659   g_return_val_if_fail (name != NULL, NULL);
14660
14661   if (self->priv->constraints == NULL)
14662     return NULL;
14663
14664   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14665 }
14666
14667 /**
14668  * clutter_actor_clear_constraints:
14669  * @self: a #ClutterActor
14670  *
14671  * Clears the list of constraints applied to @self
14672  *
14673  * Since: 1.4
14674  */
14675 void
14676 clutter_actor_clear_constraints (ClutterActor *self)
14677 {
14678   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14679
14680   if (self->priv->constraints == NULL)
14681     return;
14682
14683   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14684
14685   clutter_actor_queue_relayout (self);
14686 }
14687
14688 /**
14689  * clutter_actor_set_clip_to_allocation:
14690  * @self: a #ClutterActor
14691  * @clip_set: %TRUE to apply a clip tracking the allocation
14692  *
14693  * Sets whether @self should be clipped to the same size as its
14694  * allocation
14695  *
14696  * Since: 1.4
14697  */
14698 void
14699 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14700                                       gboolean      clip_set)
14701 {
14702   ClutterActorPrivate *priv;
14703
14704   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14705
14706   clip_set = !!clip_set;
14707
14708   priv = self->priv;
14709
14710   if (priv->clip_to_allocation != clip_set)
14711     {
14712       priv->clip_to_allocation = clip_set;
14713
14714       clutter_actor_queue_redraw (self);
14715
14716       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14717     }
14718 }
14719
14720 /**
14721  * clutter_actor_get_clip_to_allocation:
14722  * @self: a #ClutterActor
14723  *
14724  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14725  *
14726  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14727  *
14728  * Since: 1.4
14729  */
14730 gboolean
14731 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14732 {
14733   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14734
14735   return self->priv->clip_to_allocation;
14736 }
14737
14738 /**
14739  * clutter_actor_add_effect:
14740  * @self: a #ClutterActor
14741  * @effect: a #ClutterEffect
14742  *
14743  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14744  *
14745  * The #ClutterActor will hold a reference on the @effect until either
14746  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14747  * called.
14748  *
14749  * Since: 1.4
14750  */
14751 void
14752 clutter_actor_add_effect (ClutterActor  *self,
14753                           ClutterEffect *effect)
14754 {
14755   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14756   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14757
14758   _clutter_actor_add_effect_internal (self, effect);
14759
14760   clutter_actor_queue_redraw (self);
14761
14762   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14763 }
14764
14765 /**
14766  * clutter_actor_add_effect_with_name:
14767  * @self: a #ClutterActor
14768  * @name: the name to set on the effect
14769  * @effect: a #ClutterEffect
14770  *
14771  * A convenience function for setting the name of a #ClutterEffect
14772  * while adding it to the list of effectss applied to @self
14773  *
14774  * This function is the logical equivalent of:
14775  *
14776  * |[
14777  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14778  *   clutter_actor_add_effect (self, effect);
14779  * ]|
14780  *
14781  * Since: 1.4
14782  */
14783 void
14784 clutter_actor_add_effect_with_name (ClutterActor  *self,
14785                                     const gchar   *name,
14786                                     ClutterEffect *effect)
14787 {
14788   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14789   g_return_if_fail (name != NULL);
14790   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14791
14792   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14793   clutter_actor_add_effect (self, effect);
14794 }
14795
14796 /**
14797  * clutter_actor_remove_effect:
14798  * @self: a #ClutterActor
14799  * @effect: a #ClutterEffect
14800  *
14801  * Removes @effect from the list of effects applied to @self
14802  *
14803  * The reference held by @self on the #ClutterEffect will be released
14804  *
14805  * Since: 1.4
14806  */
14807 void
14808 clutter_actor_remove_effect (ClutterActor  *self,
14809                              ClutterEffect *effect)
14810 {
14811   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14812   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14813
14814   _clutter_actor_remove_effect_internal (self, effect);
14815
14816   clutter_actor_queue_redraw (self);
14817
14818   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14819 }
14820
14821 /**
14822  * clutter_actor_remove_effect_by_name:
14823  * @self: a #ClutterActor
14824  * @name: the name of the effect to remove
14825  *
14826  * Removes the #ClutterEffect with the given name from the list
14827  * of effects applied to @self
14828  *
14829  * Since: 1.4
14830  */
14831 void
14832 clutter_actor_remove_effect_by_name (ClutterActor *self,
14833                                      const gchar  *name)
14834 {
14835   ClutterActorPrivate *priv;
14836   ClutterActorMeta *meta;
14837
14838   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14839   g_return_if_fail (name != NULL);
14840
14841   priv = self->priv;
14842
14843   if (priv->effects == NULL)
14844     return;
14845
14846   meta = _clutter_meta_group_get_meta (priv->effects, name);
14847   if (meta == NULL)
14848     return;
14849
14850   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14851 }
14852
14853 /**
14854  * clutter_actor_get_effects:
14855  * @self: a #ClutterActor
14856  *
14857  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14858  *
14859  * Return value: (transfer container) (element-type Clutter.Effect): a list
14860  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14861  *   list are owned by Clutter and they should not be freed. You should
14862  *   free the returned list using g_list_free() when done
14863  *
14864  * Since: 1.4
14865  */
14866 GList *
14867 clutter_actor_get_effects (ClutterActor *self)
14868 {
14869   ClutterActorPrivate *priv;
14870
14871   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14872
14873   priv = self->priv;
14874
14875   if (priv->effects == NULL)
14876     return NULL;
14877
14878   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14879 }
14880
14881 /**
14882  * clutter_actor_get_effect:
14883  * @self: a #ClutterActor
14884  * @name: the name of the effect to retrieve
14885  *
14886  * Retrieves the #ClutterEffect with the given name in the list
14887  * of effects applied to @self
14888  *
14889  * Return value: (transfer none): a #ClutterEffect for the given
14890  *   name, or %NULL. The returned #ClutterEffect is owned by the
14891  *   actor and it should not be unreferenced directly
14892  *
14893  * Since: 1.4
14894  */
14895 ClutterEffect *
14896 clutter_actor_get_effect (ClutterActor *self,
14897                           const gchar  *name)
14898 {
14899   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14900   g_return_val_if_fail (name != NULL, NULL);
14901
14902   if (self->priv->effects == NULL)
14903     return NULL;
14904
14905   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14906 }
14907
14908 /**
14909  * clutter_actor_clear_effects:
14910  * @self: a #ClutterActor
14911  *
14912  * Clears the list of effects applied to @self
14913  *
14914  * Since: 1.4
14915  */
14916 void
14917 clutter_actor_clear_effects (ClutterActor *self)
14918 {
14919   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14920
14921   if (self->priv->effects == NULL)
14922     return;
14923
14924   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14925
14926   clutter_actor_queue_redraw (self);
14927 }
14928
14929 /**
14930  * clutter_actor_has_key_focus:
14931  * @self: a #ClutterActor
14932  *
14933  * Checks whether @self is the #ClutterActor that has key focus
14934  *
14935  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14936  *
14937  * Since: 1.4
14938  */
14939 gboolean
14940 clutter_actor_has_key_focus (ClutterActor *self)
14941 {
14942   ClutterActor *stage;
14943
14944   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14945
14946   stage = _clutter_actor_get_stage_internal (self);
14947   if (stage == NULL)
14948     return FALSE;
14949
14950   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14951 }
14952
14953 static gboolean
14954 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14955                                       ClutterPaintVolume *pv)
14956 {
14957   ClutterActorPrivate *priv = self->priv;
14958
14959   /* Actors are only expected to report a valid paint volume
14960    * while they have a valid allocation. */
14961   if (G_UNLIKELY (priv->needs_allocation))
14962     {
14963       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14964                     "Actor needs allocation",
14965                     _clutter_actor_get_debug_name (self));
14966       return FALSE;
14967     }
14968
14969   /* Check if there are any handlers connected to the paint
14970    * signal. If there are then all bets are off for what the paint
14971    * volume for this actor might possibly be!
14972    *
14973    * XXX: It's expected that this is going to end up being quite a
14974    * costly check to have to do here, but we haven't come up with
14975    * another solution that can reliably catch paint signal handlers at
14976    * the right time to either avoid artefacts due to invalid stage
14977    * clipping or due to incorrect culling.
14978    *
14979    * Previously we checked in clutter_actor_paint(), but at that time
14980    * we may already be using a stage clip that could be derived from
14981    * an invalid paint-volume. We used to try and handle that by
14982    * queuing a follow up, unclipped, redraw but still the previous
14983    * checking wasn't enough to catch invalid volumes involved in
14984    * culling (considering that containers may derive their volume from
14985    * children that haven't yet been painted)
14986    *
14987    * Longer term, improved solutions could be:
14988    * - Disallow painting in the paint signal, only allow using it
14989    *   for tracking when paints happen. We can add another API that
14990    *   allows monkey patching the paint of arbitrary actors but in a
14991    *   more controlled way and that also supports modifying the
14992    *   paint-volume.
14993    * - If we could be notified somehow when signal handlers are
14994    *   connected we wouldn't have to poll for handlers like this.
14995    */
14996   if (g_signal_has_handler_pending (self,
14997                                     actor_signals[PAINT],
14998                                     0,
14999                                     TRUE))
15000     {
15001       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15002                     "Actor has \"paint\" signal handlers",
15003                     _clutter_actor_get_debug_name (self));
15004       return FALSE;
15005     }
15006
15007   _clutter_paint_volume_init_static (pv, self);
15008
15009   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15010     {
15011       clutter_paint_volume_free (pv);
15012       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15013                     "Actor failed to report a volume",
15014                     _clutter_actor_get_debug_name (self));
15015       return FALSE;
15016     }
15017
15018   /* since effects can modify the paint volume, we allow them to actually
15019    * do this by making get_paint_volume() "context sensitive"
15020    */
15021   if (priv->effects != NULL)
15022     {
15023       if (priv->current_effect != NULL)
15024         {
15025           const GList *effects, *l;
15026
15027           /* if we are being called from within the paint sequence of
15028            * an actor, get the paint volume up to the current effect
15029            */
15030           effects = _clutter_meta_group_peek_metas (priv->effects);
15031           for (l = effects;
15032                l != NULL || (l != NULL && l->data != priv->current_effect);
15033                l = l->next)
15034             {
15035               if (!_clutter_effect_get_paint_volume (l->data, pv))
15036                 {
15037                   clutter_paint_volume_free (pv);
15038                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15039                                 "Effect (%s) failed to report a volume",
15040                                 _clutter_actor_get_debug_name (self),
15041                                 _clutter_actor_meta_get_debug_name (l->data));
15042                   return FALSE;
15043                 }
15044             }
15045         }
15046       else
15047         {
15048           const GList *effects, *l;
15049
15050           /* otherwise, get the cumulative volume */
15051           effects = _clutter_meta_group_peek_metas (priv->effects);
15052           for (l = effects; l != NULL; l = l->next)
15053             if (!_clutter_effect_get_paint_volume (l->data, pv))
15054               {
15055                 clutter_paint_volume_free (pv);
15056                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15057                               "Effect (%s) failed to report a volume",
15058                               _clutter_actor_get_debug_name (self),
15059                               _clutter_actor_meta_get_debug_name (l->data));
15060                 return FALSE;
15061               }
15062         }
15063     }
15064
15065   return TRUE;
15066 }
15067
15068 /* The public clutter_actor_get_paint_volume API returns a const
15069  * pointer since we return a pointer directly to the cached
15070  * PaintVolume associated with the actor and don't want the user to
15071  * inadvertently modify it, but for internal uses we sometimes need
15072  * access to the same PaintVolume but need to apply some book-keeping
15073  * modifications to it so we don't want a const pointer.
15074  */
15075 static ClutterPaintVolume *
15076 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15077 {
15078   ClutterActorPrivate *priv;
15079
15080   priv = self->priv;
15081
15082   if (priv->paint_volume_valid)
15083     clutter_paint_volume_free (&priv->paint_volume);
15084
15085   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15086     {
15087       priv->paint_volume_valid = TRUE;
15088       return &priv->paint_volume;
15089     }
15090   else
15091     {
15092       priv->paint_volume_valid = FALSE;
15093       return NULL;
15094     }
15095 }
15096
15097 /**
15098  * clutter_actor_get_paint_volume:
15099  * @self: a #ClutterActor
15100  *
15101  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15102  * when a paint volume can't be determined.
15103  *
15104  * The paint volume is defined as the 3D space occupied by an actor
15105  * when being painted.
15106  *
15107  * This function will call the <function>get_paint_volume()</function>
15108  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15109  * should not usually care about overriding the default implementation,
15110  * unless they are, for instance: painting outside their allocation, or
15111  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15112  * 3D depth).
15113  *
15114  * <note>2D actors overriding <function>get_paint_volume()</function>
15115  * ensure their volume has a depth of 0. (This will be true so long as
15116  * you don't call clutter_paint_volume_set_depth().)</note>
15117  *
15118  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15119  *   or %NULL if no volume could be determined. The returned pointer
15120  *   is not guaranteed to be valid across multiple frames; if you want
15121  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15122  *
15123  * Since: 1.6
15124  */
15125 const ClutterPaintVolume *
15126 clutter_actor_get_paint_volume (ClutterActor *self)
15127 {
15128   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15129
15130   return _clutter_actor_get_paint_volume_mutable (self);
15131 }
15132
15133 /**
15134  * clutter_actor_get_transformed_paint_volume:
15135  * @self: a #ClutterActor
15136  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15137  *    (or %NULL for the stage)
15138  *
15139  * Retrieves the 3D paint volume of an actor like
15140  * clutter_actor_get_paint_volume() does (Please refer to the
15141  * documentation of clutter_actor_get_paint_volume() for more
15142  * details.) and it additionally transforms the paint volume into the
15143  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15144  * is passed for @relative_to_ancestor)
15145  *
15146  * This can be used by containers that base their paint volume on
15147  * the volume of their children. Such containers can query the
15148  * transformed paint volume of all of its children and union them
15149  * together using clutter_paint_volume_union().
15150  *
15151  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15152  *   or %NULL if no volume could be determined. The returned pointer is
15153  *   not guaranteed to be valid across multiple frames; if you wish to
15154  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15155  *
15156  * Since: 1.6
15157  */
15158 const ClutterPaintVolume *
15159 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15160                                             ClutterActor *relative_to_ancestor)
15161 {
15162   const ClutterPaintVolume *volume;
15163   ClutterActor *stage;
15164   ClutterPaintVolume *transformed_volume;
15165
15166   stage = _clutter_actor_get_stage_internal (self);
15167   if (G_UNLIKELY (stage == NULL))
15168     return NULL;
15169
15170   if (relative_to_ancestor == NULL)
15171     relative_to_ancestor = stage;
15172
15173   volume = clutter_actor_get_paint_volume (self);
15174   if (volume == NULL)
15175     return NULL;
15176
15177   transformed_volume =
15178     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15179
15180   _clutter_paint_volume_copy_static (volume, transformed_volume);
15181
15182   _clutter_paint_volume_transform_relative (transformed_volume,
15183                                             relative_to_ancestor);
15184
15185   return transformed_volume;
15186 }
15187
15188 /**
15189  * clutter_actor_get_paint_box:
15190  * @self: a #ClutterActor
15191  * @box: (out): return location for a #ClutterActorBox
15192  *
15193  * Retrieves the paint volume of the passed #ClutterActor, and
15194  * transforms it into a 2D bounding box in stage coordinates.
15195  *
15196  * This function is useful to determine the on screen area occupied by
15197  * the actor. The box is only an approximation and may often be
15198  * considerably larger due to the optimizations used to calculate the
15199  * box. The box is never smaller though, so it can reliably be used
15200  * for culling.
15201  *
15202  * There are times when a 2D paint box can't be determined, e.g.
15203  * because the actor isn't yet parented under a stage or because
15204  * the actor is unable to determine a paint volume.
15205  *
15206  * Return value: %TRUE if a 2D paint box could be determined, else
15207  * %FALSE.
15208  *
15209  * Since: 1.6
15210  */
15211 gboolean
15212 clutter_actor_get_paint_box (ClutterActor    *self,
15213                              ClutterActorBox *box)
15214 {
15215   ClutterActor *stage;
15216   ClutterPaintVolume *pv;
15217
15218   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15219   g_return_val_if_fail (box != NULL, FALSE);
15220
15221   stage = _clutter_actor_get_stage_internal (self);
15222   if (G_UNLIKELY (!stage))
15223     return FALSE;
15224
15225   pv = _clutter_actor_get_paint_volume_mutable (self);
15226   if (G_UNLIKELY (!pv))
15227     return FALSE;
15228
15229   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15230
15231   return TRUE;
15232 }
15233
15234 /**
15235  * clutter_actor_has_overlaps:
15236  * @self: A #ClutterActor
15237  *
15238  * Asks the actor's implementation whether it may contain overlapping
15239  * primitives.
15240  *
15241  * For example; Clutter may use this to determine whether the painting
15242  * should be redirected to an offscreen buffer to correctly implement
15243  * the opacity property.
15244  *
15245  * Custom actors can override the default response by implementing the
15246  * #ClutterActor <function>has_overlaps</function> virtual function. See
15247  * clutter_actor_set_offscreen_redirect() for more information.
15248  *
15249  * Return value: %TRUE if the actor may have overlapping primitives, and
15250  *   %FALSE otherwise
15251  *
15252  * Since: 1.8
15253  */
15254 gboolean
15255 clutter_actor_has_overlaps (ClutterActor *self)
15256 {
15257   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15258
15259   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15260 }
15261
15262 /**
15263  * clutter_actor_has_effects:
15264  * @self: A #ClutterActor
15265  *
15266  * Returns whether the actor has any effects applied.
15267  *
15268  * Return value: %TRUE if the actor has any effects,
15269  *   %FALSE otherwise
15270  *
15271  * Since: 1.10
15272  */
15273 gboolean
15274 clutter_actor_has_effects (ClutterActor *self)
15275 {
15276   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15277
15278   if (self->priv->effects == NULL)
15279     return FALSE;
15280
15281   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15282 }
15283
15284 /**
15285  * clutter_actor_has_constraints:
15286  * @self: A #ClutterActor
15287  *
15288  * Returns whether the actor has any constraints applied.
15289  *
15290  * Return value: %TRUE if the actor has any constraints,
15291  *   %FALSE otherwise
15292  *
15293  * Since: 1.10
15294  */
15295 gboolean
15296 clutter_actor_has_constraints (ClutterActor *self)
15297 {
15298   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15299
15300   return self->priv->constraints != NULL;
15301 }
15302
15303 /**
15304  * clutter_actor_has_actions:
15305  * @self: A #ClutterActor
15306  *
15307  * Returns whether the actor has any actions applied.
15308  *
15309  * Return value: %TRUE if the actor has any actions,
15310  *   %FALSE otherwise
15311  *
15312  * Since: 1.10
15313  */
15314 gboolean
15315 clutter_actor_has_actions (ClutterActor *self)
15316 {
15317   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15318
15319   return self->priv->actions != NULL;
15320 }
15321
15322 /**
15323  * clutter_actor_get_n_children:
15324  * @self: a #ClutterActor
15325  *
15326  * Retrieves the number of children of @self.
15327  *
15328  * Return value: the number of children of an actor
15329  *
15330  * Since: 1.10
15331  */
15332 gint
15333 clutter_actor_get_n_children (ClutterActor *self)
15334 {
15335   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15336
15337   return self->priv->n_children;
15338 }
15339
15340 /**
15341  * clutter_actor_get_child_at_index:
15342  * @self: a #ClutterActor
15343  * @index_: the position in the list of children
15344  *
15345  * Retrieves the actor at the given @index_ inside the list of
15346  * children of @self.
15347  *
15348  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15349  *
15350  * Since: 1.10
15351  */
15352 ClutterActor *
15353 clutter_actor_get_child_at_index (ClutterActor *self,
15354                                   gint          index_)
15355 {
15356   ClutterActor *iter;
15357   int i;
15358
15359   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15360   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15361
15362   for (iter = self->priv->first_child, i = 0;
15363        iter != NULL && i < index_;
15364        iter = iter->priv->next_sibling, i += 1)
15365     ;
15366
15367   return iter;
15368 }
15369
15370 /*< private >
15371  * _clutter_actor_foreach_child:
15372  * @actor: The actor whos children you want to iterate
15373  * @callback: The function to call for each child
15374  * @user_data: Private data to pass to @callback
15375  *
15376  * Calls a given @callback once for each child of the specified @actor and
15377  * passing the @user_data pointer each time.
15378  *
15379  * Return value: returns %TRUE if all children were iterated, else
15380  *    %FALSE if a callback broke out of iteration early.
15381  */
15382 gboolean
15383 _clutter_actor_foreach_child (ClutterActor           *self,
15384                               ClutterForeachCallback  callback,
15385                               gpointer                user_data)
15386 {
15387   ClutterActorPrivate *priv = self->priv;
15388   ClutterActor *iter;
15389   gboolean cont;
15390
15391   for (cont = TRUE, iter = priv->first_child;
15392        cont && iter != NULL;
15393        iter = iter->priv->next_sibling)
15394     {
15395       cont = callback (iter, user_data);
15396     }
15397
15398   return cont;
15399 }
15400
15401 #if 0
15402 /* For debugging purposes this gives us a simple way to print out
15403  * the scenegraph e.g in gdb using:
15404  * [|
15405  *   _clutter_actor_traverse (stage,
15406  *                            0,
15407  *                            clutter_debug_print_actor_cb,
15408  *                            NULL,
15409  *                            NULL);
15410  * |]
15411  */
15412 static ClutterActorTraverseVisitFlags
15413 clutter_debug_print_actor_cb (ClutterActor *actor,
15414                               int depth,
15415                               void *user_data)
15416 {
15417   g_print ("%*s%s:%p\n",
15418            depth * 2, "",
15419            _clutter_actor_get_debug_name (actor),
15420            actor);
15421
15422   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15423 }
15424 #endif
15425
15426 static void
15427 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15428                                  ClutterTraverseCallback callback,
15429                                  gpointer                user_data)
15430 {
15431   GQueue *queue = g_queue_new ();
15432   ClutterActor dummy;
15433   int current_depth = 0;
15434
15435   g_queue_push_tail (queue, actor);
15436   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15437
15438   while ((actor = g_queue_pop_head (queue)))
15439     {
15440       ClutterActorTraverseVisitFlags flags;
15441
15442       if (actor == &dummy)
15443         {
15444           current_depth++;
15445           g_queue_push_tail (queue, &dummy);
15446           continue;
15447         }
15448
15449       flags = callback (actor, current_depth, user_data);
15450       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15451         break;
15452       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15453         {
15454           ClutterActor *iter;
15455
15456           for (iter = actor->priv->first_child;
15457                iter != NULL;
15458                iter = iter->priv->next_sibling)
15459             {
15460               g_queue_push_tail (queue, iter);
15461             }
15462         }
15463     }
15464
15465   g_queue_free (queue);
15466 }
15467
15468 static ClutterActorTraverseVisitFlags
15469 _clutter_actor_traverse_depth (ClutterActor           *actor,
15470                                ClutterTraverseCallback before_children_callback,
15471                                ClutterTraverseCallback after_children_callback,
15472                                int                     current_depth,
15473                                gpointer                user_data)
15474 {
15475   ClutterActorTraverseVisitFlags flags;
15476
15477   flags = before_children_callback (actor, current_depth, user_data);
15478   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15479     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15480
15481   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15482     {
15483       ClutterActor *iter;
15484
15485       for (iter = actor->priv->first_child;
15486            iter != NULL;
15487            iter = iter->priv->next_sibling)
15488         {
15489           flags = _clutter_actor_traverse_depth (iter,
15490                                                  before_children_callback,
15491                                                  after_children_callback,
15492                                                  current_depth + 1,
15493                                                  user_data);
15494
15495           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15496             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15497         }
15498     }
15499
15500   if (after_children_callback)
15501     return after_children_callback (actor, current_depth, user_data);
15502   else
15503     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15504 }
15505
15506 /* _clutter_actor_traverse:
15507  * @actor: The actor to start traversing the graph from
15508  * @flags: These flags may affect how the traversal is done
15509  * @before_children_callback: A function to call before visiting the
15510  *   children of the current actor.
15511  * @after_children_callback: A function to call after visiting the
15512  *   children of the current actor. (Ignored if
15513  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15514  * @user_data: The private data to pass to the callbacks
15515  *
15516  * Traverses the scenegraph starting at the specified @actor and
15517  * descending through all its children and its children's children.
15518  * For each actor traversed @before_children_callback and
15519  * @after_children_callback are called with the specified
15520  * @user_data, before and after visiting that actor's children.
15521  *
15522  * The callbacks can return flags that affect the ongoing traversal
15523  * such as by skipping over an actors children or bailing out of
15524  * any further traversing.
15525  */
15526 void
15527 _clutter_actor_traverse (ClutterActor              *actor,
15528                          ClutterActorTraverseFlags  flags,
15529                          ClutterTraverseCallback    before_children_callback,
15530                          ClutterTraverseCallback    after_children_callback,
15531                          gpointer                   user_data)
15532 {
15533   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15534     _clutter_actor_traverse_breadth (actor,
15535                                      before_children_callback,
15536                                      user_data);
15537   else /* DEPTH_FIRST */
15538     _clutter_actor_traverse_depth (actor,
15539                                    before_children_callback,
15540                                    after_children_callback,
15541                                    0, /* start depth */
15542                                    user_data);
15543 }
15544
15545 static void
15546 on_layout_manager_changed (ClutterLayoutManager *manager,
15547                            ClutterActor         *self)
15548 {
15549   clutter_actor_queue_relayout (self);
15550 }
15551
15552 /**
15553  * clutter_actor_set_layout_manager:
15554  * @self: a #ClutterActor
15555  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15556  *
15557  * Sets the #ClutterLayoutManager delegate object that will be used to
15558  * lay out the children of @self.
15559  *
15560  * The #ClutterActor will take a reference on the passed @manager which
15561  * will be released either when the layout manager is removed, or when
15562  * the actor is destroyed.
15563  *
15564  * Since: 1.10
15565  */
15566 void
15567 clutter_actor_set_layout_manager (ClutterActor         *self,
15568                                   ClutterLayoutManager *manager)
15569 {
15570   ClutterActorPrivate *priv;
15571
15572   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15573   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15574
15575   priv = self->priv;
15576
15577   if (priv->layout_manager != NULL)
15578     {
15579       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15580                                             G_CALLBACK (on_layout_manager_changed),
15581                                             self);
15582       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15583       g_object_unref (priv->layout_manager);
15584     }
15585
15586   priv->layout_manager = manager;
15587
15588   if (priv->layout_manager != NULL)
15589     {
15590       g_object_ref_sink (priv->layout_manager);
15591       clutter_layout_manager_set_container (priv->layout_manager,
15592                                             CLUTTER_CONTAINER (self));
15593       g_signal_connect (priv->layout_manager, "layout-changed",
15594                         G_CALLBACK (on_layout_manager_changed),
15595                         self);
15596     }
15597
15598   clutter_actor_queue_relayout (self);
15599
15600   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15601 }
15602
15603 /**
15604  * clutter_actor_get_layout_manager:
15605  * @self: a #ClutterActor
15606  *
15607  * Retrieves the #ClutterLayoutManager used by @self.
15608  *
15609  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15610  *   or %NULL
15611  *
15612  * Since: 1.10
15613  */
15614 ClutterLayoutManager *
15615 clutter_actor_get_layout_manager (ClutterActor *self)
15616 {
15617   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15618
15619   return self->priv->layout_manager;
15620 }
15621
15622 static const ClutterLayoutInfo default_layout_info = {
15623   0.f,                          /* fixed-x */
15624   0.f,                          /* fixed-y */
15625   { 0, 0, 0, 0 },               /* margin */
15626   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15627   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15628   0.f, 0.f,                     /* min_width, natural_width */
15629   0.f, 0.f,                     /* natual_width, natural_height */
15630 };
15631
15632 static void
15633 layout_info_free (gpointer data)
15634 {
15635   if (G_LIKELY (data != NULL))
15636     g_slice_free (ClutterLayoutInfo, data);
15637 }
15638
15639 /*< private >
15640  * _clutter_actor_get_layout_info:
15641  * @self: a #ClutterActor
15642  *
15643  * Retrieves a pointer to the ClutterLayoutInfo structure.
15644  *
15645  * If the actor does not have a ClutterLayoutInfo associated to it, one
15646  * will be created and initialized to the default values.
15647  *
15648  * This function should be used for setters.
15649  *
15650  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15651  * instead.
15652  *
15653  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15654  */
15655 ClutterLayoutInfo *
15656 _clutter_actor_get_layout_info (ClutterActor *self)
15657 {
15658   ClutterLayoutInfo *retval;
15659
15660   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15661   if (retval == NULL)
15662     {
15663       retval = g_slice_new (ClutterLayoutInfo);
15664
15665       *retval = default_layout_info;
15666
15667       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15668                                retval,
15669                                layout_info_free);
15670     }
15671
15672   return retval;
15673 }
15674
15675 /*< private >
15676  * _clutter_actor_get_layout_info_or_defaults:
15677  * @self: a #ClutterActor
15678  *
15679  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15680  *
15681  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15682  * then the default structure will be returned.
15683  *
15684  * This function should only be used for getters.
15685  *
15686  * Return value: a const pointer to the ClutterLayoutInfo structure
15687  */
15688 const ClutterLayoutInfo *
15689 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15690 {
15691   const ClutterLayoutInfo *info;
15692
15693   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15694   if (info == NULL)
15695     return &default_layout_info;
15696
15697   return info;
15698 }
15699
15700 /**
15701  * clutter_actor_set_x_align:
15702  * @self: a #ClutterActor
15703  * @x_align: the horizontal alignment policy
15704  *
15705  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15706  * actor received extra horizontal space.
15707  *
15708  * See also the #ClutterActor:x-align property.
15709  *
15710  * Since: 1.10
15711  */
15712 void
15713 clutter_actor_set_x_align (ClutterActor      *self,
15714                            ClutterActorAlign  x_align)
15715 {
15716   ClutterLayoutInfo *info;
15717
15718   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15719
15720   info = _clutter_actor_get_layout_info (self);
15721
15722   if (info->x_align != x_align)
15723     {
15724       info->x_align = x_align;
15725
15726       clutter_actor_queue_relayout (self);
15727
15728       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15729     }
15730 }
15731
15732 /**
15733  * clutter_actor_get_x_align:
15734  * @self: a #ClutterActor
15735  *
15736  * Retrieves the horizontal alignment policy set using
15737  * clutter_actor_set_x_align().
15738  *
15739  * Return value: the horizontal alignment policy.
15740  *
15741  * Since: 1.10
15742  */
15743 ClutterActorAlign
15744 clutter_actor_get_x_align (ClutterActor *self)
15745 {
15746   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15747
15748   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15749 }
15750
15751 /**
15752  * clutter_actor_set_y_align:
15753  * @self: a #ClutterActor
15754  * @y_align: the vertical alignment policy
15755  *
15756  * Sets the vertical alignment policy of a #ClutterActor, in case the
15757  * actor received extra vertical space.
15758  *
15759  * See also the #ClutterActor:y-align property.
15760  *
15761  * Since: 1.10
15762  */
15763 void
15764 clutter_actor_set_y_align (ClutterActor      *self,
15765                            ClutterActorAlign  y_align)
15766 {
15767   ClutterLayoutInfo *info;
15768
15769   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15770
15771   info = _clutter_actor_get_layout_info (self);
15772
15773   if (info->y_align != y_align)
15774     {
15775       info->y_align = y_align;
15776
15777       clutter_actor_queue_relayout (self);
15778
15779       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15780     }
15781 }
15782
15783 /**
15784  * clutter_actor_get_y_align:
15785  * @self: a #ClutterActor
15786  *
15787  * Retrieves the vertical alignment policy set using
15788  * clutter_actor_set_y_align().
15789  *
15790  * Return value: the vertical alignment policy.
15791  *
15792  * Since: 1.10
15793  */
15794 ClutterActorAlign
15795 clutter_actor_get_y_align (ClutterActor *self)
15796 {
15797   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15798
15799   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15800 }
15801
15802
15803 /**
15804  * clutter_margin_new:
15805  *
15806  * Creates a new #ClutterMargin.
15807  *
15808  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15809  *   clutter_margin_free() to free the resources associated with it when
15810  *   done.
15811  *
15812  * Since: 1.10
15813  */
15814 ClutterMargin *
15815 clutter_margin_new (void)
15816 {
15817   return g_slice_new0 (ClutterMargin);
15818 }
15819
15820 /**
15821  * clutter_margin_copy:
15822  * @margin_: a #ClutterMargin
15823  *
15824  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15825  * the newly created structure.
15826  *
15827  * Return value: (transfer full): a copy of the #ClutterMargin.
15828  *
15829  * Since: 1.10
15830  */
15831 ClutterMargin *
15832 clutter_margin_copy (const ClutterMargin *margin_)
15833 {
15834   if (G_LIKELY (margin_ != NULL))
15835     return g_slice_dup (ClutterMargin, margin_);
15836
15837   return NULL;
15838 }
15839
15840 /**
15841  * clutter_margin_free:
15842  * @margin_: a #ClutterMargin
15843  *
15844  * Frees the resources allocated by clutter_margin_new() and
15845  * clutter_margin_copy().
15846  *
15847  * Since: 1.10
15848  */
15849 void
15850 clutter_margin_free (ClutterMargin *margin_)
15851 {
15852   if (G_LIKELY (margin_ != NULL))
15853     g_slice_free (ClutterMargin, margin_);
15854 }
15855
15856 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15857                      clutter_margin_copy,
15858                      clutter_margin_free)
15859
15860 /**
15861  * clutter_actor_set_margin:
15862  * @self: a #ClutterActor
15863  * @margin: a #ClutterMargin
15864  *
15865  * Sets all the components of the margin of a #ClutterActor.
15866  *
15867  * Since: 1.10
15868  */
15869 void
15870 clutter_actor_set_margin (ClutterActor        *self,
15871                           const ClutterMargin *margin)
15872 {
15873   ClutterLayoutInfo *info;
15874   gboolean changed;
15875   GObject *obj;
15876
15877   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15878   g_return_if_fail (margin != NULL);
15879
15880   obj = G_OBJECT (self);
15881   changed = FALSE;
15882
15883   g_object_freeze_notify (obj);
15884
15885   info = _clutter_actor_get_layout_info (self);
15886
15887   if (info->margin.top != margin->top)
15888     {
15889       info->margin.top = margin->top;
15890       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15891       changed = TRUE;
15892     }
15893
15894   if (info->margin.right != margin->right)
15895     {
15896       info->margin.right = margin->right;
15897       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15898       changed = TRUE;
15899     }
15900
15901   if (info->margin.bottom != margin->bottom)
15902     {
15903       info->margin.bottom = margin->bottom;
15904       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15905       changed = TRUE;
15906     }
15907
15908   if (info->margin.left != margin->left)
15909     {
15910       info->margin.left = margin->left;
15911       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15912       changed = TRUE;
15913     }
15914
15915   if (changed)
15916     clutter_actor_queue_relayout (self);
15917
15918   g_object_thaw_notify (obj);
15919 }
15920
15921 /**
15922  * clutter_actor_get_margin:
15923  * @self: a #ClutterActor
15924  * @margin: (out caller-allocates): return location for a #ClutterMargin
15925  *
15926  * Retrieves all the components of the margin of a #ClutterActor.
15927  *
15928  * Since: 1.10
15929  */
15930 void
15931 clutter_actor_get_margin (ClutterActor  *self,
15932                           ClutterMargin *margin)
15933 {
15934   const ClutterLayoutInfo *info;
15935
15936   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15937   g_return_if_fail (margin != NULL);
15938
15939   info = _clutter_actor_get_layout_info_or_defaults (self);
15940
15941   *margin = info->margin;
15942 }
15943
15944 /**
15945  * clutter_actor_set_margin_top:
15946  * @self: a #ClutterActor
15947  * @margin: the top margin
15948  *
15949  * Sets the margin from the top of a #ClutterActor.
15950  *
15951  * Since: 1.10
15952  */
15953 void
15954 clutter_actor_set_margin_top (ClutterActor *self,
15955                               gfloat        margin)
15956 {
15957   ClutterLayoutInfo *info;
15958
15959   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15960   g_return_if_fail (margin >= 0.f);
15961
15962   info = _clutter_actor_get_layout_info (self);
15963
15964   if (info->margin.top == margin)
15965     return;
15966
15967   info->margin.top = margin;
15968
15969   clutter_actor_queue_relayout (self);
15970
15971   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15972 }
15973
15974 /**
15975  * clutter_actor_get_margin_top:
15976  * @self: a #ClutterActor
15977  *
15978  * Retrieves the top margin of a #ClutterActor.
15979  *
15980  * Return value: the top margin
15981  *
15982  * Since: 1.10
15983  */
15984 gfloat
15985 clutter_actor_get_margin_top (ClutterActor *self)
15986 {
15987   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15988
15989   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15990 }
15991
15992 /**
15993  * clutter_actor_set_margin_bottom:
15994  * @self: a #ClutterActor
15995  * @margin: the bottom margin
15996  *
15997  * Sets the margin from the bottom of a #ClutterActor.
15998  *
15999  * Since: 1.10
16000  */
16001 void
16002 clutter_actor_set_margin_bottom (ClutterActor *self,
16003                                  gfloat        margin)
16004 {
16005   ClutterLayoutInfo *info;
16006
16007   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16008   g_return_if_fail (margin >= 0.f);
16009
16010   info = _clutter_actor_get_layout_info (self);
16011
16012   if (info->margin.bottom == margin)
16013     return;
16014
16015   info->margin.bottom = margin;
16016
16017   clutter_actor_queue_relayout (self);
16018
16019   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16020 }
16021
16022 /**
16023  * clutter_actor_get_margin_bottom:
16024  * @self: a #ClutterActor
16025  *
16026  * Retrieves the bottom margin of a #ClutterActor.
16027  *
16028  * Return value: the bottom margin
16029  *
16030  * Since: 1.10
16031  */
16032 gfloat
16033 clutter_actor_get_margin_bottom (ClutterActor *self)
16034 {
16035   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16036
16037   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16038 }
16039
16040 /**
16041  * clutter_actor_set_margin_left:
16042  * @self: a #ClutterActor
16043  * @margin: the left margin
16044  *
16045  * Sets the margin from the left of a #ClutterActor.
16046  *
16047  * Since: 1.10
16048  */
16049 void
16050 clutter_actor_set_margin_left (ClutterActor *self,
16051                                gfloat        margin)
16052 {
16053   ClutterLayoutInfo *info;
16054
16055   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16056   g_return_if_fail (margin >= 0.f);
16057
16058   info = _clutter_actor_get_layout_info (self);
16059
16060   if (info->margin.left == margin)
16061     return;
16062
16063   info->margin.left = margin;
16064
16065   clutter_actor_queue_relayout (self);
16066
16067   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16068 }
16069
16070 /**
16071  * clutter_actor_get_margin_left:
16072  * @self: a #ClutterActor
16073  *
16074  * Retrieves the left margin of a #ClutterActor.
16075  *
16076  * Return value: the left margin
16077  *
16078  * Since: 1.10
16079  */
16080 gfloat
16081 clutter_actor_get_margin_left (ClutterActor *self)
16082 {
16083   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16084
16085   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16086 }
16087
16088 /**
16089  * clutter_actor_set_margin_right:
16090  * @self: a #ClutterActor
16091  * @margin: the right margin
16092  *
16093  * Sets the margin from the right of a #ClutterActor.
16094  *
16095  * Since: 1.10
16096  */
16097 void
16098 clutter_actor_set_margin_right (ClutterActor *self,
16099                                 gfloat        margin)
16100 {
16101   ClutterLayoutInfo *info;
16102
16103   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16104   g_return_if_fail (margin >= 0.f);
16105
16106   info = _clutter_actor_get_layout_info (self);
16107
16108   if (info->margin.right == margin)
16109     return;
16110
16111   info->margin.right = margin;
16112
16113   clutter_actor_queue_relayout (self);
16114
16115   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16116 }
16117
16118 /**
16119  * clutter_actor_get_margin_right:
16120  * @self: a #ClutterActor
16121  *
16122  * Retrieves the right margin of a #ClutterActor.
16123  *
16124  * Return value: the right margin
16125  *
16126  * Since: 1.10
16127  */
16128 gfloat
16129 clutter_actor_get_margin_right (ClutterActor *self)
16130 {
16131   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16132
16133   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16134 }
16135
16136 static inline void
16137 clutter_actor_set_background_color_internal (ClutterActor *self,
16138                                              const ClutterColor *color)
16139 {
16140   ClutterActorPrivate *priv = self->priv;
16141   GObject *obj;
16142
16143   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16144     return;
16145
16146   obj = G_OBJECT (self);
16147
16148   priv->bg_color = *color;
16149   priv->bg_color_set = TRUE;
16150
16151   clutter_actor_queue_redraw (self);
16152
16153   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16154   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16155 }
16156
16157 /**
16158  * clutter_actor_set_background_color:
16159  * @self: a #ClutterActor
16160  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16161  *  set color
16162  *
16163  * Sets the background color of a #ClutterActor.
16164  *
16165  * The background color will be used to cover the whole allocation of the
16166  * actor. The default background color of an actor is transparent.
16167  *
16168  * To check whether an actor has a background color, you can use the
16169  * #ClutterActor:background-color-set actor property.
16170  *
16171  * The #ClutterActor:background-color property is animatable.
16172  *
16173  * Since: 1.10
16174  */
16175 void
16176 clutter_actor_set_background_color (ClutterActor       *self,
16177                                     const ClutterColor *color)
16178 {
16179   ClutterActorPrivate *priv;
16180   GObject *obj;
16181   GParamSpec *bg_color_pspec;
16182
16183   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16184
16185   obj = G_OBJECT (self);
16186
16187   priv = self->priv;
16188
16189   if (color == NULL)
16190     {
16191       priv->bg_color_set = FALSE;
16192       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16193       clutter_actor_queue_redraw (self);
16194       return;
16195     }
16196
16197   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16198   if (clutter_actor_get_easing_duration (self) != 0)
16199     {
16200       ClutterTransition *transition;
16201
16202       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16203       if (transition == NULL)
16204         {
16205           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16206                                                          &priv->bg_color,
16207                                                          color);
16208           clutter_timeline_start (CLUTTER_TIMELINE (transition));
16209         }
16210       else
16211         _clutter_actor_update_transition (self, bg_color_pspec, color);
16212
16213       clutter_actor_queue_redraw (self);
16214     }
16215   else
16216     clutter_actor_set_background_color_internal (self, color);
16217 }
16218
16219 /**
16220  * clutter_actor_get_background_color:
16221  * @self: a #ClutterActor
16222  * @color: (out caller-allocates): return location for a #ClutterColor
16223  *
16224  * Retrieves the color set using clutter_actor_set_background_color().
16225  *
16226  * Since: 1.10
16227  */
16228 void
16229 clutter_actor_get_background_color (ClutterActor *self,
16230                                     ClutterColor *color)
16231 {
16232   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16233   g_return_if_fail (color != NULL);
16234
16235   *color = self->priv->bg_color;
16236 }
16237
16238 /**
16239  * clutter_actor_get_previous_sibling:
16240  * @self: a #ClutterActor
16241  *
16242  * Retrieves the sibling of @self that comes before it in the list
16243  * of children of @self's parent.
16244  *
16245  * The returned pointer is only valid until the scene graph changes; it
16246  * is not safe to modify the list of children of @self while iterating
16247  * it.
16248  *
16249  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16250  *
16251  * Since: 1.10
16252  */
16253 ClutterActor *
16254 clutter_actor_get_previous_sibling (ClutterActor *self)
16255 {
16256   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16257
16258   return self->priv->prev_sibling;
16259 }
16260
16261 /**
16262  * clutter_actor_get_next_sibling:
16263  * @self: a #ClutterActor
16264  *
16265  * Retrieves the sibling of @self that comes after it in the list
16266  * of children of @self's parent.
16267  *
16268  * The returned pointer is only valid until the scene graph changes; it
16269  * is not safe to modify the list of children of @self while iterating
16270  * it.
16271  *
16272  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16273  *
16274  * Since: 1.10
16275  */
16276 ClutterActor *
16277 clutter_actor_get_next_sibling (ClutterActor *self)
16278 {
16279   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16280
16281   return self->priv->next_sibling;
16282 }
16283
16284 /**
16285  * clutter_actor_get_first_child:
16286  * @self: a #ClutterActor
16287  *
16288  * Retrieves the first child of @self.
16289  *
16290  * The returned pointer is only valid until the scene graph changes; it
16291  * is not safe to modify the list of children of @self while iterating
16292  * it.
16293  *
16294  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16295  *
16296  * Since: 1.10
16297  */
16298 ClutterActor *
16299 clutter_actor_get_first_child (ClutterActor *self)
16300 {
16301   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16302
16303   return self->priv->first_child;
16304 }
16305
16306 /**
16307  * clutter_actor_get_last_child:
16308  * @self: a #ClutterActor
16309  *
16310  * Retrieves the last child of @self.
16311  *
16312  * The returned pointer is only valid until the scene graph changes; it
16313  * is not safe to modify the list of children of @self while iterating
16314  * it.
16315  *
16316  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16317  *
16318  * Since: 1.10
16319  */
16320 ClutterActor *
16321 clutter_actor_get_last_child (ClutterActor *self)
16322 {
16323   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16324
16325   return self->priv->last_child;
16326 }
16327
16328 /* easy way to have properly named fields instead of the dummy ones
16329  * we use in the public structure
16330  */
16331 typedef struct _RealActorIter
16332 {
16333   ClutterActor *root;           /* dummy1 */
16334   ClutterActor *current;        /* dummy2 */
16335   gpointer padding_1;           /* dummy3 */
16336   gint age;                     /* dummy4 */
16337   gpointer padding_2;           /* dummy5 */
16338 } RealActorIter;
16339
16340 /**
16341  * clutter_actor_iter_init:
16342  * @iter: a #ClutterActorIter
16343  * @root: a #ClutterActor
16344  *
16345  * Initializes a #ClutterActorIter, which can then be used to iterate
16346  * efficiently over a section of the scene graph, and associates it
16347  * with @root.
16348  *
16349  * Modifying the scene graph section that contains @root will invalidate
16350  * the iterator.
16351  *
16352  * |[
16353  *   ClutterActorIter iter;
16354  *   ClutterActor *child;
16355  *
16356  *   clutter_actor_iter_init (&iter, container);
16357  *   while (clutter_actor_iter_next (&iter, &child))
16358  *     {
16359  *       /&ast; do something with child &ast;/
16360  *     }
16361  * ]|
16362  *
16363  * Since: 1.10
16364  */
16365 void
16366 clutter_actor_iter_init (ClutterActorIter *iter,
16367                          ClutterActor     *root)
16368 {
16369   RealActorIter *ri = (RealActorIter *) iter;
16370
16371   g_return_if_fail (iter != NULL);
16372   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16373
16374   ri->root = root;
16375   ri->current = NULL;
16376   ri->age = root->priv->age;
16377 }
16378
16379 /**
16380  * clutter_actor_iter_next:
16381  * @iter: a #ClutterActorIter
16382  * @child: (out): return location for a #ClutterActor
16383  *
16384  * Advances the @iter and retrieves the next child of the root #ClutterActor
16385  * that was used to initialize the #ClutterActorIterator.
16386  *
16387  * If the iterator can advance, this function returns %TRUE and sets the
16388  * @child argument.
16389  *
16390  * If the iterator cannot advance, this function returns %FALSE, and
16391  * the contents of @child are undefined.
16392  *
16393  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16394  *
16395  * Since: 1.10
16396  */
16397 gboolean
16398 clutter_actor_iter_next (ClutterActorIter  *iter,
16399                          ClutterActor     **child)
16400 {
16401   RealActorIter *ri = (RealActorIter *) iter;
16402
16403   g_return_val_if_fail (iter != NULL, FALSE);
16404   g_return_val_if_fail (ri->root != NULL, FALSE);
16405 #ifndef G_DISABLE_ASSERT
16406   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16407 #endif
16408
16409   if (ri->current == NULL)
16410     ri->current = ri->root->priv->first_child;
16411   else
16412     ri->current = ri->current->priv->next_sibling;
16413
16414   if (child != NULL)
16415     *child = ri->current;
16416
16417   return ri->current != NULL;
16418 }
16419
16420 /**
16421  * clutter_actor_iter_prev:
16422  * @iter: a #ClutterActorIter
16423  * @child: (out): return location for a #ClutterActor
16424  *
16425  * Advances the @iter and retrieves the previous child of the root
16426  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16427  *
16428  * If the iterator can advance, this function returns %TRUE and sets the
16429  * @child argument.
16430  *
16431  * If the iterator cannot advance, this function returns %FALSE, and
16432  * the contents of @child are undefined.
16433  *
16434  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16435  *
16436  * Since: 1.10
16437  */
16438 gboolean
16439 clutter_actor_iter_prev (ClutterActorIter  *iter,
16440                          ClutterActor     **child)
16441 {
16442   RealActorIter *ri = (RealActorIter *) iter;
16443
16444   g_return_val_if_fail (iter != NULL, FALSE);
16445   g_return_val_if_fail (ri->root != NULL, FALSE);
16446 #ifndef G_DISABLE_ASSERT
16447   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16448 #endif
16449
16450   if (ri->current == NULL)
16451     ri->current = ri->root->priv->last_child;
16452   else
16453     ri->current = ri->current->priv->prev_sibling;
16454
16455   if (child != NULL)
16456     *child = ri->current;
16457
16458   return ri->current != NULL;
16459 }
16460
16461 /**
16462  * clutter_actor_iter_remove:
16463  * @iter: a #ClutterActorIter
16464  *
16465  * Safely removes the #ClutterActor currently pointer to by the iterator
16466  * from its parent.
16467  *
16468  * This function can only be called after clutter_actor_iter_next() or
16469  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16470  * than once for the same actor.
16471  *
16472  * This function will call clutter_actor_remove_child() internally.
16473  *
16474  * Since: 1.10
16475  */
16476 void
16477 clutter_actor_iter_remove (ClutterActorIter *iter)
16478 {
16479   RealActorIter *ri = (RealActorIter *) iter;
16480   ClutterActor *cur;
16481
16482   g_return_if_fail (iter != NULL);
16483   g_return_if_fail (ri->root != NULL);
16484 #ifndef G_DISABLE_ASSERT
16485   g_return_if_fail (ri->age == ri->root->priv->age);
16486 #endif
16487   g_return_if_fail (ri->current != NULL);
16488
16489   cur = ri->current;
16490
16491   if (cur != NULL)
16492     {
16493       ri->current = cur->priv->prev_sibling;
16494
16495       clutter_actor_remove_child_internal (ri->root, cur,
16496                                            REMOVE_CHILD_DEFAULT_FLAGS);
16497
16498       ri->age += 1;
16499     }
16500 }
16501
16502 /**
16503  * clutter_actor_iter_destroy:
16504  * @iter: a #ClutterActorIter
16505  *
16506  * Safely destroys the #ClutterActor currently pointer to by the iterator
16507  * from its parent.
16508  *
16509  * This function can only be called after clutter_actor_iter_next() or
16510  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16511  * than once for the same actor.
16512  *
16513  * This function will call clutter_actor_destroy() internally.
16514  *
16515  * Since: 1.10
16516  */
16517 void
16518 clutter_actor_iter_destroy (ClutterActorIter *iter)
16519 {
16520   RealActorIter *ri = (RealActorIter *) iter;
16521   ClutterActor *cur;
16522
16523   g_return_if_fail (iter != NULL);
16524   g_return_if_fail (ri->root != NULL);
16525 #ifndef G_DISABLE_ASSERT
16526   g_return_if_fail (ri->age == ri->root->priv->age);
16527 #endif
16528   g_return_if_fail (ri->current != NULL);
16529
16530   cur = ri->current;
16531
16532   if (cur != NULL)
16533     {
16534       ri->current = cur->priv->prev_sibling;
16535
16536       clutter_actor_destroy (cur);
16537
16538       ri->age += 1;
16539     }
16540 }
16541
16542 static const ClutterAnimationInfo default_animation_info = {
16543   NULL,         /* transitions */
16544   NULL,         /* states */
16545   NULL,         /* cur_state */
16546 };
16547
16548 static void
16549 clutter_animation_info_free (gpointer data)
16550 {
16551   if (data != NULL)
16552     {
16553       ClutterAnimationInfo *info = data;
16554
16555       if (info->transitions != NULL)
16556         g_hash_table_unref (info->transitions);
16557
16558       if (info->states != NULL)
16559         g_array_unref (info->states);
16560
16561       g_slice_free (ClutterAnimationInfo, info);
16562     }
16563 }
16564
16565 const ClutterAnimationInfo *
16566 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16567 {
16568   const ClutterAnimationInfo *res;
16569   GObject *obj = G_OBJECT (self);
16570
16571   res = g_object_get_qdata (obj, quark_actor_animation_info);
16572   if (res != NULL)
16573     return res;
16574
16575   return &default_animation_info;
16576 }
16577
16578 ClutterAnimationInfo *
16579 _clutter_actor_get_animation_info (ClutterActor *self)
16580 {
16581   GObject *obj = G_OBJECT (self);
16582   ClutterAnimationInfo *res;
16583
16584   res = g_object_get_qdata (obj, quark_actor_animation_info);
16585   if (res == NULL)
16586     {
16587       res = g_slice_new (ClutterAnimationInfo);
16588
16589       *res = default_animation_info;
16590
16591       g_object_set_qdata_full (obj, quark_actor_animation_info,
16592                                res,
16593                                clutter_animation_info_free);
16594     }
16595
16596   return res;
16597 }
16598
16599 ClutterTransition *
16600 _clutter_actor_get_transition (ClutterActor *actor,
16601                                GParamSpec   *pspec)
16602 {
16603   const ClutterAnimationInfo *info;
16604
16605   info = _clutter_actor_get_animation_info_or_defaults (actor);
16606
16607   if (info->transitions == NULL)
16608     return NULL;
16609
16610   return g_hash_table_lookup (info->transitions, pspec->name);
16611 }
16612
16613 typedef struct _TransitionClosure
16614 {
16615   ClutterActor *actor;
16616   ClutterTransition *transition;
16617   GParamSpec *property;
16618   gulong completed_id;
16619 } TransitionClosure;
16620
16621 static void
16622 on_transition_completed (ClutterTransition *transition,
16623                          TransitionClosure *clos)
16624 {
16625   ClutterAnimationInfo *info;
16626
16627   info = _clutter_actor_get_animation_info (clos->actor);
16628
16629   g_hash_table_remove (info->transitions, clos->property->name);
16630
16631   g_signal_handler_disconnect (transition, clos->completed_id);
16632
16633   g_slice_free (TransitionClosure, clos);
16634 }
16635
16636 void
16637 _clutter_actor_update_transition (ClutterActor *actor,
16638                                   GParamSpec   *pspec,
16639                                   ...)
16640 {
16641   ClutterTransition *transition;
16642   ClutterInterval *interval;
16643   const ClutterAnimationInfo *info;
16644   va_list var_args;
16645   GType ptype;
16646   GValue initial = G_VALUE_INIT;
16647   GValue final = G_VALUE_INIT;
16648   char *error = NULL;
16649
16650   info = _clutter_actor_get_animation_info_or_defaults (actor);
16651
16652   if (info->transitions == NULL)
16653     return;
16654
16655   transition = g_hash_table_lookup (info->transitions, pspec->name);
16656   if (transition == NULL)
16657     return;
16658
16659   va_start (var_args, pspec);
16660
16661   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16662
16663   g_value_init (&initial, ptype);
16664   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16665                                         pspec->name,
16666                                         &initial);
16667
16668   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16669   if (error != NULL)
16670     {
16671       g_critical ("%s: %s", G_STRLOC, error);
16672       g_free (error);
16673       goto out;
16674     }
16675
16676   interval = clutter_transition_get_interval (transition);
16677   clutter_interval_set_initial_value (interval, &initial);
16678   clutter_interval_set_final_value (interval, &final);
16679
16680   clutter_timeline_rewind (CLUTTER_TIMELINE (transition));
16681
16682 out:
16683   g_value_unset (&initial);
16684   g_value_unset (&final);
16685
16686   va_end (var_args);
16687 }
16688
16689 /*< private >*
16690  * _clutter_actor_create_transition:
16691  * @actor: a #ClutterActor
16692  * @pspec: the property used for the transition
16693  * @...: initial and final state
16694  *
16695  * Creates a #ClutterTransition for the property represented by @pspec.
16696  *
16697  * Return value: a #ClutterTransition
16698  */
16699 ClutterTransition *
16700 _clutter_actor_create_transition (ClutterActor *actor,
16701                                   GParamSpec   *pspec,
16702                                   ...)
16703 {
16704   ClutterAnimationInfo *info;
16705   ClutterTransition *res = NULL;
16706   gboolean call_restore = FALSE;
16707   va_list var_args;
16708
16709   info = _clutter_actor_get_animation_info (actor);
16710
16711   if (info->states == NULL)
16712     {
16713       clutter_actor_save_easing_state (actor);
16714       call_restore = TRUE;
16715     }
16716
16717   if (info->transitions == NULL)
16718     info->transitions = g_hash_table_new (g_str_hash, g_str_equal);
16719
16720   va_start (var_args, pspec);
16721
16722   res = g_hash_table_lookup (info->transitions, pspec->name);
16723   if (res == NULL)
16724     {
16725       ClutterInterval *interval;
16726       GValue initial = G_VALUE_INIT;
16727       GValue final = G_VALUE_INIT;
16728       GType ptype;
16729       char *error;
16730       TransitionClosure *clos;
16731
16732       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16733
16734       G_VALUE_COLLECT_INIT (&initial, ptype,
16735                             var_args, 0,
16736                             &error);
16737       if (error != NULL)
16738         {
16739           g_critical ("%s: %s", G_STRLOC, error);
16740           g_free (error);
16741           goto out;
16742         }
16743
16744       G_VALUE_COLLECT_INIT (&final, ptype,
16745                             var_args, 0,
16746                             &error);
16747
16748       if (error != NULL)
16749         {
16750           g_critical ("%s: %s", G_STRLOC, error);
16751           g_value_unset (&initial);
16752           g_free (error);
16753           goto out;
16754         }
16755
16756       interval = clutter_interval_new_with_values (ptype, &initial, &final);
16757
16758       g_value_unset (&initial);
16759       g_value_unset (&final);
16760
16761       res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
16762                                              pspec->name);
16763
16764       clutter_transition_set_interval (res, interval);
16765       clutter_transition_set_remove_on_complete (res, TRUE);
16766
16767       clutter_timeline_set_delay (CLUTTER_TIMELINE (res),
16768                                   info->cur_state->easing_delay);
16769       clutter_timeline_set_duration (CLUTTER_TIMELINE (res),
16770                                      info->cur_state->easing_duration);
16771       clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (res),
16772                                           info->cur_state->easing_mode);
16773
16774       clos = g_slice_new (TransitionClosure);
16775       clos->actor = actor;
16776       clos->transition = res;
16777       clos->property = pspec;
16778       clos->completed_id =
16779         g_signal_connect (res, "completed",
16780                           G_CALLBACK (on_transition_completed),
16781                           clos);
16782
16783       g_hash_table_insert (info->transitions, (gpointer) pspec->name, res);
16784     }
16785
16786 out:
16787   if (call_restore)
16788     clutter_actor_restore_easing_state (actor);
16789
16790   va_end (var_args);
16791
16792   return res;
16793 }
16794
16795 /**
16796  * clutter_actor_set_easing_duration:
16797  * @self: a #ClutterActor
16798  * @msecs: the duration of the easing, or %NULL
16799  *
16800  * Sets the duration of the tweening for animatable properties
16801  * of @self for the current easing state.
16802  *
16803  * Calling this function will implicitly call
16804  * clutter_actor_save_easing_state() if no previous call to
16805  * that function was made.
16806  *
16807  * Since: 1.10
16808  */
16809 void
16810 clutter_actor_set_easing_duration (ClutterActor *self,
16811                                    guint         msecs)
16812 {
16813   ClutterAnimationInfo *info;
16814
16815   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16816
16817   info = _clutter_actor_get_animation_info (self);
16818
16819   if (info->states == NULL)
16820     clutter_actor_save_easing_state (self);
16821
16822   if (info->cur_state->easing_duration != msecs)
16823     info->cur_state->easing_duration = msecs;
16824 }
16825
16826 /**
16827  * clutter_actor_get_easing_duration:
16828  * @self: a #ClutterActor
16829  *
16830  * Retrieves the duration of the tweening for animatable
16831  * properties of @self for the current easing state.
16832  *
16833  * Return value: the duration of the tweening, in milliseconds
16834  *
16835  * Since: 1.10
16836  */
16837 guint
16838 clutter_actor_get_easing_duration (ClutterActor *self)
16839 {
16840   const ClutterAnimationInfo *info;
16841
16842   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
16843
16844   info = _clutter_actor_get_animation_info_or_defaults (self);
16845
16846   if (info->cur_state != NULL)
16847     return info->cur_state->easing_duration;
16848
16849   return 0;
16850 }
16851
16852 /**
16853  * clutter_actor_set_easing_mode:
16854  * @self: a #ClutterActor
16855  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
16856  *
16857  * Sets the easing mode for the tweening of animatable properties
16858  * of @self.
16859  *
16860  * Calling this function will implicitly call
16861  * clutter_actor_save_easing_state() if no previous calls to
16862  * that function were made.
16863  *
16864  * Since: 1.10
16865  */
16866 void
16867 clutter_actor_set_easing_mode (ClutterActor         *self,
16868                                ClutterAnimationMode  mode)
16869 {
16870   ClutterAnimationInfo *info;
16871
16872   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16873   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
16874   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
16875
16876   info = _clutter_actor_get_animation_info (self);
16877
16878   if (info->states == NULL)
16879     clutter_actor_save_easing_state (self);
16880
16881   if (info->cur_state->easing_mode != mode)
16882     info->cur_state->easing_mode = mode;
16883 }
16884
16885 /**
16886  * clutter_actor_get_easing_mode:
16887  * @self: a #ClutterActor
16888  *
16889  * Retrieves the easing mode for the tweening of animatable properties
16890  * of @self for the current easing state.
16891  *
16892  * Return value: an easing mode
16893  *
16894  * Since: 1.10
16895  */
16896 ClutterAnimationMode
16897 clutter_actor_get_easing_mode (ClutterActor *self)
16898 {
16899   const ClutterAnimationInfo *info;
16900
16901   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
16902
16903   info = _clutter_actor_get_animation_info_or_defaults (self);
16904
16905   if (info->cur_state != NULL)
16906     return info->cur_state->easing_mode;
16907
16908   return CLUTTER_EASE_OUT_CUBIC;
16909 }
16910
16911 /**
16912  * clutter_actor_set_easing_delay:
16913  * @self: a #ClutterActor
16914  * @msecs: the delay before the start of the tweening, in milliseconds
16915  *
16916  * Sets the delay that should be applied before tweening animatable
16917  * properties.
16918  *
16919  * Calling this function will implicitly call
16920  * clutter_actor_save_easing_state() if no previous calls to
16921  * that function were made.
16922  *
16923  * Since: 1.10
16924  */
16925 void
16926 clutter_actor_set_easing_delay (ClutterActor *self,
16927                                 guint         msecs)
16928 {
16929   ClutterAnimationInfo *info;
16930
16931   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16932
16933   info = _clutter_actor_get_animation_info (self);
16934
16935   if (info->states == NULL)
16936     clutter_actor_save_easing_state (self);
16937
16938   if (info->cur_state->easing_delay != msecs)
16939     info->cur_state->easing_delay = msecs;
16940 }
16941
16942 /**
16943  * clutter_actor_get_easing_delay:
16944  * @self: a #ClutterActor
16945  *
16946  * Retrieves the delay that should be applied when tweening animatable
16947  * properties.
16948  *
16949  * Return value: a delay, in milliseconds
16950  *
16951  * Since: 1.10
16952  */
16953 guint
16954 clutter_actor_get_easing_delay (ClutterActor *self)
16955 {
16956   const ClutterAnimationInfo *info;
16957
16958   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
16959
16960   info = _clutter_actor_get_animation_info_or_defaults (self);
16961
16962   if (info->cur_state != NULL)
16963     return info->cur_state->easing_delay;
16964
16965   return 0;
16966 }
16967
16968 /**
16969  * clutter_actor_get_transition:
16970  * @self: a #ClutterActor
16971  * @name: the name of the transition
16972  *
16973  * Retrieves the #ClutterTransition of a #ClutterActor by using the
16974  * transition @name.
16975  *
16976  * Transitions created for animatable properties use the name of the
16977  * property itself, for instance the code below:
16978  *
16979  * |[
16980  *   clutter_actor_set_easing_duration (actor, 1000);
16981  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
16982  *
16983  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
16984  *   g_signal_connect (transition, "completed",
16985  *                     G_CALLBACK (on_transition_complete),
16986  *                     actor);
16987  * ]|
16988  *
16989  * will call the <function>on_transition_complete</function> callback when
16990  * the transition is complete.
16991  *
16992  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
16993  *   was found to match the passed name; the returned instance is owned
16994  *   by Clutter and it should not be freed
16995  *
16996  * Since: 1.10
16997  */
16998 ClutterTransition *
16999 clutter_actor_get_transition (ClutterActor *self,
17000                               const char   *name)
17001 {
17002   const ClutterAnimationInfo *info;
17003
17004   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17005   g_return_val_if_fail (name != NULL, NULL);
17006
17007   info = _clutter_actor_get_animation_info_or_defaults (self);
17008
17009   if (info->transitions == NULL)
17010     return NULL;
17011
17012   return g_hash_table_lookup (info->transitions, name);
17013 }
17014
17015 /**
17016  * clutter_actor_save_easing_state:
17017  * @self: a #ClutterActor
17018  *
17019  * Saves the current easing state for animatable properties, and creates
17020  * a new state with the default values for easing mode and duration.
17021  *
17022  * Since: 1.10
17023  */
17024 void
17025 clutter_actor_save_easing_state (ClutterActor *self)
17026 {
17027   ClutterAnimationInfo *info;
17028   AState new_state;
17029
17030   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17031
17032   info = _clutter_actor_get_animation_info (self);
17033
17034   if (info->states == NULL)
17035     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17036
17037   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17038   new_state.easing_duration = 250;
17039   new_state.easing_delay = 0;
17040
17041   g_array_append_val (info->states, new_state);
17042
17043   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17044 }
17045
17046 /**
17047  * clutter_actor_restore_easing_state:
17048  * @self: a #ClutterActor
17049  *
17050  * Restores the easing state as it was prior to a call to
17051  * clutter_actor_save_easing_state().
17052  *
17053  * Since: 1.10
17054  */
17055 void
17056 clutter_actor_restore_easing_state (ClutterActor *self)
17057 {
17058   ClutterAnimationInfo *info;
17059
17060   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17061
17062   info = _clutter_actor_get_animation_info (self);
17063
17064   if (info->states == NULL)
17065     {
17066       g_critical ("The function clutter_actor_restore_easing_state() has "
17067                   "called without a previous call to "
17068                   "clutter_actor_save_easing_state().");
17069       return;
17070     }
17071
17072   g_array_remove_index (info->states, info->states->len - 1);
17073   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17074 }