actor: Add freeze/thaw when changing the first/last child
[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 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="bin-layout">
113  *     <title>Actors</title>
114  *     <graphic fileref="test-actor.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
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
327
328 #include "clutter-actor-private.h"
329
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-main.h"
342 #include "clutter-marshal.h"
343 #include "clutter-flatten-effect.h"
344 #include "clutter-paint-volume-private.h"
345 #include "clutter-private.h"
346 #include "clutter-profile.h"
347 #include "clutter-scriptable.h"
348 #include "clutter-script-private.h"
349 #include "clutter-stage-private.h"
350 #include "clutter-units.h"
351
352 #include "deprecated/clutter-behaviour.h"
353 #include "deprecated/clutter-container.h"
354
355 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
356 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
357
358 /* Internal enum used to control mapped state update.  This is a hint
359  * which indicates when to do something other than just enforce
360  * invariants.
361  */
362 typedef enum {
363   MAP_STATE_CHECK,           /* just enforce invariants. */
364   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
365                               * used when about to unparent.
366                               */
367   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
368                               * used to set mapped on toplevels.
369                               */
370   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
371                               * used just before unmapping parent.
372                               */
373 } MapStateChange;
374
375 /* 3 entries should be a good compromise, few layout managers
376  * will ask for 3 different preferred size in each allocation cycle */
377 #define N_CACHED_SIZE_REQUESTS 3
378
379 struct _ClutterActorPrivate
380 {
381   /* request mode */
382   ClutterRequestMode request_mode;
383
384   /* our cached size requests for different width / height */
385   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
386   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
387
388   /* An age of 0 means the entry is not set */
389   guint cached_height_age;
390   guint cached_width_age;
391
392   /* the bounding box of the actor, relative to the parent's
393    * allocation
394    */
395   ClutterActorBox allocation;
396   ClutterAllocationFlags allocation_flags;
397
398   /* depth */
399   gfloat z;
400
401   /* clip, in actor coordinates */
402   cairo_rectangle_t clip;
403
404   /* the cached transformation matrix; see apply_transform() */
405   CoglMatrix transform;
406
407   guint8 opacity;
408   gint opacity_override;
409
410   ClutterOffscreenRedirect offscreen_redirect;
411
412   /* This is an internal effect used to implement the
413      offscreen-redirect property */
414   ClutterEffect *flatten_effect;
415
416   /* scene graph */
417   ClutterActor *parent;
418   ClutterActor *prev_sibling;
419   ClutterActor *next_sibling;
420   ClutterActor *first_child;
421   ClutterActor *last_child;
422
423   gint n_children;
424
425   /* tracks whenever the children of an actor are changed; the
426    * age is incremented by 1 whenever an actor is added or
427    * removed. the age is not incremented when the first or the
428    * last child pointers are changed, or when grandchildren of
429    * an actor are changed.
430    */
431   gint age;
432
433   gchar *name; /* a non-unique name, used for debugging */
434   guint32 id; /* unique id, used for backward compatibility */
435
436   gint32 pick_id; /* per-stage unique id, used for picking */
437
438   /* a back-pointer to the Pango context that we can use
439    * to create pre-configured PangoLayout
440    */
441   PangoContext *pango_context;
442
443   /* the text direction configured for this child - either by
444    * application code, or by the actor's parent
445    */
446   ClutterTextDirection text_direction;
447
448   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
449   gint internal_child;
450
451   /* meta classes */
452   ClutterMetaGroup *actions;
453   ClutterMetaGroup *constraints;
454   ClutterMetaGroup *effects;
455
456   /* delegate object used to allocate the children of this actor */
457   ClutterLayoutManager *layout_manager;
458
459   /* used when painting, to update the paint volume */
460   ClutterEffect *current_effect;
461
462   /* This is used to store an effect which needs to be redrawn. A
463      redraw can be queued to start from a particular effect. This is
464      used by parametrised effects that can cache an image of the
465      actor. If a parameter of the effect changes then it only needs to
466      redraw the cached image, not the actual actor. The pointer is
467      only valid if is_dirty == TRUE. If the pointer is NULL then the
468      whole actor is dirty. */
469   ClutterEffect *effect_to_redraw;
470
471   /* This is used when painting effects to implement the
472      clutter_actor_continue_paint() function. It points to the node in
473      the list of effects that is next in the chain */
474   const GList *next_effect_to_paint;
475
476   ClutterPaintVolume paint_volume;
477
478   /* NB: This volume isn't relative to this actor, it is in eye
479    * coordinates so that it can remain valid after the actor changes.
480    */
481   ClutterPaintVolume last_paint_volume;
482
483   ClutterStageQueueRedrawEntry *queue_redraw_entry;
484
485   ClutterColor bg_color;
486
487   /* bitfields */
488
489   /* fixed position and sizes */
490   guint position_set                : 1;
491   guint min_width_set               : 1;
492   guint min_height_set              : 1;
493   guint natural_width_set           : 1;
494   guint natural_height_set          : 1;
495   /* cached request is invalid (implies allocation is too) */
496   guint needs_width_request         : 1;
497   /* cached request is invalid (implies allocation is too) */
498   guint needs_height_request        : 1;
499   /* cached allocation is invalid (request has changed, probably) */
500   guint needs_allocation            : 1;
501   guint show_on_set_parent          : 1;
502   guint has_clip                    : 1;
503   guint clip_to_allocation          : 1;
504   guint enable_model_view_transform : 1;
505   guint enable_paint_unmapped       : 1;
506   guint has_pointer                 : 1;
507   guint propagated_one_redraw       : 1;
508   guint paint_volume_valid          : 1;
509   guint last_paint_volume_valid     : 1;
510   guint in_clone_paint              : 1;
511   guint transform_valid             : 1;
512   /* This is TRUE if anything has queued a redraw since we were last
513      painted. In this case effect_to_redraw will point to an effect
514      the redraw was queued from or it will be NULL if the redraw was
515      queued without an effect. */
516   guint is_dirty                    : 1;
517   guint bg_color_set                : 1;
518 };
519
520 enum
521 {
522   PROP_0,
523
524   PROP_NAME,
525
526   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
527    * when set they force a size request, when gotten they
528    * get the allocation if the allocation is valid, and the
529    * request otherwise
530    */
531   PROP_X,
532   PROP_Y,
533   PROP_WIDTH,
534   PROP_HEIGHT,
535
536   /* Then the rest of these size-related properties are the "actual"
537    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
538    */
539   PROP_FIXED_X,
540   PROP_FIXED_Y,
541
542   PROP_FIXED_POSITION_SET,
543
544   PROP_MIN_WIDTH,
545   PROP_MIN_WIDTH_SET,
546
547   PROP_MIN_HEIGHT,
548   PROP_MIN_HEIGHT_SET,
549
550   PROP_NATURAL_WIDTH,
551   PROP_NATURAL_WIDTH_SET,
552
553   PROP_NATURAL_HEIGHT,
554   PROP_NATURAL_HEIGHT_SET,
555
556   PROP_REQUEST_MODE,
557
558   /* Allocation properties are read-only */
559   PROP_ALLOCATION,
560
561   PROP_DEPTH,
562
563   PROP_CLIP,
564   PROP_HAS_CLIP,
565   PROP_CLIP_TO_ALLOCATION,
566
567   PROP_OPACITY,
568
569   PROP_OFFSCREEN_REDIRECT,
570
571   PROP_VISIBLE,
572   PROP_MAPPED,
573   PROP_REALIZED,
574   PROP_REACTIVE,
575
576   PROP_SCALE_X,
577   PROP_SCALE_Y,
578   PROP_SCALE_CENTER_X,
579   PROP_SCALE_CENTER_Y,
580   PROP_SCALE_GRAVITY,
581
582   PROP_ROTATION_ANGLE_X,
583   PROP_ROTATION_ANGLE_Y,
584   PROP_ROTATION_ANGLE_Z,
585   PROP_ROTATION_CENTER_X,
586   PROP_ROTATION_CENTER_Y,
587   PROP_ROTATION_CENTER_Z,
588   /* This property only makes sense for the z rotation because the
589      others would depend on the actor having a size along the
590      z-axis */
591   PROP_ROTATION_CENTER_Z_GRAVITY,
592
593   PROP_ANCHOR_X,
594   PROP_ANCHOR_Y,
595   PROP_ANCHOR_GRAVITY,
596
597   PROP_SHOW_ON_SET_PARENT,
598
599   PROP_TEXT_DIRECTION,
600   PROP_HAS_POINTER,
601
602   PROP_ACTIONS,
603   PROP_CONSTRAINTS,
604   PROP_EFFECT,
605
606   PROP_LAYOUT_MANAGER,
607
608   PROP_X_ALIGN,
609   PROP_Y_ALIGN,
610   PROP_MARGIN_TOP,
611   PROP_MARGIN_BOTTOM,
612   PROP_MARGIN_LEFT,
613   PROP_MARGIN_RIGHT,
614
615   PROP_BACKGROUND_COLOR,
616   PROP_BACKGROUND_COLOR_SET,
617
618   PROP_FIRST_CHILD,
619   PROP_LAST_CHILD,
620
621   PROP_LAST
622 };
623
624 static GParamSpec *obj_props[PROP_LAST];
625
626 enum
627 {
628   SHOW,
629   HIDE,
630   DESTROY,
631   PARENT_SET,
632   KEY_FOCUS_IN,
633   KEY_FOCUS_OUT,
634   PAINT,
635   PICK,
636   REALIZE,
637   UNREALIZE,
638   QUEUE_REDRAW,
639   QUEUE_RELAYOUT,
640   EVENT,
641   CAPTURED_EVENT,
642   BUTTON_PRESS_EVENT,
643   BUTTON_RELEASE_EVENT,
644   SCROLL_EVENT,
645   KEY_PRESS_EVENT,
646   KEY_RELEASE_EVENT,
647   MOTION_EVENT,
648   ENTER_EVENT,
649   LEAVE_EVENT,
650   ALLOCATION_CHANGED,
651
652   LAST_SIGNAL
653 };
654
655 static guint actor_signals[LAST_SIGNAL] = { 0, };
656
657 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
658 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
659 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
660 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
661
662 /* These setters are all static for now, maybe they should be in the
663  * public API, but they are perhaps obscure enough to leave only as
664  * properties
665  */
666 static void clutter_actor_set_min_width          (ClutterActor *self,
667                                                   gfloat        min_width);
668 static void clutter_actor_set_min_height         (ClutterActor *self,
669                                                   gfloat        min_height);
670 static void clutter_actor_set_natural_width      (ClutterActor *self,
671                                                   gfloat        natural_width);
672 static void clutter_actor_set_natural_height     (ClutterActor *self,
673                                                   gfloat        natural_height);
674 static void clutter_actor_set_min_width_set      (ClutterActor *self,
675                                                   gboolean      use_min_width);
676 static void clutter_actor_set_min_height_set     (ClutterActor *self,
677                                                   gboolean      use_min_height);
678 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
679                                                   gboolean  use_natural_width);
680 static void clutter_actor_set_natural_height_set (ClutterActor *self,
681                                                   gboolean  use_natural_height);
682 static void clutter_actor_update_map_state       (ClutterActor  *self,
683                                                   MapStateChange change);
684 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
685
686 /* Helper routines for managing anchor coords */
687 static void clutter_anchor_coord_get_units (ClutterActor      *self,
688                                             const AnchorCoord *coord,
689                                             gfloat            *x,
690                                             gfloat            *y,
691                                             gfloat            *z);
692 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
693                                             gfloat             x,
694                                             gfloat             y,
695                                             gfloat             z);
696
697 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
698 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
699                                                         ClutterGravity     gravity);
700
701 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
702
703 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
704
705 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
706                                                                ClutterActor *ancestor,
707                                                                CoglMatrix *matrix);
708
709 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
710
711 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
712
713 static void on_layout_manager_changed (ClutterLayoutManager *manager,
714                                        ClutterActor         *self);
715
716 /* Helper macro which translates by the anchor coord, applies the
717    given transformation and then translates back */
718 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
719   gfloat _tx, _ty, _tz;                                                \
720   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
721   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
722   { _transform; }                                                      \
723   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
724
725 static GQuark quark_shader_data = 0;
726 static GQuark quark_actor_layout_info = 0;
727 static GQuark quark_actor_transform_info = 0;
728
729 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
730                          clutter_actor,
731                          G_TYPE_INITIALLY_UNOWNED,
732                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
733                                                 clutter_container_iface_init)
734                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
735                                                 clutter_scriptable_iface_init)
736                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
737                                                 clutter_animatable_iface_init)
738                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
739                                                 atk_implementor_iface_init));
740
741 /*< private >
742  * clutter_actor_get_debug_name:
743  * @actor: a #ClutterActor
744  *
745  * Retrieves a printable name of @actor for debugging messages
746  *
747  * Return value: a string with a printable name
748  */
749 const gchar *
750 _clutter_actor_get_debug_name (ClutterActor *actor)
751 {
752   return actor->priv->name != NULL ? actor->priv->name
753                                    : G_OBJECT_TYPE_NAME (actor);
754 }
755
756 #ifdef CLUTTER_ENABLE_DEBUG
757 /* XXX - this is for debugging only, remove once working (or leave
758  * in only in some debug mode). Should leave it for a little while
759  * until we're confident in the new map/realize/visible handling.
760  */
761 static inline void
762 clutter_actor_verify_map_state (ClutterActor *self)
763 {
764   ClutterActorPrivate *priv = self->priv;
765
766   if (CLUTTER_ACTOR_IS_REALIZED (self))
767     {
768       /* all bets are off during reparent when we're potentially realized,
769        * but should not be according to invariants
770        */
771       if (!CLUTTER_ACTOR_IN_REPARENT (self))
772         {
773           if (priv->parent == NULL)
774             {
775               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
776                 {
777                 }
778               else
779                 g_warning ("Realized non-toplevel actor '%s' should "
780                            "have a parent",
781                            _clutter_actor_get_debug_name (self));
782             }
783           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
784             {
785               g_warning ("Realized actor %s has an unrealized parent %s",
786                          _clutter_actor_get_debug_name (self),
787                          _clutter_actor_get_debug_name (priv->parent));
788             }
789         }
790     }
791
792   if (CLUTTER_ACTOR_IS_MAPPED (self))
793     {
794       if (!CLUTTER_ACTOR_IS_REALIZED (self))
795         g_warning ("Actor '%s' is mapped but not realized",
796                    _clutter_actor_get_debug_name (self));
797
798       /* remaining bets are off during reparent when we're potentially
799        * mapped, but should not be according to invariants
800        */
801       if (!CLUTTER_ACTOR_IN_REPARENT (self))
802         {
803           if (priv->parent == NULL)
804             {
805               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
806                 {
807                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
808                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
809                     {
810                       g_warning ("Toplevel actor '%s' is mapped "
811                                  "but not visible",
812                                  _clutter_actor_get_debug_name (self));
813                     }
814                 }
815               else
816                 {
817                   g_warning ("Mapped actor '%s' should have a parent",
818                              _clutter_actor_get_debug_name (self));
819                 }
820             }
821           else
822             {
823               ClutterActor *iter = self;
824
825               /* check for the enable_paint_unmapped flag on the actor
826                * and parents; if the flag is enabled at any point of this
827                * branch of the scene graph then all the later checks
828                * become pointless
829                */
830               while (iter != NULL)
831                 {
832                   if (iter->priv->enable_paint_unmapped)
833                     return;
834
835                   iter = iter->priv->parent;
836                 }
837
838               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
839                 {
840                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
841                              "is not visible",
842                              _clutter_actor_get_debug_name (self),
843                              _clutter_actor_get_debug_name (priv->parent));
844                 }
845
846               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
847                 {
848                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
849                              "is not realized",
850                              _clutter_actor_get_debug_name (self),
851                              _clutter_actor_get_debug_name (priv->parent));
852                 }
853
854               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
855                 {
856                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
857                     g_warning ("Actor '%s' is mapped but its non-toplevel "
858                                "parent '%s' is not mapped",
859                                _clutter_actor_get_debug_name (self),
860                                _clutter_actor_get_debug_name (priv->parent));
861                 }
862             }
863         }
864     }
865 }
866
867 #endif /* CLUTTER_ENABLE_DEBUG */
868
869 static void
870 clutter_actor_set_mapped (ClutterActor *self,
871                           gboolean      mapped)
872 {
873   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
874     return;
875
876   if (mapped)
877     {
878       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
879       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
880     }
881   else
882     {
883       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
884       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
885     }
886 }
887
888 /* this function updates the mapped and realized states according to
889  * invariants, in the appropriate order.
890  */
891 static void
892 clutter_actor_update_map_state (ClutterActor  *self,
893                                 MapStateChange change)
894 {
895   gboolean was_mapped;
896
897   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
898
899   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
900     {
901       /* the mapped flag on top-level actors must be set by the
902        * per-backend implementation because it might be asynchronous.
903        *
904        * That is, the MAPPED flag on toplevels currently tracks the X
905        * server mapped-ness of the window, while the expected behavior
906        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
907        * This creates some weird complexity by breaking the invariant
908        * that if we're visible and all ancestors shown then we are
909        * also mapped - instead, we are mapped if all ancestors
910        * _possibly excepting_ the stage are mapped. The stage
911        * will map/unmap for example when it is minimized or
912        * moved to another workspace.
913        *
914        * So, the only invariant on the stage is that if visible it
915        * should be realized, and that it has to be visible to be
916        * mapped.
917        */
918       if (CLUTTER_ACTOR_IS_VISIBLE (self))
919         clutter_actor_realize (self);
920
921       switch (change)
922         {
923         case MAP_STATE_CHECK:
924           break;
925
926         case MAP_STATE_MAKE_MAPPED:
927           g_assert (!was_mapped);
928           clutter_actor_set_mapped (self, TRUE);
929           break;
930
931         case MAP_STATE_MAKE_UNMAPPED:
932           g_assert (was_mapped);
933           clutter_actor_set_mapped (self, FALSE);
934           break;
935
936         case MAP_STATE_MAKE_UNREALIZED:
937           /* we only use MAKE_UNREALIZED in unparent,
938            * and unparenting a stage isn't possible.
939            * If someone wants to just unrealize a stage
940            * then clutter_actor_unrealize() doesn't
941            * go through this codepath.
942            */
943           g_warning ("Trying to force unrealize stage is not allowed");
944           break;
945         }
946
947       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
948           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
949           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
950         {
951           g_warning ("Clutter toplevel of type '%s' is not visible, but "
952                      "it is somehow still mapped",
953                      _clutter_actor_get_debug_name (self));
954         }
955     }
956   else
957     {
958       ClutterActorPrivate *priv = self->priv;
959       ClutterActor *parent = priv->parent;
960       gboolean should_be_mapped;
961       gboolean may_be_realized;
962       gboolean must_be_realized;
963
964       should_be_mapped = FALSE;
965       may_be_realized = TRUE;
966       must_be_realized = FALSE;
967
968       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
969         {
970           may_be_realized = FALSE;
971         }
972       else
973         {
974           /* Maintain invariant that if parent is mapped, and we are
975            * visible, then we are mapped ...  unless parent is a
976            * stage, in which case we map regardless of parent's map
977            * state but do require stage to be visible and realized.
978            *
979            * If parent is realized, that does not force us to be
980            * realized; but if parent is unrealized, that does force
981            * us to be unrealized.
982            *
983            * The reason we don't force children to realize with
984            * parents is _clutter_actor_rerealize(); if we require that
985            * a realized parent means children are realized, then to
986            * unrealize an actor we would have to unrealize its
987            * parents, which would end up meaning unrealizing and
988            * hiding the entire stage. So we allow unrealizing a
989            * child (as long as that child is not mapped) while that
990            * child still has a realized parent.
991            *
992            * Also, if we unrealize from leaf nodes to root, and
993            * realize from root to leaf, the invariants are never
994            * violated if we allow children to be unrealized
995            * while parents are realized.
996            *
997            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
998            * to force us to unmap, even though parent is still
999            * mapped. This is because we're unmapping from leaf nodes
1000            * up to root nodes.
1001            */
1002           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1003               change != MAP_STATE_MAKE_UNMAPPED)
1004             {
1005               gboolean parent_is_visible_realized_toplevel;
1006
1007               parent_is_visible_realized_toplevel =
1008                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1009                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1010                  CLUTTER_ACTOR_IS_REALIZED (parent));
1011
1012               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1013                   parent_is_visible_realized_toplevel)
1014                 {
1015                   must_be_realized = TRUE;
1016                   should_be_mapped = TRUE;
1017                 }
1018             }
1019
1020           /* if the actor has been set to be painted even if unmapped
1021            * then we should map it and check for realization as well;
1022            * this is an override for the branch of the scene graph
1023            * which begins with this node
1024            */
1025           if (priv->enable_paint_unmapped)
1026             {
1027               if (priv->parent == NULL)
1028                 g_warning ("Attempting to map an unparented actor '%s'",
1029                            _clutter_actor_get_debug_name (self));
1030
1031               should_be_mapped = TRUE;
1032               must_be_realized = TRUE;
1033             }
1034
1035           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1036             may_be_realized = FALSE;
1037         }
1038
1039       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1040         {
1041           if (parent == NULL)
1042             g_warning ("Attempting to map a child that does not "
1043                        "meet the necessary invariants: the actor '%s' "
1044                        "has no parent",
1045                        _clutter_actor_get_debug_name (self));
1046           else
1047             g_warning ("Attempting to map a child that does not "
1048                        "meet the necessary invariants: the actor '%s' "
1049                        "is parented to an unmapped actor '%s'",
1050                        _clutter_actor_get_debug_name (self),
1051                        _clutter_actor_get_debug_name (priv->parent));
1052         }
1053
1054       /* If in reparent, we temporarily suspend unmap and unrealize.
1055        *
1056        * We want to go in the order "realize, map" and "unmap, unrealize"
1057        */
1058
1059       /* Unmap */
1060       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1061         clutter_actor_set_mapped (self, FALSE);
1062
1063       /* Realize */
1064       if (must_be_realized)
1065         clutter_actor_realize (self);
1066
1067       /* if we must be realized then we may be, presumably */
1068       g_assert (!(must_be_realized && !may_be_realized));
1069
1070       /* Unrealize */
1071       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1072         clutter_actor_unrealize_not_hiding (self);
1073
1074       /* Map */
1075       if (should_be_mapped)
1076         {
1077           if (!must_be_realized)
1078             g_warning ("Somehow we think actor '%s' should be mapped but "
1079                        "not realized, which isn't allowed",
1080                        _clutter_actor_get_debug_name (self));
1081
1082           /* realization is allowed to fail (though I don't know what
1083            * an app is supposed to do about that - shouldn't it just
1084            * be a g_error? anyway, we have to avoid mapping if this
1085            * happens)
1086            */
1087           if (CLUTTER_ACTOR_IS_REALIZED (self))
1088             clutter_actor_set_mapped (self, TRUE);
1089         }
1090     }
1091
1092 #ifdef CLUTTER_ENABLE_DEBUG
1093   /* check all invariants were kept */
1094   clutter_actor_verify_map_state (self);
1095 #endif
1096 }
1097
1098 static void
1099 clutter_actor_real_map (ClutterActor *self)
1100 {
1101   ClutterActorPrivate *priv = self->priv;
1102   ClutterActor *stage, *iter;
1103
1104   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1105
1106   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1107                 _clutter_actor_get_debug_name (self));
1108
1109   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1110
1111   stage = _clutter_actor_get_stage_internal (self);
1112   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1113
1114   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1115                 priv->pick_id,
1116                 _clutter_actor_get_debug_name (self));
1117
1118   /* notify on parent mapped before potentially mapping
1119    * children, so apps see a top-down notification.
1120    */
1121   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1122
1123   for (iter = self->priv->first_child;
1124        iter != NULL;
1125        iter = iter->priv->next_sibling)
1126     {
1127       clutter_actor_map (iter);
1128     }
1129 }
1130
1131 /**
1132  * clutter_actor_map:
1133  * @self: A #ClutterActor
1134  *
1135  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1136  * and realizes its children if they are visible. Does nothing if the
1137  * actor is not visible.
1138  *
1139  * Calling this function is strongly disencouraged: the default
1140  * implementation of #ClutterActorClass.map() will map all the children
1141  * of an actor when mapping its parent.
1142  *
1143  * When overriding map, it is mandatory to chain up to the parent
1144  * implementation.
1145  *
1146  * Since: 1.0
1147  */
1148 void
1149 clutter_actor_map (ClutterActor *self)
1150 {
1151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1152
1153   if (CLUTTER_ACTOR_IS_MAPPED (self))
1154     return;
1155
1156   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1157     return;
1158
1159   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1160 }
1161
1162 static void
1163 clutter_actor_real_unmap (ClutterActor *self)
1164 {
1165   ClutterActorPrivate *priv = self->priv;
1166   ClutterActor *iter;
1167
1168   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1169
1170   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1171                 _clutter_actor_get_debug_name (self));
1172
1173   for (iter = self->priv->first_child;
1174        iter != NULL;
1175        iter = iter->priv->next_sibling)
1176     {
1177       clutter_actor_unmap (iter);
1178     }
1179
1180   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1181
1182   /* clear the contents of the last paint volume, so that hiding + moving +
1183    * showing will not result in the wrong area being repainted
1184    */
1185   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1186   priv->last_paint_volume_valid = TRUE;
1187
1188   /* notify on parent mapped after potentially unmapping
1189    * children, so apps see a bottom-up notification.
1190    */
1191   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1192
1193   /* relinquish keyboard focus if we were unmapped while owning it */
1194   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1195     {
1196       ClutterStage *stage;
1197
1198       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1199
1200       if (stage != NULL)
1201         _clutter_stage_release_pick_id (stage, priv->pick_id);
1202
1203       priv->pick_id = -1;
1204
1205       if (stage != NULL &&
1206           clutter_stage_get_key_focus (stage) == self)
1207         {
1208           clutter_stage_set_key_focus (stage, NULL);
1209         }
1210     }
1211 }
1212
1213 /**
1214  * clutter_actor_unmap:
1215  * @self: A #ClutterActor
1216  *
1217  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1218  * unmaps its children if they were mapped.
1219  *
1220  * Calling this function is not encouraged: the default #ClutterActor
1221  * implementation of #ClutterActorClass.unmap() will also unmap any
1222  * eventual children by default when their parent is unmapped.
1223  *
1224  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1225  * chain up to the parent implementation.
1226  *
1227  * <note>It is important to note that the implementation of the
1228  * #ClutterActorClass.unmap() virtual function may be called after
1229  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1230  * implementation, but it is guaranteed to be called before the
1231  * #GObjectClass.finalize() implementation.</note>
1232  *
1233  * Since: 1.0
1234  */
1235 void
1236 clutter_actor_unmap (ClutterActor *self)
1237 {
1238   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1239
1240   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1241     return;
1242
1243   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1244 }
1245
1246 static void
1247 clutter_actor_real_show (ClutterActor *self)
1248 {
1249   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1250     {
1251       ClutterActorPrivate *priv = self->priv;
1252
1253       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1254
1255       /* we notify on the "visible" flag in the clutter_actor_show()
1256        * wrapper so the entire show signal emission completes first
1257        * (?)
1258        */
1259       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1260
1261       /* we queue a relayout unless the actor is inside a
1262        * container that explicitly told us not to
1263        */
1264       if (priv->parent != NULL &&
1265           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1266         {
1267           /* While an actor is hidden the parent may not have
1268            * allocated/requested so we need to start from scratch
1269            * and avoid the short-circuiting in
1270            * clutter_actor_queue_relayout().
1271            */
1272           priv->needs_width_request  = FALSE;
1273           priv->needs_height_request = FALSE;
1274           priv->needs_allocation     = FALSE;
1275           clutter_actor_queue_relayout (self);
1276         }
1277     }
1278 }
1279
1280 static inline void
1281 set_show_on_set_parent (ClutterActor *self,
1282                         gboolean      set_show)
1283 {
1284   ClutterActorPrivate *priv = self->priv;
1285
1286   set_show = !!set_show;
1287
1288   if (priv->show_on_set_parent == set_show)
1289     return;
1290
1291   if (priv->parent == NULL)
1292     {
1293       priv->show_on_set_parent = set_show;
1294       g_object_notify_by_pspec (G_OBJECT (self),
1295                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1296     }
1297 }
1298
1299 /**
1300  * clutter_actor_show:
1301  * @self: A #ClutterActor
1302  *
1303  * Flags an actor to be displayed. An actor that isn't shown will not
1304  * be rendered on the stage.
1305  *
1306  * Actors are visible by default.
1307  *
1308  * If this function is called on an actor without a parent, the
1309  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1310  * effect.
1311  */
1312 void
1313 clutter_actor_show (ClutterActor *self)
1314 {
1315   ClutterActorPrivate *priv;
1316
1317   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1318
1319   /* simple optimization */
1320   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1321     {
1322       /* we still need to set the :show-on-set-parent property, in
1323        * case show() is called on an unparented actor
1324        */
1325       set_show_on_set_parent (self, TRUE);
1326       return;
1327     }
1328
1329 #ifdef CLUTTER_ENABLE_DEBUG
1330   clutter_actor_verify_map_state (self);
1331 #endif
1332
1333   priv = self->priv;
1334
1335   g_object_freeze_notify (G_OBJECT (self));
1336
1337   set_show_on_set_parent (self, TRUE);
1338
1339   g_signal_emit (self, actor_signals[SHOW], 0);
1340   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1341
1342   if (priv->parent != NULL)
1343     clutter_actor_queue_redraw (priv->parent);
1344
1345   g_object_thaw_notify (G_OBJECT (self));
1346 }
1347
1348 /**
1349  * clutter_actor_show_all:
1350  * @self: a #ClutterActor
1351  *
1352  * Calls clutter_actor_show() on all children of an actor (if any).
1353  *
1354  * Since: 0.2
1355  *
1356  * Deprecated: 1.10: Actors are visible by default
1357  */
1358 void
1359 clutter_actor_show_all (ClutterActor *self)
1360 {
1361   ClutterActorClass *klass;
1362
1363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1364
1365   klass = CLUTTER_ACTOR_GET_CLASS (self);
1366   if (klass->show_all)
1367     klass->show_all (self);
1368 }
1369
1370 static void
1371 clutter_actor_real_hide (ClutterActor *self)
1372 {
1373   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1374     {
1375       ClutterActorPrivate *priv = self->priv;
1376
1377       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1378
1379       /* we notify on the "visible" flag in the clutter_actor_hide()
1380        * wrapper so the entire hide signal emission completes first
1381        * (?)
1382        */
1383       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1384
1385       /* we queue a relayout unless the actor is inside a
1386        * container that explicitly told us not to
1387        */
1388       if (priv->parent != NULL &&
1389           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1390         clutter_actor_queue_relayout (priv->parent);
1391     }
1392 }
1393
1394 /**
1395  * clutter_actor_hide:
1396  * @self: A #ClutterActor
1397  *
1398  * Flags an actor to be hidden. A hidden actor will not be
1399  * rendered on the stage.
1400  *
1401  * Actors are visible by default.
1402  *
1403  * If this function is called on an actor without a parent, the
1404  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1405  * as a side-effect.
1406  */
1407 void
1408 clutter_actor_hide (ClutterActor *self)
1409 {
1410   ClutterActorPrivate *priv;
1411
1412   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1413
1414   /* simple optimization */
1415   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1416     {
1417       /* we still need to set the :show-on-set-parent property, in
1418        * case hide() is called on an unparented actor
1419        */
1420       set_show_on_set_parent (self, FALSE);
1421       return;
1422     }
1423
1424 #ifdef CLUTTER_ENABLE_DEBUG
1425   clutter_actor_verify_map_state (self);
1426 #endif
1427
1428   priv = self->priv;
1429
1430   g_object_freeze_notify (G_OBJECT (self));
1431
1432   set_show_on_set_parent (self, FALSE);
1433
1434   g_signal_emit (self, actor_signals[HIDE], 0);
1435   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1436
1437   if (priv->parent != NULL)
1438     clutter_actor_queue_redraw (priv->parent);
1439
1440   g_object_thaw_notify (G_OBJECT (self));
1441 }
1442
1443 /**
1444  * clutter_actor_hide_all:
1445  * @self: a #ClutterActor
1446  *
1447  * Calls clutter_actor_hide() on all child actors (if any).
1448  *
1449  * Since: 0.2
1450  *
1451  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1452  *   prevent its children from being painted as well.
1453  */
1454 void
1455 clutter_actor_hide_all (ClutterActor *self)
1456 {
1457   ClutterActorClass *klass;
1458
1459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1460
1461   klass = CLUTTER_ACTOR_GET_CLASS (self);
1462   if (klass->hide_all)
1463     klass->hide_all (self);
1464 }
1465
1466 /**
1467  * clutter_actor_realize:
1468  * @self: A #ClutterActor
1469  *
1470  * Realization informs the actor that it is attached to a stage. It
1471  * can use this to allocate resources if it wanted to delay allocation
1472  * until it would be rendered. However it is perfectly acceptable for
1473  * an actor to create resources before being realized because Clutter
1474  * only ever has a single rendering context so that actor is free to
1475  * be moved from one stage to another.
1476  *
1477  * This function does nothing if the actor is already realized.
1478  *
1479  * Because a realized actor must have realized parent actors, calling
1480  * clutter_actor_realize() will also realize all parents of the actor.
1481  *
1482  * This function does not realize child actors, except in the special
1483  * case that realizing the stage, when the stage is visible, will
1484  * suddenly map (and thus realize) the children of the stage.
1485  **/
1486 void
1487 clutter_actor_realize (ClutterActor *self)
1488 {
1489   ClutterActorPrivate *priv;
1490
1491   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1492
1493   priv = self->priv;
1494
1495 #ifdef CLUTTER_ENABLE_DEBUG
1496   clutter_actor_verify_map_state (self);
1497 #endif
1498
1499   if (CLUTTER_ACTOR_IS_REALIZED (self))
1500     return;
1501
1502   /* To be realized, our parent actors must be realized first.
1503    * This will only succeed if we're inside a toplevel.
1504    */
1505   if (priv->parent != NULL)
1506     clutter_actor_realize (priv->parent);
1507
1508   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1509     {
1510       /* toplevels can be realized at any time */
1511     }
1512   else
1513     {
1514       /* "Fail" the realization if parent is missing or unrealized;
1515        * this should really be a g_warning() not some kind of runtime
1516        * failure; how can an app possibly recover? Instead it's a bug
1517        * in the app and the app should get an explanatory warning so
1518        * someone can fix it. But for now it's too hard to fix this
1519        * because e.g. ClutterTexture needs reworking.
1520        */
1521       if (priv->parent == NULL ||
1522           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1523         return;
1524     }
1525
1526   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1527
1528   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1529   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1530
1531   g_signal_emit (self, actor_signals[REALIZE], 0);
1532
1533   /* Stage actor is allowed to unset the realized flag again in its
1534    * default signal handler, though that is a pathological situation.
1535    */
1536
1537   /* If realization "failed" we'll have to update child state. */
1538   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1539 }
1540
1541 static void
1542 clutter_actor_real_unrealize (ClutterActor *self)
1543 {
1544   /* we must be unmapped (implying our children are also unmapped) */
1545   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1546 }
1547
1548 /**
1549  * clutter_actor_unrealize:
1550  * @self: A #ClutterActor
1551  *
1552  * Unrealization informs the actor that it may be being destroyed or
1553  * moved to another stage. The actor may want to destroy any
1554  * underlying graphics resources at this point. However it is
1555  * perfectly acceptable for it to retain the resources until the actor
1556  * is destroyed because Clutter only ever uses a single rendering
1557  * context and all of the graphics resources are valid on any stage.
1558  *
1559  * Because mapped actors must be realized, actors may not be
1560  * unrealized if they are mapped. This function hides the actor to be
1561  * sure it isn't mapped, an application-visible side effect that you
1562  * may not be expecting.
1563  *
1564  * This function should not be called by application code.
1565  */
1566 void
1567 clutter_actor_unrealize (ClutterActor *self)
1568 {
1569   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1570   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1571
1572 /* This function should not really be in the public API, because
1573  * there isn't a good reason to call it. ClutterActor will already
1574  * unrealize things for you when it's important to do so.
1575  *
1576  * If you were using clutter_actor_unrealize() in a dispose
1577  * implementation, then don't, just chain up to ClutterActor's
1578  * dispose.
1579  *
1580  * If you were using clutter_actor_unrealize() to implement
1581  * unrealizing children of your container, then don't, ClutterActor
1582  * will already take care of that.
1583  *
1584  * If you were using clutter_actor_unrealize() to re-realize to
1585  * create your resources in a different way, then use
1586  * _clutter_actor_rerealize() (inside Clutter) or just call your
1587  * code that recreates your resources directly (outside Clutter).
1588  */
1589
1590 #ifdef CLUTTER_ENABLE_DEBUG
1591   clutter_actor_verify_map_state (self);
1592 #endif
1593
1594   clutter_actor_hide (self);
1595
1596   clutter_actor_unrealize_not_hiding (self);
1597 }
1598
1599 static ClutterActorTraverseVisitFlags
1600 unrealize_actor_before_children_cb (ClutterActor *self,
1601                                     int depth,
1602                                     void *user_data)
1603 {
1604   /* If an actor is already unrealized we know its children have also
1605    * already been unrealized... */
1606   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1607     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1608
1609   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1610
1611   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1612 }
1613
1614 static ClutterActorTraverseVisitFlags
1615 unrealize_actor_after_children_cb (ClutterActor *self,
1616                                    int depth,
1617                                    void *user_data)
1618 {
1619   /* We want to unset the realized flag only _after_
1620    * child actors are unrealized, to maintain invariants.
1621    */
1622   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1623   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1624   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1625 }
1626
1627 /*
1628  * clutter_actor_unrealize_not_hiding:
1629  * @self: A #ClutterActor
1630  *
1631  * Unrealization informs the actor that it may be being destroyed or
1632  * moved to another stage. The actor may want to destroy any
1633  * underlying graphics resources at this point. However it is
1634  * perfectly acceptable for it to retain the resources until the actor
1635  * is destroyed because Clutter only ever uses a single rendering
1636  * context and all of the graphics resources are valid on any stage.
1637  *
1638  * Because mapped actors must be realized, actors may not be
1639  * unrealized if they are mapped. You must hide the actor or one of
1640  * its parents before attempting to unrealize.
1641  *
1642  * This function is separate from clutter_actor_unrealize() because it
1643  * does not automatically hide the actor.
1644  * Actors need not be hidden to be unrealized, they just need to
1645  * be unmapped. In fact we don't want to mess up the application's
1646  * setting of the "visible" flag, so hiding is very undesirable.
1647  *
1648  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1649  * backward compatibility.
1650  */
1651 static void
1652 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1653 {
1654   _clutter_actor_traverse (self,
1655                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1656                            unrealize_actor_before_children_cb,
1657                            unrealize_actor_after_children_cb,
1658                            NULL);
1659 }
1660
1661 /*
1662  * _clutter_actor_rerealize:
1663  * @self: A #ClutterActor
1664  * @callback: Function to call while unrealized
1665  * @data: data for callback
1666  *
1667  * If an actor is already unrealized, this just calls the callback.
1668  *
1669  * If it is realized, it unrealizes temporarily, calls the callback,
1670  * and then re-realizes the actor.
1671  *
1672  * As a side effect, leaves all children of the actor unrealized if
1673  * the actor was realized but not showing.  This is because when we
1674  * unrealize the actor temporarily we must unrealize its children
1675  * (e.g. children of a stage can't be realized if stage window is
1676  * gone). And we aren't clever enough to save the realization state of
1677  * all children. In most cases this should not matter, because
1678  * the children will automatically realize when they next become mapped.
1679  */
1680 void
1681 _clutter_actor_rerealize (ClutterActor    *self,
1682                           ClutterCallback  callback,
1683                           void            *data)
1684 {
1685   gboolean was_mapped;
1686   gboolean was_showing;
1687   gboolean was_realized;
1688
1689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1690
1691 #ifdef CLUTTER_ENABLE_DEBUG
1692   clutter_actor_verify_map_state (self);
1693 #endif
1694
1695   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1696   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1697   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1698
1699   /* Must be unmapped to unrealize. Note we only have to hide this
1700    * actor if it was mapped (if all parents were showing).  If actor
1701    * is merely visible (but not mapped), then that's fine, we can
1702    * leave it visible.
1703    */
1704   if (was_mapped)
1705     clutter_actor_hide (self);
1706
1707   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1708
1709   /* unrealize self and all children */
1710   clutter_actor_unrealize_not_hiding (self);
1711
1712   if (callback != NULL)
1713     {
1714       (* callback) (self, data);
1715     }
1716
1717   if (was_showing)
1718     clutter_actor_show (self); /* will realize only if mapping implies it */
1719   else if (was_realized)
1720     clutter_actor_realize (self); /* realize self and all parents */
1721 }
1722
1723 static void
1724 clutter_actor_real_pick (ClutterActor       *self,
1725                          const ClutterColor *color)
1726 {
1727   /* the default implementation is just to paint a rectangle
1728    * with the same size of the actor using the passed color
1729    */
1730   if (clutter_actor_should_pick_paint (self))
1731     {
1732       ClutterActorBox box = { 0, };
1733       float width, height;
1734
1735       clutter_actor_get_allocation_box (self, &box);
1736
1737       width = box.x2 - box.x1;
1738       height = box.y2 - box.y1;
1739
1740       cogl_set_source_color4ub (color->red,
1741                                 color->green,
1742                                 color->blue,
1743                                 color->alpha);
1744
1745       cogl_rectangle (0, 0, width, height);
1746     }
1747
1748   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1749    * with existing container classes that override the pick() virtual
1750    * and chain up to the default implementation - otherwise we'll end up
1751    * painting our children twice.
1752    *
1753    * this has to go away for 2.0; hopefully along the pick() itself.
1754    */
1755   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1756     {
1757       ClutterActor *iter;
1758
1759       for (iter = self->priv->first_child;
1760            iter != NULL;
1761            iter = iter->priv->next_sibling)
1762         clutter_actor_paint (iter);
1763     }
1764 }
1765
1766 /**
1767  * clutter_actor_should_pick_paint:
1768  * @self: A #ClutterActor
1769  *
1770  * Should be called inside the implementation of the
1771  * #ClutterActor::pick virtual function in order to check whether
1772  * the actor should paint itself in pick mode or not.
1773  *
1774  * This function should never be called directly by applications.
1775  *
1776  * Return value: %TRUE if the actor should paint its silhouette,
1777  *   %FALSE otherwise
1778  */
1779 gboolean
1780 clutter_actor_should_pick_paint (ClutterActor *self)
1781 {
1782   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1783
1784   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1785       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1786        CLUTTER_ACTOR_IS_REACTIVE (self)))
1787     return TRUE;
1788
1789   return FALSE;
1790 }
1791
1792 static void
1793 clutter_actor_real_get_preferred_width (ClutterActor *self,
1794                                         gfloat        for_height,
1795                                         gfloat       *min_width_p,
1796                                         gfloat       *natural_width_p)
1797 {
1798   ClutterActorPrivate *priv = self->priv;
1799
1800   if (priv->n_children != 0 &&
1801       priv->layout_manager != NULL)
1802     {
1803       ClutterContainer *container = CLUTTER_CONTAINER (self);
1804
1805       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1806                     "for the preferred width",
1807                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1808                     priv->layout_manager);
1809
1810       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1811                                                   container,
1812                                                   for_height,
1813                                                   min_width_p,
1814                                                   natural_width_p);
1815
1816       return;
1817     }
1818
1819   /* Default implementation is always 0x0, usually an actor
1820    * using this default is relying on someone to set the
1821    * request manually
1822    */
1823   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1824
1825   if (min_width_p)
1826     *min_width_p = 0;
1827
1828   if (natural_width_p)
1829     *natural_width_p = 0;
1830 }
1831
1832 static void
1833 clutter_actor_real_get_preferred_height (ClutterActor *self,
1834                                          gfloat        for_width,
1835                                          gfloat       *min_height_p,
1836                                          gfloat       *natural_height_p)
1837 {
1838   ClutterActorPrivate *priv = self->priv;
1839
1840   if (priv->n_children != 0 &&
1841       priv->layout_manager != NULL)
1842     {
1843       ClutterContainer *container = CLUTTER_CONTAINER (self);
1844
1845       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1846                     "for the preferred height",
1847                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1848                     priv->layout_manager);
1849
1850       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1851                                                    container,
1852                                                    for_width,
1853                                                    min_height_p,
1854                                                    natural_height_p);
1855
1856       return;
1857     }
1858   /* Default implementation is always 0x0, usually an actor
1859    * using this default is relying on someone to set the
1860    * request manually
1861    */
1862   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1863
1864   if (min_height_p)
1865     *min_height_p = 0;
1866
1867   if (natural_height_p)
1868     *natural_height_p = 0;
1869 }
1870
1871 static void
1872 clutter_actor_store_old_geometry (ClutterActor    *self,
1873                                   ClutterActorBox *box)
1874 {
1875   *box = self->priv->allocation;
1876 }
1877
1878 static inline void
1879 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1880                                           const ClutterActorBox *old)
1881 {
1882   ClutterActorPrivate *priv = self->priv;
1883   GObject *obj = G_OBJECT (self);
1884
1885   g_object_freeze_notify (obj);
1886
1887   /* to avoid excessive requisition or allocation cycles we
1888    * use the cached values.
1889    *
1890    * - if we don't have an allocation we assume that we need
1891    *   to notify anyway
1892    * - if we don't have a width or a height request we notify
1893    *   width and height
1894    * - if we have a valid allocation then we check the old
1895    *   bounding box with the current allocation and we notify
1896    *   the changes
1897    */
1898   if (priv->needs_allocation)
1899     {
1900       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1901       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1904     }
1905   else if (priv->needs_width_request || priv->needs_height_request)
1906     {
1907       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1908       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1909     }
1910   else
1911     {
1912       gfloat xu, yu;
1913       gfloat widthu, heightu;
1914
1915       xu = priv->allocation.x1;
1916       yu = priv->allocation.y1;
1917       widthu = priv->allocation.x2 - priv->allocation.x1;
1918       heightu = priv->allocation.y2 - priv->allocation.y1;
1919
1920       if (xu != old->x1)
1921         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1922
1923       if (yu != old->y1)
1924         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1925
1926       if (widthu != (old->x2 - old->x1))
1927         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1928
1929       if (heightu != (old->y2 - old->y1))
1930         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1931     }
1932
1933   g_object_thaw_notify (obj);
1934 }
1935
1936 /*< private >
1937  * clutter_actor_set_allocation_internal:
1938  * @self: a #ClutterActor
1939  * @box: a #ClutterActorBox
1940  * @flags: allocation flags
1941  *
1942  * Stores the allocation of @self.
1943  *
1944  * This function only performs basic storage and property notification.
1945  *
1946  * This function should be called by clutter_actor_set_allocation()
1947  * and by the default implementation of #ClutterActorClass.allocate().
1948  *
1949  * Return value: %TRUE if the allocation of the #ClutterActor has been
1950  *   changed, and %FALSE otherwise
1951  */
1952 static inline gboolean
1953 clutter_actor_set_allocation_internal (ClutterActor           *self,
1954                                        const ClutterActorBox  *box,
1955                                        ClutterAllocationFlags  flags)
1956 {
1957   ClutterActorPrivate *priv = self->priv;
1958   GObject *obj;
1959   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1960   gboolean flags_changed;
1961   gboolean retval;
1962   ClutterActorBox old_alloc = { 0, };
1963
1964   obj = G_OBJECT (self);
1965
1966   g_object_freeze_notify (obj);
1967
1968   clutter_actor_store_old_geometry (self, &old_alloc);
1969
1970   x1_changed = priv->allocation.x1 != box->x1;
1971   y1_changed = priv->allocation.y1 != box->y1;
1972   x2_changed = priv->allocation.x2 != box->x2;
1973   y2_changed = priv->allocation.y2 != box->y2;
1974
1975   flags_changed = priv->allocation_flags != flags;
1976
1977   priv->allocation = *box;
1978   priv->allocation_flags = flags;
1979
1980   /* allocation is authoritative */
1981   priv->needs_width_request = FALSE;
1982   priv->needs_height_request = FALSE;
1983   priv->needs_allocation = FALSE;
1984
1985   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1986     {
1987       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1988                     _clutter_actor_get_debug_name (self));
1989
1990       priv->transform_valid = FALSE;
1991
1992       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1993
1994       retval = TRUE;
1995     }
1996   else
1997     retval = FALSE;
1998
1999   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2000
2001   g_object_thaw_notify (obj);
2002
2003   return retval;
2004 }
2005
2006 static void clutter_actor_real_allocate (ClutterActor           *self,
2007                                          const ClutterActorBox  *box,
2008                                          ClutterAllocationFlags  flags);
2009
2010 static inline void
2011 clutter_actor_maybe_layout_children (ClutterActor           *self,
2012                                      const ClutterActorBox  *allocation,
2013                                      ClutterAllocationFlags  flags)
2014 {
2015   ClutterActorPrivate *priv = self->priv;
2016
2017   /* this is going to be a bit hard to follow, so let's put an explanation
2018    * here.
2019    *
2020    * we want ClutterActor to have a default layout manager if the actor was
2021    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2022    *
2023    * we also want any subclass of ClutterActor that does not override the
2024    * ::allocate() virtual function to delegate to a layout manager.
2025    *
2026    * finally, we want to allow people subclassing ClutterActor and overriding
2027    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2028    *
2029    * on the other hand, we want existing actor subclasses overriding the
2030    * ::allocate() virtual function and chaining up to the parent's
2031    * implementation to continue working without allocating their children
2032    * twice, or without entering an allocation loop.
2033    *
2034    * for the first two points, we check if the class of the actor is
2035    * overridding the ::allocate() virtual function; if it isn't, then we
2036    * follow through with checking whether we have children and a layout
2037    * manager, and eventually calling clutter_layout_manager_allocate().
2038    *
2039    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2040    * allocation flags that we got passed, and if it is present, we continue
2041    * with the check above.
2042    *
2043    * if neither of these two checks yields a positive result, we just
2044    * assume that the ::allocate() virtual function that resulted in this
2045    * function being called will also allocate the children of the actor.
2046    */
2047
2048   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2049     goto check_layout;
2050
2051   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2052     goto check_layout;
2053
2054   return;
2055
2056 check_layout:
2057   if (priv->n_children != 0 &&
2058       priv->layout_manager != NULL)
2059     {
2060       ClutterContainer *container = CLUTTER_CONTAINER (self);
2061       ClutterAllocationFlags children_flags;
2062       ClutterActorBox children_box;
2063
2064       /* normalize the box passed to the layout manager */
2065       children_box.x1 = children_box.y1 = 0.f;
2066       children_box.x2 = (allocation->x2 - allocation->x1);
2067       children_box.y2 = (allocation->y2 - allocation->y1);
2068
2069       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2070        * the actor's children, since it refers only to the current
2071        * actor's allocation.
2072        */
2073       children_flags = flags;
2074       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2075
2076       CLUTTER_NOTE (LAYOUT,
2077                     "Allocating %d children of %s "
2078                     "at { %.2f, %.2f - %.2f x %.2f } "
2079                     "using %s",
2080                     priv->n_children,
2081                     _clutter_actor_get_debug_name (self),
2082                     allocation->x1,
2083                     allocation->y1,
2084                     (allocation->x2 - allocation->x1),
2085                     (allocation->y2 - allocation->y1),
2086                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2087
2088       clutter_layout_manager_allocate (priv->layout_manager,
2089                                        container,
2090                                        &children_box,
2091                                        children_flags);
2092     }
2093 }
2094
2095 static void
2096 clutter_actor_real_allocate (ClutterActor           *self,
2097                              const ClutterActorBox  *box,
2098                              ClutterAllocationFlags  flags)
2099 {
2100   ClutterActorPrivate *priv = self->priv;
2101   gboolean changed;
2102
2103   g_object_freeze_notify (G_OBJECT (self));
2104
2105   changed = clutter_actor_set_allocation_internal (self, box, flags);
2106
2107   /* we allocate our children before we notify changes in our geometry,
2108    * so that people connecting to properties will be able to get valid
2109    * data out of the sub-tree of the scene graph that has this actor at
2110    * the root.
2111    */
2112   clutter_actor_maybe_layout_children (self, box, flags);
2113
2114   if (changed)
2115     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2116                    &priv->allocation,
2117                    priv->allocation_flags);
2118
2119   g_object_thaw_notify (G_OBJECT (self));
2120 }
2121
2122 static void
2123 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2124                                     ClutterActor *origin)
2125 {
2126   /* no point in queuing a redraw on a destroyed actor */
2127   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2128     return;
2129
2130   /* NB: We can't bail out early here if the actor is hidden in case
2131    * the actor bas been cloned. In this case the clone will need to
2132    * receive the signal so it can queue its own redraw.
2133    */
2134
2135   /* calls klass->queue_redraw in default handler */
2136   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2137 }
2138
2139 static void
2140 clutter_actor_real_queue_redraw (ClutterActor *self,
2141                                  ClutterActor *origin)
2142 {
2143   ClutterActor *parent;
2144
2145   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2146                 _clutter_actor_get_debug_name (self),
2147                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2148                                : "same actor");
2149
2150   /* no point in queuing a redraw on a destroyed actor */
2151   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2152     return;
2153
2154   /* If the queue redraw is coming from a child then the actor has
2155      become dirty and any queued effect is no longer valid */
2156   if (self != origin)
2157     {
2158       self->priv->is_dirty = TRUE;
2159       self->priv->effect_to_redraw = NULL;
2160     }
2161
2162   /* If the actor isn't visible, we still had to emit the signal
2163    * to allow for a ClutterClone, but the appearance of the parent
2164    * won't change so we don't have to propagate up the hierarchy.
2165    */
2166   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2167     return;
2168
2169   /* Although we could determine here that a full stage redraw
2170    * has already been queued and immediately bail out, we actually
2171    * guarantee that we will propagate a queue-redraw signal to our
2172    * parent at least once so that it's possible to implement a
2173    * container that tracks which of its children have queued a
2174    * redraw.
2175    */
2176   if (self->priv->propagated_one_redraw)
2177     {
2178       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2179       if (stage != NULL &&
2180           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2181         return;
2182     }
2183
2184   self->priv->propagated_one_redraw = TRUE;
2185
2186   /* notify parents, if they are all visible eventually we'll
2187    * queue redraw on the stage, which queues the redraw idle.
2188    */
2189   parent = clutter_actor_get_parent (self);
2190   if (parent != NULL)
2191     {
2192       /* this will go up recursively */
2193       _clutter_actor_signal_queue_redraw (parent, origin);
2194     }
2195 }
2196
2197 static void
2198 clutter_actor_real_queue_relayout (ClutterActor *self)
2199 {
2200   ClutterActorPrivate *priv = self->priv;
2201
2202   /* no point in queueing a redraw on a destroyed actor */
2203   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2204     return;
2205
2206   priv->needs_width_request  = TRUE;
2207   priv->needs_height_request = TRUE;
2208   priv->needs_allocation     = TRUE;
2209
2210   /* reset the cached size requests */
2211   memset (priv->width_requests, 0,
2212           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2213   memset (priv->height_requests, 0,
2214           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2215
2216   /* We need to go all the way up the hierarchy */
2217   if (priv->parent != NULL)
2218     _clutter_actor_queue_only_relayout (priv->parent);
2219 }
2220
2221 /**
2222  * clutter_actor_apply_relative_transform_to_point:
2223  * @self: A #ClutterActor
2224  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2225  *   default #ClutterStage
2226  * @point: A point as #ClutterVertex
2227  * @vertex: (out caller-allocates): The translated #ClutterVertex
2228  *
2229  * Transforms @point in coordinates relative to the actor into
2230  * ancestor-relative coordinates using the relevant transform
2231  * stack (i.e. scale, rotation, etc).
2232  *
2233  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2234  * this case, the coordinates returned will be the coordinates on
2235  * the stage before the projection is applied. This is different from
2236  * the behaviour of clutter_actor_apply_transform_to_point().
2237  *
2238  * Since: 0.6
2239  */
2240 void
2241 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2242                                                  ClutterActor        *ancestor,
2243                                                  const ClutterVertex *point,
2244                                                  ClutterVertex       *vertex)
2245 {
2246   gfloat w;
2247   CoglMatrix matrix;
2248
2249   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2250   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2251   g_return_if_fail (point != NULL);
2252   g_return_if_fail (vertex != NULL);
2253
2254   *vertex = *point;
2255   w = 1.0;
2256
2257   if (ancestor == NULL)
2258     ancestor = _clutter_actor_get_stage_internal (self);
2259
2260   if (ancestor == NULL)
2261     {
2262       *vertex = *point;
2263       return;
2264     }
2265
2266   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2267   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2268 }
2269
2270 static gboolean
2271 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2272                                          const ClutterVertex *vertices_in,
2273                                          ClutterVertex *vertices_out,
2274                                          int n_vertices)
2275 {
2276   ClutterActor *stage;
2277   CoglMatrix modelview;
2278   CoglMatrix projection;
2279   float viewport[4];
2280
2281   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2282
2283   stage = _clutter_actor_get_stage_internal (self);
2284
2285   /* We really can't do anything meaningful in this case so don't try
2286    * to do any transform */
2287   if (stage == NULL)
2288     return FALSE;
2289
2290   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2291    * that gets us to stage coordinates, we want to go all the way to eye
2292    * coordinates */
2293   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2294
2295   /* Fetch the projection and viewport */
2296   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2297   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2298                                &viewport[0],
2299                                &viewport[1],
2300                                &viewport[2],
2301                                &viewport[3]);
2302
2303   _clutter_util_fully_transform_vertices (&modelview,
2304                                           &projection,
2305                                           viewport,
2306                                           vertices_in,
2307                                           vertices_out,
2308                                           n_vertices);
2309
2310   return TRUE;
2311 }
2312
2313 /**
2314  * clutter_actor_apply_transform_to_point:
2315  * @self: A #ClutterActor
2316  * @point: A point as #ClutterVertex
2317  * @vertex: (out caller-allocates): The translated #ClutterVertex
2318  *
2319  * Transforms @point in coordinates relative to the actor
2320  * into screen-relative coordinates with the current actor
2321  * transformation (i.e. scale, rotation, etc)
2322  *
2323  * Since: 0.4
2324  **/
2325 void
2326 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2327                                         const ClutterVertex *point,
2328                                         ClutterVertex       *vertex)
2329 {
2330   g_return_if_fail (point != NULL);
2331   g_return_if_fail (vertex != NULL);
2332   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2333 }
2334
2335 /*
2336  * _clutter_actor_get_relative_transformation_matrix:
2337  * @self: The actor whose coordinate space you want to transform from.
2338  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2339  *            or %NULL if you want to transform all the way to eye coordinates.
2340  * @matrix: A #CoglMatrix to store the transformation
2341  *
2342  * This gets a transformation @matrix that will transform coordinates from the
2343  * coordinate space of @self into the coordinate space of @ancestor.
2344  *
2345  * For example if you need a matrix that can transform the local actor
2346  * coordinates of @self into stage coordinates you would pass the actor's stage
2347  * pointer as the @ancestor.
2348  *
2349  * If you pass %NULL then the transformation will take you all the way through
2350  * to eye coordinates. This can be useful if you want to extract the entire
2351  * modelview transform that Clutter applies before applying the projection
2352  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2353  * using cogl_set_modelview_matrix() for example then you would want a matrix
2354  * that transforms into eye coordinates.
2355  *
2356  * <note><para>This function explicitly initializes the given @matrix. If you just
2357  * want clutter to multiply a relative transformation with an existing matrix
2358  * you can use clutter_actor_apply_relative_transformation_matrix()
2359  * instead.</para></note>
2360  *
2361  */
2362 /* XXX: We should consider caching the stage relative modelview along with
2363  * the actor itself */
2364 static void
2365 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2366                                                    ClutterActor *ancestor,
2367                                                    CoglMatrix *matrix)
2368 {
2369   cogl_matrix_init_identity (matrix);
2370
2371   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2372 }
2373
2374 /* Project the given @box into stage window coordinates, writing the
2375  * transformed vertices to @verts[]. */
2376 static gboolean
2377 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2378                                           const ClutterActorBox *box,
2379                                           ClutterVertex          verts[])
2380 {
2381   ClutterVertex box_vertices[4];
2382
2383   box_vertices[0].x = box->x1;
2384   box_vertices[0].y = box->y1;
2385   box_vertices[0].z = 0;
2386   box_vertices[1].x = box->x2;
2387   box_vertices[1].y = box->y1;
2388   box_vertices[1].z = 0;
2389   box_vertices[2].x = box->x1;
2390   box_vertices[2].y = box->y2;
2391   box_vertices[2].z = 0;
2392   box_vertices[3].x = box->x2;
2393   box_vertices[3].y = box->y2;
2394   box_vertices[3].z = 0;
2395
2396   return
2397     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2398 }
2399
2400 /**
2401  * clutter_actor_get_allocation_vertices:
2402  * @self: A #ClutterActor
2403  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2404  *   against, or %NULL to use the #ClutterStage
2405  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2406  *   location for an array of 4 #ClutterVertex in which to store the result
2407  *
2408  * Calculates the transformed coordinates of the four corners of the
2409  * actor in the plane of @ancestor. The returned vertices relate to
2410  * the #ClutterActorBox coordinates as follows:
2411  * <itemizedlist>
2412  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2413  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2414  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2415  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2416  * </itemizedlist>
2417  *
2418  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2419  * this case, the coordinates returned will be the coordinates on
2420  * the stage before the projection is applied. This is different from
2421  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2422  *
2423  * Since: 0.6
2424  */
2425 void
2426 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2427                                        ClutterActor  *ancestor,
2428                                        ClutterVertex  verts[])
2429 {
2430   ClutterActorPrivate *priv;
2431   ClutterActorBox box;
2432   ClutterVertex vertices[4];
2433   CoglMatrix modelview;
2434
2435   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2436   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2437
2438   if (ancestor == NULL)
2439     ancestor = _clutter_actor_get_stage_internal (self);
2440
2441   /* Fallback to a NOP transform if the actor isn't parented under a
2442    * stage. */
2443   if (ancestor == NULL)
2444     ancestor = self;
2445
2446   priv = self->priv;
2447
2448   /* if the actor needs to be allocated we force a relayout, so that
2449    * we will have valid values to use in the transformations */
2450   if (priv->needs_allocation)
2451     {
2452       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2453       if (stage)
2454         _clutter_stage_maybe_relayout (stage);
2455       else
2456         {
2457           box.x1 = box.y1 = 0;
2458           /* The result isn't really meaningful in this case but at
2459            * least try to do something *vaguely* reasonable... */
2460           clutter_actor_get_size (self, &box.x2, &box.y2);
2461         }
2462     }
2463
2464   clutter_actor_get_allocation_box (self, &box);
2465
2466   vertices[0].x = box.x1;
2467   vertices[0].y = box.y1;
2468   vertices[0].z = 0;
2469   vertices[1].x = box.x2;
2470   vertices[1].y = box.y1;
2471   vertices[1].z = 0;
2472   vertices[2].x = box.x1;
2473   vertices[2].y = box.y2;
2474   vertices[2].z = 0;
2475   vertices[3].x = box.x2;
2476   vertices[3].y = box.y2;
2477   vertices[3].z = 0;
2478
2479   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2480                                                      &modelview);
2481
2482   cogl_matrix_transform_points (&modelview,
2483                                 3,
2484                                 sizeof (ClutterVertex),
2485                                 vertices,
2486                                 sizeof (ClutterVertex),
2487                                 vertices,
2488                                 4);
2489 }
2490
2491 /**
2492  * clutter_actor_get_abs_allocation_vertices:
2493  * @self: A #ClutterActor
2494  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2495  *   of 4 #ClutterVertex where to store the result.
2496  *
2497  * Calculates the transformed screen coordinates of the four corners of
2498  * the actor; the returned vertices relate to the #ClutterActorBox
2499  * coordinates  as follows:
2500  * <itemizedlist>
2501  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2502  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2503  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2504  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2505  * </itemizedlist>
2506  *
2507  * Since: 0.4
2508  */
2509 void
2510 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2511                                            ClutterVertex  verts[])
2512 {
2513   ClutterActorPrivate *priv;
2514   ClutterActorBox actor_space_allocation;
2515
2516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2517
2518   priv = self->priv;
2519
2520   /* if the actor needs to be allocated we force a relayout, so that
2521    * the actor allocation box will be valid for
2522    * _clutter_actor_transform_and_project_box()
2523    */
2524   if (priv->needs_allocation)
2525     {
2526       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2527       /* There's nothing meaningful we can do now */
2528       if (!stage)
2529         return;
2530
2531       _clutter_stage_maybe_relayout (stage);
2532     }
2533
2534   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2535    * own coordinate space... */
2536   actor_space_allocation.x1 = 0;
2537   actor_space_allocation.y1 = 0;
2538   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2539   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2540   _clutter_actor_transform_and_project_box (self,
2541                                             &actor_space_allocation,
2542                                             verts);
2543 }
2544
2545 static void
2546 clutter_actor_real_apply_transform (ClutterActor *self,
2547                                     CoglMatrix   *matrix)
2548 {
2549   ClutterActorPrivate *priv = self->priv;
2550
2551   if (!priv->transform_valid)
2552     {
2553       CoglMatrix *transform = &priv->transform;
2554       const ClutterTransformInfo *info;
2555
2556       info = _clutter_actor_get_transform_info_or_defaults (self);
2557
2558       cogl_matrix_init_identity (transform);
2559
2560       cogl_matrix_translate (transform,
2561                              priv->allocation.x1,
2562                              priv->allocation.y1,
2563                              0.0);
2564
2565       if (priv->z)
2566         cogl_matrix_translate (transform, 0, 0, priv->z);
2567
2568       /*
2569        * because the rotation involves translations, we must scale
2570        * before applying the rotations (if we apply the scale after
2571        * the rotations, the translations included in the rotation are
2572        * not scaled and so the entire object will move on the screen
2573        * as a result of rotating it).
2574        */
2575       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2576         {
2577           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2578                                         &info->scale_center,
2579                                         cogl_matrix_scale (transform,
2580                                                            info->scale_x,
2581                                                            info->scale_y,
2582                                                            1.0));
2583         }
2584
2585       if (info->rz_angle)
2586         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2587                                       &info->rz_center,
2588                                       cogl_matrix_rotate (transform,
2589                                                           info->rz_angle,
2590                                                           0, 0, 1.0));
2591
2592       if (info->ry_angle)
2593         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2594                                       &info->ry_center,
2595                                       cogl_matrix_rotate (transform,
2596                                                           info->ry_angle,
2597                                                           0, 1.0, 0));
2598
2599       if (info->rx_angle)
2600         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2601                                       &info->rx_center,
2602                                       cogl_matrix_rotate (transform,
2603                                                           info->rx_angle,
2604                                                           1.0, 0, 0));
2605
2606       if (!clutter_anchor_coord_is_zero (&info->anchor))
2607         {
2608           gfloat x, y, z;
2609
2610           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2611           cogl_matrix_translate (transform, -x, -y, -z);
2612         }
2613
2614       priv->transform_valid = TRUE;
2615     }
2616
2617   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2618 }
2619
2620 /* Applies the transforms associated with this actor to the given
2621  * matrix. */
2622 void
2623 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2624                                           CoglMatrix *matrix)
2625 {
2626   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2627 }
2628
2629 /*
2630  * clutter_actor_apply_relative_transformation_matrix:
2631  * @self: The actor whose coordinate space you want to transform from.
2632  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2633  *            or %NULL if you want to transform all the way to eye coordinates.
2634  * @matrix: A #CoglMatrix to apply the transformation too.
2635  *
2636  * This multiplies a transform with @matrix that will transform coordinates
2637  * from the coordinate space of @self into the coordinate space of @ancestor.
2638  *
2639  * For example if you need a matrix that can transform the local actor
2640  * coordinates of @self into stage coordinates you would pass the actor's stage
2641  * pointer as the @ancestor.
2642  *
2643  * If you pass %NULL then the transformation will take you all the way through
2644  * to eye coordinates. This can be useful if you want to extract the entire
2645  * modelview transform that Clutter applies before applying the projection
2646  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2647  * using cogl_set_modelview_matrix() for example then you would want a matrix
2648  * that transforms into eye coordinates.
2649  *
2650  * <note>This function doesn't initialize the given @matrix, it simply
2651  * multiplies the requested transformation matrix with the existing contents of
2652  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2653  * before calling this function, or you can use
2654  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2655  */
2656 void
2657 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2658                                                      ClutterActor *ancestor,
2659                                                      CoglMatrix *matrix)
2660 {
2661   ClutterActor *parent;
2662
2663   /* Note we terminate before ever calling stage->apply_transform()
2664    * since that would conceptually be relative to the underlying
2665    * window OpenGL coordinates so we'd need a special @ancestor
2666    * value to represent the fake parent of the stage. */
2667   if (self == ancestor)
2668     return;
2669
2670   parent = clutter_actor_get_parent (self);
2671
2672   if (parent != NULL)
2673     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2674                                                          matrix);
2675
2676   _clutter_actor_apply_modelview_transform (self, matrix);
2677 }
2678
2679 static void
2680 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2681                                        ClutterPaintVolume *pv,
2682                                        const char *label,
2683                                        const CoglColor *color)
2684 {
2685   static CoglPipeline *outline = NULL;
2686   CoglPrimitive *prim;
2687   ClutterVertex line_ends[12 * 2];
2688   int n_vertices;
2689   CoglContext *ctx =
2690     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2691   /* XXX: at some point we'll query this from the stage but we can't
2692    * do that until the osx backend uses Cogl natively. */
2693   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2694
2695   if (outline == NULL)
2696     outline = cogl_pipeline_new ();
2697
2698   _clutter_paint_volume_complete (pv);
2699
2700   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2701
2702   /* Front face */
2703   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2704   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2705   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2706   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2707
2708   if (!pv->is_2d)
2709     {
2710       /* Back face */
2711       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2712       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2713       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2714       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2715
2716       /* Lines connecting front face to back face */
2717       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2718       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2719       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2720       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2721     }
2722
2723   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES, n_vertices,
2724                                 (CoglVertexP3 *)line_ends);
2725
2726   cogl_pipeline_set_color (outline, color);
2727   cogl_framebuffer_draw_primitive (fb, outline, prim);
2728   cogl_object_unref (prim);
2729
2730   if (label)
2731     {
2732       PangoLayout *layout;
2733       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2734       pango_layout_set_text (layout, label, -1);
2735       cogl_pango_render_layout (layout,
2736                                 pv->vertices[0].x,
2737                                 pv->vertices[0].y,
2738                                 color,
2739                                 0);
2740       g_object_unref (layout);
2741     }
2742 }
2743
2744 static void
2745 _clutter_actor_draw_paint_volume (ClutterActor *self)
2746 {
2747   ClutterPaintVolume *pv;
2748   CoglColor color;
2749
2750   pv = _clutter_actor_get_paint_volume_mutable (self);
2751   if (!pv)
2752     {
2753       gfloat width, height;
2754       ClutterPaintVolume fake_pv;
2755
2756       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2757       _clutter_paint_volume_init_static (&fake_pv, stage);
2758
2759       clutter_actor_get_size (self, &width, &height);
2760       clutter_paint_volume_set_width (&fake_pv, width);
2761       clutter_paint_volume_set_height (&fake_pv, height);
2762
2763       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2764       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2765                                              _clutter_actor_get_debug_name (self),
2766                                              &color);
2767
2768       clutter_paint_volume_free (&fake_pv);
2769     }
2770   else
2771     {
2772       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2773       _clutter_actor_draw_paint_volume_full (self, pv,
2774                                              _clutter_actor_get_debug_name (self),
2775                                              &color);
2776     }
2777 }
2778
2779 static void
2780 _clutter_actor_paint_cull_result (ClutterActor *self,
2781                                   gboolean success,
2782                                   ClutterCullResult result)
2783 {
2784   ClutterPaintVolume *pv;
2785   CoglColor color;
2786
2787   if (success)
2788     {
2789       if (result == CLUTTER_CULL_RESULT_IN)
2790         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2791       else if (result == CLUTTER_CULL_RESULT_OUT)
2792         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2793       else
2794         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2795     }
2796   else
2797     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2798
2799   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2800     _clutter_actor_draw_paint_volume_full (self, pv,
2801                                            _clutter_actor_get_debug_name (self),
2802                                            &color);
2803   else
2804     {
2805       PangoLayout *layout;
2806       char *label =
2807         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2808       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2809       cogl_set_source_color (&color);
2810
2811       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2812       pango_layout_set_text (layout, label, -1);
2813       cogl_pango_render_layout (layout,
2814                                 0,
2815                                 0,
2816                                 &color,
2817                                 0);
2818       g_free (label);
2819       g_object_unref (layout);
2820     }
2821 }
2822
2823 static int clone_paint_level = 0;
2824
2825 void
2826 _clutter_actor_push_clone_paint (void)
2827 {
2828   clone_paint_level++;
2829 }
2830
2831 void
2832 _clutter_actor_pop_clone_paint (void)
2833 {
2834   clone_paint_level--;
2835 }
2836
2837 static gboolean
2838 in_clone_paint (void)
2839 {
2840   return clone_paint_level > 0;
2841 }
2842
2843 /* Returns TRUE if the actor can be ignored */
2844 /* FIXME: we should return a ClutterCullResult, and
2845  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2846  * means there's no point in trying to cull descendants of the current
2847  * node. */
2848 static gboolean
2849 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2850 {
2851   ClutterActorPrivate *priv = self->priv;
2852   ClutterActor *stage;
2853   const ClutterPlane *stage_clip;
2854
2855   if (!priv->last_paint_volume_valid)
2856     {
2857       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2858                     "->last_paint_volume_valid == FALSE",
2859                     _clutter_actor_get_debug_name (self));
2860       return FALSE;
2861     }
2862
2863   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2864     return FALSE;
2865
2866   stage = _clutter_actor_get_stage_internal (self);
2867   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2868   if (G_UNLIKELY (!stage_clip))
2869     {
2870       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2871                     "No stage clip set",
2872                     _clutter_actor_get_debug_name (self));
2873       return FALSE;
2874     }
2875
2876   if (cogl_get_draw_framebuffer () !=
2877       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2878     {
2879       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2880                     "Current framebuffer doesn't correspond to stage",
2881                     _clutter_actor_get_debug_name (self));
2882       return FALSE;
2883     }
2884
2885   *result_out =
2886     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2887   return TRUE;
2888 }
2889
2890 static void
2891 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2892 {
2893   ClutterActorPrivate *priv = self->priv;
2894   const ClutterPaintVolume *pv;
2895
2896   if (priv->last_paint_volume_valid)
2897     {
2898       clutter_paint_volume_free (&priv->last_paint_volume);
2899       priv->last_paint_volume_valid = FALSE;
2900     }
2901
2902   pv = clutter_actor_get_paint_volume (self);
2903   if (!pv)
2904     {
2905       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2906                     "Actor failed to report a paint volume",
2907                     _clutter_actor_get_debug_name (self));
2908       return;
2909     }
2910
2911   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2912
2913   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2914                                             NULL); /* eye coordinates */
2915
2916   priv->last_paint_volume_valid = TRUE;
2917 }
2918
2919 static inline gboolean
2920 actor_has_shader_data (ClutterActor *self)
2921 {
2922   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2923 }
2924
2925 guint32
2926 _clutter_actor_get_pick_id (ClutterActor *self)
2927 {
2928   if (self->priv->pick_id < 0)
2929     return 0;
2930
2931   return self->priv->pick_id;
2932 }
2933
2934 /* This is the same as clutter_actor_add_effect except that it doesn't
2935    queue a redraw and it doesn't notify on the effect property */
2936 static void
2937 _clutter_actor_add_effect_internal (ClutterActor  *self,
2938                                     ClutterEffect *effect)
2939 {
2940   ClutterActorPrivate *priv = self->priv;
2941
2942   if (priv->effects == NULL)
2943     {
2944       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2945       priv->effects->actor = self;
2946     }
2947
2948   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2949 }
2950
2951 /* This is the same as clutter_actor_remove_effect except that it doesn't
2952    queue a redraw and it doesn't notify on the effect property */
2953 static void
2954 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2955                                        ClutterEffect *effect)
2956 {
2957   ClutterActorPrivate *priv = self->priv;
2958
2959   if (priv->effects == NULL)
2960     return;
2961
2962   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2963 }
2964
2965 static gboolean
2966 needs_flatten_effect (ClutterActor *self)
2967 {
2968   ClutterActorPrivate *priv = self->priv;
2969
2970   if (G_UNLIKELY (clutter_paint_debug_flags &
2971                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2972     return FALSE;
2973
2974   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2975     return TRUE;
2976   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2977     {
2978       if (clutter_actor_get_paint_opacity (self) < 255 &&
2979           clutter_actor_has_overlaps (self))
2980         return TRUE;
2981     }
2982
2983   return FALSE;
2984 }
2985
2986 static void
2987 add_or_remove_flatten_effect (ClutterActor *self)
2988 {
2989   ClutterActorPrivate *priv = self->priv;
2990
2991   /* Add or remove the flatten effect depending on the
2992      offscreen-redirect property. */
2993   if (needs_flatten_effect (self))
2994     {
2995       if (priv->flatten_effect == NULL)
2996         {
2997           ClutterActorMeta *actor_meta;
2998           gint priority;
2999
3000           priv->flatten_effect = _clutter_flatten_effect_new ();
3001           /* Keep a reference to the effect so that we can queue
3002              redraws from it */
3003           g_object_ref_sink (priv->flatten_effect);
3004
3005           /* Set the priority of the effect to high so that it will
3006              always be applied to the actor first. It uses an internal
3007              priority so that it won't be visible to applications */
3008           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3009           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3010           _clutter_actor_meta_set_priority (actor_meta, priority);
3011
3012           /* This will add the effect without queueing a redraw */
3013           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3014         }
3015     }
3016   else
3017     {
3018       if (priv->flatten_effect != NULL)
3019         {
3020           /* Destroy the effect so that it will lose its fbo cache of
3021              the actor */
3022           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3023           g_object_unref (priv->flatten_effect);
3024           priv->flatten_effect = NULL;
3025         }
3026     }
3027 }
3028
3029 static void
3030 clutter_actor_real_paint (ClutterActor *actor)
3031 {
3032   ClutterActorPrivate *priv = actor->priv;
3033   ClutterActor *iter;
3034
3035   /* paint the background color, if set */
3036   if (priv->bg_color_set)
3037     {
3038       float width, height;
3039       guint8 real_alpha;
3040
3041       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3042
3043       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3044                  * priv->bg_color.alpha
3045                  / 255;
3046
3047       cogl_set_source_color4ub (priv->bg_color.red,
3048                                 priv->bg_color.green,
3049                                 priv->bg_color.blue,
3050                                 real_alpha);
3051
3052       cogl_rectangle (0, 0, width, height);
3053     }
3054
3055   for (iter = priv->first_child;
3056        iter != NULL;
3057        iter = iter->priv->next_sibling)
3058     {
3059       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3060                     _clutter_actor_get_debug_name (iter),
3061                     _clutter_actor_get_debug_name (actor),
3062                     iter->priv->allocation.x1,
3063                     iter->priv->allocation.y1,
3064                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3065                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3066
3067       clutter_actor_paint (iter);
3068     }
3069 }
3070
3071 /**
3072  * clutter_actor_paint:
3073  * @self: A #ClutterActor
3074  *
3075  * Renders the actor to display.
3076  *
3077  * This function should not be called directly by applications.
3078  * Call clutter_actor_queue_redraw() to queue paints, instead.
3079  *
3080  * This function is context-aware, and will either cause a
3081  * regular paint or a pick paint.
3082  *
3083  * This function will emit the #ClutterActor::paint signal or
3084  * the #ClutterActor::pick signal, depending on the context.
3085  *
3086  * This function does not paint the actor if the actor is set to 0,
3087  * unless it is performing a pick paint.
3088  */
3089 void
3090 clutter_actor_paint (ClutterActor *self)
3091 {
3092   ClutterActorPrivate *priv;
3093   ClutterPickMode pick_mode;
3094   gboolean clip_set = FALSE;
3095   gboolean shader_applied = FALSE;
3096
3097   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3098                           "Actor real-paint counter",
3099                           "Increments each time any actor is painted",
3100                           0 /* no application private data */);
3101   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3102                           "Actor pick-paint counter",
3103                           "Increments each time any actor is painted "
3104                           "for picking",
3105                           0 /* no application private data */);
3106
3107   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3108
3109   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3110     return;
3111
3112   priv = self->priv;
3113
3114   pick_mode = _clutter_context_get_pick_mode ();
3115
3116   if (pick_mode == CLUTTER_PICK_NONE)
3117     priv->propagated_one_redraw = FALSE;
3118
3119   /* It's an important optimization that we consider painting of
3120    * actors with 0 opacity to be a NOP... */
3121   if (pick_mode == CLUTTER_PICK_NONE &&
3122       /* ignore top-levels, since they might be transparent */
3123       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3124       /* Use the override opacity if its been set */
3125       ((priv->opacity_override >= 0) ?
3126        priv->opacity_override : priv->opacity) == 0)
3127     return;
3128
3129   /* if we aren't paintable (not in a toplevel with all
3130    * parents paintable) then do nothing.
3131    */
3132   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3133     return;
3134
3135   /* mark that we are in the paint process */
3136   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3137
3138   cogl_push_matrix();
3139
3140   if (priv->enable_model_view_transform)
3141     {
3142       CoglMatrix matrix;
3143
3144       /* XXX: It could be better to cache the modelview with the actor
3145        * instead of progressively building up the transformations on
3146        * the matrix stack every time we paint. */
3147       cogl_get_modelview_matrix (&matrix);
3148       _clutter_actor_apply_modelview_transform (self, &matrix);
3149
3150 #ifdef CLUTTER_ENABLE_DEBUG
3151       /* Catch when out-of-band transforms have been made by actors not as part
3152        * of an apply_transform vfunc... */
3153       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3154         {
3155           CoglMatrix expected_matrix;
3156
3157           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3158                                                              &expected_matrix);
3159
3160           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3161             {
3162               GString *buf = g_string_sized_new (1024);
3163               ClutterActor *parent;
3164
3165               parent = self;
3166               while (parent != NULL)
3167                 {
3168                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3169
3170                   if (parent->priv->parent != NULL)
3171                     g_string_append (buf, "->");
3172
3173                   parent = parent->priv->parent;
3174                 }
3175
3176               g_warning ("Unexpected transform found when painting actor "
3177                          "\"%s\". This will be caused by one of the actor's "
3178                          "ancestors (%s) using the Cogl API directly to transform "
3179                          "children instead of using ::apply_transform().",
3180                          _clutter_actor_get_debug_name (self),
3181                          buf->str);
3182
3183               g_string_free (buf, TRUE);
3184             }
3185         }
3186 #endif /* CLUTTER_ENABLE_DEBUG */
3187
3188       cogl_set_modelview_matrix (&matrix);
3189     }
3190
3191   if (priv->has_clip)
3192     {
3193       cogl_clip_push_rectangle (priv->clip.x,
3194                                 priv->clip.y,
3195                                 priv->clip.x + priv->clip.width,
3196                                 priv->clip.y + priv->clip.height);
3197       clip_set = TRUE;
3198     }
3199   else if (priv->clip_to_allocation)
3200     {
3201       gfloat width, height;
3202
3203       width  = priv->allocation.x2 - priv->allocation.x1;
3204       height = priv->allocation.y2 - priv->allocation.y1;
3205
3206       cogl_clip_push_rectangle (0, 0, width, height);
3207       clip_set = TRUE;
3208     }
3209
3210   if (pick_mode == CLUTTER_PICK_NONE)
3211     {
3212       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3213
3214       /* We check whether we need to add the flatten effect before
3215          each paint so that we can avoid having a mechanism for
3216          applications to notify when the value of the
3217          has_overlaps virtual changes. */
3218       add_or_remove_flatten_effect (self);
3219     }
3220   else
3221     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3222
3223   /* We save the current paint volume so that the next time the
3224    * actor queues a redraw we can constrain the redraw to just
3225    * cover the union of the new bounding box and the old.
3226    *
3227    * We also fetch the current paint volume to perform culling so
3228    * we can avoid painting actors outside the current clip region.
3229    *
3230    * If we are painting inside a clone, we should neither update
3231    * the paint volume or use it to cull painting, since the paint
3232    * box represents the location of the source actor on the
3233    * screen.
3234    *
3235    * XXX: We are starting to do a lot of vertex transforms on
3236    * the CPU in a typical paint, so at some point we should
3237    * audit these and consider caching some things.
3238    *
3239    * NB: We don't perform culling while picking at this point because
3240    * clutter-stage.c doesn't setup the clipping planes appropriately.
3241    *
3242    * NB: We don't want to update the last-paint-volume during picking
3243    * because the last-paint-volume is used to determine the old screen
3244    * space location of an actor that has moved so we can know the
3245    * minimal region to redraw to clear an old view of the actor. If we
3246    * update this during picking then by the time we come around to
3247    * paint then the last-paint-volume would likely represent the new
3248    * actor position not the old.
3249    */
3250   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3251     {
3252       gboolean success;
3253       /* annoyingly gcc warns if uninitialized even though
3254        * the initialization is redundant :-( */
3255       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3256
3257       if (G_LIKELY ((clutter_paint_debug_flags &
3258                      (CLUTTER_DEBUG_DISABLE_CULLING |
3259                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3260                     (CLUTTER_DEBUG_DISABLE_CULLING |
3261                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3262         _clutter_actor_update_last_paint_volume (self);
3263
3264       success = cull_actor (self, &result);
3265
3266       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3267         _clutter_actor_paint_cull_result (self, success, result);
3268       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3269         goto done;
3270     }
3271
3272   if (priv->effects == NULL)
3273     {
3274       if (pick_mode == CLUTTER_PICK_NONE &&
3275           actor_has_shader_data (self))
3276         {
3277           _clutter_actor_shader_pre_paint (self, FALSE);
3278           shader_applied = TRUE;
3279         }
3280
3281       priv->next_effect_to_paint = NULL;
3282     }
3283   else
3284     priv->next_effect_to_paint =
3285       _clutter_meta_group_peek_metas (priv->effects);
3286
3287   clutter_actor_continue_paint (self);
3288
3289   if (shader_applied)
3290     _clutter_actor_shader_post_paint (self);
3291
3292   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3293                   pick_mode == CLUTTER_PICK_NONE))
3294     _clutter_actor_draw_paint_volume (self);
3295
3296 done:
3297   /* If we make it here then the actor has run through a complete
3298      paint run including all the effects so it's no longer dirty */
3299   if (pick_mode == CLUTTER_PICK_NONE)
3300     priv->is_dirty = FALSE;
3301
3302   if (clip_set)
3303     cogl_clip_pop();
3304
3305   cogl_pop_matrix();
3306
3307   /* paint sequence complete */
3308   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3309 }
3310
3311 /**
3312  * clutter_actor_continue_paint:
3313  * @self: A #ClutterActor
3314  *
3315  * Run the next stage of the paint sequence. This function should only
3316  * be called within the implementation of the ‘run’ virtual of a
3317  * #ClutterEffect. It will cause the run method of the next effect to
3318  * be applied, or it will paint the actual actor if the current effect
3319  * is the last effect in the chain.
3320  *
3321  * Since: 1.8
3322  */
3323 void
3324 clutter_actor_continue_paint (ClutterActor *self)
3325 {
3326   ClutterActorPrivate *priv;
3327
3328   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3329   /* This should only be called from with in the ‘run’ implementation
3330      of a ClutterEffect */
3331   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3332
3333   priv = self->priv;
3334
3335   /* Skip any effects that are disabled */
3336   while (priv->next_effect_to_paint &&
3337          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3338     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3339
3340   /* If this has come from the last effect then we'll just paint the
3341      actual actor */
3342   if (priv->next_effect_to_paint == NULL)
3343     {
3344       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3345         {
3346           g_signal_emit (self, actor_signals[PAINT], 0);
3347         }
3348       else
3349         {
3350           ClutterColor col = { 0, };
3351
3352           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3353
3354           /* Actor will then paint silhouette of itself in supplied
3355            * color.  See clutter_stage_get_actor_at_pos() for where
3356            * picking is enabled.
3357            */
3358           g_signal_emit (self, actor_signals[PICK], 0, &col);
3359         }
3360     }
3361   else
3362     {
3363       ClutterEffect *old_current_effect;
3364       ClutterEffectPaintFlags run_flags = 0;
3365
3366       /* Cache the current effect so that we can put it back before
3367          returning */
3368       old_current_effect = priv->current_effect;
3369
3370       priv->current_effect = priv->next_effect_to_paint->data;
3371       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3372
3373       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3374         {
3375           if (priv->is_dirty)
3376             {
3377               /* If there's an effect queued with this redraw then all
3378                  effects up to that one will be considered dirty. It
3379                  is expected the queued effect will paint the cached
3380                  image and not call clutter_actor_continue_paint again
3381                  (although it should work ok if it does) */
3382               if (priv->effect_to_redraw == NULL ||
3383                   priv->current_effect != priv->effect_to_redraw)
3384                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3385             }
3386
3387           _clutter_effect_paint (priv->current_effect, run_flags);
3388         }
3389       else
3390         {
3391           /* We can't determine when an actor has been modified since
3392              its last pick so lets just assume it has always been
3393              modified */
3394           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3395
3396           _clutter_effect_pick (priv->current_effect, run_flags);
3397         }
3398
3399       priv->current_effect = old_current_effect;
3400     }
3401 }
3402
3403 static ClutterActorTraverseVisitFlags
3404 invalidate_queue_redraw_entry (ClutterActor *self,
3405                                int           depth,
3406                                gpointer      user_data)
3407 {
3408   ClutterActorPrivate *priv = self->priv;
3409
3410   if (priv->queue_redraw_entry != NULL)
3411     {
3412       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3413       priv->queue_redraw_entry = NULL;
3414     }
3415
3416   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3417 }
3418
3419 static inline void
3420 remove_child (ClutterActor *self,
3421               ClutterActor *child)
3422 {
3423   ClutterActor *prev_sibling, *next_sibling;
3424
3425   prev_sibling = child->priv->prev_sibling;
3426   next_sibling = child->priv->next_sibling;
3427
3428   if (prev_sibling != NULL)
3429     prev_sibling->priv->next_sibling = next_sibling;
3430
3431   if (next_sibling != NULL)
3432     next_sibling->priv->prev_sibling = prev_sibling;
3433
3434   if (self->priv->first_child == child)
3435     self->priv->first_child = next_sibling;
3436
3437   if (self->priv->last_child == child)
3438     self->priv->last_child = prev_sibling;
3439
3440   child->priv->parent = NULL;
3441   child->priv->prev_sibling = NULL;
3442   child->priv->next_sibling = NULL;
3443 }
3444
3445 typedef enum {
3446   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3447   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3448   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3449   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3450   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3451   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3452
3453   /* default flags for public API */
3454   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3455                                     REMOVE_CHILD_EMIT_PARENT_SET |
3456                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3457                                     REMOVE_CHILD_CHECK_STATE |
3458                                     REMOVE_CHILD_FLUSH_QUEUE |
3459                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3460
3461   /* flags for legacy/deprecated API */
3462   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3463                                     REMOVE_CHILD_FLUSH_QUEUE |
3464                                     REMOVE_CHILD_EMIT_PARENT_SET |
3465                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3466 } ClutterActorRemoveChildFlags;
3467
3468 /*< private >
3469  * clutter_actor_remove_child_internal:
3470  * @self: a #ClutterActor
3471  * @child: the child of @self that has to be removed
3472  * @flags: control the removal operations
3473  *
3474  * Removes @child from the list of children of @self.
3475  */
3476 static void
3477 clutter_actor_remove_child_internal (ClutterActor                 *self,
3478                                      ClutterActor                 *child,
3479                                      ClutterActorRemoveChildFlags  flags)
3480 {
3481   ClutterActor *old_first, *old_last;
3482   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3483   gboolean flush_queue;
3484   gboolean notify_first_last;
3485   gboolean was_mapped;
3486
3487   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3488   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3489   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3490   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3491   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3492   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3493
3494   g_object_freeze_notify (G_OBJECT (self));
3495
3496   if (destroy_meta)
3497     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3498
3499   if (check_state)
3500     {
3501       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3502
3503       /* we need to unrealize *before* we set parent_actor to NULL,
3504        * because in an unrealize method actors are dissociating from the
3505        * stage, which means they need to be able to
3506        * clutter_actor_get_stage().
3507        *
3508        * yhis should unmap and unrealize, unless we're reparenting.
3509        */
3510       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3511     }
3512   else
3513     was_mapped = FALSE;
3514
3515   if (flush_queue)
3516     {
3517       /* We take this opportunity to invalidate any queue redraw entry
3518        * associated with the actor and descendants since we won't be able to
3519        * determine the appropriate stage after this.
3520        *
3521        * we do this after we updated the mapped state because actors might
3522        * end up queueing redraws inside their mapped/unmapped virtual
3523        * functions, and if we invalidate the redraw entry we could end up
3524        * with an inconsistent state and weird memory corruption. see
3525        * bugs:
3526        *
3527        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3528        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3529        */
3530       _clutter_actor_traverse (child,
3531                                0,
3532                                invalidate_queue_redraw_entry,
3533                                NULL,
3534                                NULL);
3535     }
3536
3537   old_first = self->priv->first_child;
3538   old_last = self->priv->last_child;
3539
3540   remove_child (self, child);
3541
3542   self->priv->n_children -= 1;
3543
3544   self->priv->age += 1;
3545
3546   /* clutter_actor_reparent() will emit ::parent-set for us */
3547   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3548     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3549
3550   /* if the child was mapped then we need to relayout ourselves to account
3551    * for the removed child
3552    */
3553   if (was_mapped)
3554     clutter_actor_queue_relayout (self);
3555
3556   /* we need to emit the signal before dropping the reference */
3557   if (emit_actor_removed)
3558     g_signal_emit_by_name (self, "actor-removed", child);
3559
3560   if (notify_first_last)
3561     {
3562       if (old_first != self->priv->first_child)
3563         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3564
3565       if (old_last != self->priv->last_child)
3566         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3567     }
3568
3569   g_object_thaw_notify (G_OBJECT (self));
3570
3571   /* remove the reference we acquired in clutter_actor_add_child() */
3572   g_object_unref (child);
3573 }
3574
3575 static const ClutterTransformInfo default_transform_info = {
3576   0.0, { 0, },          /* rotation-x */
3577   0.0, { 0, },          /* rotation-y */
3578   0.0, { 0, },          /* rotation-z */
3579
3580   1.0, 1.0, { 0, },     /* scale */
3581
3582   { 0, },               /* anchor */
3583 };
3584
3585 /*< private >
3586  * _clutter_actor_get_transform_info_or_defaults:
3587  * @self: a #ClutterActor
3588  *
3589  * Retrieves the ClutterTransformInfo structure associated to an actor.
3590  *
3591  * If the actor does not have a ClutterTransformInfo structure associated
3592  * to it, then the default structure will be returned.
3593  *
3594  * This function should only be used for getters.
3595  *
3596  * Return value: a const pointer to the ClutterTransformInfo structure
3597  */
3598 const ClutterTransformInfo *
3599 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3600 {
3601   ClutterTransformInfo *info;
3602
3603   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3604   if (info != NULL)
3605     return info;
3606
3607   return &default_transform_info;
3608 }
3609
3610 static void
3611 clutter_transform_info_free (gpointer data)
3612 {
3613   if (data != NULL)
3614     g_slice_free (ClutterTransformInfo, data);
3615 }
3616
3617 /*< private >
3618  * _clutter_actor_get_transform_info:
3619  * @self: a #ClutterActor
3620  *
3621  * Retrieves a pointer to the ClutterTransformInfo structure.
3622  *
3623  * If the actor does not have a ClutterTransformInfo associated to it, one
3624  * will be created and initialized to the default values.
3625  *
3626  * This function should be used for setters.
3627  *
3628  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3629  * instead.
3630  *
3631  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3632  *   structure
3633  */
3634 ClutterTransformInfo *
3635 _clutter_actor_get_transform_info (ClutterActor *self)
3636 {
3637   ClutterTransformInfo *info;
3638
3639   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3640   if (info == NULL)
3641     {
3642       info = g_slice_new (ClutterTransformInfo);
3643
3644       *info = default_transform_info;
3645
3646       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3647                                info,
3648                                clutter_transform_info_free);
3649     }
3650
3651   return info;
3652 }
3653
3654 /*< private >
3655  * clutter_actor_set_rotation_angle_internal:
3656  * @self: a #ClutterActor
3657  * @axis: the axis of the angle to change
3658  * @angle: the angle of rotation
3659  *
3660  * Sets the rotation angle on the given axis without affecting the
3661  * rotation center point.
3662  */
3663 static inline void
3664 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3665                                            ClutterRotateAxis  axis,
3666                                            gdouble            angle)
3667 {
3668   GObject *obj = G_OBJECT (self);
3669   ClutterTransformInfo *info;
3670
3671   info = _clutter_actor_get_transform_info (self);
3672
3673   g_object_freeze_notify (obj);
3674
3675   switch (axis)
3676     {
3677     case CLUTTER_X_AXIS:
3678       info->rx_angle = angle;
3679       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3680       break;
3681
3682     case CLUTTER_Y_AXIS:
3683       info->ry_angle = angle;
3684       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3685       break;
3686
3687     case CLUTTER_Z_AXIS:
3688       info->rz_angle = angle;
3689       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3690       break;
3691     }
3692
3693   self->priv->transform_valid = FALSE;
3694
3695   g_object_thaw_notify (obj);
3696
3697   clutter_actor_queue_redraw (self);
3698 }
3699
3700 /*< private >
3701  * clutter_actor_set_rotation_center_internal:
3702  * @self: a #ClutterActor
3703  * @axis: the axis of the center to change
3704  * @center: the coordinates of the rotation center
3705  *
3706  * Sets the rotation center on the given axis without affecting the
3707  * rotation angle.
3708  */
3709 static inline void
3710 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3711                                             ClutterRotateAxis    axis,
3712                                             const ClutterVertex *center)
3713 {
3714   GObject *obj = G_OBJECT (self);
3715   ClutterTransformInfo *info;
3716   ClutterVertex v = { 0, 0, 0 };
3717
3718   info = _clutter_actor_get_transform_info (self);
3719
3720   if (center != NULL)
3721     v = *center;
3722
3723   g_object_freeze_notify (obj);
3724
3725   switch (axis)
3726     {
3727     case CLUTTER_X_AXIS:
3728       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3729       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3730       break;
3731
3732     case CLUTTER_Y_AXIS:
3733       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3734       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3735       break;
3736
3737     case CLUTTER_Z_AXIS:
3738       /* if the previously set rotation center was fractional, then
3739        * setting explicit coordinates will have to notify the
3740        * :rotation-center-z-gravity property as well
3741        */
3742       if (info->rz_center.is_fractional)
3743         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3744
3745       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3746       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3747       break;
3748     }
3749
3750   self->priv->transform_valid = FALSE;
3751
3752   g_object_thaw_notify (obj);
3753
3754   clutter_actor_queue_redraw (self);
3755 }
3756
3757 static inline void
3758 clutter_actor_set_scale_factor (ClutterActor      *self,
3759                                 ClutterRotateAxis  axis,
3760                                 gdouble            factor)
3761 {
3762   GObject *obj = G_OBJECT (self);
3763   ClutterTransformInfo *info;
3764
3765   info = _clutter_actor_get_transform_info (self);
3766
3767   g_object_freeze_notify (obj);
3768
3769   switch (axis)
3770     {
3771     case CLUTTER_X_AXIS:
3772       info->scale_x = factor;
3773       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3774       break;
3775
3776     case CLUTTER_Y_AXIS:
3777       info->scale_y = factor;
3778       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3779       break;
3780
3781     default:
3782       g_assert_not_reached ();
3783     }
3784
3785   self->priv->transform_valid = FALSE;
3786
3787   clutter_actor_queue_redraw (self);
3788
3789   g_object_thaw_notify (obj);
3790 }
3791
3792 static inline void
3793 clutter_actor_set_scale_center (ClutterActor      *self,
3794                                 ClutterRotateAxis  axis,
3795                                 gfloat             coord)
3796 {
3797   GObject *obj = G_OBJECT (self);
3798   ClutterTransformInfo *info;
3799   gfloat center_x, center_y;
3800
3801   info = _clutter_actor_get_transform_info (self);
3802
3803   g_object_freeze_notify (obj);
3804
3805   /* get the current scale center coordinates */
3806   clutter_anchor_coord_get_units (self, &info->scale_center,
3807                                   &center_x,
3808                                   &center_y,
3809                                   NULL);
3810
3811   /* we need to notify this too, because setting explicit coordinates will
3812    * change the gravity as a side effect
3813    */
3814   if (info->scale_center.is_fractional)
3815     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3816
3817   switch (axis)
3818     {
3819     case CLUTTER_X_AXIS:
3820       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3821       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3822       break;
3823
3824     case CLUTTER_Y_AXIS:
3825       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3826       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3827       break;
3828
3829     default:
3830       g_assert_not_reached ();
3831     }
3832
3833   self->priv->transform_valid = FALSE;
3834
3835   clutter_actor_queue_redraw (self);
3836
3837   g_object_thaw_notify (obj);
3838 }
3839
3840 static inline void
3841 clutter_actor_set_anchor_coord (ClutterActor      *self,
3842                                 ClutterRotateAxis  axis,
3843                                 gfloat             coord)
3844 {
3845   GObject *obj = G_OBJECT (self);
3846   ClutterTransformInfo *info;
3847   gfloat anchor_x, anchor_y;
3848
3849   info = _clutter_actor_get_transform_info (self);
3850
3851   g_object_freeze_notify (obj);
3852
3853   clutter_anchor_coord_get_units (self, &info->anchor,
3854                                   &anchor_x,
3855                                   &anchor_y,
3856                                   NULL);
3857
3858   if (info->anchor.is_fractional)
3859     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3860
3861   switch (axis)
3862     {
3863     case CLUTTER_X_AXIS:
3864       clutter_anchor_coord_set_units (&info->anchor,
3865                                       coord,
3866                                       anchor_y,
3867                                       0.0);
3868       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3869       break;
3870
3871     case CLUTTER_Y_AXIS:
3872       clutter_anchor_coord_set_units (&info->anchor,
3873                                       anchor_x,
3874                                       coord,
3875                                       0.0);
3876       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3877       break;
3878
3879     default:
3880       g_assert_not_reached ();
3881     }
3882
3883   self->priv->transform_valid = FALSE;
3884
3885   clutter_actor_queue_redraw (self);
3886
3887   g_object_thaw_notify (obj);
3888 }
3889
3890 static void
3891 clutter_actor_set_property (GObject      *object,
3892                             guint         prop_id,
3893                             const GValue *value,
3894                             GParamSpec   *pspec)
3895 {
3896   ClutterActor *actor = CLUTTER_ACTOR (object);
3897   ClutterActorPrivate *priv = actor->priv;
3898
3899   switch (prop_id)
3900     {
3901     case PROP_X:
3902       clutter_actor_set_x (actor, g_value_get_float (value));
3903       break;
3904
3905     case PROP_Y:
3906       clutter_actor_set_y (actor, g_value_get_float (value));
3907       break;
3908
3909     case PROP_WIDTH:
3910       clutter_actor_set_width (actor, g_value_get_float (value));
3911       break;
3912
3913     case PROP_HEIGHT:
3914       clutter_actor_set_height (actor, g_value_get_float (value));
3915       break;
3916
3917     case PROP_FIXED_X:
3918       clutter_actor_set_x (actor, g_value_get_float (value));
3919       break;
3920
3921     case PROP_FIXED_Y:
3922       clutter_actor_set_y (actor, g_value_get_float (value));
3923       break;
3924
3925     case PROP_FIXED_POSITION_SET:
3926       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3927       break;
3928
3929     case PROP_MIN_WIDTH:
3930       clutter_actor_set_min_width (actor, g_value_get_float (value));
3931       break;
3932
3933     case PROP_MIN_HEIGHT:
3934       clutter_actor_set_min_height (actor, g_value_get_float (value));
3935       break;
3936
3937     case PROP_NATURAL_WIDTH:
3938       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3939       break;
3940
3941     case PROP_NATURAL_HEIGHT:
3942       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3943       break;
3944
3945     case PROP_MIN_WIDTH_SET:
3946       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3947       break;
3948
3949     case PROP_MIN_HEIGHT_SET:
3950       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3951       break;
3952
3953     case PROP_NATURAL_WIDTH_SET:
3954       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3955       break;
3956
3957     case PROP_NATURAL_HEIGHT_SET:
3958       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3959       break;
3960
3961     case PROP_REQUEST_MODE:
3962       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3963       break;
3964
3965     case PROP_DEPTH:
3966       clutter_actor_set_depth (actor, g_value_get_float (value));
3967       break;
3968
3969     case PROP_OPACITY:
3970       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3971       break;
3972
3973     case PROP_OFFSCREEN_REDIRECT:
3974       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3975       break;
3976
3977     case PROP_NAME:
3978       clutter_actor_set_name (actor, g_value_get_string (value));
3979       break;
3980
3981     case PROP_VISIBLE:
3982       if (g_value_get_boolean (value) == TRUE)
3983         clutter_actor_show (actor);
3984       else
3985         clutter_actor_hide (actor);
3986       break;
3987
3988     case PROP_SCALE_X:
3989       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3990                                       g_value_get_double (value));
3991       break;
3992
3993     case PROP_SCALE_Y:
3994       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3995                                       g_value_get_double (value));
3996       break;
3997
3998     case PROP_SCALE_CENTER_X:
3999       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4000                                       g_value_get_float (value));
4001       break;
4002
4003     case PROP_SCALE_CENTER_Y:
4004       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4005                                       g_value_get_float (value));
4006       break;
4007
4008     case PROP_SCALE_GRAVITY:
4009       {
4010         const ClutterTransformInfo *info;
4011         ClutterGravity gravity;
4012
4013         info = _clutter_actor_get_transform_info_or_defaults (actor);
4014         gravity = g_value_get_enum (value);
4015
4016         clutter_actor_set_scale_with_gravity (actor,
4017                                               info->scale_x,
4018                                               info->scale_y,
4019                                               gravity);
4020       }
4021       break;
4022
4023     case PROP_CLIP:
4024       {
4025         const ClutterGeometry *geom = g_value_get_boxed (value);
4026
4027         clutter_actor_set_clip (actor,
4028                                 geom->x, geom->y,
4029                                 geom->width, geom->height);
4030       }
4031       break;
4032
4033     case PROP_CLIP_TO_ALLOCATION:
4034       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4035       break;
4036
4037     case PROP_REACTIVE:
4038       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4039       break;
4040
4041     case PROP_ROTATION_ANGLE_X:
4042       clutter_actor_set_rotation_angle_internal (actor,
4043                                                  CLUTTER_X_AXIS,
4044                                                  g_value_get_double (value));
4045       break;
4046
4047     case PROP_ROTATION_ANGLE_Y:
4048       clutter_actor_set_rotation_angle_internal (actor,
4049                                                  CLUTTER_Y_AXIS,
4050                                                  g_value_get_double (value));
4051       break;
4052
4053     case PROP_ROTATION_ANGLE_Z:
4054       clutter_actor_set_rotation_angle_internal (actor,
4055                                                  CLUTTER_Z_AXIS,
4056                                                  g_value_get_double (value));
4057       break;
4058
4059     case PROP_ROTATION_CENTER_X:
4060       clutter_actor_set_rotation_center_internal (actor,
4061                                                   CLUTTER_X_AXIS,
4062                                                   g_value_get_boxed (value));
4063       break;
4064
4065     case PROP_ROTATION_CENTER_Y:
4066       clutter_actor_set_rotation_center_internal (actor,
4067                                                   CLUTTER_Y_AXIS,
4068                                                   g_value_get_boxed (value));
4069       break;
4070
4071     case PROP_ROTATION_CENTER_Z:
4072       clutter_actor_set_rotation_center_internal (actor,
4073                                                   CLUTTER_Z_AXIS,
4074                                                   g_value_get_boxed (value));
4075       break;
4076
4077     case PROP_ROTATION_CENTER_Z_GRAVITY:
4078       {
4079         const ClutterTransformInfo *info;
4080
4081         info = _clutter_actor_get_transform_info_or_defaults (actor);
4082         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4083                                                    g_value_get_enum (value));
4084       }
4085       break;
4086
4087     case PROP_ANCHOR_X:
4088       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4089                                       g_value_get_float (value));
4090       break;
4091
4092     case PROP_ANCHOR_Y:
4093       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4094                                       g_value_get_float (value));
4095       break;
4096
4097     case PROP_ANCHOR_GRAVITY:
4098       clutter_actor_set_anchor_point_from_gravity (actor,
4099                                                    g_value_get_enum (value));
4100       break;
4101
4102     case PROP_SHOW_ON_SET_PARENT:
4103       priv->show_on_set_parent = g_value_get_boolean (value);
4104       break;
4105
4106     case PROP_TEXT_DIRECTION:
4107       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4108       break;
4109
4110     case PROP_ACTIONS:
4111       clutter_actor_add_action (actor, g_value_get_object (value));
4112       break;
4113
4114     case PROP_CONSTRAINTS:
4115       clutter_actor_add_constraint (actor, g_value_get_object (value));
4116       break;
4117
4118     case PROP_EFFECT:
4119       clutter_actor_add_effect (actor, g_value_get_object (value));
4120       break;
4121
4122     case PROP_LAYOUT_MANAGER:
4123       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4124       break;
4125
4126     case PROP_X_ALIGN:
4127       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4128       break;
4129
4130     case PROP_Y_ALIGN:
4131       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4132       break;
4133
4134     case PROP_MARGIN_TOP:
4135       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4136       break;
4137
4138     case PROP_MARGIN_BOTTOM:
4139       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4140       break;
4141
4142     case PROP_MARGIN_LEFT:
4143       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4144       break;
4145
4146     case PROP_MARGIN_RIGHT:
4147       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4148       break;
4149
4150     case PROP_BACKGROUND_COLOR:
4151       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4152       break;
4153
4154     default:
4155       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4156       break;
4157     }
4158 }
4159
4160 static void
4161 clutter_actor_get_property (GObject    *object,
4162                             guint       prop_id,
4163                             GValue     *value,
4164                             GParamSpec *pspec)
4165 {
4166   ClutterActor *actor = CLUTTER_ACTOR (object);
4167   ClutterActorPrivate *priv = actor->priv;
4168
4169   switch (prop_id)
4170     {
4171     case PROP_X:
4172       g_value_set_float (value, clutter_actor_get_x (actor));
4173       break;
4174
4175     case PROP_Y:
4176       g_value_set_float (value, clutter_actor_get_y (actor));
4177       break;
4178
4179     case PROP_WIDTH:
4180       g_value_set_float (value, clutter_actor_get_width (actor));
4181       break;
4182
4183     case PROP_HEIGHT:
4184       g_value_set_float (value, clutter_actor_get_height (actor));
4185       break;
4186
4187     case PROP_FIXED_X:
4188       {
4189         const ClutterLayoutInfo *info;
4190
4191         info = _clutter_actor_get_layout_info_or_defaults (actor);
4192         g_value_set_float (value, info->fixed_x);
4193       }
4194       break;
4195
4196     case PROP_FIXED_Y:
4197       {
4198         const ClutterLayoutInfo *info;
4199
4200         info = _clutter_actor_get_layout_info_or_defaults (actor);
4201         g_value_set_float (value, info->fixed_y);
4202       }
4203       break;
4204
4205     case PROP_FIXED_POSITION_SET:
4206       g_value_set_boolean (value, priv->position_set);
4207       break;
4208
4209     case PROP_MIN_WIDTH:
4210       {
4211         const ClutterLayoutInfo *info;
4212
4213         info = _clutter_actor_get_layout_info_or_defaults (actor);
4214         g_value_set_float (value, info->min_width);
4215       }
4216       break;
4217
4218     case PROP_MIN_HEIGHT:
4219       {
4220         const ClutterLayoutInfo *info;
4221
4222         info = _clutter_actor_get_layout_info_or_defaults (actor);
4223         g_value_set_float (value, info->min_height);
4224       }
4225       break;
4226
4227     case PROP_NATURAL_WIDTH:
4228       {
4229         const ClutterLayoutInfo *info;
4230
4231         info = _clutter_actor_get_layout_info_or_defaults (actor);
4232         g_value_set_float (value, info->natural_width);
4233       }
4234       break;
4235
4236     case PROP_NATURAL_HEIGHT:
4237       {
4238         const ClutterLayoutInfo *info;
4239
4240         info = _clutter_actor_get_layout_info_or_defaults (actor);
4241         g_value_set_float (value, info->natural_height);
4242       }
4243       break;
4244
4245     case PROP_MIN_WIDTH_SET:
4246       g_value_set_boolean (value, priv->min_width_set);
4247       break;
4248
4249     case PROP_MIN_HEIGHT_SET:
4250       g_value_set_boolean (value, priv->min_height_set);
4251       break;
4252
4253     case PROP_NATURAL_WIDTH_SET:
4254       g_value_set_boolean (value, priv->natural_width_set);
4255       break;
4256
4257     case PROP_NATURAL_HEIGHT_SET:
4258       g_value_set_boolean (value, priv->natural_height_set);
4259       break;
4260
4261     case PROP_REQUEST_MODE:
4262       g_value_set_enum (value, priv->request_mode);
4263       break;
4264
4265     case PROP_ALLOCATION:
4266       g_value_set_boxed (value, &priv->allocation);
4267       break;
4268
4269     case PROP_DEPTH:
4270       g_value_set_float (value, clutter_actor_get_depth (actor));
4271       break;
4272
4273     case PROP_OPACITY:
4274       g_value_set_uint (value, priv->opacity);
4275       break;
4276
4277     case PROP_OFFSCREEN_REDIRECT:
4278       g_value_set_enum (value, priv->offscreen_redirect);
4279       break;
4280
4281     case PROP_NAME:
4282       g_value_set_string (value, priv->name);
4283       break;
4284
4285     case PROP_VISIBLE:
4286       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4287       break;
4288
4289     case PROP_MAPPED:
4290       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4291       break;
4292
4293     case PROP_REALIZED:
4294       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4295       break;
4296
4297     case PROP_HAS_CLIP:
4298       g_value_set_boolean (value, priv->has_clip);
4299       break;
4300
4301     case PROP_CLIP:
4302       {
4303         ClutterGeometry clip;
4304
4305         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4306         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4307         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4308         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4309
4310         g_value_set_boxed (value, &clip);
4311       }
4312       break;
4313
4314     case PROP_CLIP_TO_ALLOCATION:
4315       g_value_set_boolean (value, priv->clip_to_allocation);
4316       break;
4317
4318     case PROP_SCALE_X:
4319       {
4320         const ClutterTransformInfo *info;
4321
4322         info = _clutter_actor_get_transform_info_or_defaults (actor);
4323         g_value_set_double (value, info->scale_x);
4324       }
4325       break;
4326
4327     case PROP_SCALE_Y:
4328       {
4329         const ClutterTransformInfo *info;
4330
4331         info = _clutter_actor_get_transform_info_or_defaults (actor);
4332         g_value_set_double (value, info->scale_y);
4333       }
4334       break;
4335
4336     case PROP_SCALE_CENTER_X:
4337       {
4338         gfloat center;
4339
4340         clutter_actor_get_scale_center (actor, &center, NULL);
4341
4342         g_value_set_float (value, center);
4343       }
4344       break;
4345
4346     case PROP_SCALE_CENTER_Y:
4347       {
4348         gfloat center;
4349
4350         clutter_actor_get_scale_center (actor, NULL, &center);
4351
4352         g_value_set_float (value, center);
4353       }
4354       break;
4355
4356     case PROP_SCALE_GRAVITY:
4357       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4358       break;
4359
4360     case PROP_REACTIVE:
4361       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4362       break;
4363
4364     case PROP_ROTATION_ANGLE_X:
4365       {
4366         const ClutterTransformInfo *info;
4367
4368         info = _clutter_actor_get_transform_info_or_defaults (actor);
4369         g_value_set_double (value, info->rx_angle);
4370       }
4371       break;
4372
4373     case PROP_ROTATION_ANGLE_Y:
4374       {
4375         const ClutterTransformInfo *info;
4376
4377         info = _clutter_actor_get_transform_info_or_defaults (actor);
4378         g_value_set_double (value, info->ry_angle);
4379       }
4380       break;
4381
4382     case PROP_ROTATION_ANGLE_Z:
4383       {
4384         const ClutterTransformInfo *info;
4385
4386         info = _clutter_actor_get_transform_info_or_defaults (actor);
4387         g_value_set_double (value, info->rz_angle);
4388       }
4389       break;
4390
4391     case PROP_ROTATION_CENTER_X:
4392       {
4393         ClutterVertex center;
4394
4395         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4396                                     &center.x,
4397                                     &center.y,
4398                                     &center.z);
4399
4400         g_value_set_boxed (value, &center);
4401       }
4402       break;
4403
4404     case PROP_ROTATION_CENTER_Y:
4405       {
4406         ClutterVertex center;
4407
4408         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4409                                     &center.x,
4410                                     &center.y,
4411                                     &center.z);
4412
4413         g_value_set_boxed (value, &center);
4414       }
4415       break;
4416
4417     case PROP_ROTATION_CENTER_Z:
4418       {
4419         ClutterVertex center;
4420
4421         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4422                                     &center.x,
4423                                     &center.y,
4424                                     &center.z);
4425
4426         g_value_set_boxed (value, &center);
4427       }
4428       break;
4429
4430     case PROP_ROTATION_CENTER_Z_GRAVITY:
4431       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4432       break;
4433
4434     case PROP_ANCHOR_X:
4435       {
4436         const ClutterTransformInfo *info;
4437         gfloat anchor_x;
4438
4439         info = _clutter_actor_get_transform_info_or_defaults (actor);
4440         clutter_anchor_coord_get_units (actor, &info->anchor,
4441                                         &anchor_x,
4442                                         NULL,
4443                                         NULL);
4444         g_value_set_float (value, anchor_x);
4445       }
4446       break;
4447
4448     case PROP_ANCHOR_Y:
4449       {
4450         const ClutterTransformInfo *info;
4451         gfloat anchor_y;
4452
4453         info = _clutter_actor_get_transform_info_or_defaults (actor);
4454         clutter_anchor_coord_get_units (actor, &info->anchor,
4455                                         NULL,
4456                                         &anchor_y,
4457                                         NULL);
4458         g_value_set_float (value, anchor_y);
4459       }
4460       break;
4461
4462     case PROP_ANCHOR_GRAVITY:
4463       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4464       break;
4465
4466     case PROP_SHOW_ON_SET_PARENT:
4467       g_value_set_boolean (value, priv->show_on_set_parent);
4468       break;
4469
4470     case PROP_TEXT_DIRECTION:
4471       g_value_set_enum (value, priv->text_direction);
4472       break;
4473
4474     case PROP_HAS_POINTER:
4475       g_value_set_boolean (value, priv->has_pointer);
4476       break;
4477
4478     case PROP_LAYOUT_MANAGER:
4479       g_value_set_object (value, priv->layout_manager);
4480       break;
4481
4482     case PROP_X_ALIGN:
4483       {
4484         const ClutterLayoutInfo *info;
4485
4486         info = _clutter_actor_get_layout_info_or_defaults (actor);
4487         g_value_set_enum (value, info->x_align);
4488       }
4489       break;
4490
4491     case PROP_Y_ALIGN:
4492       {
4493         const ClutterLayoutInfo *info;
4494
4495         info = _clutter_actor_get_layout_info_or_defaults (actor);
4496         g_value_set_enum (value, info->y_align);
4497       }
4498       break;
4499
4500     case PROP_MARGIN_TOP:
4501       {
4502         const ClutterLayoutInfo *info;
4503
4504         info = _clutter_actor_get_layout_info_or_defaults (actor);
4505         g_value_set_float (value, info->margin.top);
4506       }
4507       break;
4508
4509     case PROP_MARGIN_BOTTOM:
4510       {
4511         const ClutterLayoutInfo *info;
4512
4513         info = _clutter_actor_get_layout_info_or_defaults (actor);
4514         g_value_set_float (value, info->margin.bottom);
4515       }
4516       break;
4517
4518     case PROP_MARGIN_LEFT:
4519       {
4520         const ClutterLayoutInfo *info;
4521
4522         info = _clutter_actor_get_layout_info_or_defaults (actor);
4523         g_value_set_float (value, info->margin.left);
4524       }
4525       break;
4526
4527     case PROP_MARGIN_RIGHT:
4528       {
4529         const ClutterLayoutInfo *info;
4530
4531         info = _clutter_actor_get_layout_info_or_defaults (actor);
4532         g_value_set_float (value, info->margin.right);
4533       }
4534       break;
4535
4536     case PROP_BACKGROUND_COLOR_SET:
4537       g_value_set_boolean (value, priv->bg_color_set);
4538       break;
4539
4540     case PROP_BACKGROUND_COLOR:
4541       g_value_set_boxed (value, &priv->bg_color);
4542       break;
4543
4544     case PROP_FIRST_CHILD:
4545       g_value_set_object (value, priv->first_child);
4546       break;
4547
4548     case PROP_LAST_CHILD:
4549       g_value_set_object (value, priv->last_child);
4550       break;
4551
4552     default:
4553       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4554       break;
4555     }
4556 }
4557
4558 static void
4559 clutter_actor_dispose (GObject *object)
4560 {
4561   ClutterActor *self = CLUTTER_ACTOR (object);
4562   ClutterActorPrivate *priv = self->priv;
4563
4564   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4565                 priv->id,
4566                 g_type_name (G_OBJECT_TYPE (self)),
4567                 object->ref_count);
4568
4569   g_signal_emit (self, actor_signals[DESTROY], 0);
4570
4571   /* avoid recursing when called from clutter_actor_destroy() */
4572   if (priv->parent != NULL)
4573     {
4574       ClutterActor *parent = priv->parent;
4575
4576       /* go through the Container implementation unless this
4577        * is an internal child and has been marked as such.
4578        *
4579        * removing the actor from its parent will reset the
4580        * realized and mapped states.
4581        */
4582       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4583         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4584       else
4585         clutter_actor_remove_child_internal (parent, self,
4586                                              REMOVE_CHILD_LEGACY_FLAGS);
4587     }
4588
4589   /* parent must be gone at this point */
4590   g_assert (priv->parent == NULL);
4591
4592   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4593     {
4594       /* can't be mapped or realized with no parent */
4595       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4596       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4597     }
4598
4599   g_clear_object (&priv->pango_context);
4600   g_clear_object (&priv->actions);
4601   g_clear_object (&priv->constraints);
4602   g_clear_object (&priv->effects);
4603   g_clear_object (&priv->flatten_effect);
4604
4605   if (priv->layout_manager != NULL)
4606     {
4607       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4608       g_object_unref (priv->layout_manager);
4609       priv->layout_manager = NULL;
4610     }
4611
4612   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4613 }
4614
4615 static void
4616 clutter_actor_finalize (GObject *object)
4617 {
4618   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4619
4620   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4621                 priv->name != NULL ? priv->name : "<none>",
4622                 priv->id,
4623                 g_type_name (G_OBJECT_TYPE (object)));
4624
4625   _clutter_context_release_id (priv->id);
4626
4627   g_free (priv->name);
4628
4629   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4630 }
4631
4632
4633 /**
4634  * clutter_actor_get_accessible:
4635  * @self: a #ClutterActor
4636  *
4637  * Returns the accessible object that describes the actor to an
4638  * assistive technology.
4639  *
4640  * If no class-specific #AtkObject implementation is available for the
4641  * actor instance in question, it will inherit an #AtkObject
4642  * implementation from the first ancestor class for which such an
4643  * implementation is defined.
4644  *
4645  * The documentation of the <ulink
4646  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4647  * library contains more information about accessible objects and
4648  * their uses.
4649  *
4650  * Returns: (transfer none): the #AtkObject associated with @actor
4651  */
4652 AtkObject *
4653 clutter_actor_get_accessible (ClutterActor *self)
4654 {
4655   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4656
4657   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4658 }
4659
4660 static AtkObject *
4661 clutter_actor_real_get_accessible (ClutterActor *actor)
4662 {
4663   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4664 }
4665
4666 static AtkObject *
4667 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4668 {
4669   AtkObject *accessible;
4670
4671   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4672   if (accessible != NULL)
4673     g_object_ref (accessible);
4674
4675   return accessible;
4676 }
4677
4678 static void
4679 atk_implementor_iface_init (AtkImplementorIface *iface)
4680 {
4681   iface->ref_accessible = _clutter_actor_ref_accessible;
4682 }
4683
4684 static gboolean
4685 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4686                                      ClutterPaintVolume *volume)
4687 {
4688   ClutterActorPrivate *priv = self->priv;
4689   ClutterActor *child;
4690   gboolean res;
4691
4692   /* this is the default return value: we cannot know if a class
4693    * is going to paint outside its allocation, so we take the
4694    * conservative approach.
4695    */
4696   res = FALSE;
4697
4698   /* we start from the allocation */
4699   clutter_paint_volume_set_width (volume,
4700                                   priv->allocation.x2 - priv->allocation.x1);
4701   clutter_paint_volume_set_height (volume,
4702                                    priv->allocation.y2 - priv->allocation.y1);
4703
4704   /* if the actor has a clip set then we have a pretty definite
4705    * size for the paint volume: the actor cannot possibly paint
4706    * outside the clip region.
4707    */
4708   if (priv->clip_to_allocation)
4709     {
4710       /* the allocation has already been set, so we just flip the
4711        * return value
4712        */
4713       res = TRUE;
4714     }
4715   else
4716     {
4717       if (priv->has_clip &&
4718           priv->clip.width >= 0 &&
4719           priv->clip.height >= 0)
4720         {
4721           ClutterVertex origin;
4722
4723           origin.x = priv->clip.x;
4724           origin.y = priv->clip.y;
4725           origin.z = 0;
4726
4727           clutter_paint_volume_set_origin (volume, &origin);
4728           clutter_paint_volume_set_width (volume, priv->clip.width);
4729           clutter_paint_volume_set_height (volume, priv->clip.height);
4730
4731           res = TRUE;
4732         }
4733
4734       /* if we don't have children we just bail out here... */
4735       if (priv->n_children == 0)
4736         return res;
4737
4738       /* ...but if we have children then we ask for their paint volume in
4739        * our coordinates. if any of our children replies that it doesn't
4740        * have a paint volume, we bail out
4741        */
4742       for (child = priv->first_child;
4743            child != NULL;
4744            child = child->priv->next_sibling)
4745         {
4746           const ClutterPaintVolume *child_volume;
4747
4748           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4749           if (child_volume == NULL)
4750             {
4751               res = FALSE;
4752               break;
4753             }
4754
4755           clutter_paint_volume_union (volume, child_volume);
4756           res = TRUE;
4757         }
4758     }
4759
4760   return res;
4761 }
4762
4763 static gboolean
4764 clutter_actor_real_has_overlaps (ClutterActor *self)
4765 {
4766   /* By default we'll assume that all actors need an offscreen redirect to get
4767    * the correct opacity. Actors such as ClutterTexture that would never need
4768    * an offscreen redirect can override this to return FALSE. */
4769   return TRUE;
4770 }
4771
4772 static void
4773 clutter_actor_real_destroy (ClutterActor *actor)
4774 {
4775   ClutterActorIter iter;
4776
4777   clutter_actor_iter_init (&iter, actor);
4778   while (clutter_actor_iter_next (&iter, NULL))
4779     clutter_actor_iter_destroy (&iter);
4780 }
4781
4782 static GObject *
4783 clutter_actor_constructor (GType gtype,
4784                            guint n_props,
4785                            GObjectConstructParam *props)
4786 {
4787   GObjectClass *gobject_class;
4788   ClutterActor *self;
4789   GObject *retval;
4790
4791   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4792   retval = gobject_class->constructor (gtype, n_props, props);
4793   self = CLUTTER_ACTOR (retval);
4794
4795   if (self->priv->layout_manager == NULL)
4796     {
4797       ClutterLayoutManager *default_layout;
4798
4799       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4800
4801       default_layout = clutter_fixed_layout_new ();
4802       clutter_actor_set_layout_manager (self, default_layout);
4803     }
4804
4805   return retval;
4806 }
4807
4808 static void
4809 clutter_actor_class_init (ClutterActorClass *klass)
4810 {
4811   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4812
4813   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4814   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4815   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4816
4817   object_class->constructor = clutter_actor_constructor;
4818   object_class->set_property = clutter_actor_set_property;
4819   object_class->get_property = clutter_actor_get_property;
4820   object_class->dispose = clutter_actor_dispose;
4821   object_class->finalize = clutter_actor_finalize;
4822
4823   klass->show = clutter_actor_real_show;
4824   klass->show_all = clutter_actor_show;
4825   klass->hide = clutter_actor_real_hide;
4826   klass->hide_all = clutter_actor_hide;
4827   klass->map = clutter_actor_real_map;
4828   klass->unmap = clutter_actor_real_unmap;
4829   klass->unrealize = clutter_actor_real_unrealize;
4830   klass->pick = clutter_actor_real_pick;
4831   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4832   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4833   klass->allocate = clutter_actor_real_allocate;
4834   klass->queue_redraw = clutter_actor_real_queue_redraw;
4835   klass->queue_relayout = clutter_actor_real_queue_relayout;
4836   klass->apply_transform = clutter_actor_real_apply_transform;
4837   klass->get_accessible = clutter_actor_real_get_accessible;
4838   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4839   klass->has_overlaps = clutter_actor_real_has_overlaps;
4840   klass->paint = clutter_actor_real_paint;
4841   klass->destroy = clutter_actor_real_destroy;
4842
4843   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4844
4845   /**
4846    * ClutterActor:x:
4847    *
4848    * X coordinate of the actor in pixels. If written, forces a fixed
4849    * position for the actor. If read, returns the fixed position if any,
4850    * otherwise the allocation if available, otherwise 0.
4851    */
4852   obj_props[PROP_X] =
4853     g_param_spec_float ("x",
4854                         P_("X coordinate"),
4855                         P_("X coordinate of the actor"),
4856                         -G_MAXFLOAT, G_MAXFLOAT,
4857                         0.0,
4858                         CLUTTER_PARAM_READWRITE);
4859
4860   /**
4861    * ClutterActor:y:
4862    *
4863    * Y coordinate of the actor in pixels. If written, forces a fixed
4864    * position for the actor.  If read, returns the fixed position if
4865    * any, otherwise the allocation if available, otherwise 0.
4866    */
4867   obj_props[PROP_Y] =
4868     g_param_spec_float ("y",
4869                         P_("Y coordinate"),
4870                         P_("Y coordinate of the actor"),
4871                         -G_MAXFLOAT, G_MAXFLOAT,
4872                         0.0,
4873                         CLUTTER_PARAM_READWRITE);
4874
4875   /**
4876    * ClutterActor:width:
4877    *
4878    * Width of the actor (in pixels). If written, forces the minimum and
4879    * natural size request of the actor to the given width. If read, returns
4880    * the allocated width if available, otherwise the width request.
4881    */
4882   obj_props[PROP_WIDTH] =
4883     g_param_spec_float ("width",
4884                         P_("Width"),
4885                         P_("Width of the actor"),
4886                         0.0, G_MAXFLOAT,
4887                         0.0,
4888                         CLUTTER_PARAM_READWRITE);
4889
4890   /**
4891    * ClutterActor:height:
4892    *
4893    * Height of the actor (in pixels).  If written, forces the minimum and
4894    * natural size request of the actor to the given height. If read, returns
4895    * the allocated height if available, otherwise the height request.
4896    */
4897   obj_props[PROP_HEIGHT] =
4898     g_param_spec_float ("height",
4899                         P_("Height"),
4900                         P_("Height of the actor"),
4901                         0.0, G_MAXFLOAT,
4902                         0.0,
4903                         CLUTTER_PARAM_READWRITE);
4904
4905   /**
4906    * ClutterActor:fixed-x:
4907    *
4908    * The fixed X position of the actor in pixels.
4909    *
4910    * Writing this property sets #ClutterActor:fixed-position-set
4911    * property as well, as a side effect
4912    *
4913    * Since: 0.8
4914    */
4915   obj_props[PROP_FIXED_X] =
4916     g_param_spec_float ("fixed-x",
4917                         P_("Fixed X"),
4918                         P_("Forced X position of the actor"),
4919                         -G_MAXFLOAT, G_MAXFLOAT,
4920                         0.0,
4921                         CLUTTER_PARAM_READWRITE);
4922
4923   /**
4924    * ClutterActor:fixed-y:
4925    *
4926    * The fixed Y position of the actor in pixels.
4927    *
4928    * Writing this property sets the #ClutterActor:fixed-position-set
4929    * property as well, as a side effect
4930    *
4931    * Since: 0.8
4932    */
4933   obj_props[PROP_FIXED_Y] =
4934     g_param_spec_float ("fixed-y",
4935                         P_("Fixed Y"),
4936                         P_("Forced Y position of the actor"),
4937                         -G_MAXFLOAT, G_MAXFLOAT,
4938                         0,
4939                         CLUTTER_PARAM_READWRITE);
4940
4941   /**
4942    * ClutterActor:fixed-position-set:
4943    *
4944    * This flag controls whether the #ClutterActor:fixed-x and
4945    * #ClutterActor:fixed-y properties are used
4946    *
4947    * Since: 0.8
4948    */
4949   obj_props[PROP_FIXED_POSITION_SET] =
4950     g_param_spec_boolean ("fixed-position-set",
4951                           P_("Fixed position set"),
4952                           P_("Whether to use fixed positioning for the actor"),
4953                           FALSE,
4954                           CLUTTER_PARAM_READWRITE);
4955
4956   /**
4957    * ClutterActor:min-width:
4958    *
4959    * A forced minimum width request for the actor, in pixels
4960    *
4961    * Writing this property sets the #ClutterActor:min-width-set property
4962    * as well, as a side effect.
4963    *
4964    *This property overrides the usual width request of the actor.
4965    *
4966    * Since: 0.8
4967    */
4968   obj_props[PROP_MIN_WIDTH] =
4969     g_param_spec_float ("min-width",
4970                         P_("Min Width"),
4971                         P_("Forced minimum width request for the actor"),
4972                         0.0, G_MAXFLOAT,
4973                         0.0,
4974                         CLUTTER_PARAM_READWRITE);
4975
4976   /**
4977    * ClutterActor:min-height:
4978    *
4979    * A forced minimum height request for the actor, in pixels
4980    *
4981    * Writing this property sets the #ClutterActor:min-height-set property
4982    * as well, as a side effect. This property overrides the usual height
4983    * request of the actor.
4984    *
4985    * Since: 0.8
4986    */
4987   obj_props[PROP_MIN_HEIGHT] =
4988     g_param_spec_float ("min-height",
4989                         P_("Min Height"),
4990                         P_("Forced minimum height request for the actor"),
4991                         0.0, G_MAXFLOAT,
4992                         0.0,
4993                         CLUTTER_PARAM_READWRITE);
4994
4995   /**
4996    * ClutterActor:natural-width:
4997    *
4998    * A forced natural width request for the actor, in pixels
4999    *
5000    * Writing this property sets the #ClutterActor:natural-width-set
5001    * property as well, as a side effect. This property overrides the
5002    * usual width request of the actor
5003    *
5004    * Since: 0.8
5005    */
5006   obj_props[PROP_NATURAL_WIDTH] =
5007     g_param_spec_float ("natural-width",
5008                         P_("Natural Width"),
5009                         P_("Forced natural width request for the actor"),
5010                         0.0, G_MAXFLOAT,
5011                         0.0,
5012                         CLUTTER_PARAM_READWRITE);
5013
5014   /**
5015    * ClutterActor:natural-height:
5016    *
5017    * A forced natural height request for the actor, in pixels
5018    *
5019    * Writing this property sets the #ClutterActor:natural-height-set
5020    * property as well, as a side effect. This property overrides the
5021    * usual height request of the actor
5022    *
5023    * Since: 0.8
5024    */
5025   obj_props[PROP_NATURAL_HEIGHT] =
5026     g_param_spec_float ("natural-height",
5027                         P_("Natural Height"),
5028                         P_("Forced natural height request for the actor"),
5029                         0.0, G_MAXFLOAT,
5030                         0.0,
5031                         CLUTTER_PARAM_READWRITE);
5032
5033   /**
5034    * ClutterActor:min-width-set:
5035    *
5036    * This flag controls whether the #ClutterActor:min-width property
5037    * is used
5038    *
5039    * Since: 0.8
5040    */
5041   obj_props[PROP_MIN_WIDTH_SET] =
5042     g_param_spec_boolean ("min-width-set",
5043                           P_("Minimum width set"),
5044                           P_("Whether to use the min-width property"),
5045                           FALSE,
5046                           CLUTTER_PARAM_READWRITE);
5047
5048   /**
5049    * ClutterActor:min-height-set:
5050    *
5051    * This flag controls whether the #ClutterActor:min-height property
5052    * is used
5053    *
5054    * Since: 0.8
5055    */
5056   obj_props[PROP_MIN_HEIGHT_SET] =
5057     g_param_spec_boolean ("min-height-set",
5058                           P_("Minimum height set"),
5059                           P_("Whether to use the min-height property"),
5060                           FALSE,
5061                           CLUTTER_PARAM_READWRITE);
5062
5063   /**
5064    * ClutterActor:natural-width-set:
5065    *
5066    * This flag controls whether the #ClutterActor:natural-width property
5067    * is used
5068    *
5069    * Since: 0.8
5070    */
5071   obj_props[PROP_NATURAL_WIDTH_SET] =
5072     g_param_spec_boolean ("natural-width-set",
5073                           P_("Natural width set"),
5074                           P_("Whether to use the natural-width property"),
5075                           FALSE,
5076                           CLUTTER_PARAM_READWRITE);
5077
5078   /**
5079    * ClutterActor:natural-height-set:
5080    *
5081    * This flag controls whether the #ClutterActor:natural-height property
5082    * is used
5083    *
5084    * Since: 0.8
5085    */
5086   obj_props[PROP_NATURAL_HEIGHT_SET] =
5087     g_param_spec_boolean ("natural-height-set",
5088                           P_("Natural height set"),
5089                           P_("Whether to use the natural-height property"),
5090                           FALSE,
5091                           CLUTTER_PARAM_READWRITE);
5092
5093   /**
5094    * ClutterActor:allocation:
5095    *
5096    * The allocation for the actor, in pixels
5097    *
5098    * This is property is read-only, but you might monitor it to know when an
5099    * actor moves or resizes
5100    *
5101    * Since: 0.8
5102    */
5103   obj_props[PROP_ALLOCATION] =
5104     g_param_spec_boxed ("allocation",
5105                         P_("Allocation"),
5106                         P_("The actor's allocation"),
5107                         CLUTTER_TYPE_ACTOR_BOX,
5108                         CLUTTER_PARAM_READABLE);
5109
5110   /**
5111    * ClutterActor:request-mode:
5112    *
5113    * Request mode for the #ClutterActor. The request mode determines the
5114    * type of geometry management used by the actor, either height for width
5115    * (the default) or width for height.
5116    *
5117    * For actors implementing height for width, the parent container should get
5118    * the preferred width first, and then the preferred height for that width.
5119    *
5120    * For actors implementing width for height, the parent container should get
5121    * the preferred height first, and then the preferred width for that height.
5122    *
5123    * For instance:
5124    *
5125    * |[
5126    *   ClutterRequestMode mode;
5127    *   gfloat natural_width, min_width;
5128    *   gfloat natural_height, min_height;
5129    *
5130    *   mode = clutter_actor_get_request_mode (child);
5131    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5132    *     {
5133    *       clutter_actor_get_preferred_width (child, -1,
5134    *                                          &amp;min_width,
5135    *                                          &amp;natural_width);
5136    *       clutter_actor_get_preferred_height (child, natural_width,
5137    *                                           &amp;min_height,
5138    *                                           &amp;natural_height);
5139    *     }
5140    *   else
5141    *     {
5142    *       clutter_actor_get_preferred_height (child, -1,
5143    *                                           &amp;min_height,
5144    *                                           &amp;natural_height);
5145    *       clutter_actor_get_preferred_width (child, natural_height,
5146    *                                          &amp;min_width,
5147    *                                          &amp;natural_width);
5148    *     }
5149    * ]|
5150    *
5151    * will retrieve the minimum and natural width and height depending on the
5152    * preferred request mode of the #ClutterActor "child".
5153    *
5154    * The clutter_actor_get_preferred_size() function will implement this
5155    * check for you.
5156    *
5157    * Since: 0.8
5158    */
5159   obj_props[PROP_REQUEST_MODE] =
5160     g_param_spec_enum ("request-mode",
5161                        P_("Request Mode"),
5162                        P_("The actor's request mode"),
5163                        CLUTTER_TYPE_REQUEST_MODE,
5164                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5165                        CLUTTER_PARAM_READWRITE);
5166
5167   /**
5168    * ClutterActor:depth:
5169    *
5170    * The position of the actor on the Z axis
5171    *
5172    * Since: 0.6
5173    */
5174   obj_props[PROP_DEPTH] =
5175     g_param_spec_float ("depth",
5176                         P_("Depth"),
5177                         P_("Position on the Z axis"),
5178                         -G_MAXFLOAT, G_MAXFLOAT,
5179                         0.0,
5180                         CLUTTER_PARAM_READWRITE);
5181
5182   /**
5183    * ClutterActor:opacity:
5184    *
5185    * Opacity of an actor, between 0 (fully transparent) and
5186    * 255 (fully opaque)
5187    */
5188   obj_props[PROP_OPACITY] =
5189     g_param_spec_uint ("opacity",
5190                        P_("Opacity"),
5191                        P_("Opacity of an actor"),
5192                        0, 255,
5193                        255,
5194                        CLUTTER_PARAM_READWRITE);
5195
5196   /**
5197    * ClutterActor:offscreen-redirect:
5198    *
5199    * Determines the conditions in which the actor will be redirected
5200    * to an offscreen framebuffer while being painted. For example this
5201    * can be used to cache an actor in a framebuffer or for improved
5202    * handling of transparent actors. See
5203    * clutter_actor_set_offscreen_redirect() for details.
5204    *
5205    * Since: 1.8
5206    */
5207   obj_props[PROP_OFFSCREEN_REDIRECT] =
5208     g_param_spec_flags ("offscreen-redirect",
5209                         P_("Offscreen redirect"),
5210                         P_("Flags controlling when to flatten the actor into a single image"),
5211                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5212                         0,
5213                         CLUTTER_PARAM_READWRITE);
5214
5215   /**
5216    * ClutterActor:visible:
5217    *
5218    * Whether the actor is set to be visible or not
5219    *
5220    * See also #ClutterActor:mapped
5221    */
5222   obj_props[PROP_VISIBLE] =
5223     g_param_spec_boolean ("visible",
5224                           P_("Visible"),
5225                           P_("Whether the actor is visible or not"),
5226                           FALSE,
5227                           CLUTTER_PARAM_READWRITE);
5228
5229   /**
5230    * ClutterActor:mapped:
5231    *
5232    * Whether the actor is mapped (will be painted when the stage
5233    * to which it belongs is mapped)
5234    *
5235    * Since: 1.0
5236    */
5237   obj_props[PROP_MAPPED] =
5238     g_param_spec_boolean ("mapped",
5239                           P_("Mapped"),
5240                           P_("Whether the actor will be painted"),
5241                           FALSE,
5242                           CLUTTER_PARAM_READABLE);
5243
5244   /**
5245    * ClutterActor:realized:
5246    *
5247    * Whether the actor has been realized
5248    *
5249    * Since: 1.0
5250    */
5251   obj_props[PROP_REALIZED] =
5252     g_param_spec_boolean ("realized",
5253                           P_("Realized"),
5254                           P_("Whether the actor has been realized"),
5255                           FALSE,
5256                           CLUTTER_PARAM_READABLE);
5257
5258   /**
5259    * ClutterActor:reactive:
5260    *
5261    * Whether the actor is reactive to events or not
5262    *
5263    * Only reactive actors will emit event-related signals
5264    *
5265    * Since: 0.6
5266    */
5267   obj_props[PROP_REACTIVE] =
5268     g_param_spec_boolean ("reactive",
5269                           P_("Reactive"),
5270                           P_("Whether the actor is reactive to events"),
5271                           FALSE,
5272                           CLUTTER_PARAM_READWRITE);
5273
5274   /**
5275    * ClutterActor:has-clip:
5276    *
5277    * Whether the actor has the #ClutterActor:clip property set or not
5278    */
5279   obj_props[PROP_HAS_CLIP] =
5280     g_param_spec_boolean ("has-clip",
5281                           P_("Has Clip"),
5282                           P_("Whether the actor has a clip set"),
5283                           FALSE,
5284                           CLUTTER_PARAM_READABLE);
5285
5286   /**
5287    * ClutterActor:clip:
5288    *
5289    * The clip region for the actor, in actor-relative coordinates
5290    *
5291    * Every part of the actor outside the clip region will not be
5292    * painted
5293    */
5294   obj_props[PROP_CLIP] =
5295     g_param_spec_boxed ("clip",
5296                         P_("Clip"),
5297                         P_("The clip region for the actor"),
5298                         CLUTTER_TYPE_GEOMETRY,
5299                         CLUTTER_PARAM_READWRITE);
5300
5301   /**
5302    * ClutterActor:name:
5303    *
5304    * The name of the actor
5305    *
5306    * Since: 0.2
5307    */
5308   obj_props[PROP_NAME] =
5309     g_param_spec_string ("name",
5310                          P_("Name"),
5311                          P_("Name of the actor"),
5312                          NULL,
5313                          CLUTTER_PARAM_READWRITE);
5314
5315   /**
5316    * ClutterActor:scale-x:
5317    *
5318    * The horizontal scale of the actor
5319    *
5320    * Since: 0.6
5321    */
5322   obj_props[PROP_SCALE_X] =
5323     g_param_spec_double ("scale-x",
5324                          P_("Scale X"),
5325                          P_("Scale factor on the X axis"),
5326                          0.0, G_MAXDOUBLE,
5327                          1.0,
5328                          CLUTTER_PARAM_READWRITE);
5329
5330   /**
5331    * ClutterActor:scale-y:
5332    *
5333    * The vertical scale of the actor
5334    *
5335    * Since: 0.6
5336    */
5337   obj_props[PROP_SCALE_Y] =
5338     g_param_spec_double ("scale-y",
5339                          P_("Scale Y"),
5340                          P_("Scale factor on the Y axis"),
5341                          0.0, G_MAXDOUBLE,
5342                          1.0,
5343                          CLUTTER_PARAM_READWRITE);
5344
5345   /**
5346    * ClutterActor:scale-center-x:
5347    *
5348    * The horizontal center point for scaling
5349    *
5350    * Since: 1.0
5351    */
5352   obj_props[PROP_SCALE_CENTER_X] =
5353     g_param_spec_float ("scale-center-x",
5354                         P_("Scale Center X"),
5355                         P_("Horizontal scale center"),
5356                         -G_MAXFLOAT, G_MAXFLOAT,
5357                         0.0,
5358                         CLUTTER_PARAM_READWRITE);
5359
5360   /**
5361    * ClutterActor:scale-center-y:
5362    *
5363    * The vertical center point for scaling
5364    *
5365    * Since: 1.0
5366    */
5367   obj_props[PROP_SCALE_CENTER_Y] =
5368     g_param_spec_float ("scale-center-y",
5369                         P_("Scale Center Y"),
5370                         P_("Vertical scale center"),
5371                         -G_MAXFLOAT, G_MAXFLOAT,
5372                         0.0,
5373                         CLUTTER_PARAM_READWRITE);
5374
5375   /**
5376    * ClutterActor:scale-gravity:
5377    *
5378    * The center point for scaling expressed as a #ClutterGravity
5379    *
5380    * Since: 1.0
5381    */
5382   obj_props[PROP_SCALE_GRAVITY] =
5383     g_param_spec_enum ("scale-gravity",
5384                        P_("Scale Gravity"),
5385                        P_("The center of scaling"),
5386                        CLUTTER_TYPE_GRAVITY,
5387                        CLUTTER_GRAVITY_NONE,
5388                        CLUTTER_PARAM_READWRITE);
5389
5390   /**
5391    * ClutterActor:rotation-angle-x:
5392    *
5393    * The rotation angle on the X axis
5394    *
5395    * Since: 0.6
5396    */
5397   obj_props[PROP_ROTATION_ANGLE_X] =
5398     g_param_spec_double ("rotation-angle-x",
5399                          P_("Rotation Angle X"),
5400                          P_("The rotation angle on the X axis"),
5401                          -G_MAXDOUBLE, G_MAXDOUBLE,
5402                          0.0,
5403                          CLUTTER_PARAM_READWRITE);
5404
5405   /**
5406    * ClutterActor:rotation-angle-y:
5407    *
5408    * The rotation angle on the Y axis
5409    *
5410    * Since: 0.6
5411    */
5412   obj_props[PROP_ROTATION_ANGLE_Y] =
5413     g_param_spec_double ("rotation-angle-y",
5414                          P_("Rotation Angle Y"),
5415                          P_("The rotation angle on the Y axis"),
5416                          -G_MAXDOUBLE, G_MAXDOUBLE,
5417                          0.0,
5418                          CLUTTER_PARAM_READWRITE);
5419
5420   /**
5421    * ClutterActor:rotation-angle-z:
5422    *
5423    * The rotation angle on the Z axis
5424    *
5425    * Since: 0.6
5426    */
5427   obj_props[PROP_ROTATION_ANGLE_Z] =
5428     g_param_spec_double ("rotation-angle-z",
5429                          P_("Rotation Angle Z"),
5430                          P_("The rotation angle on the Z axis"),
5431                          -G_MAXDOUBLE, G_MAXDOUBLE,
5432                          0.0,
5433                          CLUTTER_PARAM_READWRITE);
5434
5435   /**
5436    * ClutterActor:rotation-center-x:
5437    *
5438    * The rotation center on the X axis.
5439    *
5440    * Since: 0.6
5441    */
5442   obj_props[PROP_ROTATION_CENTER_X] =
5443     g_param_spec_boxed ("rotation-center-x",
5444                         P_("Rotation Center X"),
5445                         P_("The rotation center on the X axis"),
5446                         CLUTTER_TYPE_VERTEX,
5447                         CLUTTER_PARAM_READWRITE);
5448
5449   /**
5450    * ClutterActor:rotation-center-y:
5451    *
5452    * The rotation center on the Y axis.
5453    *
5454    * Since: 0.6
5455    */
5456   obj_props[PROP_ROTATION_CENTER_Y] =
5457     g_param_spec_boxed ("rotation-center-y",
5458                         P_("Rotation Center Y"),
5459                         P_("The rotation center on the Y axis"),
5460                         CLUTTER_TYPE_VERTEX,
5461                         CLUTTER_PARAM_READWRITE);
5462
5463   /**
5464    * ClutterActor:rotation-center-z:
5465    *
5466    * The rotation center on the Z axis.
5467    *
5468    * Since: 0.6
5469    */
5470   obj_props[PROP_ROTATION_CENTER_Z] =
5471     g_param_spec_boxed ("rotation-center-z",
5472                         P_("Rotation Center Z"),
5473                         P_("The rotation center on the Z axis"),
5474                         CLUTTER_TYPE_VERTEX,
5475                         CLUTTER_PARAM_READWRITE);
5476
5477   /**
5478    * ClutterActor:rotation-center-z-gravity:
5479    *
5480    * The rotation center on the Z axis expressed as a #ClutterGravity.
5481    *
5482    * Since: 1.0
5483    */
5484   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5485     g_param_spec_enum ("rotation-center-z-gravity",
5486                        P_("Rotation Center Z Gravity"),
5487                        P_("Center point for rotation around the Z axis"),
5488                        CLUTTER_TYPE_GRAVITY,
5489                        CLUTTER_GRAVITY_NONE,
5490                        CLUTTER_PARAM_READWRITE);
5491
5492   /**
5493    * ClutterActor:anchor-x:
5494    *
5495    * The X coordinate of an actor's anchor point, relative to
5496    * the actor coordinate space, in pixels
5497    *
5498    * Since: 0.8
5499    */
5500   obj_props[PROP_ANCHOR_X] =
5501     g_param_spec_float ("anchor-x",
5502                         P_("Anchor X"),
5503                         P_("X coordinate of the anchor point"),
5504                         -G_MAXFLOAT, G_MAXFLOAT,
5505                         0,
5506                         CLUTTER_PARAM_READWRITE);
5507
5508   /**
5509    * ClutterActor:anchor-y:
5510    *
5511    * The Y coordinate of an actor's anchor point, relative to
5512    * the actor coordinate space, in pixels
5513    *
5514    * Since: 0.8
5515    */
5516   obj_props[PROP_ANCHOR_Y] =
5517     g_param_spec_float ("anchor-y",
5518                         P_("Anchor Y"),
5519                         P_("Y coordinate of the anchor point"),
5520                         -G_MAXFLOAT, G_MAXFLOAT,
5521                         0,
5522                         CLUTTER_PARAM_READWRITE);
5523
5524   /**
5525    * ClutterActor:anchor-gravity:
5526    *
5527    * The anchor point expressed as a #ClutterGravity
5528    *
5529    * Since: 1.0
5530    */
5531   obj_props[PROP_ANCHOR_GRAVITY] =
5532     g_param_spec_enum ("anchor-gravity",
5533                        P_("Anchor Gravity"),
5534                        P_("The anchor point as a ClutterGravity"),
5535                        CLUTTER_TYPE_GRAVITY,
5536                        CLUTTER_GRAVITY_NONE,
5537                        CLUTTER_PARAM_READWRITE);
5538
5539   /**
5540    * ClutterActor:show-on-set-parent:
5541    *
5542    * If %TRUE, the actor is automatically shown when parented.
5543    *
5544    * Calling clutter_actor_hide() on an actor which has not been
5545    * parented will set this property to %FALSE as a side effect.
5546    *
5547    * Since: 0.8
5548    */
5549   obj_props[PROP_SHOW_ON_SET_PARENT] =
5550     g_param_spec_boolean ("show-on-set-parent",
5551                           P_("Show on set parent"),
5552                           P_("Whether the actor is shown when parented"),
5553                           TRUE,
5554                           CLUTTER_PARAM_READWRITE);
5555
5556   /**
5557    * ClutterActor:clip-to-allocation:
5558    *
5559    * Whether the clip region should track the allocated area
5560    * of the actor.
5561    *
5562    * This property is ignored if a clip area has been explicitly
5563    * set using clutter_actor_set_clip().
5564    *
5565    * Since: 1.0
5566    */
5567   obj_props[PROP_CLIP_TO_ALLOCATION] =
5568     g_param_spec_boolean ("clip-to-allocation",
5569                           P_("Clip to Allocation"),
5570                           P_("Sets the clip region to track the actor's allocation"),
5571                           FALSE,
5572                           CLUTTER_PARAM_READWRITE);
5573
5574   /**
5575    * ClutterActor:text-direction:
5576    *
5577    * The direction of the text inside a #ClutterActor.
5578    *
5579    * Since: 1.0
5580    */
5581   obj_props[PROP_TEXT_DIRECTION] =
5582     g_param_spec_enum ("text-direction",
5583                        P_("Text Direction"),
5584                        P_("Direction of the text"),
5585                        CLUTTER_TYPE_TEXT_DIRECTION,
5586                        CLUTTER_TEXT_DIRECTION_LTR,
5587                        CLUTTER_PARAM_READWRITE);
5588
5589   /**
5590    * ClutterActor:has-pointer:
5591    *
5592    * Whether the actor contains the pointer of a #ClutterInputDevice
5593    * or not.
5594    *
5595    * Since: 1.2
5596    */
5597   obj_props[PROP_HAS_POINTER] =
5598     g_param_spec_boolean ("has-pointer",
5599                           P_("Has Pointer"),
5600                           P_("Whether the actor contains the pointer of an input device"),
5601                           FALSE,
5602                           CLUTTER_PARAM_READABLE);
5603
5604   /**
5605    * ClutterActor:actions:
5606    *
5607    * Adds a #ClutterAction to the actor
5608    *
5609    * Since: 1.4
5610    */
5611   obj_props[PROP_ACTIONS] =
5612     g_param_spec_object ("actions",
5613                          P_("Actions"),
5614                          P_("Adds an action to the actor"),
5615                          CLUTTER_TYPE_ACTION,
5616                          CLUTTER_PARAM_WRITABLE);
5617
5618   /**
5619    * ClutterActor:constraints:
5620    *
5621    * Adds a #ClutterConstraint to the actor
5622    *
5623    * Since: 1.4
5624    */
5625   obj_props[PROP_CONSTRAINTS] =
5626     g_param_spec_object ("constraints",
5627                          P_("Constraints"),
5628                          P_("Adds a constraint to the actor"),
5629                          CLUTTER_TYPE_CONSTRAINT,
5630                          CLUTTER_PARAM_WRITABLE);
5631
5632   /**
5633    * ClutterActor:effect:
5634    *
5635    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5636    *
5637    * Since: 1.4
5638    */
5639   obj_props[PROP_EFFECT] =
5640     g_param_spec_object ("effect",
5641                          P_("Effect"),
5642                          P_("Add an effect to be applied on the actor"),
5643                          CLUTTER_TYPE_EFFECT,
5644                          CLUTTER_PARAM_WRITABLE);
5645
5646   /**
5647    * ClutterActor:layout-manager:
5648    *
5649    * A delegate object for controlling the layout of the children of
5650    * an actor.
5651    *
5652    * Since: 1.10
5653    */
5654   obj_props[PROP_LAYOUT_MANAGER] =
5655     g_param_spec_object ("layout-manager",
5656                          P_("Layout Manager"),
5657                          P_("The object controlling the layout of an actor's children"),
5658                          CLUTTER_TYPE_LAYOUT_MANAGER,
5659                          CLUTTER_PARAM_READWRITE);
5660
5661
5662   /**
5663    * ClutterActor:x-align:
5664    *
5665    * The alignment of an actor on the X axis, if the actor has been given
5666    * extra space for its allocation.
5667    *
5668    * Since: 1.10
5669    */
5670   obj_props[PROP_X_ALIGN] =
5671     g_param_spec_enum ("x-align",
5672                        P_("X Alignment"),
5673                        P_("The alignment of the actor on the X axis within its allocation"),
5674                        CLUTTER_TYPE_ACTOR_ALIGN,
5675                        CLUTTER_ACTOR_ALIGN_FILL,
5676                        CLUTTER_PARAM_READWRITE);
5677
5678   /**
5679    * ClutterActor:y-align:
5680    *
5681    * The alignment of an actor on the Y axis, if the actor has been given
5682    * extra space for its allocation.
5683    *
5684    * Since: 1.10
5685    */
5686   obj_props[PROP_Y_ALIGN] =
5687     g_param_spec_enum ("y-align",
5688                        P_("Y Alignment"),
5689                        P_("The alignment of the actor on the Y axis within its allocation"),
5690                        CLUTTER_TYPE_ACTOR_ALIGN,
5691                        CLUTTER_ACTOR_ALIGN_FILL,
5692                        CLUTTER_PARAM_READWRITE);
5693
5694   /**
5695    * ClutterActor:margin-top:
5696    *
5697    * The margin (in pixels) from the top of the actor.
5698    *
5699    * This property adds a margin to the actor's preferred size; the margin
5700    * will be automatically taken into account when allocating the actor.
5701    *
5702    * Since: 1.10
5703    */
5704   obj_props[PROP_MARGIN_TOP] =
5705     g_param_spec_float ("margin-top",
5706                         P_("Margin Top"),
5707                         P_("Extra space at the top"),
5708                         0.0, G_MAXFLOAT,
5709                         0.0,
5710                         CLUTTER_PARAM_READWRITE);
5711
5712   /**
5713    * ClutterActor:margin-bottom:
5714    *
5715    * The margin (in pixels) from the bottom of the actor.
5716    *
5717    * This property adds a margin to the actor's preferred size; the margin
5718    * will be automatically taken into account when allocating the actor.
5719    *
5720    * Since: 1.10
5721    */
5722   obj_props[PROP_MARGIN_BOTTOM] =
5723     g_param_spec_float ("margin-bottom",
5724                         P_("Margin Bottom"),
5725                         P_("Extra space at the bottom"),
5726                         0.0, G_MAXFLOAT,
5727                         0.0,
5728                         CLUTTER_PARAM_READWRITE);
5729
5730   /**
5731    * ClutterActor:margin-left:
5732    *
5733    * The margin (in pixels) from the left of the actor.
5734    *
5735    * This property adds a margin to the actor's preferred size; the margin
5736    * will be automatically taken into account when allocating the actor.
5737    *
5738    * Since: 1.10
5739    */
5740   obj_props[PROP_MARGIN_LEFT] =
5741     g_param_spec_float ("margin-left",
5742                         P_("Margin Left"),
5743                         P_("Extra space at the left"),
5744                         0.0, G_MAXFLOAT,
5745                         0.0,
5746                         CLUTTER_PARAM_READWRITE);
5747
5748   /**
5749    * ClutterActor:margin-right:
5750    *
5751    * The margin (in pixels) from the right of the actor.
5752    *
5753    * This property adds a margin to the actor's preferred size; the margin
5754    * will be automatically taken into account when allocating the actor.
5755    *
5756    * Since: 1.10
5757    */
5758   obj_props[PROP_MARGIN_RIGHT] =
5759     g_param_spec_float ("margin-right",
5760                         P_("Margin Right"),
5761                         P_("Extra space at the right"),
5762                         0.0, G_MAXFLOAT,
5763                         0.0,
5764                         CLUTTER_PARAM_READWRITE);
5765
5766   /**
5767    * ClutterActor:background-color-set:
5768    *
5769    * Whether the #ClutterActor:background-color property has been set.
5770    *
5771    * Since: 1.10
5772    */
5773   obj_props[PROP_BACKGROUND_COLOR_SET] =
5774     g_param_spec_boolean ("background-color-set",
5775                           P_("Background Color Set"),
5776                           P_("Whether the background color is set"),
5777                           FALSE,
5778                           CLUTTER_PARAM_READABLE);
5779
5780   /**
5781    * ClutterActor:background-color:
5782    *
5783    * Paints a solid fill of the actor's allocation using the specified
5784    * color.
5785    *
5786    * Since: 1.10
5787    */
5788   obj_props[PROP_BACKGROUND_COLOR] =
5789     clutter_param_spec_color ("background-color",
5790                               P_("Background color"),
5791                               P_("The actor's background color"),
5792                               CLUTTER_COLOR_Transparent,
5793                               CLUTTER_PARAM_READWRITE);
5794
5795   /**
5796    * ClutterActor:first-child:
5797    *
5798    * The actor's first child.
5799    *
5800    * Since: 1.10
5801    */
5802   obj_props[PROP_FIRST_CHILD] =
5803     g_param_spec_object ("first-child",
5804                          P_("First Child"),
5805                          P_("The actor's first child"),
5806                          CLUTTER_TYPE_ACTOR,
5807                          CLUTTER_PARAM_READABLE);
5808
5809   /**
5810    * ClutterActor:last-child:
5811    *
5812    * The actor's last child.
5813    *
5814    * Since: 1.10
5815    */
5816   obj_props[PROP_LAST_CHILD] =
5817     g_param_spec_object ("last-child",
5818                          P_("Last Child"),
5819                          P_("The actor's last child"),
5820                          CLUTTER_TYPE_ACTOR,
5821                          CLUTTER_PARAM_READABLE);
5822
5823   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5824
5825   /**
5826    * ClutterActor::destroy:
5827    * @actor: the #ClutterActor which emitted the signal
5828    *
5829    * The ::destroy signal notifies that all references held on the
5830    * actor which emitted it should be released.
5831    *
5832    * The ::destroy signal should be used by all holders of a reference
5833    * on @actor.
5834    *
5835    * This signal might result in the finalization of the #ClutterActor
5836    * if all references are released.
5837    *
5838    * Composite actors and actors implementing the #ClutterContainer
5839    * interface should override the default implementation of the
5840    * class handler of this signal and call clutter_actor_destroy() on
5841    * their children. When overriding the default class handler, it is
5842    * required to chain up to the parent's implementation.
5843    *
5844    * Since: 0.2
5845    */
5846   actor_signals[DESTROY] =
5847     g_signal_new (I_("destroy"),
5848                   G_TYPE_FROM_CLASS (object_class),
5849                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5850                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5851                   NULL, NULL,
5852                   _clutter_marshal_VOID__VOID,
5853                   G_TYPE_NONE, 0);
5854   /**
5855    * ClutterActor::show:
5856    * @actor: the object which received the signal
5857    *
5858    * The ::show signal is emitted when an actor is visible and
5859    * rendered on the stage.
5860    *
5861    * Since: 0.2
5862    */
5863   actor_signals[SHOW] =
5864     g_signal_new (I_("show"),
5865                   G_TYPE_FROM_CLASS (object_class),
5866                   G_SIGNAL_RUN_FIRST,
5867                   G_STRUCT_OFFSET (ClutterActorClass, show),
5868                   NULL, NULL,
5869                   _clutter_marshal_VOID__VOID,
5870                   G_TYPE_NONE, 0);
5871   /**
5872    * ClutterActor::hide:
5873    * @actor: the object which received the signal
5874    *
5875    * The ::hide signal is emitted when an actor is no longer rendered
5876    * on the stage.
5877    *
5878    * Since: 0.2
5879    */
5880   actor_signals[HIDE] =
5881     g_signal_new (I_("hide"),
5882                   G_TYPE_FROM_CLASS (object_class),
5883                   G_SIGNAL_RUN_FIRST,
5884                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5885                   NULL, NULL,
5886                   _clutter_marshal_VOID__VOID,
5887                   G_TYPE_NONE, 0);
5888   /**
5889    * ClutterActor::parent-set:
5890    * @actor: the object which received the signal
5891    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5892    *
5893    * This signal is emitted when the parent of the actor changes.
5894    *
5895    * Since: 0.2
5896    */
5897   actor_signals[PARENT_SET] =
5898     g_signal_new (I_("parent-set"),
5899                   G_TYPE_FROM_CLASS (object_class),
5900                   G_SIGNAL_RUN_LAST,
5901                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5902                   NULL, NULL,
5903                   _clutter_marshal_VOID__OBJECT,
5904                   G_TYPE_NONE, 1,
5905                   CLUTTER_TYPE_ACTOR);
5906
5907   /**
5908    * ClutterActor::queue-redraw:
5909    * @actor: the actor we're bubbling the redraw request through
5910    * @origin: the actor which initiated the redraw request
5911    *
5912    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5913    * is called on @origin.
5914    *
5915    * The default implementation for #ClutterActor chains up to the
5916    * parent actor and queues a redraw on the parent, thus "bubbling"
5917    * the redraw queue up through the actor graph. The default
5918    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5919    * in a main loop idle handler.
5920    *
5921    * Note that the @origin actor may be the stage, or a container; it
5922    * does not have to be a leaf node in the actor graph.
5923    *
5924    * Toolkits embedding a #ClutterStage which require a redraw and
5925    * relayout cycle can stop the emission of this signal using the
5926    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
5927    * themselves, like:
5928    *
5929    * |[
5930    *   static void
5931    *   on_redraw_complete (gpointer data)
5932    *   {
5933    *     ClutterStage *stage = data;
5934    *
5935    *     /&ast; execute the Clutter drawing pipeline &ast;/
5936    *     clutter_stage_ensure_redraw (stage);
5937    *   }
5938    *
5939    *   static void
5940    *   on_stage_queue_redraw (ClutterStage *stage)
5941    *   {
5942    *     /&ast; this prevents the default handler to run &ast;/
5943    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
5944    *
5945    *     /&ast; queue a redraw with the host toolkit and call
5946    *      &ast; a function when the redraw has been completed
5947    *      &ast;/
5948    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
5949    *   }
5950    * ]|
5951    *
5952    * <note><para>This signal is emitted before the Clutter paint
5953    * pipeline is executed. If you want to know when the pipeline has
5954    * been completed you should connect to the ::paint signal on the
5955    * Stage with g_signal_connect_after().</para></note>
5956    *
5957    * Since: 1.0
5958    */
5959   actor_signals[QUEUE_REDRAW] =
5960     g_signal_new (I_("queue-redraw"),
5961                   G_TYPE_FROM_CLASS (object_class),
5962                   G_SIGNAL_RUN_LAST,
5963                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
5964                   NULL, NULL,
5965                   _clutter_marshal_VOID__OBJECT,
5966                   G_TYPE_NONE, 1,
5967                   CLUTTER_TYPE_ACTOR);
5968
5969   /**
5970    * ClutterActor::queue-relayout
5971    * @actor: the actor being queued for relayout
5972    *
5973    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
5974    * is called on an actor.
5975    *
5976    * The default implementation for #ClutterActor chains up to the
5977    * parent actor and queues a relayout on the parent, thus "bubbling"
5978    * the relayout queue up through the actor graph.
5979    *
5980    * The main purpose of this signal is to allow relayout to be propagated
5981    * properly in the procense of #ClutterClone actors. Applications will
5982    * not normally need to connect to this signal.
5983    *
5984    * Since: 1.2
5985    */
5986   actor_signals[QUEUE_RELAYOUT] =
5987     g_signal_new (I_("queue-relayout"),
5988                   G_TYPE_FROM_CLASS (object_class),
5989                   G_SIGNAL_RUN_LAST,
5990                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
5991                   NULL, NULL,
5992                   _clutter_marshal_VOID__VOID,
5993                   G_TYPE_NONE, 0);
5994
5995   /**
5996    * ClutterActor::event:
5997    * @actor: the actor which received the event
5998    * @event: a #ClutterEvent
5999    *
6000    * The ::event signal is emitted each time an event is received
6001    * by the @actor. This signal will be emitted on every actor,
6002    * following the hierarchy chain, until it reaches the top-level
6003    * container (the #ClutterStage).
6004    *
6005    * Return value: %TRUE if the event has been handled by the actor,
6006    *   or %FALSE to continue the emission.
6007    *
6008    * Since: 0.6
6009    */
6010   actor_signals[EVENT] =
6011     g_signal_new (I_("event"),
6012                   G_TYPE_FROM_CLASS (object_class),
6013                   G_SIGNAL_RUN_LAST,
6014                   G_STRUCT_OFFSET (ClutterActorClass, event),
6015                   _clutter_boolean_handled_accumulator, NULL,
6016                   _clutter_marshal_BOOLEAN__BOXED,
6017                   G_TYPE_BOOLEAN, 1,
6018                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6019   /**
6020    * ClutterActor::button-press-event:
6021    * @actor: the actor which received the event
6022    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6023    *
6024    * The ::button-press-event signal is emitted each time a mouse button
6025    * is pressed on @actor.
6026    *
6027    * Return value: %TRUE if the event has been handled by the actor,
6028    *   or %FALSE to continue the emission.
6029    *
6030    * Since: 0.6
6031    */
6032   actor_signals[BUTTON_PRESS_EVENT] =
6033     g_signal_new (I_("button-press-event"),
6034                   G_TYPE_FROM_CLASS (object_class),
6035                   G_SIGNAL_RUN_LAST,
6036                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6037                   _clutter_boolean_handled_accumulator, NULL,
6038                   _clutter_marshal_BOOLEAN__BOXED,
6039                   G_TYPE_BOOLEAN, 1,
6040                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6041   /**
6042    * ClutterActor::button-release-event:
6043    * @actor: the actor which received the event
6044    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6045    *
6046    * The ::button-release-event signal is emitted each time a mouse button
6047    * is released on @actor.
6048    *
6049    * Return value: %TRUE if the event has been handled by the actor,
6050    *   or %FALSE to continue the emission.
6051    *
6052    * Since: 0.6
6053    */
6054   actor_signals[BUTTON_RELEASE_EVENT] =
6055     g_signal_new (I_("button-release-event"),
6056                   G_TYPE_FROM_CLASS (object_class),
6057                   G_SIGNAL_RUN_LAST,
6058                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6059                   _clutter_boolean_handled_accumulator, NULL,
6060                   _clutter_marshal_BOOLEAN__BOXED,
6061                   G_TYPE_BOOLEAN, 1,
6062                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6063   /**
6064    * ClutterActor::scroll-event:
6065    * @actor: the actor which received the event
6066    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6067    *
6068    * The ::scroll-event signal is emitted each time the mouse is
6069    * scrolled on @actor
6070    *
6071    * Return value: %TRUE if the event has been handled by the actor,
6072    *   or %FALSE to continue the emission.
6073    *
6074    * Since: 0.6
6075    */
6076   actor_signals[SCROLL_EVENT] =
6077     g_signal_new (I_("scroll-event"),
6078                   G_TYPE_FROM_CLASS (object_class),
6079                   G_SIGNAL_RUN_LAST,
6080                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6081                   _clutter_boolean_handled_accumulator, NULL,
6082                   _clutter_marshal_BOOLEAN__BOXED,
6083                   G_TYPE_BOOLEAN, 1,
6084                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6085   /**
6086    * ClutterActor::key-press-event:
6087    * @actor: the actor which received the event
6088    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6089    *
6090    * The ::key-press-event signal is emitted each time a keyboard button
6091    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6092    *
6093    * Return value: %TRUE if the event has been handled by the actor,
6094    *   or %FALSE to continue the emission.
6095    *
6096    * Since: 0.6
6097    */
6098   actor_signals[KEY_PRESS_EVENT] =
6099     g_signal_new (I_("key-press-event"),
6100                   G_TYPE_FROM_CLASS (object_class),
6101                   G_SIGNAL_RUN_LAST,
6102                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6103                   _clutter_boolean_handled_accumulator, NULL,
6104                   _clutter_marshal_BOOLEAN__BOXED,
6105                   G_TYPE_BOOLEAN, 1,
6106                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6107   /**
6108    * ClutterActor::key-release-event:
6109    * @actor: the actor which received the event
6110    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6111    *
6112    * The ::key-release-event signal is emitted each time a keyboard button
6113    * is released while @actor has key focus (see
6114    * clutter_stage_set_key_focus()).
6115    *
6116    * Return value: %TRUE if the event has been handled by the actor,
6117    *   or %FALSE to continue the emission.
6118    *
6119    * Since: 0.6
6120    */
6121   actor_signals[KEY_RELEASE_EVENT] =
6122     g_signal_new (I_("key-release-event"),
6123                   G_TYPE_FROM_CLASS (object_class),
6124                   G_SIGNAL_RUN_LAST,
6125                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6126                   _clutter_boolean_handled_accumulator, NULL,
6127                   _clutter_marshal_BOOLEAN__BOXED,
6128                   G_TYPE_BOOLEAN, 1,
6129                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6130   /**
6131    * ClutterActor::motion-event:
6132    * @actor: the actor which received the event
6133    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6134    *
6135    * The ::motion-event signal is emitted each time the mouse pointer is
6136    * moved over @actor.
6137    *
6138    * Return value: %TRUE if the event has been handled by the actor,
6139    *   or %FALSE to continue the emission.
6140    *
6141    * Since: 0.6
6142    */
6143   actor_signals[MOTION_EVENT] =
6144     g_signal_new (I_("motion-event"),
6145                   G_TYPE_FROM_CLASS (object_class),
6146                   G_SIGNAL_RUN_LAST,
6147                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6148                   _clutter_boolean_handled_accumulator, NULL,
6149                   _clutter_marshal_BOOLEAN__BOXED,
6150                   G_TYPE_BOOLEAN, 1,
6151                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6152
6153   /**
6154    * ClutterActor::key-focus-in:
6155    * @actor: the actor which now has key focus
6156    *
6157    * The ::key-focus-in signal is emitted when @actor receives key focus.
6158    *
6159    * Since: 0.6
6160    */
6161   actor_signals[KEY_FOCUS_IN] =
6162     g_signal_new (I_("key-focus-in"),
6163                   G_TYPE_FROM_CLASS (object_class),
6164                   G_SIGNAL_RUN_LAST,
6165                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6166                   NULL, NULL,
6167                   _clutter_marshal_VOID__VOID,
6168                   G_TYPE_NONE, 0);
6169
6170   /**
6171    * ClutterActor::key-focus-out:
6172    * @actor: the actor which now has key focus
6173    *
6174    * The ::key-focus-out signal is emitted when @actor loses key focus.
6175    *
6176    * Since: 0.6
6177    */
6178   actor_signals[KEY_FOCUS_OUT] =
6179     g_signal_new (I_("key-focus-out"),
6180                   G_TYPE_FROM_CLASS (object_class),
6181                   G_SIGNAL_RUN_LAST,
6182                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6183                   NULL, NULL,
6184                   _clutter_marshal_VOID__VOID,
6185                   G_TYPE_NONE, 0);
6186
6187   /**
6188    * ClutterActor::enter-event:
6189    * @actor: the actor which the pointer has entered.
6190    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6191    *
6192    * The ::enter-event signal is emitted when the pointer enters the @actor
6193    *
6194    * Return value: %TRUE if the event has been handled by the actor,
6195    *   or %FALSE to continue the emission.
6196    *
6197    * Since: 0.6
6198    */
6199   actor_signals[ENTER_EVENT] =
6200     g_signal_new (I_("enter-event"),
6201                   G_TYPE_FROM_CLASS (object_class),
6202                   G_SIGNAL_RUN_LAST,
6203                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6204                   _clutter_boolean_handled_accumulator, NULL,
6205                   _clutter_marshal_BOOLEAN__BOXED,
6206                   G_TYPE_BOOLEAN, 1,
6207                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6208
6209   /**
6210    * ClutterActor::leave-event:
6211    * @actor: the actor which the pointer has left
6212    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6213    *
6214    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6215    *
6216    * Return value: %TRUE if the event has been handled by the actor,
6217    *   or %FALSE to continue the emission.
6218    *
6219    * Since: 0.6
6220    */
6221   actor_signals[LEAVE_EVENT] =
6222     g_signal_new (I_("leave-event"),
6223                   G_TYPE_FROM_CLASS (object_class),
6224                   G_SIGNAL_RUN_LAST,
6225                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6226                   _clutter_boolean_handled_accumulator, NULL,
6227                   _clutter_marshal_BOOLEAN__BOXED,
6228                   G_TYPE_BOOLEAN, 1,
6229                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6230
6231   /**
6232    * ClutterActor::captured-event:
6233    * @actor: the actor which received the signal
6234    * @event: a #ClutterEvent
6235    *
6236    * The ::captured-event signal is emitted when an event is captured
6237    * by Clutter. This signal will be emitted starting from the top-level
6238    * container (the #ClutterStage) to the actor which received the event
6239    * going down the hierarchy. This signal can be used to intercept every
6240    * event before the specialized events (like
6241    * ClutterActor::button-press-event or ::key-released-event) are
6242    * emitted.
6243    *
6244    * Return value: %TRUE if the event has been handled by the actor,
6245    *   or %FALSE to continue the emission.
6246    *
6247    * Since: 0.6
6248    */
6249   actor_signals[CAPTURED_EVENT] =
6250     g_signal_new (I_("captured-event"),
6251                   G_TYPE_FROM_CLASS (object_class),
6252                   G_SIGNAL_RUN_LAST,
6253                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6254                   _clutter_boolean_handled_accumulator, NULL,
6255                   _clutter_marshal_BOOLEAN__BOXED,
6256                   G_TYPE_BOOLEAN, 1,
6257                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6258
6259   /**
6260    * ClutterActor::paint:
6261    * @actor: the #ClutterActor that received the signal
6262    *
6263    * The ::paint signal is emitted each time an actor is being painted.
6264    *
6265    * Subclasses of #ClutterActor should override the class signal handler
6266    * and paint themselves in that function.
6267    *
6268    * It is possible to connect a handler to the ::paint signal in order
6269    * to set up some custom aspect of a paint.
6270    *
6271    * Since: 0.8
6272    */
6273   actor_signals[PAINT] =
6274     g_signal_new (I_("paint"),
6275                   G_TYPE_FROM_CLASS (object_class),
6276                   G_SIGNAL_RUN_LAST,
6277                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6278                   NULL, NULL,
6279                   _clutter_marshal_VOID__VOID,
6280                   G_TYPE_NONE, 0);
6281   /**
6282    * ClutterActor::realize:
6283    * @actor: the #ClutterActor that received the signal
6284    *
6285    * The ::realize signal is emitted each time an actor is being
6286    * realized.
6287    *
6288    * Since: 0.8
6289    */
6290   actor_signals[REALIZE] =
6291     g_signal_new (I_("realize"),
6292                   G_TYPE_FROM_CLASS (object_class),
6293                   G_SIGNAL_RUN_LAST,
6294                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6295                   NULL, NULL,
6296                   _clutter_marshal_VOID__VOID,
6297                   G_TYPE_NONE, 0);
6298   /**
6299    * ClutterActor::unrealize:
6300    * @actor: the #ClutterActor that received the signal
6301    *
6302    * The ::unrealize signal is emitted each time an actor is being
6303    * unrealized.
6304    *
6305    * Since: 0.8
6306    */
6307   actor_signals[UNREALIZE] =
6308     g_signal_new (I_("unrealize"),
6309                   G_TYPE_FROM_CLASS (object_class),
6310                   G_SIGNAL_RUN_LAST,
6311                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6312                   NULL, NULL,
6313                   _clutter_marshal_VOID__VOID,
6314                   G_TYPE_NONE, 0);
6315
6316   /**
6317    * ClutterActor::pick:
6318    * @actor: the #ClutterActor that received the signal
6319    * @color: the #ClutterColor to be used when picking
6320    *
6321    * The ::pick signal is emitted each time an actor is being painted
6322    * in "pick mode". The pick mode is used to identify the actor during
6323    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6324    * The actor should paint its shape using the passed @pick_color.
6325    *
6326    * Subclasses of #ClutterActor should override the class signal handler
6327    * and paint themselves in that function.
6328    *
6329    * It is possible to connect a handler to the ::pick signal in order
6330    * to set up some custom aspect of a paint in pick mode.
6331    *
6332    * Since: 1.0
6333    */
6334   actor_signals[PICK] =
6335     g_signal_new (I_("pick"),
6336                   G_TYPE_FROM_CLASS (object_class),
6337                   G_SIGNAL_RUN_LAST,
6338                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6339                   NULL, NULL,
6340                   _clutter_marshal_VOID__BOXED,
6341                   G_TYPE_NONE, 1,
6342                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6343
6344   /**
6345    * ClutterActor::allocation-changed:
6346    * @actor: the #ClutterActor that emitted the signal
6347    * @box: a #ClutterActorBox with the new allocation
6348    * @flags: #ClutterAllocationFlags for the allocation
6349    *
6350    * The ::allocation-changed signal is emitted when the
6351    * #ClutterActor:allocation property changes. Usually, application
6352    * code should just use the notifications for the :allocation property
6353    * but if you want to track the allocation flags as well, for instance
6354    * to know whether the absolute origin of @actor changed, then you might
6355    * want use this signal instead.
6356    *
6357    * Since: 1.0
6358    */
6359   actor_signals[ALLOCATION_CHANGED] =
6360     g_signal_new (I_("allocation-changed"),
6361                   G_TYPE_FROM_CLASS (object_class),
6362                   G_SIGNAL_RUN_LAST,
6363                   0,
6364                   NULL, NULL,
6365                   _clutter_marshal_VOID__BOXED_FLAGS,
6366                   G_TYPE_NONE, 2,
6367                   CLUTTER_TYPE_ACTOR_BOX,
6368                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6369 }
6370
6371 static void
6372 clutter_actor_init (ClutterActor *self)
6373 {
6374   ClutterActorPrivate *priv;
6375
6376   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6377
6378   priv->id = _clutter_context_acquire_id (self);
6379   priv->pick_id = -1;
6380
6381   priv->opacity = 0xff;
6382   priv->show_on_set_parent = TRUE;
6383
6384   priv->needs_width_request = TRUE;
6385   priv->needs_height_request = TRUE;
6386   priv->needs_allocation = TRUE;
6387
6388   priv->cached_width_age = 1;
6389   priv->cached_height_age = 1;
6390
6391   priv->opacity_override = -1;
6392   priv->enable_model_view_transform = TRUE;
6393
6394   /* Initialize an empty paint volume to start with */
6395   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6396   priv->last_paint_volume_valid = TRUE;
6397
6398   priv->transform_valid = FALSE;
6399 }
6400
6401 /**
6402  * clutter_actor_new:
6403  *
6404  * Creates a new #ClutterActor.
6405  *
6406  * A newly created actor has a floating reference, which will be sunk
6407  * when it is added to another actor.
6408  *
6409  * Return value: (transfer full): the newly created #ClutterActor
6410  *
6411  * Since: 1.10
6412  */
6413 ClutterActor *
6414 clutter_actor_new (void)
6415 {
6416   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6417 }
6418
6419 /**
6420  * clutter_actor_destroy:
6421  * @self: a #ClutterActor
6422  *
6423  * Destroys an actor.  When an actor is destroyed, it will break any
6424  * references it holds to other objects.  If the actor is inside a
6425  * container, the actor will be removed.
6426  *
6427  * When you destroy a container, its children will be destroyed as well.
6428  *
6429  * Note: you cannot destroy the #ClutterStage returned by
6430  * clutter_stage_get_default().
6431  */
6432 void
6433 clutter_actor_destroy (ClutterActor *self)
6434 {
6435   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6436
6437   g_object_ref (self);
6438
6439   /* avoid recursion while destroying */
6440   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6441     {
6442       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6443
6444       g_object_run_dispose (G_OBJECT (self));
6445
6446       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6447     }
6448
6449   g_object_unref (self);
6450 }
6451
6452 void
6453 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6454                                     ClutterPaintVolume *clip)
6455 {
6456   ClutterActorPrivate *priv = self->priv;
6457   ClutterPaintVolume *pv;
6458   gboolean clipped;
6459
6460   /* If we've been explicitly passed a clip volume then there's
6461    * nothing more to calculate, but otherwise the only thing we know
6462    * is that the change is constrained to the given actor.
6463    *
6464    * The idea is that if we know the paint volume for where the actor
6465    * was last drawn (in eye coordinates) and we also have the paint
6466    * volume for where it will be drawn next (in actor coordinates)
6467    * then if we queue a redraw for both these volumes that will cover
6468    * everything that needs to be redrawn to clear the old view and
6469    * show the latest view of the actor.
6470    *
6471    * Don't clip this redraw if we don't know what position we had for
6472    * the previous redraw since we don't know where to set the clip so
6473    * it will clear the actor as it is currently.
6474    */
6475   if (clip)
6476     {
6477       _clutter_actor_set_queue_redraw_clip (self, clip);
6478       clipped = TRUE;
6479     }
6480   else if (G_LIKELY (priv->last_paint_volume_valid))
6481     {
6482       pv = _clutter_actor_get_paint_volume_mutable (self);
6483       if (pv)
6484         {
6485           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6486
6487           /* make sure we redraw the actors old position... */
6488           _clutter_actor_set_queue_redraw_clip (stage,
6489                                                 &priv->last_paint_volume);
6490           _clutter_actor_signal_queue_redraw (stage, stage);
6491           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6492
6493           /* XXX: Ideally the redraw signal would take a clip volume
6494            * argument, but that would be an ABI break. Until we can
6495            * break the ABI we pass the argument out-of-band
6496            */
6497
6498           /* setup the clip for the actors new position... */
6499           _clutter_actor_set_queue_redraw_clip (self, pv);
6500           clipped = TRUE;
6501         }
6502       else
6503         clipped = FALSE;
6504     }
6505   else
6506     clipped = FALSE;
6507
6508   _clutter_actor_signal_queue_redraw (self, self);
6509
6510   /* Just in case anyone is manually firing redraw signals without
6511    * using the public queue_redraw() API we are careful to ensure that
6512    * our out-of-band clip member is cleared before returning...
6513    *
6514    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6515    */
6516   if (G_LIKELY (clipped))
6517     _clutter_actor_set_queue_redraw_clip (self, NULL);
6518
6519   priv->queue_redraw_entry = NULL;
6520 }
6521
6522 static void
6523 _clutter_actor_get_allocation_clip (ClutterActor *self,
6524                                     ClutterActorBox *clip)
6525 {
6526   ClutterActorBox allocation;
6527
6528   /* XXX: we don't care if we get an out of date allocation here
6529    * because clutter_actor_queue_redraw_with_clip knows to ignore
6530    * the clip if the actor's allocation is invalid.
6531    *
6532    * This is noted because clutter_actor_get_allocation_box does some
6533    * unnecessary work to support buggy code with a comment suggesting
6534    * that it could be changed later which would be good for this use
6535    * case!
6536    */
6537   clutter_actor_get_allocation_box (self, &allocation);
6538
6539   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6540    * actor's own coordinate space but the allocation is in parent
6541    * coordinates */
6542   clip->x1 = 0;
6543   clip->y1 = 0;
6544   clip->x2 = allocation.x2 - allocation.x1;
6545   clip->y2 = allocation.y2 - allocation.y1;
6546 }
6547
6548 void
6549 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6550                                   ClutterRedrawFlags  flags,
6551                                   ClutterPaintVolume *volume,
6552                                   ClutterEffect      *effect)
6553 {
6554   ClutterActorPrivate *priv = self->priv;
6555   ClutterPaintVolume allocation_pv;
6556   ClutterPaintVolume *pv;
6557   gboolean should_free_pv;
6558   ClutterActor *stage;
6559
6560   /* Here's an outline of the actor queue redraw mechanism:
6561    *
6562    * The process starts in one of the following two functions which
6563    * are wrappers for this function:
6564    * clutter_actor_queue_redraw
6565    * _clutter_actor_queue_redraw_with_clip
6566    *
6567    * additionally, an effect can queue a redraw by wrapping this
6568    * function in clutter_effect_queue_rerun
6569    *
6570    * This functions queues an entry in a list associated with the
6571    * stage which is a list of actors that queued a redraw while
6572    * updating the timelines, performing layouting and processing other
6573    * mainloop sources before the next paint starts.
6574    *
6575    * We aim to minimize the processing done at this point because
6576    * there is a good chance other events will happen while updating
6577    * the scenegraph that would invalidate any expensive work we might
6578    * otherwise try to do here. For example we don't try and resolve
6579    * the screen space bounding box of an actor at this stage so as to
6580    * minimize how much of the screen redraw because it's possible
6581    * something else will happen which will force a full redraw anyway.
6582    *
6583    * When all updates are complete and we come to paint the stage then
6584    * we iterate this list and actually emit the "queue-redraw" signals
6585    * for each of the listed actors which will bubble up to the stage
6586    * for each actor and at that point we will transform the actors
6587    * paint volume into screen coordinates to determine the clip region
6588    * for what needs to be redrawn in the next paint.
6589    *
6590    * Besides minimizing redundant work another reason for this
6591    * deferred design is that it's more likely we will be able to
6592    * determine the paint volume of an actor once we've finished
6593    * updating the scenegraph because its allocation should be up to
6594    * date. NB: If we can't determine an actors paint volume then we
6595    * can't automatically queue a clipped redraw which can make a big
6596    * difference to performance.
6597    *
6598    * So the control flow goes like this:
6599    * One of clutter_actor_queue_redraw,
6600    *        _clutter_actor_queue_redraw_with_clip
6601    *     or clutter_effect_queue_rerun
6602    *
6603    * then control moves to:
6604    *   _clutter_stage_queue_actor_redraw
6605    *
6606    * later during _clutter_stage_do_update, once relayouting is done
6607    * and the scenegraph has been updated we will call:
6608    * _clutter_stage_finish_queue_redraws
6609    *
6610    * _clutter_stage_finish_queue_redraws will call
6611    * _clutter_actor_finish_queue_redraw for each listed actor.
6612    * Note: actors *are* allowed to queue further redraws during this
6613    * process (considering clone actors or texture_new_from_actor which
6614    * respond to their source queueing a redraw by queuing a redraw
6615    * themselves). We repeat the process until the list is empty.
6616    *
6617    * This will result in the "queue-redraw" signal being fired for
6618    * each actor which will pass control to the default signal handler:
6619    * clutter_actor_real_queue_redraw
6620    *
6621    * This will bubble up to the stages handler:
6622    * clutter_stage_real_queue_redraw
6623    *
6624    * clutter_stage_real_queue_redraw will transform the actors paint
6625    * volume into screen space and add it as a clip region for the next
6626    * paint.
6627    */
6628
6629   /* ignore queueing a redraw for actors being destroyed */
6630   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6631     return;
6632
6633   stage = _clutter_actor_get_stage_internal (self);
6634
6635   /* Ignore queueing a redraw for actors not descended from a stage */
6636   if (stage == NULL)
6637     return;
6638
6639   /* ignore queueing a redraw on stages that are being destroyed */
6640   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6641     return;
6642
6643   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6644     {
6645       ClutterActorBox allocation_clip;
6646       ClutterVertex origin;
6647
6648       /* If the actor doesn't have a valid allocation then we will
6649        * queue a full stage redraw. */
6650       if (priv->needs_allocation)
6651         {
6652           /* NB: NULL denotes an undefined clip which will result in a
6653            * full redraw... */
6654           _clutter_actor_set_queue_redraw_clip (self, NULL);
6655           _clutter_actor_signal_queue_redraw (self, self);
6656           return;
6657         }
6658
6659       _clutter_paint_volume_init_static (&allocation_pv, self);
6660       pv = &allocation_pv;
6661
6662       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6663
6664       origin.x = allocation_clip.x1;
6665       origin.y = allocation_clip.y1;
6666       origin.z = 0;
6667       clutter_paint_volume_set_origin (pv, &origin);
6668       clutter_paint_volume_set_width (pv,
6669                                       allocation_clip.x2 - allocation_clip.x1);
6670       clutter_paint_volume_set_height (pv,
6671                                        allocation_clip.y2 -
6672                                        allocation_clip.y1);
6673       should_free_pv = TRUE;
6674     }
6675   else
6676     {
6677       pv = volume;
6678       should_free_pv = FALSE;
6679     }
6680
6681   self->priv->queue_redraw_entry =
6682     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6683                                        priv->queue_redraw_entry,
6684                                        self,
6685                                        pv);
6686
6687   if (should_free_pv)
6688     clutter_paint_volume_free (pv);
6689
6690   /* If this is the first redraw queued then we can directly use the
6691      effect parameter */
6692   if (!priv->is_dirty)
6693     priv->effect_to_redraw = effect;
6694   /* Otherwise we need to merge it with the existing effect parameter */
6695   else if (effect != NULL)
6696     {
6697       /* If there's already an effect then we need to use whichever is
6698          later in the chain of actors. Otherwise a full redraw has
6699          already been queued on the actor so we need to ignore the
6700          effect parameter */
6701       if (priv->effect_to_redraw != NULL)
6702         {
6703           if (priv->effects == NULL)
6704             g_warning ("Redraw queued with an effect that is "
6705                        "not applied to the actor");
6706           else
6707             {
6708               const GList *l;
6709
6710               for (l = _clutter_meta_group_peek_metas (priv->effects);
6711                    l != NULL;
6712                    l = l->next)
6713                 {
6714                   if (l->data == priv->effect_to_redraw ||
6715                       l->data == effect)
6716                     priv->effect_to_redraw = l->data;
6717                 }
6718             }
6719         }
6720     }
6721   else
6722     {
6723       /* If no effect is specified then we need to redraw the whole
6724          actor */
6725       priv->effect_to_redraw = NULL;
6726     }
6727
6728   priv->is_dirty = TRUE;
6729 }
6730
6731 /**
6732  * clutter_actor_queue_redraw:
6733  * @self: A #ClutterActor
6734  *
6735  * Queues up a redraw of an actor and any children. The redraw occurs
6736  * once the main loop becomes idle (after the current batch of events
6737  * has been processed, roughly).
6738  *
6739  * Applications rarely need to call this, as redraws are handled
6740  * automatically by modification functions.
6741  *
6742  * This function will not do anything if @self is not visible, or
6743  * if the actor is inside an invisible part of the scenegraph.
6744  *
6745  * Also be aware that painting is a NOP for actors with an opacity of
6746  * 0
6747  *
6748  * When you are implementing a custom actor you must queue a redraw
6749  * whenever some private state changes that will affect painting or
6750  * picking of your actor.
6751  */
6752 void
6753 clutter_actor_queue_redraw (ClutterActor *self)
6754 {
6755   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6756
6757   _clutter_actor_queue_redraw_full (self,
6758                                     0, /* flags */
6759                                     NULL, /* clip volume */
6760                                     NULL /* effect */);
6761 }
6762
6763 /*< private >
6764  * _clutter_actor_queue_redraw_with_clip:
6765  * @self: A #ClutterActor
6766  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6767  *   this queue redraw.
6768  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6769  *   redrawn or %NULL if you are just using a @flag to state your
6770  *   desired clipping.
6771  *
6772  * Queues up a clipped redraw of an actor and any children. The redraw
6773  * occurs once the main loop becomes idle (after the current batch of
6774  * events has been processed, roughly).
6775  *
6776  * If no flags are given the clip volume is defined by @volume
6777  * specified in actor coordinates and tells Clutter that only content
6778  * within this volume has been changed so Clutter can optionally
6779  * optimize the redraw.
6780  *
6781  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6782  * should be %NULL and this tells Clutter to use the actor's current
6783  * allocation as a clip box. This flag can only be used for 2D actors,
6784  * because any actor with depth may be projected outside its
6785  * allocation.
6786  *
6787  * Applications rarely need to call this, as redraws are handled
6788  * automatically by modification functions.
6789  *
6790  * This function will not do anything if @self is not visible, or if
6791  * the actor is inside an invisible part of the scenegraph.
6792  *
6793  * Also be aware that painting is a NOP for actors with an opacity of
6794  * 0
6795  *
6796  * When you are implementing a custom actor you must queue a redraw
6797  * whenever some private state changes that will affect painting or
6798  * picking of your actor.
6799  */
6800 void
6801 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6802                                        ClutterRedrawFlags  flags,
6803                                        ClutterPaintVolume *volume)
6804 {
6805   _clutter_actor_queue_redraw_full (self,
6806                                     flags, /* flags */
6807                                     volume, /* clip volume */
6808                                     NULL /* effect */);
6809 }
6810
6811 static void
6812 _clutter_actor_queue_only_relayout (ClutterActor *self)
6813 {
6814   ClutterActorPrivate *priv = self->priv;
6815
6816   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6817     return;
6818
6819   if (priv->needs_width_request &&
6820       priv->needs_height_request &&
6821       priv->needs_allocation)
6822     return; /* save some cpu cycles */
6823
6824 #if CLUTTER_ENABLE_DEBUG
6825   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6826     {
6827       g_warning ("The actor '%s' is currently inside an allocation "
6828                  "cycle; calling clutter_actor_queue_relayout() is "
6829                  "not recommended",
6830                  _clutter_actor_get_debug_name (self));
6831     }
6832 #endif /* CLUTTER_ENABLE_DEBUG */
6833
6834   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6835 }
6836
6837 /**
6838  * clutter_actor_queue_redraw_with_clip:
6839  * @self: a #ClutterActor
6840  * @clip: (allow-none): a rectangular clip region, or %NULL
6841  *
6842  * Queues a redraw on @self limited to a specific, actor-relative
6843  * rectangular area.
6844  *
6845  * If @clip is %NULL this function is equivalent to
6846  * clutter_actor_queue_redraw().
6847  *
6848  * Since: 1.10
6849  */
6850 void
6851 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6852                                       const cairo_rectangle_int_t *clip)
6853 {
6854   ClutterPaintVolume volume;
6855   ClutterVertex origin;
6856
6857   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6858
6859   if (clip == NULL)
6860     {
6861       clutter_actor_queue_redraw (self);
6862       return;
6863     }
6864
6865   _clutter_paint_volume_init_static (&volume, self);
6866
6867   origin.x = clip->x;
6868   origin.y = clip->y;
6869   origin.z = 0.0f;
6870
6871   clutter_paint_volume_set_origin (&volume, &origin);
6872   clutter_paint_volume_set_width (&volume, clip->width);
6873   clutter_paint_volume_set_height (&volume, clip->height);
6874
6875   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6876
6877   clutter_paint_volume_free (&volume);
6878 }
6879
6880 /**
6881  * clutter_actor_queue_relayout:
6882  * @self: A #ClutterActor
6883  *
6884  * Indicates that the actor's size request or other layout-affecting
6885  * properties may have changed. This function is used inside #ClutterActor
6886  * subclass implementations, not by applications directly.
6887  *
6888  * Queueing a new layout automatically queues a redraw as well.
6889  *
6890  * Since: 0.8
6891  */
6892 void
6893 clutter_actor_queue_relayout (ClutterActor *self)
6894 {
6895   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6896
6897   _clutter_actor_queue_only_relayout (self);
6898   clutter_actor_queue_redraw (self);
6899 }
6900
6901 /**
6902  * clutter_actor_get_preferred_size:
6903  * @self: a #ClutterActor
6904  * @min_width_p: (out) (allow-none): return location for the minimum
6905  *   width, or %NULL
6906  * @min_height_p: (out) (allow-none): return location for the minimum
6907  *   height, or %NULL
6908  * @natural_width_p: (out) (allow-none): return location for the natural
6909  *   width, or %NULL
6910  * @natural_height_p: (out) (allow-none): return location for the natural
6911  *   height, or %NULL
6912  *
6913  * Computes the preferred minimum and natural size of an actor, taking into
6914  * account the actor's geometry management (either height-for-width
6915  * or width-for-height).
6916  *
6917  * The width and height used to compute the preferred height and preferred
6918  * width are the actor's natural ones.
6919  *
6920  * If you need to control the height for the preferred width, or the width for
6921  * the preferred height, you should use clutter_actor_get_preferred_width()
6922  * and clutter_actor_get_preferred_height(), and check the actor's preferred
6923  * geometry management using the #ClutterActor:request-mode property.
6924  *
6925  * Since: 0.8
6926  */
6927 void
6928 clutter_actor_get_preferred_size (ClutterActor *self,
6929                                   gfloat       *min_width_p,
6930                                   gfloat       *min_height_p,
6931                                   gfloat       *natural_width_p,
6932                                   gfloat       *natural_height_p)
6933 {
6934   ClutterActorPrivate *priv;
6935   gfloat min_width, min_height;
6936   gfloat natural_width, natural_height;
6937
6938   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6939
6940   priv = self->priv;
6941
6942   min_width = min_height = 0;
6943   natural_width = natural_height = 0;
6944
6945   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
6946     {
6947       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
6948       clutter_actor_get_preferred_width (self, -1,
6949                                          &min_width,
6950                                          &natural_width);
6951       clutter_actor_get_preferred_height (self, natural_width,
6952                                           &min_height,
6953                                           &natural_height);
6954     }
6955   else
6956     {
6957       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
6958       clutter_actor_get_preferred_height (self, -1,
6959                                           &min_height,
6960                                           &natural_height);
6961       clutter_actor_get_preferred_width (self, natural_height,
6962                                          &min_width,
6963                                          &natural_width);
6964     }
6965
6966   if (min_width_p)
6967     *min_width_p = min_width;
6968
6969   if (min_height_p)
6970     *min_height_p = min_height;
6971
6972   if (natural_width_p)
6973     *natural_width_p = natural_width;
6974
6975   if (natural_height_p)
6976     *natural_height_p = natural_height;
6977 }
6978
6979 /*< private >
6980  * effective_align:
6981  * @align: a #ClutterActorAlign
6982  * @direction: a #ClutterTextDirection
6983  *
6984  * Retrieves the correct alignment depending on the text direction
6985  *
6986  * Return value: the effective alignment
6987  */
6988 static ClutterActorAlign
6989 effective_align (ClutterActorAlign    align,
6990                  ClutterTextDirection direction)
6991 {
6992   ClutterActorAlign res;
6993
6994   switch (align)
6995     {
6996     case CLUTTER_ACTOR_ALIGN_START:
6997       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
6998           ? CLUTTER_ACTOR_ALIGN_END
6999           : CLUTTER_ACTOR_ALIGN_START;
7000       break;
7001
7002     case CLUTTER_ACTOR_ALIGN_END:
7003       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7004           ? CLUTTER_ACTOR_ALIGN_START
7005           : CLUTTER_ACTOR_ALIGN_END;
7006       break;
7007
7008     default:
7009       res = align;
7010       break;
7011     }
7012
7013   return res;
7014 }
7015
7016 static inline void
7017 adjust_for_margin (float  margin_start,
7018                    float  margin_end,
7019                    float *minimum_size,
7020                    float *natural_size,
7021                    float *allocated_start,
7022                    float *allocated_end)
7023 {
7024   *minimum_size -= (margin_start + margin_end);
7025   *natural_size -= (margin_start + margin_end);
7026   *allocated_start += margin_start;
7027   *allocated_end -= margin_end;
7028 }
7029
7030 static inline void
7031 adjust_for_alignment (ClutterActorAlign  alignment,
7032                       float              natural_size,
7033                       float             *allocated_start,
7034                       float             *allocated_end)
7035 {
7036   float allocated_size = *allocated_end - *allocated_start;
7037
7038   switch (alignment)
7039     {
7040     case CLUTTER_ACTOR_ALIGN_FILL:
7041       /* do nothing */
7042       break;
7043
7044     case CLUTTER_ACTOR_ALIGN_START:
7045       /* keep start */
7046       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7047       break;
7048
7049     case CLUTTER_ACTOR_ALIGN_END:
7050       if (allocated_size > natural_size)
7051         {
7052           *allocated_start += (allocated_size - natural_size);
7053           *allocated_end = *allocated_start + natural_size;
7054         }
7055       break;
7056
7057     case CLUTTER_ACTOR_ALIGN_CENTER:
7058       if (allocated_size > natural_size)
7059         {
7060           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7061           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7062         }
7063       break;
7064     }
7065 }
7066
7067 /*< private >
7068  * clutter_actor_adjust_width:
7069  * @self: a #ClutterActor
7070  * @minimum_width: (inout): the actor's preferred minimum width, which
7071  *   will be adjusted depending on the margin
7072  * @natural_width: (inout): the actor's preferred natural width, which
7073  *   will be adjusted depending on the margin
7074  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7075  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7076  *
7077  * Adjusts the preferred and allocated position and size of an actor,
7078  * depending on the margin and alignment properties.
7079  */
7080 static void
7081 clutter_actor_adjust_width (ClutterActor *self,
7082                             gfloat       *minimum_width,
7083                             gfloat       *natural_width,
7084                             gfloat       *adjusted_x1,
7085                             gfloat       *adjusted_x2)
7086 {
7087   ClutterTextDirection text_dir;
7088   const ClutterLayoutInfo *info;
7089
7090   info = _clutter_actor_get_layout_info_or_defaults (self);
7091   text_dir = clutter_actor_get_text_direction (self);
7092
7093   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7094
7095   /* this will tweak natural_width to remove the margin, so that
7096    * adjust_for_alignment() will use the correct size
7097    */
7098   adjust_for_margin (info->margin.left, info->margin.right,
7099                      minimum_width, natural_width,
7100                      adjusted_x1, adjusted_x2);
7101
7102   adjust_for_alignment (effective_align (info->x_align, text_dir),
7103                         *natural_width,
7104                         adjusted_x1, adjusted_x2);
7105 }
7106
7107 /*< private >
7108  * clutter_actor_adjust_height:
7109  * @self: a #ClutterActor
7110  * @minimum_height: (inout): the actor's preferred minimum height, which
7111  *   will be adjusted depending on the margin
7112  * @natural_height: (inout): the actor's preferred natural height, which
7113  *   will be adjusted depending on the margin
7114  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7115  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7116  *
7117  * Adjusts the preferred and allocated position and size of an actor,
7118  * depending on the margin and alignment properties.
7119  */
7120 static void
7121 clutter_actor_adjust_height (ClutterActor *self,
7122                              gfloat       *minimum_height,
7123                              gfloat       *natural_height,
7124                              gfloat       *adjusted_y1,
7125                              gfloat       *adjusted_y2)
7126 {
7127   const ClutterLayoutInfo *info;
7128
7129   info = _clutter_actor_get_layout_info_or_defaults (self);
7130
7131   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7132
7133   /* this will tweak natural_height to remove the margin, so that
7134    * adjust_for_alignment() will use the correct size
7135    */
7136   adjust_for_margin (info->margin.top, info->margin.bottom,
7137                      minimum_height, natural_height,
7138                      adjusted_y1,
7139                      adjusted_y2);
7140
7141   /* we don't use effective_align() here, because text direction
7142    * only affects the horizontal axis
7143    */
7144   adjust_for_alignment (info->y_align,
7145                         *natural_height,
7146                         adjusted_y1,
7147                         adjusted_y2);
7148
7149 }
7150
7151 /* looks for a cached size request for this for_size. If not
7152  * found, returns the oldest entry so it can be overwritten */
7153 static gboolean
7154 _clutter_actor_get_cached_size_request (gfloat         for_size,
7155                                         SizeRequest   *cached_size_requests,
7156                                         SizeRequest  **result)
7157 {
7158   guint i;
7159
7160   *result = &cached_size_requests[0];
7161
7162   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7163     {
7164       SizeRequest *sr;
7165
7166       sr = &cached_size_requests[i];
7167
7168       if (sr->age > 0 &&
7169           sr->for_size == for_size)
7170         {
7171           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7172           *result = sr;
7173           return TRUE;
7174         }
7175       else if (sr->age < (*result)->age)
7176         {
7177           *result = sr;
7178         }
7179     }
7180
7181   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7182
7183   return FALSE;
7184 }
7185
7186 /**
7187  * clutter_actor_get_preferred_width:
7188  * @self: A #ClutterActor
7189  * @for_height: available height when computing the preferred width,
7190  *   or a negative value to indicate that no height is defined
7191  * @min_width_p: (out) (allow-none): return location for minimum width,
7192  *   or %NULL
7193  * @natural_width_p: (out) (allow-none): return location for the natural
7194  *   width, or %NULL
7195  *
7196  * Computes the requested minimum and natural widths for an actor,
7197  * optionally depending on the specified height, or if they are
7198  * already computed, returns the cached values.
7199  *
7200  * An actor may not get its request - depending on the layout
7201  * manager that's in effect.
7202  *
7203  * A request should not incorporate the actor's scale or anchor point;
7204  * those transformations do not affect layout, only rendering.
7205  *
7206  * Since: 0.8
7207  */
7208 void
7209 clutter_actor_get_preferred_width (ClutterActor *self,
7210                                    gfloat        for_height,
7211                                    gfloat       *min_width_p,
7212                                    gfloat       *natural_width_p)
7213 {
7214   float request_min_width, request_natural_width;
7215   SizeRequest *cached_size_request;
7216   const ClutterLayoutInfo *info;
7217   ClutterActorPrivate *priv;
7218   gboolean found_in_cache;
7219
7220   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7221
7222   priv = self->priv;
7223
7224   info = _clutter_actor_get_layout_info_or_defaults (self);
7225
7226   /* we shortcircuit the case of a fixed size set using set_width() */
7227   if (priv->min_width_set && priv->natural_width_set)
7228     {
7229       if (min_width_p != NULL)
7230         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7231
7232       if (natural_width_p != NULL)
7233         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7234
7235       return;
7236     }
7237
7238   /* the remaining cases are:
7239    *
7240    *   - either min_width or natural_width have been set
7241    *   - neither min_width or natural_width have been set
7242    *
7243    * in both cases, we go through the cache (and through the actor in case
7244    * of cache misses) and determine the authoritative value depending on
7245    * the *_set flags.
7246    */
7247
7248   if (!priv->needs_width_request)
7249     {
7250       found_in_cache =
7251         _clutter_actor_get_cached_size_request (for_height,
7252                                                 priv->width_requests,
7253                                                 &cached_size_request);
7254     }
7255   else
7256     {
7257       /* if the actor needs a width request we use the first slot */
7258       found_in_cache = FALSE;
7259       cached_size_request = &priv->width_requests[0];
7260     }
7261
7262   if (!found_in_cache)
7263     {
7264       gfloat minimum_width, natural_width;
7265       ClutterActorClass *klass;
7266
7267       minimum_width = natural_width = 0;
7268
7269       /* adjust for the margin */
7270       if (for_height >= 0)
7271         {
7272           for_height -= (info->margin.top + info->margin.bottom);
7273           if (for_height < 0)
7274             for_height = 0;
7275         }
7276
7277       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7278
7279       klass = CLUTTER_ACTOR_GET_CLASS (self);
7280       klass->get_preferred_width (self, for_height,
7281                                   &minimum_width,
7282                                   &natural_width);
7283
7284       /* adjust for the margin */
7285       minimum_width += (info->margin.left + info->margin.right);
7286       natural_width += (info->margin.left + info->margin.right);
7287
7288       /* Due to accumulated float errors, it's better not to warn
7289        * on this, but just fix it.
7290        */
7291       if (natural_width < minimum_width)
7292         natural_width = minimum_width;
7293
7294       cached_size_request->min_size = minimum_width;
7295       cached_size_request->natural_size = natural_width;
7296       cached_size_request->for_size = for_height;
7297       cached_size_request->age = priv->cached_width_age;
7298
7299       priv->cached_width_age += 1;
7300       priv->needs_width_request = FALSE;
7301     }
7302
7303   if (!priv->min_width_set)
7304     request_min_width = cached_size_request->min_size;
7305   else
7306     request_min_width = info->min_width;
7307
7308   if (!priv->natural_width_set)
7309     request_natural_width = cached_size_request->natural_size;
7310   else
7311     request_natural_width = info->natural_width;
7312
7313   if (min_width_p)
7314     *min_width_p = request_min_width;
7315
7316   if (natural_width_p)
7317     *natural_width_p = request_natural_width;
7318 }
7319
7320 /**
7321  * clutter_actor_get_preferred_height:
7322  * @self: A #ClutterActor
7323  * @for_width: available width to assume in computing desired height,
7324  *   or a negative value to indicate that no width is defined
7325  * @min_height_p: (out) (allow-none): return location for minimum height,
7326  *   or %NULL
7327  * @natural_height_p: (out) (allow-none): return location for natural
7328  *   height, or %NULL
7329  *
7330  * Computes the requested minimum and natural heights for an actor,
7331  * or if they are already computed, returns the cached values.
7332  *
7333  * An actor may not get its request - depending on the layout
7334  * manager that's in effect.
7335  *
7336  * A request should not incorporate the actor's scale or anchor point;
7337  * those transformations do not affect layout, only rendering.
7338  *
7339  * Since: 0.8
7340  */
7341 void
7342 clutter_actor_get_preferred_height (ClutterActor *self,
7343                                     gfloat        for_width,
7344                                     gfloat       *min_height_p,
7345                                     gfloat       *natural_height_p)
7346 {
7347   float request_min_height, request_natural_height;
7348   SizeRequest *cached_size_request;
7349   const ClutterLayoutInfo *info;
7350   ClutterActorPrivate *priv;
7351   gboolean found_in_cache;
7352
7353   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7354
7355   priv = self->priv;
7356
7357   info = _clutter_actor_get_layout_info_or_defaults (self);
7358
7359   /* we shortcircuit the case of a fixed size set using set_height() */
7360   if (priv->min_height_set && priv->natural_height_set)
7361     {
7362       if (min_height_p != NULL)
7363         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7364
7365       if (natural_height_p != NULL)
7366         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7367
7368       return;
7369     }
7370
7371   /* the remaining cases are:
7372    *
7373    *   - either min_height or natural_height have been set
7374    *   - neither min_height or natural_height have been set
7375    *
7376    * in both cases, we go through the cache (and through the actor in case
7377    * of cache misses) and determine the authoritative value depending on
7378    * the *_set flags.
7379    */
7380
7381   if (!priv->needs_height_request)
7382     {
7383       found_in_cache =
7384         _clutter_actor_get_cached_size_request (for_width,
7385                                                 priv->height_requests,
7386                                                 &cached_size_request);
7387     }
7388   else
7389     {
7390       found_in_cache = FALSE;
7391       cached_size_request = &priv->height_requests[0];
7392     }
7393
7394   if (!found_in_cache)
7395     {
7396       gfloat minimum_height, natural_height;
7397       ClutterActorClass *klass;
7398
7399       minimum_height = natural_height = 0;
7400
7401       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7402
7403       /* adjust for margin */
7404       if (for_width >= 0)
7405         {
7406           for_width -= (info->margin.left + info->margin.right);
7407           if (for_width < 0)
7408             for_width = 0;
7409         }
7410
7411       klass = CLUTTER_ACTOR_GET_CLASS (self);
7412       klass->get_preferred_height (self, for_width,
7413                                    &minimum_height,
7414                                    &natural_height);
7415
7416       /* adjust for margin */
7417       minimum_height += (info->margin.top + info->margin.bottom);
7418       natural_height += (info->margin.top + info->margin.bottom);
7419
7420       /* Due to accumulated float errors, it's better not to warn
7421        * on this, but just fix it.
7422        */
7423       if (natural_height < minimum_height)
7424         natural_height = minimum_height;
7425
7426       cached_size_request->min_size = minimum_height;
7427       cached_size_request->natural_size = natural_height;
7428       cached_size_request->for_size = for_width;
7429       cached_size_request->age = priv->cached_height_age;
7430
7431       priv->cached_height_age += 1;
7432       priv->needs_height_request = FALSE;
7433     }
7434
7435   if (!priv->min_height_set)
7436     request_min_height = cached_size_request->min_size;
7437   else
7438     request_min_height = info->min_height;
7439
7440   if (!priv->natural_height_set)
7441     request_natural_height = cached_size_request->natural_size;
7442   else
7443     request_natural_height = info->natural_height;
7444
7445   if (min_height_p)
7446     *min_height_p = request_min_height;
7447
7448   if (natural_height_p)
7449     *natural_height_p = request_natural_height;
7450 }
7451
7452 /**
7453  * clutter_actor_get_allocation_box:
7454  * @self: A #ClutterActor
7455  * @box: (out): the function fills this in with the actor's allocation
7456  *
7457  * Gets the layout box an actor has been assigned. The allocation can
7458  * only be assumed valid inside a paint() method; anywhere else, it
7459  * may be out-of-date.
7460  *
7461  * An allocation does not incorporate the actor's scale or anchor point;
7462  * those transformations do not affect layout, only rendering.
7463  *
7464  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7465  * of functions inside the implementation of the get_preferred_width()
7466  * or get_preferred_height() virtual functions.</note>
7467  *
7468  * Since: 0.8
7469  */
7470 void
7471 clutter_actor_get_allocation_box (ClutterActor    *self,
7472                                   ClutterActorBox *box)
7473 {
7474   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7475
7476   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7477    * which limits calling get_allocation to inside paint() basically; or
7478    * we can 2) force a layout, which could be expensive if someone calls
7479    * get_allocation somewhere silly; or we can 3) just return the latest
7480    * value, allowing it to be out-of-date, and assume people know what
7481    * they are doing.
7482    *
7483    * The least-surprises approach that keeps existing code working is
7484    * likely to be 2). People can end up doing some inefficient things,
7485    * though, and in general code that requires 2) is probably broken.
7486    */
7487
7488   /* this implements 2) */
7489   if (G_UNLIKELY (self->priv->needs_allocation))
7490     {
7491       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7492
7493       /* do not queue a relayout on an unparented actor */
7494       if (stage)
7495         _clutter_stage_maybe_relayout (stage);
7496     }
7497
7498   /* commenting out the code above and just keeping this assigment
7499    * implements 3)
7500    */
7501   *box = self->priv->allocation;
7502 }
7503
7504 /**
7505  * clutter_actor_get_allocation_geometry:
7506  * @self: A #ClutterActor
7507  * @geom: (out): allocation geometry in pixels
7508  *
7509  * Gets the layout box an actor has been assigned.  The allocation can
7510  * only be assumed valid inside a paint() method; anywhere else, it
7511  * may be out-of-date.
7512  *
7513  * An allocation does not incorporate the actor's scale or anchor point;
7514  * those transformations do not affect layout, only rendering.
7515  *
7516  * The returned rectangle is in pixels.
7517  *
7518  * Since: 0.8
7519  */
7520 void
7521 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7522                                        ClutterGeometry *geom)
7523 {
7524   ClutterActorBox box;
7525
7526   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7527   g_return_if_fail (geom != NULL);
7528
7529   clutter_actor_get_allocation_box (self, &box);
7530
7531   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7532   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7533   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7534   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7535 }
7536
7537 static void
7538 clutter_actor_update_constraints (ClutterActor    *self,
7539                                   ClutterActorBox *allocation)
7540 {
7541   ClutterActorPrivate *priv = self->priv;
7542   const GList *constraints, *l;
7543
7544   if (priv->constraints == NULL)
7545     return;
7546
7547   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7548   for (l = constraints; l != NULL; l = l->next)
7549     {
7550       ClutterConstraint *constraint = l->data;
7551       ClutterActorMeta *meta = l->data;
7552
7553       if (clutter_actor_meta_get_enabled (meta))
7554         {
7555           _clutter_constraint_update_allocation (constraint,
7556                                                  self,
7557                                                  allocation);
7558         }
7559     }
7560 }
7561
7562 /*< private >
7563  * clutter_actor_adjust_allocation:
7564  * @self: a #ClutterActor
7565  * @allocation: (inout): the allocation to adjust
7566  *
7567  * Adjusts the passed allocation box taking into account the actor's
7568  * layout information, like alignment, expansion, and margin.
7569  */
7570 static void
7571 clutter_actor_adjust_allocation (ClutterActor    *self,
7572                                  ClutterActorBox *allocation)
7573 {
7574   ClutterActorBox adj_allocation;
7575   float alloc_width, alloc_height;
7576   float min_width, min_height;
7577   float nat_width, nat_height;
7578   ClutterRequestMode req_mode;
7579
7580   adj_allocation = *allocation;
7581
7582   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7583
7584   /* we want to hit the cache, so we use the public API */
7585   req_mode = clutter_actor_get_request_mode (self);
7586
7587   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7588     {
7589       clutter_actor_get_preferred_width (self, -1,
7590                                          &min_width,
7591                                          &nat_width);
7592       clutter_actor_get_preferred_height (self, alloc_width,
7593                                           &min_height,
7594                                           &nat_height);
7595     }
7596   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7597     {
7598       clutter_actor_get_preferred_height (self, -1,
7599                                           &min_height,
7600                                           &nat_height);
7601       clutter_actor_get_preferred_height (self, alloc_height,
7602                                           &min_width,
7603                                           &nat_width);
7604     }
7605
7606 #ifdef CLUTTER_ENABLE_DEBUG
7607   /* warn about underallocations */
7608   if (_clutter_diagnostic_enabled () &&
7609       (floorf (min_width - alloc_width) > 0 ||
7610        floorf (min_height - alloc_height) > 0))
7611     {
7612       ClutterActor *parent = clutter_actor_get_parent (self);
7613
7614       /* the only actors that are allowed to be underallocated are the Stage,
7615        * as it doesn't have an implicit size, and Actors that specifically
7616        * told us that they want to opt-out from layout control mechanisms
7617        * through the NO_LAYOUT escape hatch.
7618        */
7619       if (parent != NULL &&
7620           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7621         {
7622           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7623                      "of %.2f x %.2f from its parent actor '%s', but its "
7624                      "requested minimum size is of %.2f x %.2f",
7625                      _clutter_actor_get_debug_name (self),
7626                      alloc_width, alloc_height,
7627                      _clutter_actor_get_debug_name (parent),
7628                      min_width, min_height);
7629         }
7630     }
7631 #endif
7632
7633   clutter_actor_adjust_width (self,
7634                               &min_width,
7635                               &nat_width,
7636                               &adj_allocation.x1,
7637                               &adj_allocation.x2);
7638
7639   clutter_actor_adjust_height (self,
7640                                &min_height,
7641                                &nat_height,
7642                                &adj_allocation.y1,
7643                                &adj_allocation.y2);
7644
7645   /* we maintain the invariant that an allocation cannot be adjusted
7646    * to be outside the parent-given box
7647    */
7648   if (adj_allocation.x1 < allocation->x1 ||
7649       adj_allocation.y1 < allocation->y1 ||
7650       adj_allocation.x2 > allocation->x2 ||
7651       adj_allocation.y2 > allocation->y2)
7652     {
7653       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7654                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7655                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7656                  _clutter_actor_get_debug_name (self),
7657                  adj_allocation.x1, adj_allocation.y1,
7658                  adj_allocation.x2 - adj_allocation.x1,
7659                  adj_allocation.y2 - adj_allocation.y1,
7660                  allocation->x1, allocation->y1,
7661                  allocation->x2 - allocation->x1,
7662                  allocation->y2 - allocation->y1);
7663       return;
7664     }
7665
7666   *allocation = adj_allocation;
7667 }
7668
7669 /**
7670  * clutter_actor_allocate:
7671  * @self: A #ClutterActor
7672  * @box: new allocation of the actor, in parent-relative coordinates
7673  * @flags: flags that control the allocation
7674  *
7675  * Called by the parent of an actor to assign the actor its size.
7676  * Should never be called by applications (except when implementing
7677  * a container or layout manager).
7678  *
7679  * Actors can know from their allocation box whether they have moved
7680  * with respect to their parent actor. The @flags parameter describes
7681  * additional information about the allocation, for instance whether
7682  * the parent has moved with respect to the stage, for example because
7683  * a grandparent's origin has moved.
7684  *
7685  * Since: 0.8
7686  */
7687 void
7688 clutter_actor_allocate (ClutterActor           *self,
7689                         const ClutterActorBox  *box,
7690                         ClutterAllocationFlags  flags)
7691 {
7692   ClutterActorPrivate *priv;
7693   ClutterActorClass *klass;
7694   ClutterActorBox old_allocation, real_allocation;
7695   gboolean origin_changed, child_moved, size_changed;
7696   gboolean stage_allocation_changed;
7697
7698   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7699   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7700     {
7701       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7702                  "which isn't a descendent of the stage!\n",
7703                  self, _clutter_actor_get_debug_name (self));
7704       return;
7705     }
7706
7707   priv = self->priv;
7708
7709   old_allocation = priv->allocation;
7710   real_allocation = *box;
7711
7712   /* constraints are allowed to modify the allocation only here; we do
7713    * this prior to all the other checks so that we can bail out if the
7714    * allocation did not change
7715    */
7716   clutter_actor_update_constraints (self, &real_allocation);
7717
7718   /* adjust the allocation depending on the align/margin properties */
7719   clutter_actor_adjust_allocation (self, &real_allocation);
7720
7721   if (real_allocation.x2 < real_allocation.x1 ||
7722       real_allocation.y2 < real_allocation.y1)
7723     {
7724       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7725                  _clutter_actor_get_debug_name (self),
7726                  real_allocation.x2 - real_allocation.x1,
7727                  real_allocation.y2 - real_allocation.y1);
7728     }
7729
7730   /* we allow 0-sized actors, but not negative-sized ones */
7731   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7732   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7733
7734   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7735
7736   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7737                  real_allocation.y1 != old_allocation.y1);
7738
7739   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7740                   real_allocation.y2 != old_allocation.y2);
7741
7742   if (origin_changed || child_moved || size_changed)
7743     stage_allocation_changed = TRUE;
7744   else
7745     stage_allocation_changed = FALSE;
7746
7747   /* If we get an allocation "out of the blue"
7748    * (we did not queue relayout), then we want to
7749    * ignore it. But if we have needs_allocation set,
7750    * we want to guarantee that allocate() virtual
7751    * method is always called, i.e. that queue_relayout()
7752    * always results in an allocate() invocation on
7753    * an actor.
7754    *
7755    * The optimization here is to avoid re-allocating
7756    * actors that did not queue relayout and were
7757    * not moved.
7758    */
7759   if (!priv->needs_allocation && !stage_allocation_changed)
7760     {
7761       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7762       return;
7763     }
7764
7765   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7766    * clutter_actor_allocate(), it indicates whether the parent has its
7767    * absolute origin moved; when passed in to ClutterActor::allocate()
7768    * virtual method though, it indicates whether the child has its
7769    * absolute origin moved.  So we set it when child_moved is TRUE
7770    */
7771   if (child_moved)
7772     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7773
7774   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7775
7776   klass = CLUTTER_ACTOR_GET_CLASS (self);
7777   klass->allocate (self, &real_allocation, flags);
7778
7779   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7780
7781   if (stage_allocation_changed)
7782     clutter_actor_queue_redraw (self);
7783 }
7784
7785 /**
7786  * clutter_actor_set_allocation:
7787  * @self: a #ClutterActor
7788  * @box: a #ClutterActorBox
7789  * @flags: allocation flags
7790  *
7791  * Stores the allocation of @self as defined by @box.
7792  *
7793  * This function can only be called from within the implementation of
7794  * the #ClutterActorClass.allocate() virtual function.
7795  *
7796  * The allocation should have been adjusted to take into account constraints,
7797  * alignment, and margin properties. If you are implementing a #ClutterActor
7798  * subclass that provides its own layout management policy for its children
7799  * instead of using a #ClutterLayoutManager delegate, you should not call
7800  * this function on the children of @self; instead, you should call
7801  * clutter_actor_allocate(), which will adjust the allocation box for
7802  * you.
7803  *
7804  * This function should only be used by subclasses of #ClutterActor
7805  * that wish to store their allocation but cannot chain up to the
7806  * parent's implementation; the default implementation of the
7807  * #ClutterActorClass.allocate() virtual function will call this
7808  * function.
7809  *
7810  * It is important to note that, while chaining up was the recommended
7811  * behaviour for #ClutterActor subclasses prior to the introduction of
7812  * this function, it is recommended to call clutter_actor_set_allocation()
7813  * instead.
7814  *
7815  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7816  * to handle the allocation of its children, this function will call
7817  * the clutter_layout_manager_allocate() function only if the
7818  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7819  * expected that the subclass will call clutter_layout_manager_allocate()
7820  * by itself. For instance, the following code:
7821  *
7822  * |[
7823  * static void
7824  * my_actor_allocate (ClutterActor *actor,
7825  *                    const ClutterActorBox *allocation,
7826  *                    ClutterAllocationFlags flags)
7827  * {
7828  *   ClutterActorBox new_alloc;
7829  *   ClutterAllocationFlags new_flags;
7830  *
7831  *   adjust_allocation (allocation, &amp;new_alloc);
7832  *
7833  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7834  *
7835  *   /&ast; this will use the layout manager set on the actor &ast;/
7836  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7837  * }
7838  * ]|
7839  *
7840  * is equivalent to this:
7841  *
7842  * |[
7843  * static void
7844  * my_actor_allocate (ClutterActor *actor,
7845  *                    const ClutterActorBox *allocation,
7846  *                    ClutterAllocationFlags flags)
7847  * {
7848  *   ClutterLayoutManager *layout;
7849  *   ClutterActorBox new_alloc;
7850  *
7851  *   adjust_allocation (allocation, &amp;new_alloc);
7852  *
7853  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7854  *
7855  *   layout = clutter_actor_get_layout_manager (actor);
7856  *   clutter_layout_manager_allocate (layout,
7857  *                                    CLUTTER_CONTAINER (actor),
7858  *                                    &amp;new_alloc,
7859  *                                    flags);
7860  * }
7861  * ]|
7862  *
7863  * Since: 1.10
7864  */
7865 void
7866 clutter_actor_set_allocation (ClutterActor           *self,
7867                               const ClutterActorBox  *box,
7868                               ClutterAllocationFlags  flags)
7869 {
7870   ClutterActorPrivate *priv;
7871   gboolean changed;
7872
7873   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7874   g_return_if_fail (box != NULL);
7875
7876   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7877     {
7878       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7879                   "can only be called from within the implementation of "
7880                   "the ClutterActor::allocate() virtual function.");
7881       return;
7882     }
7883
7884   priv = self->priv;
7885
7886   g_object_freeze_notify (G_OBJECT (self));
7887
7888   changed = clutter_actor_set_allocation_internal (self, box, flags);
7889
7890   /* we allocate our children before we notify changes in our geometry,
7891    * so that people connecting to properties will be able to get valid
7892    * data out of the sub-tree of the scene graph that has this actor at
7893    * the root.
7894    */
7895   clutter_actor_maybe_layout_children (self, box, flags);
7896
7897   if (changed)
7898     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7899                    &priv->allocation,
7900                    priv->allocation_flags);
7901
7902   g_object_thaw_notify (G_OBJECT (self));
7903 }
7904
7905 /**
7906  * clutter_actor_set_geometry:
7907  * @self: A #ClutterActor
7908  * @geometry: A #ClutterGeometry
7909  *
7910  * Sets the actor's fixed position and forces its minimum and natural
7911  * size, in pixels. This means the untransformed actor will have the
7912  * given geometry. This is the same as calling clutter_actor_set_position()
7913  * and clutter_actor_set_size().
7914  *
7915  * Deprecated: 1.10: Use clutter_actor_set_position() and
7916  *   clutter_actor_set_size() instead.
7917  */
7918 void
7919 clutter_actor_set_geometry (ClutterActor          *self,
7920                             const ClutterGeometry *geometry)
7921 {
7922   g_object_freeze_notify (G_OBJECT (self));
7923
7924   clutter_actor_set_position (self, geometry->x, geometry->y);
7925   clutter_actor_set_size (self, geometry->width, geometry->height);
7926
7927   g_object_thaw_notify (G_OBJECT (self));
7928 }
7929
7930 /**
7931  * clutter_actor_get_geometry:
7932  * @self: A #ClutterActor
7933  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
7934  *
7935  * Gets the size and position of an actor relative to its parent
7936  * actor. This is the same as calling clutter_actor_get_position() and
7937  * clutter_actor_get_size(). It tries to "do what you mean" and get the
7938  * requested size and position if the actor's allocation is invalid.
7939  *
7940  * Deprecated: 1.10: Use clutter_actor_get_position() and
7941  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
7942  *   instead.
7943  */
7944 void
7945 clutter_actor_get_geometry (ClutterActor    *self,
7946                             ClutterGeometry *geometry)
7947 {
7948   gfloat x, y, width, height;
7949
7950   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7951   g_return_if_fail (geometry != NULL);
7952
7953   clutter_actor_get_position (self, &x, &y);
7954   clutter_actor_get_size (self, &width, &height);
7955
7956   geometry->x = (int) x;
7957   geometry->y = (int) y;
7958   geometry->width = (int) width;
7959   geometry->height = (int) height;
7960 }
7961
7962 /**
7963  * clutter_actor_set_position:
7964  * @self: A #ClutterActor
7965  * @x: New left position of actor in pixels.
7966  * @y: New top position of actor in pixels.
7967  *
7968  * Sets the actor's fixed position in pixels relative to any parent
7969  * actor.
7970  *
7971  * If a layout manager is in use, this position will override the
7972  * layout manager and force a fixed position.
7973  */
7974 void
7975 clutter_actor_set_position (ClutterActor *self,
7976                             gfloat        x,
7977                             gfloat        y)
7978 {
7979   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7980
7981   g_object_freeze_notify (G_OBJECT (self));
7982
7983   clutter_actor_set_x (self, x);
7984   clutter_actor_set_y (self, y);
7985
7986   g_object_thaw_notify (G_OBJECT (self));
7987 }
7988
7989 /**
7990  * clutter_actor_get_fixed_position_set:
7991  * @self: A #ClutterActor
7992  *
7993  * Checks whether an actor has a fixed position set (and will thus be
7994  * unaffected by any layout manager).
7995  *
7996  * Return value: %TRUE if the fixed position is set on the actor
7997  *
7998  * Since: 0.8
7999  */
8000 gboolean
8001 clutter_actor_get_fixed_position_set (ClutterActor *self)
8002 {
8003   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8004
8005   return self->priv->position_set;
8006 }
8007
8008 /**
8009  * clutter_actor_set_fixed_position_set:
8010  * @self: A #ClutterActor
8011  * @is_set: whether to use fixed position
8012  *
8013  * Sets whether an actor has a fixed position set (and will thus be
8014  * unaffected by any layout manager).
8015  *
8016  * Since: 0.8
8017  */
8018 void
8019 clutter_actor_set_fixed_position_set (ClutterActor *self,
8020                                       gboolean      is_set)
8021 {
8022   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8023
8024   if (self->priv->position_set == (is_set != FALSE))
8025     return;
8026
8027   self->priv->position_set = is_set != FALSE;
8028   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8029
8030   clutter_actor_queue_relayout (self);
8031 }
8032
8033 /**
8034  * clutter_actor_move_by:
8035  * @self: A #ClutterActor
8036  * @dx: Distance to move Actor on X axis.
8037  * @dy: Distance to move Actor on Y axis.
8038  *
8039  * Moves an actor by the specified distance relative to its current
8040  * position in pixels.
8041  *
8042  * This function modifies the fixed position of an actor and thus removes
8043  * it from any layout management. Another way to move an actor is with an
8044  * anchor point, see clutter_actor_set_anchor_point().
8045  *
8046  * Since: 0.2
8047  */
8048 void
8049 clutter_actor_move_by (ClutterActor *self,
8050                        gfloat        dx,
8051                        gfloat        dy)
8052 {
8053   const ClutterLayoutInfo *info;
8054   gfloat x, y;
8055
8056   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8057
8058   info = _clutter_actor_get_layout_info_or_defaults (self);
8059   x = info->fixed_x;
8060   y = info->fixed_y;
8061
8062   clutter_actor_set_position (self, x + dx, y + dy);
8063 }
8064
8065 static void
8066 clutter_actor_set_min_width (ClutterActor *self,
8067                              gfloat        min_width)
8068 {
8069   ClutterActorPrivate *priv = self->priv;
8070   ClutterActorBox old = { 0, };
8071   ClutterLayoutInfo *info;
8072
8073   /* if we are setting the size on a top-level actor and the
8074    * backend only supports static top-levels (e.g. framebuffers)
8075    * then we ignore the passed value and we override it with
8076    * the stage implementation's preferred size.
8077    */
8078   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8079       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8080     return;
8081
8082   info = _clutter_actor_get_layout_info (self);
8083
8084   if (priv->min_width_set && min_width == info->min_width)
8085     return;
8086
8087   g_object_freeze_notify (G_OBJECT (self));
8088
8089   clutter_actor_store_old_geometry (self, &old);
8090
8091   info->min_width = min_width;
8092   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8093   clutter_actor_set_min_width_set (self, TRUE);
8094
8095   clutter_actor_notify_if_geometry_changed (self, &old);
8096
8097   g_object_thaw_notify (G_OBJECT (self));
8098
8099   clutter_actor_queue_relayout (self);
8100 }
8101
8102 static void
8103 clutter_actor_set_min_height (ClutterActor *self,
8104                               gfloat        min_height)
8105
8106 {
8107   ClutterActorPrivate *priv = self->priv;
8108   ClutterActorBox old = { 0, };
8109   ClutterLayoutInfo *info;
8110
8111   /* if we are setting the size on a top-level actor and the
8112    * backend only supports static top-levels (e.g. framebuffers)
8113    * then we ignore the passed value and we override it with
8114    * the stage implementation's preferred size.
8115    */
8116   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8117       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8118     return;
8119
8120   info = _clutter_actor_get_layout_info (self);
8121
8122   if (priv->min_height_set && min_height == info->min_height)
8123     return;
8124
8125   g_object_freeze_notify (G_OBJECT (self));
8126
8127   clutter_actor_store_old_geometry (self, &old);
8128
8129   info->min_height = min_height;
8130   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8131   clutter_actor_set_min_height_set (self, TRUE);
8132
8133   clutter_actor_notify_if_geometry_changed (self, &old);
8134
8135   g_object_thaw_notify (G_OBJECT (self));
8136
8137   clutter_actor_queue_relayout (self);
8138 }
8139
8140 static void
8141 clutter_actor_set_natural_width (ClutterActor *self,
8142                                  gfloat        natural_width)
8143 {
8144   ClutterActorPrivate *priv = self->priv;
8145   ClutterActorBox old = { 0, };
8146   ClutterLayoutInfo *info;
8147
8148   /* if we are setting the size on a top-level actor and the
8149    * backend only supports static top-levels (e.g. framebuffers)
8150    * then we ignore the passed value and we override it with
8151    * the stage implementation's preferred size.
8152    */
8153   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8154       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8155     return;
8156
8157   info = _clutter_actor_get_layout_info (self);
8158
8159   if (priv->natural_width_set && natural_width == info->natural_width)
8160     return;
8161
8162   g_object_freeze_notify (G_OBJECT (self));
8163
8164   clutter_actor_store_old_geometry (self, &old);
8165
8166   info->natural_width = natural_width;
8167   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8168   clutter_actor_set_natural_width_set (self, TRUE);
8169
8170   clutter_actor_notify_if_geometry_changed (self, &old);
8171
8172   g_object_thaw_notify (G_OBJECT (self));
8173
8174   clutter_actor_queue_relayout (self);
8175 }
8176
8177 static void
8178 clutter_actor_set_natural_height (ClutterActor *self,
8179                                   gfloat        natural_height)
8180 {
8181   ClutterActorPrivate *priv = self->priv;
8182   ClutterActorBox old = { 0, };
8183   ClutterLayoutInfo *info;
8184
8185   /* if we are setting the size on a top-level actor and the
8186    * backend only supports static top-levels (e.g. framebuffers)
8187    * then we ignore the passed value and we override it with
8188    * the stage implementation's preferred size.
8189    */
8190   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8191       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8192     return;
8193
8194   info = _clutter_actor_get_layout_info (self);
8195
8196   if (priv->natural_height_set && natural_height == info->natural_height)
8197     return;
8198
8199   g_object_freeze_notify (G_OBJECT (self));
8200
8201   clutter_actor_store_old_geometry (self, &old);
8202
8203   info->natural_height = natural_height;
8204   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8205   clutter_actor_set_natural_height_set (self, TRUE);
8206
8207   clutter_actor_notify_if_geometry_changed (self, &old);
8208
8209   g_object_thaw_notify (G_OBJECT (self));
8210
8211   clutter_actor_queue_relayout (self);
8212 }
8213
8214 static void
8215 clutter_actor_set_min_width_set (ClutterActor *self,
8216                                  gboolean      use_min_width)
8217 {
8218   ClutterActorPrivate *priv = self->priv;
8219   ClutterActorBox old = { 0, };
8220
8221   if (priv->min_width_set == (use_min_width != FALSE))
8222     return;
8223
8224   clutter_actor_store_old_geometry (self, &old);
8225
8226   priv->min_width_set = use_min_width != FALSE;
8227   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8228
8229   clutter_actor_notify_if_geometry_changed (self, &old);
8230
8231   clutter_actor_queue_relayout (self);
8232 }
8233
8234 static void
8235 clutter_actor_set_min_height_set (ClutterActor *self,
8236                                   gboolean      use_min_height)
8237 {
8238   ClutterActorPrivate *priv = self->priv;
8239   ClutterActorBox old = { 0, };
8240
8241   if (priv->min_height_set == (use_min_height != FALSE))
8242     return;
8243
8244   clutter_actor_store_old_geometry (self, &old);
8245
8246   priv->min_height_set = use_min_height != FALSE;
8247   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8248
8249   clutter_actor_notify_if_geometry_changed (self, &old);
8250
8251   clutter_actor_queue_relayout (self);
8252 }
8253
8254 static void
8255 clutter_actor_set_natural_width_set (ClutterActor *self,
8256                                      gboolean      use_natural_width)
8257 {
8258   ClutterActorPrivate *priv = self->priv;
8259   ClutterActorBox old = { 0, };
8260
8261   if (priv->natural_width_set == (use_natural_width != FALSE))
8262     return;
8263
8264   clutter_actor_store_old_geometry (self, &old);
8265
8266   priv->natural_width_set = use_natural_width != FALSE;
8267   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8268
8269   clutter_actor_notify_if_geometry_changed (self, &old);
8270
8271   clutter_actor_queue_relayout (self);
8272 }
8273
8274 static void
8275 clutter_actor_set_natural_height_set (ClutterActor *self,
8276                                       gboolean      use_natural_height)
8277 {
8278   ClutterActorPrivate *priv = self->priv;
8279   ClutterActorBox old = { 0, };
8280
8281   if (priv->natural_height_set == (use_natural_height != FALSE))
8282     return;
8283
8284   clutter_actor_store_old_geometry (self, &old);
8285
8286   priv->natural_height_set = use_natural_height != FALSE;
8287   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8288
8289   clutter_actor_notify_if_geometry_changed (self, &old);
8290
8291   clutter_actor_queue_relayout (self);
8292 }
8293
8294 /**
8295  * clutter_actor_set_request_mode:
8296  * @self: a #ClutterActor
8297  * @mode: the request mode
8298  *
8299  * Sets the geometry request mode of @self.
8300  *
8301  * The @mode determines the order for invoking
8302  * clutter_actor_get_preferred_width() and
8303  * clutter_actor_get_preferred_height()
8304  *
8305  * Since: 1.2
8306  */
8307 void
8308 clutter_actor_set_request_mode (ClutterActor       *self,
8309                                 ClutterRequestMode  mode)
8310 {
8311   ClutterActorPrivate *priv;
8312
8313   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8314
8315   priv = self->priv;
8316
8317   if (priv->request_mode == mode)
8318     return;
8319
8320   priv->request_mode = mode;
8321
8322   priv->needs_width_request = TRUE;
8323   priv->needs_height_request = TRUE;
8324
8325   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8326
8327   clutter_actor_queue_relayout (self);
8328 }
8329
8330 /**
8331  * clutter_actor_get_request_mode:
8332  * @self: a #ClutterActor
8333  *
8334  * Retrieves the geometry request mode of @self
8335  *
8336  * Return value: the request mode for the actor
8337  *
8338  * Since: 1.2
8339  */
8340 ClutterRequestMode
8341 clutter_actor_get_request_mode (ClutterActor *self)
8342 {
8343   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8344                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8345
8346   return self->priv->request_mode;
8347 }
8348
8349 /* variant of set_width() without checks and without notification
8350  * freeze+thaw, for internal usage only
8351  */
8352 static inline void
8353 clutter_actor_set_width_internal (ClutterActor *self,
8354                                   gfloat        width)
8355 {
8356   if (width >= 0)
8357     {
8358       /* the Stage will use the :min-width to control the minimum
8359        * width to be resized to, so we should not be setting it
8360        * along with the :natural-width
8361        */
8362       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8363         clutter_actor_set_min_width (self, width);
8364
8365       clutter_actor_set_natural_width (self, width);
8366     }
8367   else
8368     {
8369       /* we only unset the :natural-width for the Stage */
8370       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8371         clutter_actor_set_min_width_set (self, FALSE);
8372
8373       clutter_actor_set_natural_width_set (self, FALSE);
8374     }
8375 }
8376
8377 /* variant of set_height() without checks and without notification
8378  * freeze+thaw, for internal usage only
8379  */
8380 static inline void
8381 clutter_actor_set_height_internal (ClutterActor *self,
8382                                    gfloat        height)
8383 {
8384   if (height >= 0)
8385     {
8386       /* see the comment above in set_width_internal() */
8387       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8388         clutter_actor_set_min_height (self, height);
8389
8390       clutter_actor_set_natural_height (self, height);
8391     }
8392   else
8393     {
8394       /* see the comment above in set_width_internal() */
8395       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8396         clutter_actor_set_min_height_set (self, FALSE);
8397
8398       clutter_actor_set_natural_height_set (self, FALSE);
8399     }
8400 }
8401
8402 /**
8403  * clutter_actor_set_size:
8404  * @self: A #ClutterActor
8405  * @width: New width of actor in pixels, or -1
8406  * @height: New height of actor in pixels, or -1
8407  *
8408  * Sets the actor's size request in pixels. This overrides any
8409  * "normal" size request the actor would have. For example
8410  * a text actor might normally request the size of the text;
8411  * this function would force a specific size instead.
8412  *
8413  * If @width and/or @height are -1 the actor will use its
8414  * "normal" size request instead of overriding it, i.e.
8415  * you can "unset" the size with -1.
8416  *
8417  * This function sets or unsets both the minimum and natural size.
8418  */
8419 void
8420 clutter_actor_set_size (ClutterActor *self,
8421                         gfloat        width,
8422                         gfloat        height)
8423 {
8424   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8425
8426   g_object_freeze_notify (G_OBJECT (self));
8427
8428   clutter_actor_set_width_internal (self, width);
8429   clutter_actor_set_height_internal (self, height);
8430
8431   g_object_thaw_notify (G_OBJECT (self));
8432 }
8433
8434 /**
8435  * clutter_actor_get_size:
8436  * @self: A #ClutterActor
8437  * @width: (out) (allow-none): return location for the width, or %NULL.
8438  * @height: (out) (allow-none): return location for the height, or %NULL.
8439  *
8440  * This function tries to "do what you mean" and return
8441  * the size an actor will have. If the actor has a valid
8442  * allocation, the allocation will be returned; otherwise,
8443  * the actors natural size request will be returned.
8444  *
8445  * If you care whether you get the request vs. the allocation, you
8446  * should probably call a different function like
8447  * clutter_actor_get_allocation_box() or
8448  * clutter_actor_get_preferred_width().
8449  *
8450  * Since: 0.2
8451  */
8452 void
8453 clutter_actor_get_size (ClutterActor *self,
8454                         gfloat       *width,
8455                         gfloat       *height)
8456 {
8457   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8458
8459   if (width)
8460     *width = clutter_actor_get_width (self);
8461
8462   if (height)
8463     *height = clutter_actor_get_height (self);
8464 }
8465
8466 /**
8467  * clutter_actor_get_position:
8468  * @self: a #ClutterActor
8469  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8470  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8471  *
8472  * This function tries to "do what you mean" and tell you where the
8473  * actor is, prior to any transformations. Retrieves the fixed
8474  * position of an actor in pixels, if one has been set; otherwise, if
8475  * the allocation is valid, returns the actor's allocated position;
8476  * otherwise, returns 0,0.
8477  *
8478  * The returned position is in pixels.
8479  *
8480  * Since: 0.6
8481  */
8482 void
8483 clutter_actor_get_position (ClutterActor *self,
8484                             gfloat       *x,
8485                             gfloat       *y)
8486 {
8487   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8488
8489   if (x)
8490     *x = clutter_actor_get_x (self);
8491
8492   if (y)
8493     *y = clutter_actor_get_y (self);
8494 }
8495
8496 /**
8497  * clutter_actor_get_transformed_position:
8498  * @self: A #ClutterActor
8499  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8500  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8501  *
8502  * Gets the absolute position of an actor, in pixels relative to the stage.
8503  *
8504  * Since: 0.8
8505  */
8506 void
8507 clutter_actor_get_transformed_position (ClutterActor *self,
8508                                         gfloat       *x,
8509                                         gfloat       *y)
8510 {
8511   ClutterVertex v1;
8512   ClutterVertex v2;
8513
8514   v1.x = v1.y = v1.z = 0;
8515   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8516
8517   if (x)
8518     *x = v2.x;
8519
8520   if (y)
8521     *y = v2.y;
8522 }
8523
8524 /**
8525  * clutter_actor_get_transformed_size:
8526  * @self: A #ClutterActor
8527  * @width: (out) (allow-none): return location for the width, or %NULL
8528  * @height: (out) (allow-none): return location for the height, or %NULL
8529  *
8530  * Gets the absolute size of an actor in pixels, taking into account the
8531  * scaling factors.
8532  *
8533  * If the actor has a valid allocation, the allocated size will be used.
8534  * If the actor has not a valid allocation then the preferred size will
8535  * be transformed and returned.
8536  *
8537  * If you want the transformed allocation, see
8538  * clutter_actor_get_abs_allocation_vertices() instead.
8539  *
8540  * <note>When the actor (or one of its ancestors) is rotated around the
8541  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8542  * as a generic quadrangle; in that case this function returns the size
8543  * of the smallest rectangle that encapsulates the entire quad. Please
8544  * note that in this case no assumptions can be made about the relative
8545  * position of this envelope to the absolute position of the actor, as
8546  * returned by clutter_actor_get_transformed_position(); if you need this
8547  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8548  * to get the coords of the actual quadrangle.</note>
8549  *
8550  * Since: 0.8
8551  */
8552 void
8553 clutter_actor_get_transformed_size (ClutterActor *self,
8554                                     gfloat       *width,
8555                                     gfloat       *height)
8556 {
8557   ClutterActorPrivate *priv;
8558   ClutterVertex v[4];
8559   gfloat x_min, x_max, y_min, y_max;
8560   gint i;
8561
8562   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8563
8564   priv = self->priv;
8565
8566   /* if the actor hasn't been allocated yet, get the preferred
8567    * size and transform that
8568    */
8569   if (priv->needs_allocation)
8570     {
8571       gfloat natural_width, natural_height;
8572       ClutterActorBox box;
8573
8574       /* Make a fake allocation to transform.
8575        *
8576        * NB: _clutter_actor_transform_and_project_box expects a box in
8577        * the actor's coordinate space... */
8578
8579       box.x1 = 0;
8580       box.y1 = 0;
8581
8582       natural_width = natural_height = 0;
8583       clutter_actor_get_preferred_size (self, NULL, NULL,
8584                                         &natural_width,
8585                                         &natural_height);
8586
8587       box.x2 = natural_width;
8588       box.y2 = natural_height;
8589
8590       _clutter_actor_transform_and_project_box (self, &box, v);
8591     }
8592   else
8593     clutter_actor_get_abs_allocation_vertices (self, v);
8594
8595   x_min = x_max = v[0].x;
8596   y_min = y_max = v[0].y;
8597
8598   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8599     {
8600       if (v[i].x < x_min)
8601         x_min = v[i].x;
8602
8603       if (v[i].x > x_max)
8604         x_max = v[i].x;
8605
8606       if (v[i].y < y_min)
8607         y_min = v[i].y;
8608
8609       if (v[i].y > y_max)
8610         y_max = v[i].y;
8611     }
8612
8613   if (width)
8614     *width  = x_max - x_min;
8615
8616   if (height)
8617     *height = y_max - y_min;
8618 }
8619
8620 /**
8621  * clutter_actor_get_width:
8622  * @self: A #ClutterActor
8623  *
8624  * Retrieves the width of a #ClutterActor.
8625  *
8626  * If the actor has a valid allocation, this function will return the
8627  * width of the allocated area given to the actor.
8628  *
8629  * If the actor does not have a valid allocation, this function will
8630  * return the actor's natural width, that is the preferred width of
8631  * the actor.
8632  *
8633  * If you care whether you get the preferred width or the width that
8634  * has been assigned to the actor, you should probably call a different
8635  * function like clutter_actor_get_allocation_box() to retrieve the
8636  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8637  * preferred width.
8638  *
8639  * If an actor has a fixed width, for instance a width that has been
8640  * assigned using clutter_actor_set_width(), the width returned will
8641  * be the same value.
8642  *
8643  * Return value: the width of the actor, in pixels
8644  */
8645 gfloat
8646 clutter_actor_get_width (ClutterActor *self)
8647 {
8648   ClutterActorPrivate *priv;
8649
8650   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8651
8652   priv = self->priv;
8653
8654   if (priv->needs_allocation)
8655     {
8656       gfloat natural_width = 0;
8657
8658       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8659         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8660       else
8661         {
8662           gfloat natural_height = 0;
8663
8664           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8665           clutter_actor_get_preferred_width (self, natural_height,
8666                                              NULL,
8667                                              &natural_width);
8668         }
8669
8670       return natural_width;
8671     }
8672   else
8673     return priv->allocation.x2 - priv->allocation.x1;
8674 }
8675
8676 /**
8677  * clutter_actor_get_height:
8678  * @self: A #ClutterActor
8679  *
8680  * Retrieves the height of a #ClutterActor.
8681  *
8682  * If the actor has a valid allocation, this function will return the
8683  * height of the allocated area given to the actor.
8684  *
8685  * If the actor does not have a valid allocation, this function will
8686  * return the actor's natural height, that is the preferred height of
8687  * the actor.
8688  *
8689  * If you care whether you get the preferred height or the height that
8690  * has been assigned to the actor, you should probably call a different
8691  * function like clutter_actor_get_allocation_box() to retrieve the
8692  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8693  * preferred height.
8694  *
8695  * If an actor has a fixed height, for instance a height that has been
8696  * assigned using clutter_actor_set_height(), the height returned will
8697  * be the same value.
8698  *
8699  * Return value: the height of the actor, in pixels
8700  */
8701 gfloat
8702 clutter_actor_get_height (ClutterActor *self)
8703 {
8704   ClutterActorPrivate *priv;
8705
8706   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8707
8708   priv = self->priv;
8709
8710   if (priv->needs_allocation)
8711     {
8712       gfloat natural_height = 0;
8713
8714       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8715         {
8716           gfloat natural_width = 0;
8717
8718           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8719           clutter_actor_get_preferred_height (self, natural_width,
8720                                               NULL, &natural_height);
8721         }
8722       else
8723         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8724
8725       return natural_height;
8726     }
8727   else
8728     return priv->allocation.y2 - priv->allocation.y1;
8729 }
8730
8731 /**
8732  * clutter_actor_set_width:
8733  * @self: A #ClutterActor
8734  * @width: Requested new width for the actor, in pixels, or -1
8735  *
8736  * Forces a width on an actor, causing the actor's preferred width
8737  * and height (if any) to be ignored.
8738  *
8739  * If @width is -1 the actor will use its preferred width request
8740  * instead of overriding it, i.e. you can "unset" the width with -1.
8741  *
8742  * This function sets both the minimum and natural size of the actor.
8743  *
8744  * since: 0.2
8745  */
8746 void
8747 clutter_actor_set_width (ClutterActor *self,
8748                          gfloat        width)
8749 {
8750   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8751
8752   g_object_freeze_notify (G_OBJECT (self));
8753
8754   clutter_actor_set_width_internal (self, width);
8755
8756   g_object_thaw_notify (G_OBJECT (self));
8757 }
8758
8759 /**
8760  * clutter_actor_set_height:
8761  * @self: A #ClutterActor
8762  * @height: Requested new height for the actor, in pixels, or -1
8763  *
8764  * Forces a height on an actor, causing the actor's preferred width
8765  * and height (if any) to be ignored.
8766  *
8767  * If @height is -1 the actor will use its preferred height instead of
8768  * overriding it, i.e. you can "unset" the height with -1.
8769  *
8770  * This function sets both the minimum and natural size of the actor.
8771  *
8772  * since: 0.2
8773  */
8774 void
8775 clutter_actor_set_height (ClutterActor *self,
8776                           gfloat        height)
8777 {
8778   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8779
8780   g_object_freeze_notify (G_OBJECT (self));
8781
8782   clutter_actor_set_height_internal (self, height);
8783
8784   g_object_thaw_notify (G_OBJECT (self));
8785 }
8786
8787 /**
8788  * clutter_actor_set_x:
8789  * @self: a #ClutterActor
8790  * @x: the actor's position on the X axis
8791  *
8792  * Sets the actor's X coordinate, relative to its parent, in pixels.
8793  *
8794  * Overrides any layout manager and forces a fixed position for
8795  * the actor.
8796  *
8797  * Since: 0.6
8798  */
8799 void
8800 clutter_actor_set_x (ClutterActor *self,
8801                      gfloat        x)
8802 {
8803   ClutterActorBox old = { 0, };
8804   ClutterActorPrivate *priv;
8805   ClutterLayoutInfo *info;
8806
8807   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8808
8809   priv = self->priv;
8810
8811   info = _clutter_actor_get_layout_info (self);
8812
8813   if (priv->position_set && info->fixed_x == x)
8814     return;
8815
8816   clutter_actor_store_old_geometry (self, &old);
8817
8818   info->fixed_x = x;
8819   clutter_actor_set_fixed_position_set (self, TRUE);
8820
8821   clutter_actor_notify_if_geometry_changed (self, &old);
8822
8823   clutter_actor_queue_relayout (self);
8824 }
8825
8826 /**
8827  * clutter_actor_set_y:
8828  * @self: a #ClutterActor
8829  * @y: the actor's position on the Y axis
8830  *
8831  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8832  *
8833  * Overrides any layout manager and forces a fixed position for
8834  * the actor.
8835  *
8836  * Since: 0.6
8837  */
8838 void
8839 clutter_actor_set_y (ClutterActor *self,
8840                      gfloat        y)
8841 {
8842   ClutterActorBox old = { 0, };
8843   ClutterActorPrivate *priv;
8844   ClutterLayoutInfo *info;
8845
8846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8847
8848   priv = self->priv;
8849
8850   info = _clutter_actor_get_layout_info (self);
8851
8852   if (priv->position_set && info->fixed_y == y)
8853     return;
8854
8855   clutter_actor_store_old_geometry (self, &old);
8856
8857   info->fixed_y = y;
8858   clutter_actor_set_fixed_position_set (self, TRUE);
8859
8860   clutter_actor_notify_if_geometry_changed (self, &old);
8861
8862   clutter_actor_queue_relayout (self);
8863 }
8864
8865 /**
8866  * clutter_actor_get_x:
8867  * @self: A #ClutterActor
8868  *
8869  * Retrieves the X coordinate of a #ClutterActor.
8870  *
8871  * This function tries to "do what you mean", by returning the
8872  * correct value depending on the actor's state.
8873  *
8874  * If the actor has a valid allocation, this function will return
8875  * the X coordinate of the origin of the allocation box.
8876  *
8877  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8878  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8879  * function will return that coordinate.
8880  *
8881  * If both the allocation and a fixed position are missing, this function
8882  * will return 0.
8883  *
8884  * Return value: the X coordinate, in pixels, ignoring any
8885  *   transformation (i.e. scaling, rotation)
8886  */
8887 gfloat
8888 clutter_actor_get_x (ClutterActor *self)
8889 {
8890   ClutterActorPrivate *priv;
8891
8892   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8893
8894   priv = self->priv;
8895
8896   if (priv->needs_allocation)
8897     {
8898       if (priv->position_set)
8899         {
8900           const ClutterLayoutInfo *info;
8901
8902           info = _clutter_actor_get_layout_info_or_defaults (self);
8903
8904           return info->fixed_x;
8905         }
8906       else
8907         return 0;
8908     }
8909   else
8910     return priv->allocation.x1;
8911 }
8912
8913 /**
8914  * clutter_actor_get_y:
8915  * @self: A #ClutterActor
8916  *
8917  * Retrieves the Y coordinate of a #ClutterActor.
8918  *
8919  * This function tries to "do what you mean", by returning the
8920  * correct value depending on the actor's state.
8921  *
8922  * If the actor has a valid allocation, this function will return
8923  * the Y coordinate of the origin of the allocation box.
8924  *
8925  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
8926  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8927  * function will return that coordinate.
8928  *
8929  * If both the allocation and a fixed position are missing, this function
8930  * will return 0.
8931  *
8932  * Return value: the Y coordinate, in pixels, ignoring any
8933  *   transformation (i.e. scaling, rotation)
8934  */
8935 gfloat
8936 clutter_actor_get_y (ClutterActor *self)
8937 {
8938   ClutterActorPrivate *priv;
8939
8940   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8941
8942   priv = self->priv;
8943
8944   if (priv->needs_allocation)
8945     {
8946       if (priv->position_set)
8947         {
8948           const ClutterLayoutInfo *info;
8949
8950           info = _clutter_actor_get_layout_info_or_defaults (self);
8951
8952           return info->fixed_y;
8953         }
8954       else
8955         return 0;
8956     }
8957   else
8958     return priv->allocation.y1;
8959 }
8960
8961 /**
8962  * clutter_actor_set_scale:
8963  * @self: A #ClutterActor
8964  * @scale_x: double factor to scale actor by horizontally.
8965  * @scale_y: double factor to scale actor by vertically.
8966  *
8967  * Scales an actor with the given factors. The scaling is relative to
8968  * the scale center and the anchor point. The scale center is
8969  * unchanged by this function and defaults to 0,0.
8970  *
8971  * Since: 0.2
8972  */
8973 void
8974 clutter_actor_set_scale (ClutterActor *self,
8975                          gdouble       scale_x,
8976                          gdouble       scale_y)
8977 {
8978   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8979
8980   g_object_freeze_notify (G_OBJECT (self));
8981
8982   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
8983   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
8984
8985   g_object_thaw_notify (G_OBJECT (self));
8986 }
8987
8988 /**
8989  * clutter_actor_set_scale_full:
8990  * @self: A #ClutterActor
8991  * @scale_x: double factor to scale actor by horizontally.
8992  * @scale_y: double factor to scale actor by vertically.
8993  * @center_x: X coordinate of the center of the scale.
8994  * @center_y: Y coordinate of the center of the scale
8995  *
8996  * Scales an actor with the given factors around the given center
8997  * point. The center point is specified in pixels relative to the
8998  * anchor point (usually the top left corner of the actor).
8999  *
9000  * Since: 1.0
9001  */
9002 void
9003 clutter_actor_set_scale_full (ClutterActor *self,
9004                               gdouble       scale_x,
9005                               gdouble       scale_y,
9006                               gfloat        center_x,
9007                               gfloat        center_y)
9008 {
9009   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9010
9011   g_object_freeze_notify (G_OBJECT (self));
9012
9013   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9014   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9015   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9016   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9017
9018   g_object_thaw_notify (G_OBJECT (self));
9019 }
9020
9021 /**
9022  * clutter_actor_set_scale_with_gravity:
9023  * @self: A #ClutterActor
9024  * @scale_x: double factor to scale actor by horizontally.
9025  * @scale_y: double factor to scale actor by vertically.
9026  * @gravity: the location of the scale center expressed as a compass
9027  * direction.
9028  *
9029  * Scales an actor with the given factors around the given
9030  * center point. The center point is specified as one of the compass
9031  * directions in #ClutterGravity. For example, setting it to north
9032  * will cause the top of the actor to remain unchanged and the rest of
9033  * the actor to expand left, right and downwards.
9034  *
9035  * Since: 1.0
9036  */
9037 void
9038 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9039                                       gdouble         scale_x,
9040                                       gdouble         scale_y,
9041                                       ClutterGravity  gravity)
9042 {
9043   ClutterTransformInfo *info;
9044   GObject *obj;
9045
9046   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9047
9048   obj = G_OBJECT (self);
9049
9050   g_object_freeze_notify (obj);
9051
9052   info = _clutter_actor_get_transform_info (self);
9053   info->scale_x = scale_x;
9054   info->scale_y = scale_y;
9055
9056   if (gravity == CLUTTER_GRAVITY_NONE)
9057     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9058   else
9059     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9060
9061   self->priv->transform_valid = FALSE;
9062
9063   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9064   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9065   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9066   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9067   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9068
9069   clutter_actor_queue_redraw (self);
9070
9071   g_object_thaw_notify (obj);
9072 }
9073
9074 /**
9075  * clutter_actor_get_scale:
9076  * @self: A #ClutterActor
9077  * @scale_x: (out) (allow-none): Location to store horizonal
9078  *   scale factor, or %NULL.
9079  * @scale_y: (out) (allow-none): Location to store vertical
9080  *   scale factor, or %NULL.
9081  *
9082  * Retrieves an actors scale factors.
9083  *
9084  * Since: 0.2
9085  */
9086 void
9087 clutter_actor_get_scale (ClutterActor *self,
9088                          gdouble      *scale_x,
9089                          gdouble      *scale_y)
9090 {
9091   const ClutterTransformInfo *info;
9092
9093   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9094
9095   info = _clutter_actor_get_transform_info_or_defaults (self);
9096
9097   if (scale_x)
9098     *scale_x = info->scale_x;
9099
9100   if (scale_y)
9101     *scale_y = info->scale_y;
9102 }
9103
9104 /**
9105  * clutter_actor_get_scale_center:
9106  * @self: A #ClutterActor
9107  * @center_x: (out) (allow-none): Location to store the X position
9108  *   of the scale center, or %NULL.
9109  * @center_y: (out) (allow-none): Location to store the Y position
9110  *   of the scale center, or %NULL.
9111  *
9112  * Retrieves the scale center coordinate in pixels relative to the top
9113  * left corner of the actor. If the scale center was specified using a
9114  * #ClutterGravity this will calculate the pixel offset using the
9115  * current size of the actor.
9116  *
9117  * Since: 1.0
9118  */
9119 void
9120 clutter_actor_get_scale_center (ClutterActor *self,
9121                                 gfloat       *center_x,
9122                                 gfloat       *center_y)
9123 {
9124   const ClutterTransformInfo *info;
9125
9126   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9127
9128   info = _clutter_actor_get_transform_info_or_defaults (self);
9129
9130   clutter_anchor_coord_get_units (self, &info->scale_center,
9131                                   center_x,
9132                                   center_y,
9133                                   NULL);
9134 }
9135
9136 /**
9137  * clutter_actor_get_scale_gravity:
9138  * @self: A #ClutterActor
9139  *
9140  * Retrieves the scale center as a compass direction. If the scale
9141  * center was specified in pixels or units this will return
9142  * %CLUTTER_GRAVITY_NONE.
9143  *
9144  * Return value: the scale gravity
9145  *
9146  * Since: 1.0
9147  */
9148 ClutterGravity
9149 clutter_actor_get_scale_gravity (ClutterActor *self)
9150 {
9151   const ClutterTransformInfo *info;
9152
9153   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9154
9155   info = _clutter_actor_get_transform_info_or_defaults (self);
9156
9157   return clutter_anchor_coord_get_gravity (&info->scale_center);
9158 }
9159
9160 /**
9161  * clutter_actor_set_opacity:
9162  * @self: A #ClutterActor
9163  * @opacity: New opacity value for the actor.
9164  *
9165  * Sets the actor's opacity, with zero being completely transparent and
9166  * 255 (0xff) being fully opaque.
9167  */
9168 void
9169 clutter_actor_set_opacity (ClutterActor *self,
9170                            guint8        opacity)
9171 {
9172   ClutterActorPrivate *priv;
9173
9174   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9175
9176   priv = self->priv;
9177
9178   if (priv->opacity != opacity)
9179     {
9180       priv->opacity = opacity;
9181
9182       /* Queue a redraw from the flatten effect so that it can use
9183          its cached image if available instead of having to redraw the
9184          actual actor. If it doesn't end up using the FBO then the
9185          effect is still able to continue the paint anyway. If there
9186          is no flatten effect yet then this is equivalent to queueing
9187          a full redraw */
9188       _clutter_actor_queue_redraw_full (self,
9189                                         0, /* flags */
9190                                         NULL, /* clip */
9191                                         priv->flatten_effect);
9192
9193       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9194     }
9195 }
9196
9197 /*
9198  * clutter_actor_get_paint_opacity_internal:
9199  * @self: a #ClutterActor
9200  *
9201  * Retrieves the absolute opacity of the actor, as it appears on the stage
9202  *
9203  * This function does not do type checks
9204  *
9205  * Return value: the absolute opacity of the actor
9206  */
9207 static guint8
9208 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9209 {
9210   ClutterActorPrivate *priv = self->priv;
9211   ClutterActor *parent;
9212
9213   /* override the top-level opacity to always be 255; even in
9214    * case of ClutterStage:use-alpha being TRUE we want the rest
9215    * of the scene to be painted
9216    */
9217   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9218     return 255;
9219
9220   if (priv->opacity_override >= 0)
9221     return priv->opacity_override;
9222
9223   parent = priv->parent;
9224
9225   /* Factor in the actual actors opacity with parents */
9226   if (parent != NULL)
9227     {
9228       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9229
9230       if (opacity != 0xff)
9231         return (opacity * priv->opacity) / 0xff;
9232     }
9233
9234   return priv->opacity;
9235
9236 }
9237
9238 /**
9239  * clutter_actor_get_paint_opacity:
9240  * @self: A #ClutterActor
9241  *
9242  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9243  *
9244  * This function traverses the hierarchy chain and composites the opacity of
9245  * the actor with that of its parents.
9246  *
9247  * This function is intended for subclasses to use in the paint virtual
9248  * function, to paint themselves with the correct opacity.
9249  *
9250  * Return value: The actor opacity value.
9251  *
9252  * Since: 0.8
9253  */
9254 guint8
9255 clutter_actor_get_paint_opacity (ClutterActor *self)
9256 {
9257   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9258
9259   return clutter_actor_get_paint_opacity_internal (self);
9260 }
9261
9262 /**
9263  * clutter_actor_get_opacity:
9264  * @self: a #ClutterActor
9265  *
9266  * Retrieves the opacity value of an actor, as set by
9267  * clutter_actor_set_opacity().
9268  *
9269  * For retrieving the absolute opacity of the actor inside a paint
9270  * virtual function, see clutter_actor_get_paint_opacity().
9271  *
9272  * Return value: the opacity of the actor
9273  */
9274 guint8
9275 clutter_actor_get_opacity (ClutterActor *self)
9276 {
9277   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9278
9279   return self->priv->opacity;
9280 }
9281
9282 /**
9283  * clutter_actor_set_offscreen_redirect:
9284  * @self: A #ClutterActor
9285  * @redirect: New offscreen redirect flags for the actor.
9286  *
9287  * Defines the circumstances where the actor should be redirected into
9288  * an offscreen image. The offscreen image is used to flatten the
9289  * actor into a single image while painting for two main reasons.
9290  * Firstly, when the actor is painted a second time without any of its
9291  * contents changing it can simply repaint the cached image without
9292  * descending further down the actor hierarchy. Secondly, it will make
9293  * the opacity look correct even if there are overlapping primitives
9294  * in the actor.
9295  *
9296  * Caching the actor could in some cases be a performance win and in
9297  * some cases be a performance lose so it is important to determine
9298  * which value is right for an actor before modifying this value. For
9299  * example, there is never any reason to flatten an actor that is just
9300  * a single texture (such as a #ClutterTexture) because it is
9301  * effectively already cached in an image so the offscreen would be
9302  * redundant. Also if the actor contains primitives that are far apart
9303  * with a large transparent area in the middle (such as a large
9304  * CluterGroup with a small actor in the top left and a small actor in
9305  * the bottom right) then the cached image will contain the entire
9306  * image of the large area and the paint will waste time blending all
9307  * of the transparent pixels in the middle.
9308  *
9309  * The default method of implementing opacity on a container simply
9310  * forwards on the opacity to all of the children. If the children are
9311  * overlapping then it will appear as if they are two separate glassy
9312  * objects and there will be a break in the color where they
9313  * overlap. By redirecting to an offscreen buffer it will be as if the
9314  * two opaque objects are combined into one and then made transparent
9315  * which is usually what is expected.
9316  *
9317  * The image below demonstrates the difference between redirecting and
9318  * not. The image shows two Clutter groups, each containing a red and
9319  * a green rectangle which overlap. The opacity on the group is set to
9320  * 128 (which is 50%). When the offscreen redirect is not used, the
9321  * red rectangle can be seen through the blue rectangle as if the two
9322  * rectangles were separately transparent. When the redirect is used
9323  * the group as a whole is transparent instead so the red rectangle is
9324  * not visible where they overlap.
9325  *
9326  * <figure id="offscreen-redirect">
9327  *   <title>Sample of using an offscreen redirect for transparency</title>
9328  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9329  * </figure>
9330  *
9331  * The default value for this property is 0, so we effectively will
9332  * never redirect an actor offscreen by default. This means that there
9333  * are times that transparent actors may look glassy as described
9334  * above. The reason this is the default is because there is a
9335  * performance trade off between quality and performance here. In many
9336  * cases the default form of glassy opacity looks good enough, but if
9337  * it's not you will need to set the
9338  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9339  * redirection for opacity.
9340  *
9341  * Custom actors that don't contain any overlapping primitives are
9342  * recommended to override the has_overlaps() virtual to return %FALSE
9343  * for maximum efficiency.
9344  *
9345  * Since: 1.8
9346  */
9347 void
9348 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9349                                       ClutterOffscreenRedirect redirect)
9350 {
9351   ClutterActorPrivate *priv;
9352
9353   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9354
9355   priv = self->priv;
9356
9357   if (priv->offscreen_redirect != redirect)
9358     {
9359       priv->offscreen_redirect = redirect;
9360
9361       /* Queue a redraw from the effect so that it can use its cached
9362          image if available instead of having to redraw the actual
9363          actor. If it doesn't end up using the FBO then the effect is
9364          still able to continue the paint anyway. If there is no
9365          effect then this is equivalent to queuing a full redraw */
9366       _clutter_actor_queue_redraw_full (self,
9367                                         0, /* flags */
9368                                         NULL, /* clip */
9369                                         priv->flatten_effect);
9370
9371       g_object_notify_by_pspec (G_OBJECT (self),
9372                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9373     }
9374 }
9375
9376 /**
9377  * clutter_actor_get_offscreen_redirect:
9378  * @self: a #ClutterActor
9379  *
9380  * Retrieves whether to redirect the actor to an offscreen buffer, as
9381  * set by clutter_actor_set_offscreen_redirect().
9382  *
9383  * Return value: the value of the offscreen-redirect property of the actor
9384  *
9385  * Since: 1.8
9386  */
9387 ClutterOffscreenRedirect
9388 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9389 {
9390   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9391
9392   return self->priv->offscreen_redirect;
9393 }
9394
9395 /**
9396  * clutter_actor_set_name:
9397  * @self: A #ClutterActor
9398  * @name: Textual tag to apply to actor
9399  *
9400  * Sets the given name to @self. The name can be used to identify
9401  * a #ClutterActor.
9402  */
9403 void
9404 clutter_actor_set_name (ClutterActor *self,
9405                         const gchar  *name)
9406 {
9407   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9408
9409   g_free (self->priv->name);
9410   self->priv->name = g_strdup (name);
9411
9412   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9413 }
9414
9415 /**
9416  * clutter_actor_get_name:
9417  * @self: A #ClutterActor
9418  *
9419  * Retrieves the name of @self.
9420  *
9421  * Return value: the name of the actor, or %NULL. The returned string is
9422  *   owned by the actor and should not be modified or freed.
9423  */
9424 const gchar *
9425 clutter_actor_get_name (ClutterActor *self)
9426 {
9427   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9428
9429   return self->priv->name;
9430 }
9431
9432 /**
9433  * clutter_actor_get_gid:
9434  * @self: A #ClutterActor
9435  *
9436  * Retrieves the unique id for @self.
9437  *
9438  * Return value: Globally unique value for this object instance.
9439  *
9440  * Since: 0.6
9441  *
9442  * Deprecated: 1.8: The id is not used any longer.
9443  */
9444 guint32
9445 clutter_actor_get_gid (ClutterActor *self)
9446 {
9447   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9448
9449   return self->priv->id;
9450 }
9451
9452 /**
9453  * clutter_actor_set_depth:
9454  * @self: a #ClutterActor
9455  * @depth: Z co-ord
9456  *
9457  * Sets the Z coordinate of @self to @depth.
9458  *
9459  * The unit used by @depth is dependant on the perspective setup. See
9460  * also clutter_stage_set_perspective().
9461  */
9462 void
9463 clutter_actor_set_depth (ClutterActor *self,
9464                          gfloat        depth)
9465 {
9466   ClutterActorPrivate *priv;
9467
9468   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9469
9470   priv = self->priv;
9471
9472   if (priv->z != depth)
9473     {
9474       /* Sets Z value - XXX 2.0: should we invert? */
9475       priv->z = depth;
9476
9477       priv->transform_valid = FALSE;
9478
9479       /* FIXME - remove this crap; sadly, there are still containers
9480        * in Clutter that depend on this utter brain damage
9481        */
9482       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9483
9484       clutter_actor_queue_redraw (self);
9485
9486       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9487     }
9488 }
9489
9490 /**
9491  * clutter_actor_get_depth:
9492  * @self: a #ClutterActor
9493  *
9494  * Retrieves the depth of @self.
9495  *
9496  * Return value: the depth of the actor
9497  */
9498 gfloat
9499 clutter_actor_get_depth (ClutterActor *self)
9500 {
9501   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9502
9503   return self->priv->z;
9504 }
9505
9506 /**
9507  * clutter_actor_set_rotation:
9508  * @self: a #ClutterActor
9509  * @axis: the axis of rotation
9510  * @angle: the angle of rotation
9511  * @x: X coordinate of the rotation center
9512  * @y: Y coordinate of the rotation center
9513  * @z: Z coordinate of the rotation center
9514  *
9515  * Sets the rotation angle of @self around the given axis.
9516  *
9517  * The rotation center coordinates used depend on the value of @axis:
9518  * <itemizedlist>
9519  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9520  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9521  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9522  * </itemizedlist>
9523  *
9524  * The rotation coordinates are relative to the anchor point of the
9525  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9526  * point is set, the upper left corner is assumed as the origin.
9527  *
9528  * Since: 0.8
9529  */
9530 void
9531 clutter_actor_set_rotation (ClutterActor      *self,
9532                             ClutterRotateAxis  axis,
9533                             gdouble            angle,
9534                             gfloat             x,
9535                             gfloat             y,
9536                             gfloat             z)
9537 {
9538   ClutterVertex v;
9539
9540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9541
9542   v.x = x;
9543   v.y = y;
9544   v.z = z;
9545
9546   g_object_freeze_notify (G_OBJECT (self));
9547
9548   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9549   clutter_actor_set_rotation_center_internal (self, axis, &v);
9550
9551   g_object_thaw_notify (G_OBJECT (self));
9552 }
9553
9554 /**
9555  * clutter_actor_set_z_rotation_from_gravity:
9556  * @self: a #ClutterActor
9557  * @angle: the angle of rotation
9558  * @gravity: the center point of the rotation
9559  *
9560  * Sets the rotation angle of @self around the Z axis using the center
9561  * point specified as a compass point. For example to rotate such that
9562  * the center of the actor remains static you can use
9563  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9564  * will move accordingly.
9565  *
9566  * Since: 1.0
9567  */
9568 void
9569 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9570                                            gdouble         angle,
9571                                            ClutterGravity  gravity)
9572 {
9573   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9574
9575   if (gravity == CLUTTER_GRAVITY_NONE)
9576     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9577   else
9578     {
9579       GObject *obj = G_OBJECT (self);
9580       ClutterTransformInfo *info;
9581
9582       info = _clutter_actor_get_transform_info (self);
9583
9584       g_object_freeze_notify (obj);
9585
9586       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9587
9588       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9589       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9590       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9591
9592       g_object_thaw_notify (obj);
9593     }
9594 }
9595
9596 /**
9597  * clutter_actor_get_rotation:
9598  * @self: a #ClutterActor
9599  * @axis: the axis of rotation
9600  * @x: (out): return value for the X coordinate of the center of rotation
9601  * @y: (out): return value for the Y coordinate of the center of rotation
9602  * @z: (out): return value for the Z coordinate of the center of rotation
9603  *
9604  * Retrieves the angle and center of rotation on the given axis,
9605  * set using clutter_actor_set_rotation().
9606  *
9607  * Return value: the angle of rotation
9608  *
9609  * Since: 0.8
9610  */
9611 gdouble
9612 clutter_actor_get_rotation (ClutterActor      *self,
9613                             ClutterRotateAxis  axis,
9614                             gfloat            *x,
9615                             gfloat            *y,
9616                             gfloat            *z)
9617 {
9618   const ClutterTransformInfo *info;
9619   const AnchorCoord *anchor_coord;
9620   gdouble retval = 0;
9621
9622   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9623
9624   info = _clutter_actor_get_transform_info_or_defaults (self);
9625
9626   switch (axis)
9627     {
9628     case CLUTTER_X_AXIS:
9629       anchor_coord = &info->rx_center;
9630       retval = info->rx_angle;
9631       break;
9632
9633     case CLUTTER_Y_AXIS:
9634       anchor_coord = &info->ry_center;
9635       retval = info->ry_angle;
9636       break;
9637
9638     case CLUTTER_Z_AXIS:
9639       anchor_coord = &info->rz_center;
9640       retval = info->rz_angle;
9641       break;
9642
9643     default:
9644       anchor_coord = NULL;
9645       retval = 0.0;
9646       break;
9647     }
9648
9649   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9650
9651   return retval;
9652 }
9653
9654 /**
9655  * clutter_actor_get_z_rotation_gravity:
9656  * @self: A #ClutterActor
9657  *
9658  * Retrieves the center for the rotation around the Z axis as a
9659  * compass direction. If the center was specified in pixels or units
9660  * this will return %CLUTTER_GRAVITY_NONE.
9661  *
9662  * Return value: the Z rotation center
9663  *
9664  * Since: 1.0
9665  */
9666 ClutterGravity
9667 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9668 {
9669   const ClutterTransformInfo *info;
9670
9671   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9672
9673   info = _clutter_actor_get_transform_info_or_defaults (self);
9674
9675   return clutter_anchor_coord_get_gravity (&info->rz_center);
9676 }
9677
9678 /**
9679  * clutter_actor_set_clip:
9680  * @self: A #ClutterActor
9681  * @xoff: X offset of the clip rectangle
9682  * @yoff: Y offset of the clip rectangle
9683  * @width: Width of the clip rectangle
9684  * @height: Height of the clip rectangle
9685  *
9686  * Sets clip area for @self. The clip area is always computed from the
9687  * upper left corner of the actor, even if the anchor point is set
9688  * otherwise.
9689  *
9690  * Since: 0.6
9691  */
9692 void
9693 clutter_actor_set_clip (ClutterActor *self,
9694                         gfloat        xoff,
9695                         gfloat        yoff,
9696                         gfloat        width,
9697                         gfloat        height)
9698 {
9699   ClutterActorPrivate *priv;
9700
9701   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9702
9703   priv = self->priv;
9704
9705   if (priv->has_clip &&
9706       priv->clip.x == xoff &&
9707       priv->clip.y == yoff &&
9708       priv->clip.width == width &&
9709       priv->clip.height == height)
9710     return;
9711
9712   priv->clip.x = xoff;
9713   priv->clip.y = yoff;
9714   priv->clip.width = width;
9715   priv->clip.height = height;
9716
9717   priv->has_clip = TRUE;
9718
9719   clutter_actor_queue_redraw (self);
9720
9721   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9722   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9723 }
9724
9725 /**
9726  * clutter_actor_remove_clip:
9727  * @self: A #ClutterActor
9728  *
9729  * Removes clip area from @self.
9730  */
9731 void
9732 clutter_actor_remove_clip (ClutterActor *self)
9733 {
9734   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9735
9736   if (!self->priv->has_clip)
9737     return;
9738
9739   self->priv->has_clip = FALSE;
9740
9741   clutter_actor_queue_redraw (self);
9742
9743   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9744 }
9745
9746 /**
9747  * clutter_actor_has_clip:
9748  * @self: a #ClutterActor
9749  *
9750  * Determines whether the actor has a clip area set or not.
9751  *
9752  * Return value: %TRUE if the actor has a clip area set.
9753  *
9754  * Since: 0.1.1
9755  */
9756 gboolean
9757 clutter_actor_has_clip (ClutterActor *self)
9758 {
9759   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9760
9761   return self->priv->has_clip;
9762 }
9763
9764 /**
9765  * clutter_actor_get_clip:
9766  * @self: a #ClutterActor
9767  * @xoff: (out) (allow-none): return location for the X offset of
9768  *   the clip rectangle, or %NULL
9769  * @yoff: (out) (allow-none): return location for the Y offset of
9770  *   the clip rectangle, or %NULL
9771  * @width: (out) (allow-none): return location for the width of
9772  *   the clip rectangle, or %NULL
9773  * @height: (out) (allow-none): return location for the height of
9774  *   the clip rectangle, or %NULL
9775  *
9776  * Gets the clip area for @self, if any is set
9777  *
9778  * Since: 0.6
9779  */
9780 void
9781 clutter_actor_get_clip (ClutterActor *self,
9782                         gfloat       *xoff,
9783                         gfloat       *yoff,
9784                         gfloat       *width,
9785                         gfloat       *height)
9786 {
9787   ClutterActorPrivate *priv;
9788
9789   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9790
9791   priv = self->priv;
9792
9793   if (!priv->has_clip)
9794     return;
9795
9796   if (xoff != NULL)
9797     *xoff = priv->clip.x;
9798
9799   if (yoff != NULL)
9800     *yoff = priv->clip.y;
9801
9802   if (width != NULL)
9803     *width = priv->clip.width;
9804
9805   if (height != NULL)
9806     *height = priv->clip.height;
9807 }
9808
9809 /**
9810  * clutter_actor_get_children:
9811  * @self: a #ClutterActor
9812  *
9813  * Retrieves the list of children of @self.
9814  *
9815  * Return value: (transfer container) (element-type ClutterActor): A newly
9816  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9817  *   done.
9818  *
9819  * Since: 1.10
9820  */
9821 GList *
9822 clutter_actor_get_children (ClutterActor *self)
9823 {
9824   ClutterActor *iter;
9825   GList *res;
9826
9827   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9828
9829   /* we walk the list backward so that we can use prepend(),
9830    * which is O(1)
9831    */
9832   for (iter = self->priv->last_child, res = NULL;
9833        iter != NULL;
9834        iter = iter->priv->prev_sibling)
9835     {
9836       res = g_list_prepend (res, iter);
9837     }
9838
9839   return res;
9840 }
9841
9842 /*< private >
9843  * insert_child_at_depth:
9844  * @self: a #ClutterActor
9845  * @child: a #ClutterActor
9846  *
9847  * Inserts @child inside the list of children held by @self, using
9848  * the depth as the insertion criteria.
9849  *
9850  * This sadly makes the insertion not O(1), but we can keep the
9851  * list sorted so that the painters algorithm we use for painting
9852  * the children will work correctly.
9853  */
9854 static void
9855 insert_child_at_depth (ClutterActor *self,
9856                        ClutterActor *child,
9857                        gpointer      dummy G_GNUC_UNUSED)
9858 {
9859   ClutterActor *iter;
9860
9861   child->priv->parent = self;
9862
9863   /* special-case the first child */
9864   if (self->priv->n_children == 0)
9865     {
9866       self->priv->first_child = child;
9867       self->priv->last_child = child;
9868
9869       child->priv->next_sibling = NULL;
9870       child->priv->prev_sibling = NULL;
9871
9872       return;
9873     }
9874
9875   /* Find the right place to insert the child so that it will still be
9876      sorted and the child will be after all of the actors at the same
9877      dept */
9878   for (iter = self->priv->first_child;
9879        iter != NULL;
9880        iter = iter->priv->next_sibling)
9881     {
9882       if (iter->priv->z > child->priv->z)
9883         break;
9884     }
9885
9886   if (iter != NULL)
9887     {
9888       ClutterActor *tmp = iter->priv->prev_sibling;
9889
9890       if (tmp != NULL)
9891         tmp->priv->next_sibling = child;
9892
9893       /* Insert the node before the found one */
9894       child->priv->prev_sibling = iter->priv->prev_sibling;
9895       child->priv->next_sibling = iter;
9896       iter->priv->prev_sibling = child;
9897     }
9898   else
9899     {
9900       ClutterActor *tmp = self->priv->last_child;
9901
9902       if (tmp != NULL)
9903         tmp->priv->next_sibling = child;
9904
9905       /* insert the node at the end of the list */
9906       child->priv->prev_sibling = self->priv->last_child;
9907       child->priv->next_sibling = NULL;
9908     }
9909
9910   if (child->priv->prev_sibling == NULL)
9911     self->priv->first_child = child;
9912
9913   if (child->priv->next_sibling == NULL)
9914     self->priv->last_child = child;
9915 }
9916
9917 static void
9918 insert_child_at_index (ClutterActor *self,
9919                        ClutterActor *child,
9920                        gpointer      data_)
9921 {
9922   gint index_ = GPOINTER_TO_INT (data_);
9923
9924   child->priv->parent = self;
9925
9926   if (index_ == 0)
9927     {
9928       ClutterActor *tmp = self->priv->first_child;
9929
9930       if (tmp != NULL)
9931         tmp->priv->prev_sibling = child;
9932
9933       child->priv->prev_sibling = NULL;
9934       child->priv->next_sibling = tmp;
9935     }
9936   else if (index_ < 0 || index_ >= self->priv->n_children)
9937     {
9938       ClutterActor *tmp = self->priv->last_child;
9939
9940       if (tmp != NULL)
9941         tmp->priv->next_sibling = child;
9942
9943       child->priv->prev_sibling = tmp;
9944       child->priv->next_sibling = NULL;
9945     }
9946   else
9947     {
9948       ClutterActor *iter;
9949       int i;
9950
9951       for (iter = self->priv->first_child, i = 0;
9952            iter != NULL;
9953            iter = iter->priv->next_sibling, i += 1)
9954         {
9955           if (index_ == i)
9956             {
9957               ClutterActor *tmp = iter->priv->prev_sibling;
9958
9959               child->priv->prev_sibling = tmp;
9960               child->priv->next_sibling = iter;
9961
9962               iter->priv->prev_sibling = child;
9963
9964               if (tmp != NULL)
9965                 tmp->priv->next_sibling = child;
9966
9967               break;
9968             }
9969         }
9970     }
9971
9972   if (child->priv->prev_sibling == NULL)
9973     self->priv->first_child = child;
9974
9975   if (child->priv->next_sibling == NULL)
9976     self->priv->last_child = child;
9977 }
9978
9979 static void
9980 insert_child_above (ClutterActor *self,
9981                     ClutterActor *child,
9982                     gpointer      data)
9983 {
9984   ClutterActor *sibling = data;
9985
9986   child->priv->parent = self;
9987
9988   if (sibling == NULL)
9989     sibling = self->priv->last_child;
9990
9991   child->priv->prev_sibling = sibling;
9992
9993   if (sibling != NULL)
9994     {
9995       ClutterActor *tmp = sibling->priv->next_sibling;
9996
9997       child->priv->next_sibling = tmp;
9998
9999       if (tmp != NULL)
10000         tmp->priv->prev_sibling = child;
10001
10002       sibling->priv->next_sibling = child;
10003     }
10004   else
10005     child->priv->next_sibling = NULL;
10006
10007   if (child->priv->prev_sibling == NULL)
10008     self->priv->first_child = child;
10009
10010   if (child->priv->next_sibling == NULL)
10011     self->priv->last_child = child;
10012 }
10013
10014 static void
10015 insert_child_below (ClutterActor *self,
10016                     ClutterActor *child,
10017                     gpointer      data)
10018 {
10019   ClutterActor *sibling = data;
10020
10021   child->priv->parent = self;
10022
10023   if (sibling == NULL)
10024     sibling = self->priv->first_child;
10025
10026   child->priv->next_sibling = sibling;
10027
10028   if (sibling != NULL)
10029     {
10030       ClutterActor *tmp = sibling->priv->prev_sibling;
10031
10032       child->priv->prev_sibling = tmp;
10033
10034       if (tmp != NULL)
10035         tmp->priv->next_sibling = child;
10036
10037       sibling->priv->prev_sibling = child;
10038     }
10039   else
10040     child->priv->prev_sibling = NULL;
10041
10042   if (child->priv->prev_sibling == NULL)
10043     self->priv->first_child = child;
10044
10045   if (child->priv->next_sibling == NULL)
10046     self->priv->last_child = child;
10047 }
10048
10049 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10050                                            ClutterActor *child,
10051                                            gpointer      data);
10052
10053 typedef enum {
10054   ADD_CHILD_CREATE_META       = 1 << 0,
10055   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10056   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10057   ADD_CHILD_CHECK_STATE       = 1 << 3,
10058   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10059
10060   /* default flags for public API */
10061   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10062                                ADD_CHILD_EMIT_PARENT_SET |
10063                                ADD_CHILD_EMIT_ACTOR_ADDED |
10064                                ADD_CHILD_CHECK_STATE |
10065                                ADD_CHILD_NOTIFY_FIRST_LAST,
10066
10067   /* flags for legacy/deprecated API */
10068   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10069                                ADD_CHILD_CHECK_STATE |
10070                                ADD_CHILD_NOTIFY_FIRST_LAST
10071 } ClutterActorAddChildFlags;
10072
10073 /*< private >
10074  * clutter_actor_add_child_internal:
10075  * @self: a #ClutterActor
10076  * @child: a #ClutterActor
10077  * @flags: control flags for actions
10078  * @add_func: delegate function
10079  * @data: (closure): data to pass to @add_func
10080  *
10081  * Adds @child to the list of children of @self.
10082  *
10083  * The actual insertion inside the list is delegated to @add_func: this
10084  * function will just set up the state, perform basic checks, and emit
10085  * signals.
10086  *
10087  * The @flags argument is used to perform additional operations.
10088  */
10089 static inline void
10090 clutter_actor_add_child_internal (ClutterActor              *self,
10091                                   ClutterActor              *child,
10092                                   ClutterActorAddChildFlags  flags,
10093                                   ClutterActorAddChildFunc   add_func,
10094                                   gpointer                   data)
10095 {
10096   ClutterTextDirection text_dir;
10097   gboolean create_meta;
10098   gboolean emit_parent_set, emit_actor_added;
10099   gboolean check_state;
10100   gboolean notify_first_last;
10101   ClutterActor *old_first_child, *old_last_child;
10102
10103   if (child->priv->parent != NULL)
10104     {
10105       g_warning ("Cannot set a parent on an actor which has a parent. "
10106                  "You must use clutter_actor_remove_child() first.");
10107       return;
10108     }
10109
10110   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10111     {
10112       g_warning ("Cannot set a parent on a toplevel actor\n");
10113       return;
10114     }
10115
10116   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10117     {
10118       g_warning ("Cannot set a parent currently being destroyed");
10119       return;
10120     }
10121
10122   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10123   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10124   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10125   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10126   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10127
10128   old_first_child = self->priv->first_child;
10129   old_last_child = self->priv->last_child;
10130
10131   g_object_freeze_notify (G_OBJECT (self));
10132
10133   if (create_meta)
10134     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10135
10136   g_object_ref_sink (child);
10137   child->priv->parent = NULL;
10138   child->priv->next_sibling = NULL;
10139   child->priv->prev_sibling = NULL;
10140
10141   /* delegate the actual insertion */
10142   add_func (self, child, data);
10143
10144   g_assert (child->priv->parent == self);
10145
10146   self->priv->n_children += 1;
10147
10148   self->priv->age += 1;
10149
10150   /* if push_internal() has been called then we automatically set
10151    * the flag on the actor
10152    */
10153   if (self->priv->internal_child)
10154     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10155
10156   /* clutter_actor_reparent() will emit ::parent-set for us */
10157   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10158     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10159
10160   if (check_state)
10161     {
10162       /* If parent is mapped or realized, we need to also be mapped or
10163        * realized once we're inside the parent.
10164        */
10165       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10166
10167       /* propagate the parent's text direction to the child */
10168       text_dir = clutter_actor_get_text_direction (self);
10169       clutter_actor_set_text_direction (child, text_dir);
10170     }
10171
10172   if (child->priv->show_on_set_parent)
10173     clutter_actor_show (child);
10174
10175   if (CLUTTER_ACTOR_IS_MAPPED (child))
10176     clutter_actor_queue_redraw (child);
10177
10178   /* maintain the invariant that if an actor needs layout,
10179    * its parents do as well
10180    */
10181   if (child->priv->needs_width_request ||
10182       child->priv->needs_height_request ||
10183       child->priv->needs_allocation)
10184     {
10185       /* we work around the short-circuiting we do
10186        * in clutter_actor_queue_relayout() since we
10187        * want to force a relayout
10188        */
10189       child->priv->needs_width_request = TRUE;
10190       child->priv->needs_height_request = TRUE;
10191       child->priv->needs_allocation = TRUE;
10192
10193       clutter_actor_queue_relayout (child->priv->parent);
10194     }
10195
10196   if (emit_actor_added)
10197     g_signal_emit_by_name (self, "actor-added", child);
10198
10199   if (notify_first_last)
10200     {
10201       if (old_first_child != self->priv->first_child)
10202         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10203
10204       if (old_last_child != self->priv->last_child)
10205         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10206     }
10207
10208   g_object_thaw_notify (G_OBJECT (self));
10209 }
10210
10211 /**
10212  * clutter_actor_add_child:
10213  * @self: a #ClutterActor
10214  * @child: a #ClutterActor
10215  *
10216  * Adds @child to the children of @self.
10217  *
10218  * This function will acquire a reference on @child that will only
10219  * be released when calling clutter_actor_remove_child().
10220  *
10221  * This function will take into consideration the #ClutterActor:depth
10222  * of @child, and will keep the list of children sorted.
10223  *
10224  * This function will emit the #ClutterContainer::actor-added signal
10225  * on @self.
10226  *
10227  * Since: 1.10
10228  */
10229 void
10230 clutter_actor_add_child (ClutterActor *self,
10231                          ClutterActor *child)
10232 {
10233   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10234   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10235   g_return_if_fail (self != child);
10236   g_return_if_fail (child->priv->parent == NULL);
10237
10238   clutter_actor_add_child_internal (self, child,
10239                                     ADD_CHILD_DEFAULT_FLAGS,
10240                                     insert_child_at_depth,
10241                                     NULL);
10242 }
10243
10244 /**
10245  * clutter_actor_insert_child_at_index:
10246  * @self: a #ClutterActor
10247  * @child: a #ClutterActor
10248  * @index_: the index
10249  *
10250  * Inserts @child into the list of children of @self, using the
10251  * given @index_. If @index_ is greater than the number of children
10252  * in @self, or is less than 0, then the new child is added at the end.
10253  *
10254  * This function will acquire a reference on @child that will only
10255  * be released when calling clutter_actor_remove_child().
10256  *
10257  * This function will not take into consideration the #ClutterActor:depth
10258  * of @child.
10259  *
10260  * This function will emit the #ClutterContainer::actor-added signal
10261  * on @self.
10262  *
10263  * Since: 1.10
10264  */
10265 void
10266 clutter_actor_insert_child_at_index (ClutterActor *self,
10267                                      ClutterActor *child,
10268                                      gint          index_)
10269 {
10270   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10271   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10272   g_return_if_fail (self != child);
10273   g_return_if_fail (child->priv->parent == NULL);
10274
10275   clutter_actor_add_child_internal (self, child,
10276                                     ADD_CHILD_DEFAULT_FLAGS,
10277                                     insert_child_at_index,
10278                                     GINT_TO_POINTER (index_));
10279 }
10280
10281 /**
10282  * clutter_actor_insert_child_above:
10283  * @self: a #ClutterActor
10284  * @child: a #ClutterActor
10285  * @sibling: (allow-none): a child of @self, or %NULL
10286  *
10287  * Inserts @child into the list of children of @self, above another
10288  * child of @self or, if @sibling is %NULL, above all the children
10289  * of @self.
10290  *
10291  * This function will acquire a reference on @child that will only
10292  * be released when calling clutter_actor_remove_child().
10293  *
10294  * This function will not take into consideration the #ClutterActor:depth
10295  * of @child.
10296  *
10297  * This function will emit the #ClutterContainer::actor-added signal
10298  * on @self.
10299  *
10300  * Since: 1.10
10301  */
10302 void
10303 clutter_actor_insert_child_above (ClutterActor *self,
10304                                   ClutterActor *child,
10305                                   ClutterActor *sibling)
10306 {
10307   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10308   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10309   g_return_if_fail (self != child);
10310   g_return_if_fail (child != sibling);
10311   g_return_if_fail (child->priv->parent == NULL);
10312   g_return_if_fail (sibling == NULL ||
10313                     (CLUTTER_IS_ACTOR (sibling) &&
10314                      sibling->priv->parent == self));
10315
10316   clutter_actor_add_child_internal (self, child,
10317                                     ADD_CHILD_DEFAULT_FLAGS,
10318                                     insert_child_above,
10319                                     sibling);
10320 }
10321
10322 /**
10323  * clutter_actor_insert_child_below:
10324  * @self: a #ClutterActor
10325  * @child: a #ClutterActor
10326  * @sibling: (allow-none): a child of @self, or %NULL
10327  *
10328  * Inserts @child into the list of children of @self, below another
10329  * child of @self or, if @sibling is %NULL, below all the children
10330  * of @self.
10331  *
10332  * This function will acquire a reference on @child that will only
10333  * be released when calling clutter_actor_remove_child().
10334  *
10335  * This function will not take into consideration the #ClutterActor:depth
10336  * of @child.
10337  *
10338  * This function will emit the #ClutterContainer::actor-added signal
10339  * on @self.
10340  *
10341  * Since: 1.10
10342  */
10343 void
10344 clutter_actor_insert_child_below (ClutterActor *self,
10345                                   ClutterActor *child,
10346                                   ClutterActor *sibling)
10347 {
10348   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10349   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10350   g_return_if_fail (self != child);
10351   g_return_if_fail (child != sibling);
10352   g_return_if_fail (child->priv->parent == NULL);
10353   g_return_if_fail (sibling == NULL ||
10354                     (CLUTTER_IS_ACTOR (sibling) &&
10355                      sibling->priv->parent == self));
10356
10357   clutter_actor_add_child_internal (self, child,
10358                                     ADD_CHILD_DEFAULT_FLAGS,
10359                                     insert_child_below,
10360                                     sibling);
10361 }
10362
10363 /**
10364  * clutter_actor_set_parent:
10365  * @self: A #ClutterActor
10366  * @parent: A new #ClutterActor parent
10367  *
10368  * Sets the parent of @self to @parent.
10369  *
10370  * This function will result in @parent acquiring a reference on @self,
10371  * eventually by sinking its floating reference first. The reference
10372  * will be released by clutter_actor_unparent().
10373  *
10374  * This function should only be called by legacy #ClutterActor<!-- -->s
10375  * implementing the #ClutterContainer interface.
10376  *
10377  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10378  */
10379 void
10380 clutter_actor_set_parent (ClutterActor *self,
10381                           ClutterActor *parent)
10382 {
10383   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10384   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10385   g_return_if_fail (self != parent);
10386   g_return_if_fail (self->priv->parent == NULL);
10387
10388   /* as this function will be called inside ClutterContainer::add
10389    * implementations or when building up a composite actor, we have
10390    * to preserve the old behaviour, and not create child meta or
10391    * emit the ::actor-added signal, to avoid recursion or double
10392    * emissions
10393    */
10394   clutter_actor_add_child_internal (parent, self,
10395                                     ADD_CHILD_LEGACY_FLAGS,
10396                                     insert_child_at_depth,
10397                                     NULL);
10398 }
10399
10400 /**
10401  * clutter_actor_get_parent:
10402  * @self: A #ClutterActor
10403  *
10404  * Retrieves the parent of @self.
10405  *
10406  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10407  *  if no parent is set
10408  */
10409 ClutterActor *
10410 clutter_actor_get_parent (ClutterActor *self)
10411 {
10412   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10413
10414   return self->priv->parent;
10415 }
10416
10417 /**
10418  * clutter_actor_get_paint_visibility:
10419  * @self: A #ClutterActor
10420  *
10421  * Retrieves the 'paint' visibility of an actor recursively checking for non
10422  * visible parents.
10423  *
10424  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10425  *
10426  * Return Value: %TRUE if the actor is visibile and will be painted.
10427  *
10428  * Since: 0.8.4
10429  */
10430 gboolean
10431 clutter_actor_get_paint_visibility (ClutterActor *actor)
10432 {
10433   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10434
10435   return CLUTTER_ACTOR_IS_MAPPED (actor);
10436 }
10437
10438 /**
10439  * clutter_actor_remove_child:
10440  * @self: a #ClutterActor
10441  * @child: a #ClutterActor
10442  *
10443  * Removes @child from the children of @self.
10444  *
10445  * This function will release the reference added by
10446  * clutter_actor_add_child(), so if you want to keep using @child
10447  * you will have to acquire a referenced on it before calling this
10448  * function.
10449  *
10450  * This function will emit the #ClutterContainer::actor-removed
10451  * signal on @self.
10452  *
10453  * Since: 1.10
10454  */
10455 void
10456 clutter_actor_remove_child (ClutterActor *self,
10457                             ClutterActor *child)
10458 {
10459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10460   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10461   g_return_if_fail (self != child);
10462   g_return_if_fail (child->priv->parent != NULL);
10463   g_return_if_fail (child->priv->parent == self);
10464
10465   clutter_actor_remove_child_internal (self, child,
10466                                        REMOVE_CHILD_DEFAULT_FLAGS);
10467 }
10468
10469 /**
10470  * clutter_actor_remove_all_children:
10471  * @self: a #ClutterActor
10472  *
10473  * Removes all children of @self.
10474  *
10475  * This function releases the reference added by inserting a child actor
10476  * in the list of children of @self.
10477  *
10478  * If the reference count of a child drops to zero, the child will be
10479  * destroyed. If you want to ensure the destruction of all the children
10480  * of @self, use clutter_actor_destroy_all_children().
10481  *
10482  * Since: 1.10
10483  */
10484 void
10485 clutter_actor_remove_all_children (ClutterActor *self)
10486 {
10487   ClutterActorIter iter;
10488
10489   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10490
10491   if (self->priv->n_children == 0)
10492     return;
10493
10494   g_object_freeze_notify (G_OBJECT (self));
10495
10496   clutter_actor_iter_init (&iter, self);
10497   while (clutter_actor_iter_next (&iter, NULL))
10498     clutter_actor_iter_remove (&iter);
10499
10500   g_object_thaw_notify (G_OBJECT (self));
10501
10502   /* sanity check */
10503   g_assert (self->priv->first_child == NULL);
10504   g_assert (self->priv->last_child == NULL);
10505   g_assert (self->priv->n_children == 0);
10506 }
10507
10508 /**
10509  * clutter_actor_destroy_all_children:
10510  * @self: a #ClutterActor
10511  *
10512  * Destroys all children of @self.
10513  *
10514  * This function releases the reference added by inserting a child
10515  * actor in the list of children of @self, and ensures that the
10516  * #ClutterActor::destroy signal is emitted on each child of the
10517  * actor.
10518  *
10519  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10520  * when its reference count drops to 0; the default handler of the
10521  * #ClutterActor::destroy signal will destroy all the children of an
10522  * actor. This function ensures that all children are destroyed, instead
10523  * of just removed from @self, unlike clutter_actor_remove_all_children()
10524  * which will merely release the reference and remove each child.
10525  *
10526  * Unless you acquired an additional reference on each child of @self
10527  * prior to calling clutter_actor_remove_all_children() and want to reuse
10528  * the actors, you should use clutter_actor_destroy_all_children() in
10529  * order to make sure that children are destroyed and signal handlers
10530  * are disconnected even in cases where circular references prevent this
10531  * from automatically happening through reference counting alone.
10532  *
10533  * Since: 1.10
10534  */
10535 void
10536 clutter_actor_destroy_all_children (ClutterActor *self)
10537 {
10538   ClutterActorIter iter;
10539
10540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10541
10542   if (self->priv->n_children == 0)
10543     return;
10544
10545   g_object_freeze_notify (G_OBJECT (self));
10546
10547   clutter_actor_iter_init (&iter, self);
10548   while (clutter_actor_iter_next (&iter, NULL))
10549     clutter_actor_iter_destroy (&iter);
10550
10551   g_object_thaw_notify (G_OBJECT (self));
10552
10553   /* sanity check */
10554   g_assert (self->priv->first_child == NULL);
10555   g_assert (self->priv->last_child == NULL);
10556   g_assert (self->priv->n_children == 0);
10557 }
10558
10559 typedef struct _InsertBetweenData {
10560   ClutterActor *prev_sibling;
10561   ClutterActor *next_sibling;
10562 } InsertBetweenData;
10563
10564 static void
10565 insert_child_between (ClutterActor *self,
10566                       ClutterActor *child,
10567                       gpointer      data_)
10568 {
10569   InsertBetweenData *data = data_;
10570   ClutterActor *prev_sibling = data->prev_sibling;
10571   ClutterActor *next_sibling = data->next_sibling;
10572
10573   child->priv->parent = self;
10574   child->priv->prev_sibling = prev_sibling;
10575   child->priv->next_sibling = next_sibling;
10576
10577   if (prev_sibling != NULL)
10578     prev_sibling->priv->next_sibling = child;
10579
10580   if (next_sibling != NULL)
10581     next_sibling->priv->prev_sibling = child;
10582
10583   if (child->priv->prev_sibling == NULL)
10584     self->priv->first_child = child;
10585
10586   if (child->priv->next_sibling == NULL)
10587     self->priv->last_child = child;
10588 }
10589
10590 /**
10591  * clutter_actor_replace_child:
10592  * @self: a #ClutterActor
10593  * @old_child: the child of @self to replace
10594  * @new_child: the #ClutterActor to replace @old_child
10595  *
10596  * Replaces @old_child with @new_child in the list of children of @self.
10597  *
10598  * Since: 1.10
10599  */
10600 void
10601 clutter_actor_replace_child (ClutterActor *self,
10602                              ClutterActor *old_child,
10603                              ClutterActor *new_child)
10604 {
10605   ClutterActor *prev_sibling, *next_sibling;
10606   InsertBetweenData clos;
10607
10608   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10609   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10610   g_return_if_fail (old_child->priv->parent == self);
10611   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10612   g_return_if_fail (old_child != new_child);
10613   g_return_if_fail (new_child != self);
10614   g_return_if_fail (new_child->priv->parent == NULL);
10615
10616   prev_sibling = old_child->priv->prev_sibling;
10617   next_sibling = old_child->priv->next_sibling;
10618   clutter_actor_remove_child_internal (self, old_child,
10619                                        REMOVE_CHILD_DEFAULT_FLAGS);
10620
10621   clos.prev_sibling = prev_sibling;
10622   clos.next_sibling = next_sibling;
10623   clutter_actor_add_child_internal (self, new_child,
10624                                     ADD_CHILD_DEFAULT_FLAGS,
10625                                     insert_child_between,
10626                                     &clos);
10627 }
10628
10629 /**
10630  * clutter_actor_unparent:
10631  * @self: a #ClutterActor
10632  *
10633  * Removes the parent of @self.
10634  *
10635  * This will cause the parent of @self to release the reference
10636  * acquired when calling clutter_actor_set_parent(), so if you
10637  * want to keep @self you will have to acquire a reference of
10638  * your own, through g_object_ref().
10639  *
10640  * This function should only be called by legacy #ClutterActor<!-- -->s
10641  * implementing the #ClutterContainer interface.
10642  *
10643  * Since: 0.1.1
10644  *
10645  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10646  */
10647 void
10648 clutter_actor_unparent (ClutterActor *self)
10649 {
10650   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10651
10652   if (self->priv->parent == NULL)
10653     return;
10654
10655   clutter_actor_remove_child_internal (self->priv->parent, self,
10656                                        REMOVE_CHILD_LEGACY_FLAGS);
10657 }
10658
10659 /**
10660  * clutter_actor_reparent:
10661  * @self: a #ClutterActor
10662  * @new_parent: the new #ClutterActor parent
10663  *
10664  * Resets the parent actor of @self.
10665  *
10666  * This function is logically equivalent to calling clutter_actor_unparent()
10667  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10668  * ensures the child is not finalized when unparented, and emits the
10669  * #ClutterActor::parent-set signal only once.
10670  *
10671  * In reality, calling this function is less useful than it sounds, as some
10672  * application code may rely on changes in the intermediate state between
10673  * removal and addition of the actor from its old parent to the @new_parent.
10674  * Thus, it is strongly encouraged to avoid using this function in application
10675  * code.
10676  *
10677  * Since: 0.2
10678  *
10679  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10680  *   clutter_actor_add_child() instead; remember to take a reference on
10681  *   the actor being removed before calling clutter_actor_remove_child()
10682  *   to avoid the reference count dropping to zero and the actor being
10683  *   destroyed.
10684  */
10685 void
10686 clutter_actor_reparent (ClutterActor *self,
10687                         ClutterActor *new_parent)
10688 {
10689   ClutterActorPrivate *priv;
10690
10691   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10692   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10693   g_return_if_fail (self != new_parent);
10694
10695   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10696     {
10697       g_warning ("Cannot set a parent on a toplevel actor");
10698       return;
10699     }
10700
10701   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10702     {
10703       g_warning ("Cannot set a parent currently being destroyed");
10704       return;
10705     }
10706
10707   priv = self->priv;
10708
10709   if (priv->parent != new_parent)
10710     {
10711       ClutterActor *old_parent;
10712
10713       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10714
10715       old_parent = priv->parent;
10716
10717       g_object_ref (self);
10718
10719       if (old_parent != NULL)
10720         {
10721          /* go through the Container implementation if this is a regular
10722           * child and not an internal one
10723           */
10724          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10725            {
10726              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10727
10728              /* this will have to call unparent() */
10729              clutter_container_remove_actor (parent, self);
10730            }
10731          else
10732            clutter_actor_remove_child_internal (old_parent, self,
10733                                                 REMOVE_CHILD_LEGACY_FLAGS);
10734         }
10735
10736       /* Note, will call set_parent() */
10737       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10738         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10739       else
10740         clutter_actor_add_child_internal (new_parent, self,
10741                                           ADD_CHILD_LEGACY_FLAGS,
10742                                           insert_child_at_depth,
10743                                           NULL);
10744
10745       /* we emit the ::parent-set signal once */
10746       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10747
10748       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10749
10750       /* the IN_REPARENT flag suspends state updates */
10751       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10752
10753       g_object_unref (self);
10754    }
10755 }
10756
10757 /**
10758  * clutter_actor_contains:
10759  * @self: A #ClutterActor
10760  * @descendant: A #ClutterActor, possibly contained in @self
10761  *
10762  * Determines if @descendant is contained inside @self (either as an
10763  * immediate child, or as a deeper descendant). If @self and
10764  * @descendant point to the same actor then it will also return %TRUE.
10765  *
10766  * Return value: whether @descendent is contained within @self
10767  *
10768  * Since: 1.4
10769  */
10770 gboolean
10771 clutter_actor_contains (ClutterActor *self,
10772                         ClutterActor *descendant)
10773 {
10774   ClutterActor *actor;
10775
10776   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10777   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10778
10779   for (actor = descendant; actor; actor = actor->priv->parent)
10780     if (actor == self)
10781       return TRUE;
10782
10783   return FALSE;
10784 }
10785
10786 /**
10787  * clutter_actor_set_child_above_sibling:
10788  * @self: a #ClutterActor
10789  * @child: a #ClutterActor child of @self
10790  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10791  *
10792  * Sets @child to be above @sibling in the list of children of @self.
10793  *
10794  * If @sibling is %NULL, @child will be the new last child of @self.
10795  *
10796  * This function is logically equivalent to removing @child and using
10797  * clutter_actor_insert_child_above(), but it will not emit signals
10798  * or change state on @child.
10799  *
10800  * Since: 1.10
10801  */
10802 void
10803 clutter_actor_set_child_above_sibling (ClutterActor *self,
10804                                        ClutterActor *child,
10805                                        ClutterActor *sibling)
10806 {
10807   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10808   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10809   g_return_if_fail (child->priv->parent == self);
10810   g_return_if_fail (child != sibling);
10811   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10812
10813   if (sibling != NULL)
10814     g_return_if_fail (sibling->priv->parent == self);
10815
10816   /* we don't want to change the state of child, or emit signals, or
10817    * regenerate ChildMeta instances here, but we still want to follow
10818    * the correct sequence of steps encoded in remove_child() and
10819    * add_child(), so that correctness is ensured, and we only go
10820    * through one known code path.
10821    */
10822   g_object_ref (child);
10823   clutter_actor_remove_child_internal (self, child, 0);
10824   clutter_actor_add_child_internal (self, child,
10825                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10826                                     insert_child_above,
10827                                     sibling);
10828
10829   clutter_actor_queue_relayout (self);
10830 }
10831
10832 /**
10833  * clutter_actor_set_child_below_sibling:
10834  * @self: a #ClutterActor
10835  * @child: a #ClutterActor child of @self
10836  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10837  *
10838  * Sets @child to be below @sibling in the list of children of @self.
10839  *
10840  * If @sibling is %NULL, @child will be the new first child of @self.
10841  *
10842  * This function is logically equivalent to removing @self and using
10843  * clutter_actor_insert_child_below(), but it will not emit signals
10844  * or change state on @child.
10845  *
10846  * Since: 1.10
10847  */
10848 void
10849 clutter_actor_set_child_below_sibling (ClutterActor *self,
10850                                        ClutterActor *child,
10851                                        ClutterActor *sibling)
10852 {
10853   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10854   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10855   g_return_if_fail (child->priv->parent == self);
10856   g_return_if_fail (child != sibling);
10857   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10858
10859   if (sibling != NULL)
10860     g_return_if_fail (sibling->priv->parent == self);
10861
10862   /* see the comment in set_child_above_sibling() */
10863   g_object_ref (child);
10864   clutter_actor_remove_child_internal (self, child, 0);
10865   clutter_actor_add_child_internal (self, child,
10866                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10867                                     insert_child_below,
10868                                     sibling);
10869
10870   clutter_actor_queue_relayout (self);
10871 }
10872
10873 /**
10874  * clutter_actor_set_child_at_index:
10875  * @self: a #ClutterActor
10876  * @child: a #ClutterActor child of @self
10877  * @index_: the new index for @child
10878  *
10879  * Changes the index of @child in the list of children of @self.
10880  *
10881  * This function is logically equivalent to removing @child and
10882  * calling clutter_actor_insert_child_at_index(), but it will not
10883  * emit signals or change state on @child.
10884  *
10885  * Since: 1.10
10886  */
10887 void
10888 clutter_actor_set_child_at_index (ClutterActor *self,
10889                                   ClutterActor *child,
10890                                   gint          index_)
10891 {
10892   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10893   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10894   g_return_if_fail (child->priv->parent == self);
10895   g_return_if_fail (index_ <= self->priv->n_children);
10896
10897   g_object_ref (child);
10898   clutter_actor_remove_child_internal (self, child, 0);
10899   clutter_actor_add_child_internal (self, child,
10900                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10901                                     insert_child_at_index,
10902                                     GINT_TO_POINTER (index_));
10903
10904   clutter_actor_queue_relayout (self);
10905 }
10906
10907 /**
10908  * clutter_actor_raise:
10909  * @self: A #ClutterActor
10910  * @below: (allow-none): A #ClutterActor to raise above.
10911  *
10912  * Puts @self above @below.
10913  *
10914  * Both actors must have the same parent, and the parent must implement
10915  * the #ClutterContainer interface
10916  *
10917  * This function calls clutter_container_raise_child() internally.
10918  *
10919  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
10920  */
10921 void
10922 clutter_actor_raise (ClutterActor *self,
10923                      ClutterActor *below)
10924 {
10925   ClutterActor *parent;
10926
10927   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10928
10929   parent = clutter_actor_get_parent (self);
10930   if (parent == NULL)
10931     {
10932       g_warning ("%s: Actor '%s' is not inside a container",
10933                  G_STRFUNC,
10934                  _clutter_actor_get_debug_name (self));
10935       return;
10936     }
10937
10938   if (below != NULL)
10939     {
10940       if (parent != clutter_actor_get_parent (below))
10941         {
10942           g_warning ("%s Actor '%s' is not in the same container as "
10943                      "actor '%s'",
10944                      G_STRFUNC,
10945                      _clutter_actor_get_debug_name (self),
10946                      _clutter_actor_get_debug_name (below));
10947           return;
10948         }
10949     }
10950
10951   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
10952 }
10953
10954 /**
10955  * clutter_actor_lower:
10956  * @self: A #ClutterActor
10957  * @above: (allow-none): A #ClutterActor to lower below
10958  *
10959  * Puts @self below @above.
10960  *
10961  * Both actors must have the same parent, and the parent must implement
10962  * the #ClutterContainer interface.
10963  *
10964  * This function calls clutter_container_lower_child() internally.
10965  *
10966  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
10967  */
10968 void
10969 clutter_actor_lower (ClutterActor *self,
10970                      ClutterActor *above)
10971 {
10972   ClutterActor *parent;
10973
10974   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10975
10976   parent = clutter_actor_get_parent (self);
10977   if (parent == NULL)
10978     {
10979       g_warning ("%s: Actor of type %s is not inside a container",
10980                  G_STRFUNC,
10981                  _clutter_actor_get_debug_name (self));
10982       return;
10983     }
10984
10985   if (above)
10986     {
10987       if (parent != clutter_actor_get_parent (above))
10988         {
10989           g_warning ("%s: Actor '%s' is not in the same container as "
10990                      "actor '%s'",
10991                      G_STRFUNC,
10992                      _clutter_actor_get_debug_name (self),
10993                      _clutter_actor_get_debug_name (above));
10994           return;
10995         }
10996     }
10997
10998   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
10999 }
11000
11001 /**
11002  * clutter_actor_raise_top:
11003  * @self: A #ClutterActor
11004  *
11005  * Raises @self to the top.
11006  *
11007  * This function calls clutter_actor_raise() internally.
11008  *
11009  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11010  *   a %NULL sibling, instead.
11011  */
11012 void
11013 clutter_actor_raise_top (ClutterActor *self)
11014 {
11015   clutter_actor_raise (self, NULL);
11016 }
11017
11018 /**
11019  * clutter_actor_lower_bottom:
11020  * @self: A #ClutterActor
11021  *
11022  * Lowers @self to the bottom.
11023  *
11024  * This function calls clutter_actor_lower() internally.
11025  *
11026  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11027  *   a %NULL sibling, instead.
11028  */
11029 void
11030 clutter_actor_lower_bottom (ClutterActor *self)
11031 {
11032   clutter_actor_lower (self, NULL);
11033 }
11034
11035 /*
11036  * Event handling
11037  */
11038
11039 /**
11040  * clutter_actor_event:
11041  * @actor: a #ClutterActor
11042  * @event: a #ClutterEvent
11043  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11044  *
11045  * This function is used to emit an event on the main stage.
11046  * You should rarely need to use this function, except for
11047  * synthetising events.
11048  *
11049  * Return value: the return value from the signal emission: %TRUE
11050  *   if the actor handled the event, or %FALSE if the event was
11051  *   not handled
11052  *
11053  * Since: 0.6
11054  */
11055 gboolean
11056 clutter_actor_event (ClutterActor *actor,
11057                      ClutterEvent *event,
11058                      gboolean      capture)
11059 {
11060   gboolean retval = FALSE;
11061   gint signal_num = -1;
11062
11063   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11064   g_return_val_if_fail (event != NULL, FALSE);
11065
11066   g_object_ref (actor);
11067
11068   if (capture)
11069     {
11070       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11071                      event,
11072                      &retval);
11073       goto out;
11074     }
11075
11076   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11077
11078   if (!retval)
11079     {
11080       switch (event->type)
11081         {
11082         case CLUTTER_NOTHING:
11083           break;
11084         case CLUTTER_BUTTON_PRESS:
11085           signal_num = BUTTON_PRESS_EVENT;
11086           break;
11087         case CLUTTER_BUTTON_RELEASE:
11088           signal_num = BUTTON_RELEASE_EVENT;
11089           break;
11090         case CLUTTER_SCROLL:
11091           signal_num = SCROLL_EVENT;
11092           break;
11093         case CLUTTER_KEY_PRESS:
11094           signal_num = KEY_PRESS_EVENT;
11095           break;
11096         case CLUTTER_KEY_RELEASE:
11097           signal_num = KEY_RELEASE_EVENT;
11098           break;
11099         case CLUTTER_MOTION:
11100           signal_num = MOTION_EVENT;
11101           break;
11102         case CLUTTER_ENTER:
11103           signal_num = ENTER_EVENT;
11104           break;
11105         case CLUTTER_LEAVE:
11106           signal_num = LEAVE_EVENT;
11107           break;
11108         case CLUTTER_DELETE:
11109         case CLUTTER_DESTROY_NOTIFY:
11110         case CLUTTER_CLIENT_MESSAGE:
11111         default:
11112           signal_num = -1;
11113           break;
11114         }
11115
11116       if (signal_num != -1)
11117         g_signal_emit (actor, actor_signals[signal_num], 0,
11118                        event, &retval);
11119     }
11120
11121 out:
11122   g_object_unref (actor);
11123
11124   return retval;
11125 }
11126
11127 /**
11128  * clutter_actor_set_reactive:
11129  * @actor: a #ClutterActor
11130  * @reactive: whether the actor should be reactive to events
11131  *
11132  * Sets @actor as reactive. Reactive actors will receive events.
11133  *
11134  * Since: 0.6
11135  */
11136 void
11137 clutter_actor_set_reactive (ClutterActor *actor,
11138                             gboolean      reactive)
11139 {
11140   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11141
11142   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11143     return;
11144
11145   if (reactive)
11146     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11147   else
11148     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11149
11150   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11151 }
11152
11153 /**
11154  * clutter_actor_get_reactive:
11155  * @actor: a #ClutterActor
11156  *
11157  * Checks whether @actor is marked as reactive.
11158  *
11159  * Return value: %TRUE if the actor is reactive
11160  *
11161  * Since: 0.6
11162  */
11163 gboolean
11164 clutter_actor_get_reactive (ClutterActor *actor)
11165 {
11166   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11167
11168   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11169 }
11170
11171 /**
11172  * clutter_actor_get_anchor_point:
11173  * @self: a #ClutterActor
11174  * @anchor_x: (out): return location for the X coordinate of the anchor point
11175  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11176  *
11177  * Gets the current anchor point of the @actor in pixels.
11178  *
11179  * Since: 0.6
11180  */
11181 void
11182 clutter_actor_get_anchor_point (ClutterActor *self,
11183                                 gfloat       *anchor_x,
11184                                 gfloat       *anchor_y)
11185 {
11186   const ClutterTransformInfo *info;
11187
11188   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11189
11190   info = _clutter_actor_get_transform_info_or_defaults (self);
11191   clutter_anchor_coord_get_units (self, &info->anchor,
11192                                   anchor_x,
11193                                   anchor_y,
11194                                   NULL);
11195 }
11196
11197 /**
11198  * clutter_actor_set_anchor_point:
11199  * @self: a #ClutterActor
11200  * @anchor_x: X coordinate of the anchor point
11201  * @anchor_y: Y coordinate of the anchor point
11202  *
11203  * Sets an anchor point for @self. The anchor point is a point in the
11204  * coordinate space of an actor to which the actor position within its
11205  * parent is relative; the default is (0, 0), i.e. the top-left corner
11206  * of the actor.
11207  *
11208  * Since: 0.6
11209  */
11210 void
11211 clutter_actor_set_anchor_point (ClutterActor *self,
11212                                 gfloat        anchor_x,
11213                                 gfloat        anchor_y)
11214 {
11215   ClutterTransformInfo *info;
11216   ClutterActorPrivate *priv;
11217   gboolean changed = FALSE;
11218   gfloat old_anchor_x, old_anchor_y;
11219   GObject *obj;
11220
11221   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11222
11223   obj = G_OBJECT (self);
11224   priv = self->priv;
11225   info = _clutter_actor_get_transform_info (self);
11226
11227   g_object_freeze_notify (obj);
11228
11229   clutter_anchor_coord_get_units (self, &info->anchor,
11230                                   &old_anchor_x,
11231                                   &old_anchor_y,
11232                                   NULL);
11233
11234   if (info->anchor.is_fractional)
11235     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11236
11237   if (old_anchor_x != anchor_x)
11238     {
11239       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11240       changed = TRUE;
11241     }
11242
11243   if (old_anchor_y != anchor_y)
11244     {
11245       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11246       changed = TRUE;
11247     }
11248
11249   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11250
11251   if (changed)
11252     {
11253       priv->transform_valid = FALSE;
11254       clutter_actor_queue_redraw (self);
11255     }
11256
11257   g_object_thaw_notify (obj);
11258 }
11259
11260 /**
11261  * clutter_actor_get_anchor_point_gravity:
11262  * @self: a #ClutterActor
11263  *
11264  * Retrieves the anchor position expressed as a #ClutterGravity. If
11265  * the anchor point was specified using pixels or units this will
11266  * return %CLUTTER_GRAVITY_NONE.
11267  *
11268  * Return value: the #ClutterGravity used by the anchor point
11269  *
11270  * Since: 1.0
11271  */
11272 ClutterGravity
11273 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11274 {
11275   const ClutterTransformInfo *info;
11276
11277   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11278
11279   info = _clutter_actor_get_transform_info_or_defaults (self);
11280
11281   return clutter_anchor_coord_get_gravity (&info->anchor);
11282 }
11283
11284 /**
11285  * clutter_actor_move_anchor_point:
11286  * @self: a #ClutterActor
11287  * @anchor_x: X coordinate of the anchor point
11288  * @anchor_y: Y coordinate of the anchor point
11289  *
11290  * Sets an anchor point for the actor, and adjusts the actor postion so that
11291  * the relative position of the actor toward its parent remains the same.
11292  *
11293  * Since: 0.6
11294  */
11295 void
11296 clutter_actor_move_anchor_point (ClutterActor *self,
11297                                  gfloat        anchor_x,
11298                                  gfloat        anchor_y)
11299 {
11300   gfloat old_anchor_x, old_anchor_y;
11301   const ClutterTransformInfo *info;
11302
11303   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11304
11305   info = _clutter_actor_get_transform_info (self);
11306   clutter_anchor_coord_get_units (self, &info->anchor,
11307                                   &old_anchor_x,
11308                                   &old_anchor_y,
11309                                   NULL);
11310
11311   g_object_freeze_notify (G_OBJECT (self));
11312
11313   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11314
11315   if (self->priv->position_set)
11316     clutter_actor_move_by (self,
11317                            anchor_x - old_anchor_x,
11318                            anchor_y - old_anchor_y);
11319
11320   g_object_thaw_notify (G_OBJECT (self));
11321 }
11322
11323 /**
11324  * clutter_actor_move_anchor_point_from_gravity:
11325  * @self: a #ClutterActor
11326  * @gravity: #ClutterGravity.
11327  *
11328  * Sets an anchor point on the actor based on the given gravity, adjusting the
11329  * actor postion so that its relative position within its parent remains
11330  * unchanged.
11331  *
11332  * Since version 1.0 the anchor point will be stored as a gravity so
11333  * that if the actor changes size then the anchor point will move. For
11334  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11335  * and later double the size of the actor, the anchor point will move
11336  * to the bottom right.
11337  *
11338  * Since: 0.6
11339  */
11340 void
11341 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11342                                               ClutterGravity  gravity)
11343 {
11344   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11345   const ClutterTransformInfo *info;
11346   ClutterActorPrivate *priv;
11347
11348   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11349
11350   priv = self->priv;
11351   info = _clutter_actor_get_transform_info (self);
11352
11353   g_object_freeze_notify (G_OBJECT (self));
11354
11355   clutter_anchor_coord_get_units (self, &info->anchor,
11356                                   &old_anchor_x,
11357                                   &old_anchor_y,
11358                                   NULL);
11359   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11360   clutter_anchor_coord_get_units (self, &info->anchor,
11361                                   &new_anchor_x,
11362                                   &new_anchor_y,
11363                                   NULL);
11364
11365   if (priv->position_set)
11366     clutter_actor_move_by (self,
11367                            new_anchor_x - old_anchor_x,
11368                            new_anchor_y - old_anchor_y);
11369
11370   g_object_thaw_notify (G_OBJECT (self));
11371 }
11372
11373 /**
11374  * clutter_actor_set_anchor_point_from_gravity:
11375  * @self: a #ClutterActor
11376  * @gravity: #ClutterGravity.
11377  *
11378  * Sets an anchor point on the actor, based on the given gravity (this is a
11379  * convenience function wrapping clutter_actor_set_anchor_point()).
11380  *
11381  * Since version 1.0 the anchor point will be stored as a gravity so
11382  * that if the actor changes size then the anchor point will move. For
11383  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11384  * and later double the size of the actor, the anchor point will move
11385  * to the bottom right.
11386  *
11387  * Since: 0.6
11388  */
11389 void
11390 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11391                                              ClutterGravity  gravity)
11392 {
11393   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11394
11395   if (gravity == CLUTTER_GRAVITY_NONE)
11396     clutter_actor_set_anchor_point (self, 0, 0);
11397   else
11398     {
11399       GObject *obj = G_OBJECT (self);
11400       ClutterTransformInfo *info;
11401
11402       g_object_freeze_notify (obj);
11403
11404       info = _clutter_actor_get_transform_info (self);
11405       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11406
11407       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11408       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11409       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11410
11411       self->priv->transform_valid = FALSE;
11412
11413       clutter_actor_queue_redraw (self);
11414
11415       g_object_thaw_notify (obj);
11416     }
11417 }
11418
11419 static void
11420 clutter_container_iface_init (ClutterContainerIface *iface)
11421 {
11422   /* we don't override anything, as ClutterContainer already has a default
11423    * implementation that we can use, and which calls into our own API.
11424    */
11425 }
11426
11427 typedef enum
11428 {
11429   PARSE_X,
11430   PARSE_Y,
11431   PARSE_WIDTH,
11432   PARSE_HEIGHT,
11433   PARSE_ANCHOR_X,
11434   PARSE_ANCHOR_Y
11435 } ParseDimension;
11436
11437 static gfloat
11438 parse_units (ClutterActor   *self,
11439              ParseDimension  dimension,
11440              JsonNode       *node)
11441 {
11442   GValue value = { 0, };
11443   gfloat retval = 0;
11444
11445   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11446     return 0;
11447
11448   json_node_get_value (node, &value);
11449
11450   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11451     {
11452       retval = (gfloat) g_value_get_int64 (&value);
11453     }
11454   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11455     {
11456       retval = g_value_get_double (&value);
11457     }
11458   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11459     {
11460       ClutterUnits units;
11461       gboolean res;
11462
11463       res = clutter_units_from_string (&units, g_value_get_string (&value));
11464       if (res)
11465         retval = clutter_units_to_pixels (&units);
11466       else
11467         {
11468           g_warning ("Invalid value '%s': integers, strings or floating point "
11469                      "values can be used for the x, y, width and height "
11470                      "properties. Valid modifiers for strings are 'px', 'mm', "
11471                      "'pt' and 'em'.",
11472                      g_value_get_string (&value));
11473           retval = 0;
11474         }
11475     }
11476   else
11477     {
11478       g_warning ("Invalid value of type '%s': integers, strings of floating "
11479                  "point values can be used for the x, y, width, height "
11480                  "anchor-x and anchor-y properties.",
11481                  g_type_name (G_VALUE_TYPE (&value)));
11482     }
11483
11484   g_value_unset (&value);
11485
11486   return retval;
11487 }
11488
11489 typedef struct {
11490   ClutterRotateAxis axis;
11491
11492   gdouble angle;
11493
11494   gfloat center_x;
11495   gfloat center_y;
11496   gfloat center_z;
11497 } RotationInfo;
11498
11499 static inline gboolean
11500 parse_rotation_array (ClutterActor *actor,
11501                       JsonArray    *array,
11502                       RotationInfo *info)
11503 {
11504   JsonNode *element;
11505
11506   if (json_array_get_length (array) != 2)
11507     return FALSE;
11508
11509   /* angle */
11510   element = json_array_get_element (array, 0);
11511   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11512     info->angle = json_node_get_double (element);
11513   else
11514     return FALSE;
11515
11516   /* center */
11517   element = json_array_get_element (array, 1);
11518   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11519     {
11520       JsonArray *center = json_node_get_array (element);
11521
11522       if (json_array_get_length (center) != 2)
11523         return FALSE;
11524
11525       switch (info->axis)
11526         {
11527         case CLUTTER_X_AXIS:
11528           info->center_y = parse_units (actor, PARSE_Y,
11529                                         json_array_get_element (center, 0));
11530           info->center_z = parse_units (actor, PARSE_Y,
11531                                         json_array_get_element (center, 1));
11532           return TRUE;
11533
11534         case CLUTTER_Y_AXIS:
11535           info->center_x = parse_units (actor, PARSE_X,
11536                                         json_array_get_element (center, 0));
11537           info->center_z = parse_units (actor, PARSE_X,
11538                                         json_array_get_element (center, 1));
11539           return TRUE;
11540
11541         case CLUTTER_Z_AXIS:
11542           info->center_x = parse_units (actor, PARSE_X,
11543                                         json_array_get_element (center, 0));
11544           info->center_y = parse_units (actor, PARSE_Y,
11545                                         json_array_get_element (center, 1));
11546           return TRUE;
11547         }
11548     }
11549
11550   return FALSE;
11551 }
11552
11553 static gboolean
11554 parse_rotation (ClutterActor *actor,
11555                 JsonNode     *node,
11556                 RotationInfo *info)
11557 {
11558   JsonArray *array;
11559   guint len, i;
11560   gboolean retval = FALSE;
11561
11562   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11563     {
11564       g_warning ("Invalid node of type '%s' found, expecting an array",
11565                  json_node_type_name (node));
11566       return FALSE;
11567     }
11568
11569   array = json_node_get_array (node);
11570   len = json_array_get_length (array);
11571
11572   for (i = 0; i < len; i++)
11573     {
11574       JsonNode *element = json_array_get_element (array, i);
11575       JsonObject *object;
11576       JsonNode *member;
11577
11578       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11579         {
11580           g_warning ("Invalid node of type '%s' found, expecting an object",
11581                      json_node_type_name (element));
11582           return FALSE;
11583         }
11584
11585       object = json_node_get_object (element);
11586
11587       if (json_object_has_member (object, "x-axis"))
11588         {
11589           member = json_object_get_member (object, "x-axis");
11590
11591           info->axis = CLUTTER_X_AXIS;
11592
11593           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11594             {
11595               info->angle = json_node_get_double (member);
11596               retval = TRUE;
11597             }
11598           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11599             retval = parse_rotation_array (actor,
11600                                            json_node_get_array (member),
11601                                            info);
11602           else
11603             retval = FALSE;
11604         }
11605       else if (json_object_has_member (object, "y-axis"))
11606         {
11607           member = json_object_get_member (object, "y-axis");
11608
11609           info->axis = CLUTTER_Y_AXIS;
11610
11611           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11612             {
11613               info->angle = json_node_get_double (member);
11614               retval = TRUE;
11615             }
11616           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11617             retval = parse_rotation_array (actor,
11618                                            json_node_get_array (member),
11619                                            info);
11620           else
11621             retval = FALSE;
11622         }
11623       else if (json_object_has_member (object, "z-axis"))
11624         {
11625           member = json_object_get_member (object, "z-axis");
11626
11627           info->axis = CLUTTER_Z_AXIS;
11628
11629           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11630             {
11631               info->angle = json_node_get_double (member);
11632               retval = TRUE;
11633             }
11634           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11635             retval = parse_rotation_array (actor,
11636                                            json_node_get_array (member),
11637                                            info);
11638           else
11639             retval = FALSE;
11640         }
11641     }
11642
11643   return retval;
11644 }
11645
11646 static GSList *
11647 parse_actor_metas (ClutterScript *script,
11648                    ClutterActor  *actor,
11649                    JsonNode      *node)
11650 {
11651   GList *elements, *l;
11652   GSList *retval = NULL;
11653
11654   if (!JSON_NODE_HOLDS_ARRAY (node))
11655     return NULL;
11656
11657   elements = json_array_get_elements (json_node_get_array (node));
11658
11659   for (l = elements; l != NULL; l = l->next)
11660     {
11661       JsonNode *element = l->data;
11662       const gchar *id_ = _clutter_script_get_id_from_node (element);
11663       GObject *meta;
11664
11665       if (id_ == NULL || *id_ == '\0')
11666         continue;
11667
11668       meta = clutter_script_get_object (script, id_);
11669       if (meta == NULL)
11670         continue;
11671
11672       retval = g_slist_prepend (retval, meta);
11673     }
11674
11675   g_list_free (elements);
11676
11677   return g_slist_reverse (retval);
11678 }
11679
11680 static GSList *
11681 parse_behaviours (ClutterScript *script,
11682                   ClutterActor  *actor,
11683                   JsonNode      *node)
11684 {
11685   GList *elements, *l;
11686   GSList *retval = NULL;
11687
11688   if (!JSON_NODE_HOLDS_ARRAY (node))
11689     return NULL;
11690
11691   elements = json_array_get_elements (json_node_get_array (node));
11692
11693   for (l = elements; l != NULL; l = l->next)
11694     {
11695       JsonNode *element = l->data;
11696       const gchar *id_ = _clutter_script_get_id_from_node (element);
11697       GObject *behaviour;
11698
11699       if (id_ == NULL || *id_ == '\0')
11700         continue;
11701
11702       behaviour = clutter_script_get_object (script, id_);
11703       if (behaviour == NULL)
11704         continue;
11705
11706       retval = g_slist_prepend (retval, behaviour);
11707     }
11708
11709   g_list_free (elements);
11710
11711   return g_slist_reverse (retval);
11712 }
11713
11714 static gboolean
11715 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11716                                  ClutterScript     *script,
11717                                  GValue            *value,
11718                                  const gchar       *name,
11719                                  JsonNode          *node)
11720 {
11721   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11722   gboolean retval = FALSE;
11723
11724   if ((name[0] == 'x' && name[1] == '\0') ||
11725       (name[0] == 'y' && name[1] == '\0') ||
11726       (strcmp (name, "width") == 0) ||
11727       (strcmp (name, "height") == 0) ||
11728       (strcmp (name, "anchor_x") == 0) ||
11729       (strcmp (name, "anchor_y") == 0))
11730     {
11731       ParseDimension dimension;
11732       gfloat units;
11733
11734       if (name[0] == 'x')
11735         dimension = PARSE_X;
11736       else if (name[0] == 'y')
11737         dimension = PARSE_Y;
11738       else if (name[0] == 'w')
11739         dimension = PARSE_WIDTH;
11740       else if (name[0] == 'h')
11741         dimension = PARSE_HEIGHT;
11742       else if (name[0] == 'a' && name[7] == 'x')
11743         dimension = PARSE_ANCHOR_X;
11744       else if (name[0] == 'a' && name[7] == 'y')
11745         dimension = PARSE_ANCHOR_Y;
11746       else
11747         return FALSE;
11748
11749       units = parse_units (actor, dimension, node);
11750
11751       /* convert back to pixels: all properties are pixel-based */
11752       g_value_init (value, G_TYPE_FLOAT);
11753       g_value_set_float (value, units);
11754
11755       retval = TRUE;
11756     }
11757   else if (strcmp (name, "rotation") == 0)
11758     {
11759       RotationInfo *info;
11760
11761       info = g_slice_new0 (RotationInfo);
11762       retval = parse_rotation (actor, node, info);
11763
11764       if (retval)
11765         {
11766           g_value_init (value, G_TYPE_POINTER);
11767           g_value_set_pointer (value, info);
11768         }
11769       else
11770         g_slice_free (RotationInfo, info);
11771     }
11772   else if (strcmp (name, "behaviours") == 0)
11773     {
11774       GSList *l;
11775
11776 #ifdef CLUTTER_ENABLE_DEBUG
11777       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11778         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11779                                      "and it should not be used in newly "
11780                                      "written ClutterScript definitions.");
11781 #endif
11782
11783       l = parse_behaviours (script, actor, node);
11784
11785       g_value_init (value, G_TYPE_POINTER);
11786       g_value_set_pointer (value, l);
11787
11788       retval = TRUE;
11789     }
11790   else if (strcmp (name, "actions") == 0 ||
11791            strcmp (name, "constraints") == 0 ||
11792            strcmp (name, "effects") == 0)
11793     {
11794       GSList *l;
11795
11796       l = parse_actor_metas (script, actor, node);
11797
11798       g_value_init (value, G_TYPE_POINTER);
11799       g_value_set_pointer (value, l);
11800
11801       retval = TRUE;
11802     }
11803
11804   return retval;
11805 }
11806
11807 static void
11808 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11809                                    ClutterScript     *script,
11810                                    const gchar       *name,
11811                                    const GValue      *value)
11812 {
11813   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11814
11815 #ifdef CLUTTER_ENABLE_DEBUG
11816   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11817     {
11818       gchar *tmp = g_strdup_value_contents (value);
11819
11820       CLUTTER_NOTE (SCRIPT,
11821                     "in ClutterActor::set_custom_property('%s') = %s",
11822                     name,
11823                     tmp);
11824
11825       g_free (tmp);
11826     }
11827 #endif /* CLUTTER_ENABLE_DEBUG */
11828
11829   if (strcmp (name, "rotation") == 0)
11830     {
11831       RotationInfo *info;
11832
11833       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11834         return;
11835
11836       info = g_value_get_pointer (value);
11837
11838       clutter_actor_set_rotation (actor,
11839                                   info->axis, info->angle,
11840                                   info->center_x,
11841                                   info->center_y,
11842                                   info->center_z);
11843
11844       g_slice_free (RotationInfo, info);
11845
11846       return;
11847     }
11848
11849   if (strcmp (name, "behaviours") == 0)
11850     {
11851       GSList *behaviours, *l;
11852
11853       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11854         return;
11855
11856       behaviours = g_value_get_pointer (value);
11857       for (l = behaviours; l != NULL; l = l->next)
11858         {
11859           ClutterBehaviour *behaviour = l->data;
11860
11861           clutter_behaviour_apply (behaviour, actor);
11862         }
11863
11864       g_slist_free (behaviours);
11865
11866       return;
11867     }
11868
11869   if (strcmp (name, "actions") == 0 ||
11870       strcmp (name, "constraints") == 0 ||
11871       strcmp (name, "effects") == 0)
11872     {
11873       GSList *metas, *l;
11874
11875       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11876         return;
11877
11878       metas = g_value_get_pointer (value);
11879       for (l = metas; l != NULL; l = l->next)
11880         {
11881           if (name[0] == 'a')
11882             clutter_actor_add_action (actor, l->data);
11883
11884           if (name[0] == 'c')
11885             clutter_actor_add_constraint (actor, l->data);
11886
11887           if (name[0] == 'e')
11888             clutter_actor_add_effect (actor, l->data);
11889         }
11890
11891       g_slist_free (metas);
11892
11893       return;
11894     }
11895
11896   g_object_set_property (G_OBJECT (scriptable), name, value);
11897 }
11898
11899 static void
11900 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
11901 {
11902   iface->parse_custom_node = clutter_actor_parse_custom_node;
11903   iface->set_custom_property = clutter_actor_set_custom_property;
11904 }
11905
11906 static ClutterActorMeta *
11907 get_meta_from_animation_property (ClutterActor  *actor,
11908                                   const gchar   *name,
11909                                   gchar        **name_p)
11910 {
11911   ClutterActorPrivate *priv = actor->priv;
11912   ClutterActorMeta *meta = NULL;
11913   gchar **tokens;
11914
11915   /* if this is not a special property, fall through */
11916   if (name[0] != '@')
11917     return NULL;
11918
11919   /* detect the properties named using the following spec:
11920    *
11921    *   @<section>.<meta-name>.<property-name>
11922    *
11923    * where <section> can be one of the following:
11924    *
11925    *   - actions
11926    *   - constraints
11927    *   - effects
11928    *
11929    * and <meta-name> is the name set on a specific ActorMeta
11930    */
11931
11932   tokens = g_strsplit (name + 1, ".", -1);
11933   if (tokens == NULL || g_strv_length (tokens) != 3)
11934     {
11935       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
11936                     name + 1);
11937       g_strfreev (tokens);
11938       return NULL;
11939     }
11940
11941   if (strcmp (tokens[0], "actions") == 0)
11942     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
11943
11944   if (strcmp (tokens[0], "constraints") == 0)
11945     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
11946
11947   if (strcmp (tokens[0], "effects") == 0)
11948     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
11949
11950   if (name_p != NULL)
11951     *name_p = g_strdup (tokens[2]);
11952
11953   CLUTTER_NOTE (ANIMATION,
11954                 "Looking for property '%s' of object '%s' in section '%s'",
11955                 tokens[2],
11956                 tokens[1],
11957                 tokens[0]);
11958
11959   g_strfreev (tokens);
11960
11961   return meta;
11962 }
11963
11964 static GParamSpec *
11965 clutter_actor_find_property (ClutterAnimatable *animatable,
11966                              const gchar       *property_name)
11967 {
11968   ClutterActorMeta *meta = NULL;
11969   GObjectClass *klass = NULL;
11970   GParamSpec *pspec = NULL;
11971   gchar *p_name = NULL;
11972
11973   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11974                                            property_name,
11975                                            &p_name);
11976
11977   if (meta != NULL)
11978     {
11979       klass = G_OBJECT_GET_CLASS (meta);
11980
11981       pspec = g_object_class_find_property (klass, p_name);
11982     }
11983   else
11984     {
11985       klass = G_OBJECT_GET_CLASS (animatable);
11986
11987       pspec = g_object_class_find_property (klass, property_name);
11988     }
11989
11990   g_free (p_name);
11991
11992   return pspec;
11993 }
11994
11995 static void
11996 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
11997                                  const gchar       *property_name,
11998                                  GValue            *initial)
11999 {
12000   ClutterActorMeta *meta = NULL;
12001   gchar *p_name = NULL;
12002
12003   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12004                                            property_name,
12005                                            &p_name);
12006
12007   if (meta != NULL)
12008     g_object_get_property (G_OBJECT (meta), p_name, initial);
12009   else
12010     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12011
12012   g_free (p_name);
12013 }
12014
12015 static void
12016 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12017                                const gchar       *property_name,
12018                                const GValue      *final)
12019 {
12020   ClutterActorMeta *meta = NULL;
12021   gchar *p_name = NULL;
12022
12023   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12024                                            property_name,
12025                                            &p_name);
12026   if (meta != NULL)
12027     g_object_set_property (G_OBJECT (meta), p_name, final);
12028   else
12029     g_object_set_property (G_OBJECT (animatable), property_name, final);
12030
12031   g_free (p_name);
12032 }
12033
12034 static void
12035 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12036 {
12037   iface->find_property = clutter_actor_find_property;
12038   iface->get_initial_state = clutter_actor_get_initial_state;
12039   iface->set_final_state = clutter_actor_set_final_state;
12040 }
12041
12042 /**
12043  * clutter_actor_transform_stage_point:
12044  * @self: A #ClutterActor
12045  * @x: (in): x screen coordinate of the point to unproject
12046  * @y: (in): y screen coordinate of the point to unproject
12047  * @x_out: (out): return location for the unprojected x coordinance
12048  * @y_out: (out): return location for the unprojected y coordinance
12049  *
12050  * This function translates screen coordinates (@x, @y) to
12051  * coordinates relative to the actor. For example, it can be used to translate
12052  * screen events from global screen coordinates into actor-local coordinates.
12053  *
12054  * The conversion can fail, notably if the transform stack results in the
12055  * actor being projected on the screen as a mere line.
12056  *
12057  * The conversion should not be expected to be pixel-perfect due to the
12058  * nature of the operation. In general the error grows when the skewing
12059  * of the actor rectangle on screen increases.
12060  *
12061  * <note><para>This function can be computationally intensive.</para></note>
12062  *
12063  * <note><para>This function only works when the allocation is up-to-date,
12064  * i.e. inside of paint().</para></note>
12065  *
12066  * Return value: %TRUE if conversion was successful.
12067  *
12068  * Since: 0.6
12069  */
12070 gboolean
12071 clutter_actor_transform_stage_point (ClutterActor *self,
12072                                      gfloat        x,
12073                                      gfloat        y,
12074                                      gfloat       *x_out,
12075                                      gfloat       *y_out)
12076 {
12077   ClutterVertex v[4];
12078   float ST[3][3];
12079   float RQ[3][3];
12080   int du, dv, xi, yi;
12081   float px, py;
12082   float xf, yf, wf, det;
12083   ClutterActorPrivate *priv;
12084
12085   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12086
12087   priv = self->priv;
12088
12089   /* This implementation is based on the quad -> quad projection algorithm
12090    * described by Paul Heckbert in:
12091    *
12092    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12093    *
12094    * and the sample implementation at:
12095    *
12096    *   http://www.cs.cmu.edu/~ph/src/texfund/
12097    *
12098    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12099    * quad to rectangle only, which significantly simplifies things; the
12100    * function calls have been unrolled, and most of the math is done in fixed
12101    * point.
12102    */
12103
12104   clutter_actor_get_abs_allocation_vertices (self, v);
12105
12106   /* Keeping these as ints simplifies the multiplication (no significant
12107    * loss of precision here).
12108    */
12109   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12110   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12111
12112   if (!du || !dv)
12113     return FALSE;
12114
12115 #define UX2FP(x)        (x)
12116 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12117
12118   /* First, find mapping from unit uv square to xy quadrilateral; this
12119    * equivalent to the pmap_square_quad() functions in the sample
12120    * implementation, which we can simplify, since our target is always
12121    * a rectangle.
12122    */
12123   px = v[0].x - v[1].x + v[3].x - v[2].x;
12124   py = v[0].y - v[1].y + v[3].y - v[2].y;
12125
12126   if (!px && !py)
12127     {
12128       /* affine transform */
12129       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12130       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12131       RQ[2][0] = UX2FP (v[0].x);
12132       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12133       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12134       RQ[2][1] = UX2FP (v[0].y);
12135       RQ[0][2] = 0;
12136       RQ[1][2] = 0;
12137       RQ[2][2] = 1.0;
12138     }
12139   else
12140     {
12141       /* projective transform */
12142       double dx1, dx2, dy1, dy2, del;
12143
12144       dx1 = UX2FP (v[1].x - v[3].x);
12145       dx2 = UX2FP (v[2].x - v[3].x);
12146       dy1 = UX2FP (v[1].y - v[3].y);
12147       dy2 = UX2FP (v[2].y - v[3].y);
12148
12149       del = DET2FP (dx1, dx2, dy1, dy2);
12150       if (!del)
12151         return FALSE;
12152
12153       /*
12154        * The division here needs to be done in floating point for
12155        * precisions reasons.
12156        */
12157       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12158       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12159       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12160       RQ[2][2] = 1.0;
12161       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12162       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12163       RQ[2][0] = UX2FP (v[0].x);
12164       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12165       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12166       RQ[2][1] = UX2FP (v[0].y);
12167     }
12168
12169   /*
12170    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12171    * square. Since our rectangle is based at 0,0 we only need to scale.
12172    */
12173   RQ[0][0] /= du;
12174   RQ[1][0] /= dv;
12175   RQ[0][1] /= du;
12176   RQ[1][1] /= dv;
12177   RQ[0][2] /= du;
12178   RQ[1][2] /= dv;
12179
12180   /*
12181    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12182    * inverse of that.
12183    */
12184   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12185   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12186   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12187   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12188   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12189   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12190   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12191   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12192   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12193
12194   /*
12195    * Check the resulting matrix is OK.
12196    */
12197   det = (RQ[0][0] * ST[0][0])
12198       + (RQ[0][1] * ST[0][1])
12199       + (RQ[0][2] * ST[0][2]);
12200   if (!det)
12201     return FALSE;
12202
12203   /*
12204    * Now transform our point with the ST matrix; the notional w
12205    * coordinate is 1, hence the last part is simply added.
12206    */
12207   xi = (int) x;
12208   yi = (int) y;
12209
12210   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12211   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12212   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12213
12214   if (x_out)
12215     *x_out = xf / wf;
12216
12217   if (y_out)
12218     *y_out = yf / wf;
12219
12220 #undef UX2FP
12221 #undef DET2FP
12222
12223   return TRUE;
12224 }
12225
12226 /*
12227  * ClutterGeometry
12228  */
12229
12230 static ClutterGeometry*
12231 clutter_geometry_copy (const ClutterGeometry *geometry)
12232 {
12233   return g_slice_dup (ClutterGeometry, geometry);
12234 }
12235
12236 static void
12237 clutter_geometry_free (ClutterGeometry *geometry)
12238 {
12239   if (G_LIKELY (geometry != NULL))
12240     g_slice_free (ClutterGeometry, geometry);
12241 }
12242
12243 /**
12244  * clutter_geometry_union:
12245  * @geometry_a: a #ClutterGeometry
12246  * @geometry_b: another #ClutterGeometry
12247  * @result: (out): location to store the result
12248  *
12249  * Find the union of two rectangles represented as #ClutterGeometry.
12250  *
12251  * Since: 1.4
12252  */
12253 void
12254 clutter_geometry_union (const ClutterGeometry *geometry_a,
12255                         const ClutterGeometry *geometry_b,
12256                         ClutterGeometry       *result)
12257 {
12258   /* We don't try to handle rectangles that can't be represented
12259    * as a signed integer box */
12260   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12261   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12262   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12263                   geometry_b->x + (gint)geometry_b->width);
12264   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12265                   geometry_b->y + (gint)geometry_b->height);
12266   result->x = x_1;
12267   result->y = y_1;
12268   result->width = x_2 - x_1;
12269   result->height = y_2 - y_1;
12270 }
12271
12272 /**
12273  * clutter_geometry_intersects:
12274  * @geometry0: The first geometry to test
12275  * @geometry1: The second geometry to test
12276  *
12277  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12278  * they do else %FALSE.
12279  *
12280  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12281  * %FALSE.
12282  *
12283  * Since: 1.4
12284  */
12285 gboolean
12286 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12287                              const ClutterGeometry *geometry1)
12288 {
12289   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12290       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12291       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12292       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12293     return FALSE;
12294   else
12295     return TRUE;
12296 }
12297
12298 static gboolean
12299 clutter_geometry_progress (const GValue *a,
12300                            const GValue *b,
12301                            gdouble       progress,
12302                            GValue       *retval)
12303 {
12304   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12305   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12306   ClutterGeometry res = { 0, };
12307   gint a_width = a_geom->width;
12308   gint b_width = b_geom->width;
12309   gint a_height = a_geom->height;
12310   gint b_height = b_geom->height;
12311
12312   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12313   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12314
12315   res.width = a_width + (b_width - a_width) * progress;
12316   res.height = a_height + (b_height - a_height) * progress;
12317
12318   g_value_set_boxed (retval, &res);
12319
12320   return TRUE;
12321 }
12322
12323 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12324                                clutter_geometry_copy,
12325                                clutter_geometry_free,
12326                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12327
12328 /*
12329  * ClutterVertices
12330  */
12331
12332 /**
12333  * clutter_vertex_new:
12334  * @x: X coordinate
12335  * @y: Y coordinate
12336  * @z: Z coordinate
12337  *
12338  * Creates a new #ClutterVertex for the point in 3D space
12339  * identified by the 3 coordinates @x, @y, @z
12340  *
12341  * Return value: the newly allocate #ClutterVertex. Use
12342  *   clutter_vertex_free() to free the resources
12343  *
12344  * Since: 1.0
12345  */
12346 ClutterVertex *
12347 clutter_vertex_new (gfloat x,
12348                     gfloat y,
12349                     gfloat z)
12350 {
12351   ClutterVertex *vertex;
12352
12353   vertex = g_slice_new (ClutterVertex);
12354   vertex->x = x;
12355   vertex->y = y;
12356   vertex->z = z;
12357
12358   return vertex;
12359 }
12360
12361 /**
12362  * clutter_vertex_copy:
12363  * @vertex: a #ClutterVertex
12364  *
12365  * Copies @vertex
12366  *
12367  * Return value: a newly allocated copy of #ClutterVertex. Use
12368  *   clutter_vertex_free() to free the allocated resources
12369  *
12370  * Since: 1.0
12371  */
12372 ClutterVertex *
12373 clutter_vertex_copy (const ClutterVertex *vertex)
12374 {
12375   if (G_LIKELY (vertex != NULL))
12376     return g_slice_dup (ClutterVertex, vertex);
12377
12378   return NULL;
12379 }
12380
12381 /**
12382  * clutter_vertex_free:
12383  * @vertex: a #ClutterVertex
12384  *
12385  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12386  *
12387  * Since: 1.0
12388  */
12389 void
12390 clutter_vertex_free (ClutterVertex *vertex)
12391 {
12392   if (G_UNLIKELY (vertex != NULL))
12393     g_slice_free (ClutterVertex, vertex);
12394 }
12395
12396 /**
12397  * clutter_vertex_equal:
12398  * @vertex_a: a #ClutterVertex
12399  * @vertex_b: a #ClutterVertex
12400  *
12401  * Compares @vertex_a and @vertex_b for equality
12402  *
12403  * Return value: %TRUE if the passed #ClutterVertex are equal
12404  *
12405  * Since: 1.0
12406  */
12407 gboolean
12408 clutter_vertex_equal (const ClutterVertex *vertex_a,
12409                       const ClutterVertex *vertex_b)
12410 {
12411   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12412
12413   if (vertex_a == vertex_b)
12414     return TRUE;
12415
12416   return vertex_a->x == vertex_b->x &&
12417          vertex_a->y == vertex_b->y &&
12418          vertex_a->z == vertex_b->z;
12419 }
12420
12421 static gboolean
12422 clutter_vertex_progress (const GValue *a,
12423                          const GValue *b,
12424                          gdouble       progress,
12425                          GValue       *retval)
12426 {
12427   const ClutterVertex *av = g_value_get_boxed (a);
12428   const ClutterVertex *bv = g_value_get_boxed (b);
12429   ClutterVertex res = { 0, };
12430
12431   res.x = av->x + (bv->x - av->x) * progress;
12432   res.y = av->y + (bv->y - av->y) * progress;
12433   res.z = av->z + (bv->z - av->z) * progress;
12434
12435   g_value_set_boxed (retval, &res);
12436
12437   return TRUE;
12438 }
12439
12440 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12441                                clutter_vertex_copy,
12442                                clutter_vertex_free,
12443                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12444
12445 /**
12446  * clutter_actor_is_rotated:
12447  * @self: a #ClutterActor
12448  *
12449  * Checks whether any rotation is applied to the actor.
12450  *
12451  * Return value: %TRUE if the actor is rotated.
12452  *
12453  * Since: 0.6
12454  */
12455 gboolean
12456 clutter_actor_is_rotated (ClutterActor *self)
12457 {
12458   const ClutterTransformInfo *info;
12459
12460   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12461
12462   info = _clutter_actor_get_transform_info_or_defaults (self);
12463
12464   if (info->rx_angle || info->ry_angle || info->rz_angle)
12465     return TRUE;
12466
12467   return FALSE;
12468 }
12469
12470 /**
12471  * clutter_actor_is_scaled:
12472  * @self: a #ClutterActor
12473  *
12474  * Checks whether the actor is scaled in either dimension.
12475  *
12476  * Return value: %TRUE if the actor is scaled.
12477  *
12478  * Since: 0.6
12479  */
12480 gboolean
12481 clutter_actor_is_scaled (ClutterActor *self)
12482 {
12483   const ClutterTransformInfo *info;
12484
12485   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12486
12487   info = _clutter_actor_get_transform_info_or_defaults (self);
12488
12489   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12490     return TRUE;
12491
12492   return FALSE;
12493 }
12494
12495 ClutterActor *
12496 _clutter_actor_get_stage_internal (ClutterActor *actor)
12497 {
12498   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12499     actor = actor->priv->parent;
12500
12501   return actor;
12502 }
12503
12504 /**
12505  * clutter_actor_get_stage:
12506  * @actor: a #ClutterActor
12507  *
12508  * Retrieves the #ClutterStage where @actor is contained.
12509  *
12510  * Return value: (transfer none) (type Clutter.Stage): the stage
12511  *   containing the actor, or %NULL
12512  *
12513  * Since: 0.8
12514  */
12515 ClutterActor *
12516 clutter_actor_get_stage (ClutterActor *actor)
12517 {
12518   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12519
12520   return _clutter_actor_get_stage_internal (actor);
12521 }
12522
12523 /**
12524  * clutter_actor_allocate_available_size:
12525  * @self: a #ClutterActor
12526  * @x: the actor's X coordinate
12527  * @y: the actor's Y coordinate
12528  * @available_width: the maximum available width, or -1 to use the
12529  *   actor's natural width
12530  * @available_height: the maximum available height, or -1 to use the
12531  *   actor's natural height
12532  * @flags: flags controlling the allocation
12533  *
12534  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12535  * preferred size, but limiting it to the maximum available width
12536  * and height provided.
12537  *
12538  * This function will do the right thing when dealing with the
12539  * actor's request mode.
12540  *
12541  * The implementation of this function is equivalent to:
12542  *
12543  * |[
12544  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12545  *     {
12546  *       clutter_actor_get_preferred_width (self, available_height,
12547  *                                          &amp;min_width,
12548  *                                          &amp;natural_width);
12549  *       width = CLAMP (natural_width, min_width, available_width);
12550  *
12551  *       clutter_actor_get_preferred_height (self, width,
12552  *                                           &amp;min_height,
12553  *                                           &amp;natural_height);
12554  *       height = CLAMP (natural_height, min_height, available_height);
12555  *     }
12556  *   else
12557  *     {
12558  *       clutter_actor_get_preferred_height (self, available_width,
12559  *                                           &amp;min_height,
12560  *                                           &amp;natural_height);
12561  *       height = CLAMP (natural_height, min_height, available_height);
12562  *
12563  *       clutter_actor_get_preferred_width (self, height,
12564  *                                          &amp;min_width,
12565  *                                          &amp;natural_width);
12566  *       width = CLAMP (natural_width, min_width, available_width);
12567  *     }
12568  *
12569  *   box.x1 = x; box.y1 = y;
12570  *   box.x2 = box.x1 + available_width;
12571  *   box.y2 = box.y1 + available_height;
12572  *   clutter_actor_allocate (self, &amp;box, flags);
12573  * ]|
12574  *
12575  * This function can be used by fluid layout managers to allocate
12576  * an actor's preferred size without making it bigger than the area
12577  * available for the container.
12578  *
12579  * Since: 1.0
12580  */
12581 void
12582 clutter_actor_allocate_available_size (ClutterActor           *self,
12583                                        gfloat                  x,
12584                                        gfloat                  y,
12585                                        gfloat                  available_width,
12586                                        gfloat                  available_height,
12587                                        ClutterAllocationFlags  flags)
12588 {
12589   ClutterActorPrivate *priv;
12590   gfloat width, height;
12591   gfloat min_width, min_height;
12592   gfloat natural_width, natural_height;
12593   ClutterActorBox box;
12594
12595   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12596
12597   priv = self->priv;
12598
12599   width = height = 0.0;
12600
12601   switch (priv->request_mode)
12602     {
12603     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12604       clutter_actor_get_preferred_width (self, available_height,
12605                                          &min_width,
12606                                          &natural_width);
12607       width  = CLAMP (natural_width, min_width, available_width);
12608
12609       clutter_actor_get_preferred_height (self, width,
12610                                           &min_height,
12611                                           &natural_height);
12612       height = CLAMP (natural_height, min_height, available_height);
12613       break;
12614
12615     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12616       clutter_actor_get_preferred_height (self, available_width,
12617                                           &min_height,
12618                                           &natural_height);
12619       height = CLAMP (natural_height, min_height, available_height);
12620
12621       clutter_actor_get_preferred_width (self, height,
12622                                          &min_width,
12623                                          &natural_width);
12624       width  = CLAMP (natural_width, min_width, available_width);
12625       break;
12626     }
12627
12628
12629   box.x1 = x;
12630   box.y1 = y;
12631   box.x2 = box.x1 + width;
12632   box.y2 = box.y1 + height;
12633   clutter_actor_allocate (self, &box, flags);
12634 }
12635
12636 /**
12637  * clutter_actor_allocate_preferred_size:
12638  * @self: a #ClutterActor
12639  * @flags: flags controlling the allocation
12640  *
12641  * Allocates the natural size of @self.
12642  *
12643  * This function is a utility call for #ClutterActor implementations
12644  * that allocates the actor's preferred natural size. It can be used
12645  * by fixed layout managers (like #ClutterGroup or so called
12646  * 'composite actors') inside the ClutterActor::allocate
12647  * implementation to give each child exactly how much space it
12648  * requires.
12649  *
12650  * This function is not meant to be used by applications. It is also
12651  * not meant to be used outside the implementation of the
12652  * ClutterActor::allocate virtual function.
12653  *
12654  * Since: 0.8
12655  */
12656 void
12657 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12658                                        ClutterAllocationFlags  flags)
12659 {
12660   gfloat actor_x, actor_y;
12661   gfloat natural_width, natural_height;
12662   ClutterActorBox actor_box;
12663
12664   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12665
12666   actor_x = clutter_actor_get_x (self);
12667   actor_y = clutter_actor_get_y (self);
12668
12669   clutter_actor_get_preferred_size (self,
12670                                     NULL, NULL,
12671                                     &natural_width,
12672                                     &natural_height);
12673
12674   actor_box.x1 = actor_x;
12675   actor_box.y1 = actor_y;
12676   actor_box.x2 = actor_box.x1 + natural_width;
12677   actor_box.y2 = actor_box.y1 + natural_height;
12678
12679   clutter_actor_allocate (self, &actor_box, flags);
12680 }
12681
12682 /**
12683  * clutter_actor_allocate_align_fill:
12684  * @self: a #ClutterActor
12685  * @box: a #ClutterActorBox, containing the available width and height
12686  * @x_align: the horizontal alignment, between 0 and 1
12687  * @y_align: the vertical alignment, between 0 and 1
12688  * @x_fill: whether the actor should fill horizontally
12689  * @y_fill: whether the actor should fill vertically
12690  * @flags: allocation flags to be passed to clutter_actor_allocate()
12691  *
12692  * Allocates @self by taking into consideration the available allocation
12693  * area; an alignment factor on either axis; and whether the actor should
12694  * fill the allocation on either axis.
12695  *
12696  * The @box should contain the available allocation width and height;
12697  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12698  * allocation will be offset by their value.
12699  *
12700  * This function takes into consideration the geometry request specified by
12701  * the #ClutterActor:request-mode property, and the text direction.
12702  *
12703  * This function is useful for fluid layout managers, like #ClutterBinLayout
12704  * or #ClutterTableLayout
12705  *
12706  * Since: 1.4
12707  */
12708 void
12709 clutter_actor_allocate_align_fill (ClutterActor           *self,
12710                                    const ClutterActorBox  *box,
12711                                    gdouble                 x_align,
12712                                    gdouble                 y_align,
12713                                    gboolean                x_fill,
12714                                    gboolean                y_fill,
12715                                    ClutterAllocationFlags  flags)
12716 {
12717   ClutterActorPrivate *priv;
12718   ClutterActorBox allocation = { 0, };
12719   gfloat x_offset, y_offset;
12720   gfloat available_width, available_height;
12721   gfloat child_width, child_height;
12722
12723   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12724   g_return_if_fail (box != NULL);
12725   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12726   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12727
12728   priv = self->priv;
12729
12730   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12731   clutter_actor_box_get_size (box, &available_width, &available_height);
12732
12733   if (available_width < 0)
12734     available_width = 0;
12735
12736   if (available_height < 0)
12737     available_height = 0;
12738
12739   if (x_fill)
12740     {
12741       allocation.x1 = x_offset;
12742       allocation.x2 = allocation.x1 + available_width;
12743     }
12744
12745   if (y_fill)
12746     {
12747       allocation.y1 = y_offset;
12748       allocation.y2 = allocation.y1 + available_height;
12749     }
12750
12751   /* if we are filling horizontally and vertically then we're done */
12752   if (x_fill && y_fill)
12753     goto out;
12754
12755   child_width = child_height = 0.0f;
12756
12757   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12758     {
12759       gfloat min_width, natural_width;
12760       gfloat min_height, natural_height;
12761
12762       clutter_actor_get_preferred_width (self, available_height,
12763                                          &min_width,
12764                                          &natural_width);
12765
12766       child_width = CLAMP (natural_width, min_width, available_width);
12767
12768       if (!y_fill)
12769         {
12770           clutter_actor_get_preferred_height (self, child_width,
12771                                               &min_height,
12772                                               &natural_height);
12773
12774           child_height = CLAMP (natural_height, min_height, available_height);
12775         }
12776     }
12777   else
12778     {
12779       gfloat min_width, natural_width;
12780       gfloat min_height, natural_height;
12781
12782       clutter_actor_get_preferred_height (self, available_width,
12783                                           &min_height,
12784                                           &natural_height);
12785
12786       child_height = CLAMP (natural_height, min_height, available_height);
12787
12788       if (!x_fill)
12789         {
12790           clutter_actor_get_preferred_width (self, child_height,
12791                                              &min_width,
12792                                              &natural_width);
12793
12794           child_width = CLAMP (natural_width, min_width, available_width);
12795         }
12796     }
12797
12798   /* invert the horizontal alignment for RTL languages */
12799   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12800     x_align = 1.0 - x_align;
12801
12802   if (!x_fill)
12803     {
12804       allocation.x1 = x_offset
12805                     + ((available_width - child_width) * x_align);
12806       allocation.x2 = allocation.x1 + child_width;
12807     }
12808
12809   if (!y_fill)
12810     {
12811       allocation.y1 = y_offset
12812                     + ((available_height - child_height) * y_align);
12813       allocation.y2 = allocation.y1 + child_height;
12814     }
12815
12816 out:
12817   clutter_actor_box_clamp_to_pixel (&allocation);
12818   clutter_actor_allocate (self, &allocation, flags);
12819 }
12820
12821 /**
12822  * clutter_actor_grab_key_focus:
12823  * @self: a #ClutterActor
12824  *
12825  * Sets the key focus of the #ClutterStage including @self
12826  * to this #ClutterActor.
12827  *
12828  * Since: 1.0
12829  */
12830 void
12831 clutter_actor_grab_key_focus (ClutterActor *self)
12832 {
12833   ClutterActor *stage;
12834
12835   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12836
12837   stage = _clutter_actor_get_stage_internal (self);
12838   if (stage != NULL)
12839     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12840 }
12841
12842 /**
12843  * clutter_actor_get_pango_context:
12844  * @self: a #ClutterActor
12845  *
12846  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12847  * is already configured using the appropriate font map, resolution
12848  * and font options.
12849  *
12850  * Unlike clutter_actor_create_pango_context(), this context is owend
12851  * by the #ClutterActor and it will be updated each time the options
12852  * stored by the #ClutterBackend change.
12853  *
12854  * You can use the returned #PangoContext to create a #PangoLayout
12855  * and render text using cogl_pango_render_layout() to reuse the
12856  * glyphs cache also used by Clutter.
12857  *
12858  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12859  *   The returned #PangoContext is owned by the actor and should not be
12860  *   unreferenced by the application code
12861  *
12862  * Since: 1.0
12863  */
12864 PangoContext *
12865 clutter_actor_get_pango_context (ClutterActor *self)
12866 {
12867   ClutterActorPrivate *priv;
12868
12869   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12870
12871   priv = self->priv;
12872
12873   if (priv->pango_context != NULL)
12874     return priv->pango_context;
12875
12876   priv->pango_context = _clutter_context_get_pango_context ();
12877   g_object_ref (priv->pango_context);
12878
12879   return priv->pango_context;
12880 }
12881
12882 /**
12883  * clutter_actor_create_pango_context:
12884  * @self: a #ClutterActor
12885  *
12886  * Creates a #PangoContext for the given actor. The #PangoContext
12887  * is already configured using the appropriate font map, resolution
12888  * and font options.
12889  *
12890  * See also clutter_actor_get_pango_context().
12891  *
12892  * Return value: (transfer full): the newly created #PangoContext.
12893  *   Use g_object_unref() on the returned value to deallocate its
12894  *   resources
12895  *
12896  * Since: 1.0
12897  */
12898 PangoContext *
12899 clutter_actor_create_pango_context (ClutterActor *self)
12900 {
12901   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12902
12903   return _clutter_context_create_pango_context ();
12904 }
12905
12906 /**
12907  * clutter_actor_create_pango_layout:
12908  * @self: a #ClutterActor
12909  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
12910  *
12911  * Creates a new #PangoLayout from the same #PangoContext used
12912  * by the #ClutterActor. The #PangoLayout is already configured
12913  * with the font map, resolution and font options, and the
12914  * given @text.
12915  *
12916  * If you want to keep around a #PangoLayout created by this
12917  * function you will have to connect to the #ClutterBackend::font-changed
12918  * and #ClutterBackend::resolution-changed signals, and call
12919  * pango_layout_context_changed() in response to them.
12920  *
12921  * Return value: (transfer full): the newly created #PangoLayout.
12922  *   Use g_object_unref() when done
12923  *
12924  * Since: 1.0
12925  */
12926 PangoLayout *
12927 clutter_actor_create_pango_layout (ClutterActor *self,
12928                                    const gchar  *text)
12929 {
12930   PangoContext *context;
12931   PangoLayout *layout;
12932
12933   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12934
12935   context = clutter_actor_get_pango_context (self);
12936   layout = pango_layout_new (context);
12937
12938   if (text)
12939     pango_layout_set_text (layout, text, -1);
12940
12941   return layout;
12942 }
12943
12944 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
12945  * ClutterOffscreenEffect.
12946  */
12947 void
12948 _clutter_actor_set_opacity_override (ClutterActor *self,
12949                                      gint          opacity)
12950 {
12951   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12952
12953   self->priv->opacity_override = opacity;
12954 }
12955
12956 gint
12957 _clutter_actor_get_opacity_override (ClutterActor *self)
12958 {
12959   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
12960
12961   return self->priv->opacity_override;
12962 }
12963
12964 /* Allows you to disable applying the actors model view transform during
12965  * a paint. Used by ClutterClone. */
12966 void
12967 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
12968                                                 gboolean      enable)
12969 {
12970   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12971
12972   self->priv->enable_model_view_transform = enable;
12973 }
12974
12975 void
12976 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
12977                                           gboolean      enable)
12978 {
12979   ClutterActorPrivate *priv;
12980
12981   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12982
12983   priv = self->priv;
12984
12985   priv->enable_paint_unmapped = enable;
12986
12987   if (priv->enable_paint_unmapped)
12988     {
12989       /* Make sure that the parents of the widget are realized first;
12990        * otherwise checks in clutter_actor_update_map_state() will
12991        * fail.
12992        */
12993       clutter_actor_realize (self);
12994
12995       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
12996     }
12997   else
12998     {
12999       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13000     }
13001 }
13002
13003 static void
13004 clutter_anchor_coord_get_units (ClutterActor      *self,
13005                                 const AnchorCoord *coord,
13006                                 gfloat            *x,
13007                                 gfloat            *y,
13008                                 gfloat            *z)
13009 {
13010   if (coord->is_fractional)
13011     {
13012       gfloat actor_width, actor_height;
13013
13014       clutter_actor_get_size (self, &actor_width, &actor_height);
13015
13016       if (x)
13017         *x = actor_width * coord->v.fraction.x;
13018
13019       if (y)
13020         *y = actor_height * coord->v.fraction.y;
13021
13022       if (z)
13023         *z = 0;
13024     }
13025   else
13026     {
13027       if (x)
13028         *x = coord->v.units.x;
13029
13030       if (y)
13031         *y = coord->v.units.y;
13032
13033       if (z)
13034         *z = coord->v.units.z;
13035     }
13036 }
13037
13038 static void
13039 clutter_anchor_coord_set_units (AnchorCoord *coord,
13040                                 gfloat       x,
13041                                 gfloat       y,
13042                                 gfloat       z)
13043 {
13044   coord->is_fractional = FALSE;
13045   coord->v.units.x = x;
13046   coord->v.units.y = y;
13047   coord->v.units.z = z;
13048 }
13049
13050 static ClutterGravity
13051 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13052 {
13053   if (coord->is_fractional)
13054     {
13055       if (coord->v.fraction.x == 0.0)
13056         {
13057           if (coord->v.fraction.y == 0.0)
13058             return CLUTTER_GRAVITY_NORTH_WEST;
13059           else if (coord->v.fraction.y == 0.5)
13060             return CLUTTER_GRAVITY_WEST;
13061           else if (coord->v.fraction.y == 1.0)
13062             return CLUTTER_GRAVITY_SOUTH_WEST;
13063           else
13064             return CLUTTER_GRAVITY_NONE;
13065         }
13066       else if (coord->v.fraction.x == 0.5)
13067         {
13068           if (coord->v.fraction.y == 0.0)
13069             return CLUTTER_GRAVITY_NORTH;
13070           else if (coord->v.fraction.y == 0.5)
13071             return CLUTTER_GRAVITY_CENTER;
13072           else if (coord->v.fraction.y == 1.0)
13073             return CLUTTER_GRAVITY_SOUTH;
13074           else
13075             return CLUTTER_GRAVITY_NONE;
13076         }
13077       else if (coord->v.fraction.x == 1.0)
13078         {
13079           if (coord->v.fraction.y == 0.0)
13080             return CLUTTER_GRAVITY_NORTH_EAST;
13081           else if (coord->v.fraction.y == 0.5)
13082             return CLUTTER_GRAVITY_EAST;
13083           else if (coord->v.fraction.y == 1.0)
13084             return CLUTTER_GRAVITY_SOUTH_EAST;
13085           else
13086             return CLUTTER_GRAVITY_NONE;
13087         }
13088       else
13089         return CLUTTER_GRAVITY_NONE;
13090     }
13091   else
13092     return CLUTTER_GRAVITY_NONE;
13093 }
13094
13095 static void
13096 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13097                                   ClutterGravity  gravity)
13098 {
13099   switch (gravity)
13100     {
13101     case CLUTTER_GRAVITY_NORTH:
13102       coord->v.fraction.x = 0.5;
13103       coord->v.fraction.y = 0.0;
13104       break;
13105
13106     case CLUTTER_GRAVITY_NORTH_EAST:
13107       coord->v.fraction.x = 1.0;
13108       coord->v.fraction.y = 0.0;
13109       break;
13110
13111     case CLUTTER_GRAVITY_EAST:
13112       coord->v.fraction.x = 1.0;
13113       coord->v.fraction.y = 0.5;
13114       break;
13115
13116     case CLUTTER_GRAVITY_SOUTH_EAST:
13117       coord->v.fraction.x = 1.0;
13118       coord->v.fraction.y = 1.0;
13119       break;
13120
13121     case CLUTTER_GRAVITY_SOUTH:
13122       coord->v.fraction.x = 0.5;
13123       coord->v.fraction.y = 1.0;
13124       break;
13125
13126     case CLUTTER_GRAVITY_SOUTH_WEST:
13127       coord->v.fraction.x = 0.0;
13128       coord->v.fraction.y = 1.0;
13129       break;
13130
13131     case CLUTTER_GRAVITY_WEST:
13132       coord->v.fraction.x = 0.0;
13133       coord->v.fraction.y = 0.5;
13134       break;
13135
13136     case CLUTTER_GRAVITY_NORTH_WEST:
13137       coord->v.fraction.x = 0.0;
13138       coord->v.fraction.y = 0.0;
13139       break;
13140
13141     case CLUTTER_GRAVITY_CENTER:
13142       coord->v.fraction.x = 0.5;
13143       coord->v.fraction.y = 0.5;
13144       break;
13145
13146     default:
13147       coord->v.fraction.x = 0.0;
13148       coord->v.fraction.y = 0.0;
13149       break;
13150     }
13151
13152   coord->is_fractional = TRUE;
13153 }
13154
13155 static gboolean
13156 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13157 {
13158   if (coord->is_fractional)
13159     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13160   else
13161     return (coord->v.units.x == 0.0
13162             && coord->v.units.y == 0.0
13163             && coord->v.units.z == 0.0);
13164 }
13165
13166 /**
13167  * clutter_actor_get_flags:
13168  * @self: a #ClutterActor
13169  *
13170  * Retrieves the flags set on @self
13171  *
13172  * Return value: a bitwise or of #ClutterActorFlags or 0
13173  *
13174  * Since: 1.0
13175  */
13176 ClutterActorFlags
13177 clutter_actor_get_flags (ClutterActor *self)
13178 {
13179   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13180
13181   return self->flags;
13182 }
13183
13184 /**
13185  * clutter_actor_set_flags:
13186  * @self: a #ClutterActor
13187  * @flags: the flags to set
13188  *
13189  * Sets @flags on @self
13190  *
13191  * This function will emit notifications for the changed properties
13192  *
13193  * Since: 1.0
13194  */
13195 void
13196 clutter_actor_set_flags (ClutterActor      *self,
13197                          ClutterActorFlags  flags)
13198 {
13199   ClutterActorFlags old_flags;
13200   GObject *obj;
13201   gboolean was_reactive_set, reactive_set;
13202   gboolean was_realized_set, realized_set;
13203   gboolean was_mapped_set, mapped_set;
13204   gboolean was_visible_set, visible_set;
13205
13206   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13207
13208   if (self->flags == flags)
13209     return;
13210
13211   obj = G_OBJECT (self);
13212   g_object_ref (obj);
13213   g_object_freeze_notify (obj);
13214
13215   old_flags = self->flags;
13216
13217   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13218   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13219   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13220   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13221
13222   self->flags |= flags;
13223
13224   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13225   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13226   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13227   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13228
13229   if (reactive_set != was_reactive_set)
13230     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13231
13232   if (realized_set != was_realized_set)
13233     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13234
13235   if (mapped_set != was_mapped_set)
13236     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13237
13238   if (visible_set != was_visible_set)
13239     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13240
13241   g_object_thaw_notify (obj);
13242   g_object_unref (obj);
13243 }
13244
13245 /**
13246  * clutter_actor_unset_flags:
13247  * @self: a #ClutterActor
13248  * @flags: the flags to unset
13249  *
13250  * Unsets @flags on @self
13251  *
13252  * This function will emit notifications for the changed properties
13253  *
13254  * Since: 1.0
13255  */
13256 void
13257 clutter_actor_unset_flags (ClutterActor      *self,
13258                            ClutterActorFlags  flags)
13259 {
13260   ClutterActorFlags old_flags;
13261   GObject *obj;
13262   gboolean was_reactive_set, reactive_set;
13263   gboolean was_realized_set, realized_set;
13264   gboolean was_mapped_set, mapped_set;
13265   gboolean was_visible_set, visible_set;
13266
13267   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13268
13269   obj = G_OBJECT (self);
13270   g_object_freeze_notify (obj);
13271
13272   old_flags = self->flags;
13273
13274   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13275   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13276   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13277   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13278
13279   self->flags &= ~flags;
13280
13281   if (self->flags == old_flags)
13282     return;
13283
13284   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13285   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13286   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13287   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13288
13289   if (reactive_set != was_reactive_set)
13290     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13291
13292   if (realized_set != was_realized_set)
13293     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13294
13295   if (mapped_set != was_mapped_set)
13296     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13297
13298   if (visible_set != was_visible_set)
13299     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13300
13301   g_object_thaw_notify (obj);
13302 }
13303
13304 /**
13305  * clutter_actor_get_transformation_matrix:
13306  * @self: a #ClutterActor
13307  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13308  *
13309  * Retrieves the transformations applied to @self relative to its
13310  * parent.
13311  *
13312  * Since: 1.0
13313  */
13314 void
13315 clutter_actor_get_transformation_matrix (ClutterActor *self,
13316                                          CoglMatrix   *matrix)
13317 {
13318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13319
13320   cogl_matrix_init_identity (matrix);
13321
13322   _clutter_actor_apply_modelview_transform (self, matrix);
13323 }
13324
13325 void
13326 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13327                                    gboolean      is_in_clone_paint)
13328 {
13329   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13330   self->priv->in_clone_paint = is_in_clone_paint;
13331 }
13332
13333 /**
13334  * clutter_actor_is_in_clone_paint:
13335  * @self: a #ClutterActor
13336  *
13337  * Checks whether @self is being currently painted by a #ClutterClone
13338  *
13339  * This function is useful only inside the ::paint virtual function
13340  * implementations or within handlers for the #ClutterActor::paint
13341  * signal
13342  *
13343  * This function should not be used by applications
13344  *
13345  * Return value: %TRUE if the #ClutterActor is currently being painted
13346  *   by a #ClutterClone, and %FALSE otherwise
13347  *
13348  * Since: 1.0
13349  */
13350 gboolean
13351 clutter_actor_is_in_clone_paint (ClutterActor *self)
13352 {
13353   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13354
13355   return self->priv->in_clone_paint;
13356 }
13357
13358 static gboolean
13359 set_direction_recursive (ClutterActor *actor,
13360                          gpointer      user_data)
13361 {
13362   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13363
13364   clutter_actor_set_text_direction (actor, text_dir);
13365
13366   return TRUE;
13367 }
13368
13369 /**
13370  * clutter_actor_set_text_direction:
13371  * @self: a #ClutterActor
13372  * @text_dir: the text direction for @self
13373  *
13374  * Sets the #ClutterTextDirection for an actor
13375  *
13376  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13377  *
13378  * If @self implements #ClutterContainer then this function will recurse
13379  * inside all the children of @self (including the internal ones).
13380  *
13381  * Composite actors not implementing #ClutterContainer, or actors requiring
13382  * special handling when the text direction changes, should connect to
13383  * the #GObject::notify signal for the #ClutterActor:text-direction property
13384  *
13385  * Since: 1.2
13386  */
13387 void
13388 clutter_actor_set_text_direction (ClutterActor         *self,
13389                                   ClutterTextDirection  text_dir)
13390 {
13391   ClutterActorPrivate *priv;
13392
13393   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13394   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13395
13396   priv = self->priv;
13397
13398   if (priv->text_direction != text_dir)
13399     {
13400       priv->text_direction = text_dir;
13401
13402       /* we need to emit the notify::text-direction first, so that
13403        * the sub-classes can catch that and do specific handling of
13404        * the text direction; see clutter_text_direction_changed_cb()
13405        * inside clutter-text.c
13406        */
13407       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13408
13409       _clutter_actor_foreach_child (self, set_direction_recursive,
13410                                     GINT_TO_POINTER (text_dir));
13411
13412       clutter_actor_queue_relayout (self);
13413     }
13414 }
13415
13416 void
13417 _clutter_actor_set_has_pointer (ClutterActor *self,
13418                                 gboolean      has_pointer)
13419 {
13420   ClutterActorPrivate *priv = self->priv;
13421
13422   if (priv->has_pointer != has_pointer)
13423     {
13424       priv->has_pointer = has_pointer;
13425
13426       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13427     }
13428 }
13429
13430 /**
13431  * clutter_actor_get_text_direction:
13432  * @self: a #ClutterActor
13433  *
13434  * Retrieves the value set using clutter_actor_set_text_direction()
13435  *
13436  * If no text direction has been previously set, the default text
13437  * direction, as returned by clutter_get_default_text_direction(), will
13438  * be returned instead
13439  *
13440  * Return value: the #ClutterTextDirection for the actor
13441  *
13442  * Since: 1.2
13443  */
13444 ClutterTextDirection
13445 clutter_actor_get_text_direction (ClutterActor *self)
13446 {
13447   ClutterActorPrivate *priv;
13448
13449   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13450                         CLUTTER_TEXT_DIRECTION_LTR);
13451
13452   priv = self->priv;
13453
13454   /* if no direction has been set yet use the default */
13455   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13456     priv->text_direction = clutter_get_default_text_direction ();
13457
13458   return priv->text_direction;
13459 }
13460
13461 /**
13462  * clutter_actor_push_internal:
13463  * @self: a #ClutterActor
13464  *
13465  * Should be used by actors implementing the #ClutterContainer and with
13466  * internal children added through clutter_actor_set_parent(), for instance:
13467  *
13468  * |[
13469  *   static void
13470  *   my_actor_init (MyActor *self)
13471  *   {
13472  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13473  *
13474  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13475  *
13476  *     /&ast; calling clutter_actor_set_parent() now will result in
13477  *      &ast; the internal flag being set on a child of MyActor
13478  *      &ast;/
13479  *
13480  *     /&ast; internal child - a background texture &ast;/
13481  *     self->priv->background_tex = clutter_texture_new ();
13482  *     clutter_actor_set_parent (self->priv->background_tex,
13483  *                               CLUTTER_ACTOR (self));
13484  *
13485  *     /&ast; internal child - a label &ast;/
13486  *     self->priv->label = clutter_text_new ();
13487  *     clutter_actor_set_parent (self->priv->label,
13488  *                               CLUTTER_ACTOR (self));
13489  *
13490  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13491  *
13492  *     /&ast; calling clutter_actor_set_parent() now will not result in
13493  *      &ast; the internal flag being set on a child of MyActor
13494  *      &ast;/
13495  *   }
13496  * ]|
13497  *
13498  * This function will be used by Clutter to toggle an "internal child"
13499  * flag whenever clutter_actor_set_parent() is called; internal children
13500  * are handled differently by Clutter, specifically when destroying their
13501  * parent.
13502  *
13503  * Call clutter_actor_pop_internal() when you finished adding internal
13504  * children.
13505  *
13506  * Nested calls to clutter_actor_push_internal() are allowed, but each
13507  * one must by followed by a clutter_actor_pop_internal() call.
13508  *
13509  * Since: 1.2
13510  *
13511  * Deprecated: 1.10: All children of an actor are accessible through
13512  *   the #ClutterActor API, and #ClutterActor implements the
13513  *   #ClutterContainer interface, so this function is only useful
13514  *   for legacy containers overriding the default implementation.
13515  */
13516 void
13517 clutter_actor_push_internal (ClutterActor *self)
13518 {
13519   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13520
13521   self->priv->internal_child += 1;
13522 }
13523
13524 /**
13525  * clutter_actor_pop_internal:
13526  * @self: a #ClutterActor
13527  *
13528  * Disables the effects of clutter_actor_push_internal().
13529  *
13530  * Since: 1.2
13531  *
13532  * Deprecated: 1.10: All children of an actor are accessible through
13533  *   the #ClutterActor API. This function is only useful for legacy
13534  *   containers overriding the default implementation of the
13535  *   #ClutterContainer interface.
13536  */
13537 void
13538 clutter_actor_pop_internal (ClutterActor *self)
13539 {
13540   ClutterActorPrivate *priv;
13541
13542   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13543
13544   priv = self->priv;
13545
13546   if (priv->internal_child == 0)
13547     {
13548       g_warning ("Mismatched %s: you need to call "
13549                  "clutter_actor_push_composite() at least once before "
13550                  "calling this function", G_STRFUNC);
13551       return;
13552     }
13553
13554   priv->internal_child -= 1;
13555 }
13556
13557 /**
13558  * clutter_actor_has_pointer:
13559  * @self: a #ClutterActor
13560  *
13561  * Checks whether an actor contains the pointer of a
13562  * #ClutterInputDevice
13563  *
13564  * Return value: %TRUE if the actor contains the pointer, and
13565  *   %FALSE otherwise
13566  *
13567  * Since: 1.2
13568  */
13569 gboolean
13570 clutter_actor_has_pointer (ClutterActor *self)
13571 {
13572   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13573
13574   return self->priv->has_pointer;
13575 }
13576
13577 /* XXX: This is a workaround for not being able to break the ABI of
13578  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13579  * clutter_actor_queue_clipped_redraw() for details.
13580  */
13581 ClutterPaintVolume *
13582 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13583 {
13584   return g_object_get_data (G_OBJECT (self),
13585                             "-clutter-actor-queue-redraw-clip");
13586 }
13587
13588 void
13589 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13590                                       ClutterPaintVolume *clip)
13591 {
13592   g_object_set_data (G_OBJECT (self),
13593                      "-clutter-actor-queue-redraw-clip",
13594                      clip);
13595 }
13596
13597 /**
13598  * clutter_actor_has_allocation:
13599  * @self: a #ClutterActor
13600  *
13601  * Checks if the actor has an up-to-date allocation assigned to
13602  * it. This means that the actor should have an allocation: it's
13603  * visible and has a parent. It also means that there is no
13604  * outstanding relayout request in progress for the actor or its
13605  * children (There might be other outstanding layout requests in
13606  * progress that will cause the actor to get a new allocation
13607  * when the stage is laid out, however).
13608  *
13609  * If this function returns %FALSE, then the actor will normally
13610  * be allocated before it is next drawn on the screen.
13611  *
13612  * Return value: %TRUE if the actor has an up-to-date allocation
13613  *
13614  * Since: 1.4
13615  */
13616 gboolean
13617 clutter_actor_has_allocation (ClutterActor *self)
13618 {
13619   ClutterActorPrivate *priv;
13620
13621   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13622
13623   priv = self->priv;
13624
13625   return priv->parent != NULL &&
13626          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13627          !priv->needs_allocation;
13628 }
13629
13630 /**
13631  * clutter_actor_add_action:
13632  * @self: a #ClutterActor
13633  * @action: a #ClutterAction
13634  *
13635  * Adds @action to the list of actions applied to @self
13636  *
13637  * A #ClutterAction can only belong to one actor at a time
13638  *
13639  * The #ClutterActor will hold a reference on @action until either
13640  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13641  * is called
13642  *
13643  * Since: 1.4
13644  */
13645 void
13646 clutter_actor_add_action (ClutterActor  *self,
13647                           ClutterAction *action)
13648 {
13649   ClutterActorPrivate *priv;
13650
13651   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13652   g_return_if_fail (CLUTTER_IS_ACTION (action));
13653
13654   priv = self->priv;
13655
13656   if (priv->actions == NULL)
13657     {
13658       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13659       priv->actions->actor = self;
13660     }
13661
13662   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13663
13664   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13665 }
13666
13667 /**
13668  * clutter_actor_add_action_with_name:
13669  * @self: a #ClutterActor
13670  * @name: the name to set on the action
13671  * @action: a #ClutterAction
13672  *
13673  * A convenience function for setting the name of a #ClutterAction
13674  * while adding it to the list of actions applied to @self
13675  *
13676  * This function is the logical equivalent of:
13677  *
13678  * |[
13679  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13680  *   clutter_actor_add_action (self, action);
13681  * ]|
13682  *
13683  * Since: 1.4
13684  */
13685 void
13686 clutter_actor_add_action_with_name (ClutterActor  *self,
13687                                     const gchar   *name,
13688                                     ClutterAction *action)
13689 {
13690   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13691   g_return_if_fail (name != NULL);
13692   g_return_if_fail (CLUTTER_IS_ACTION (action));
13693
13694   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13695   clutter_actor_add_action (self, action);
13696 }
13697
13698 /**
13699  * clutter_actor_remove_action:
13700  * @self: a #ClutterActor
13701  * @action: a #ClutterAction
13702  *
13703  * Removes @action from the list of actions applied to @self
13704  *
13705  * The reference held by @self on the #ClutterAction will be released
13706  *
13707  * Since: 1.4
13708  */
13709 void
13710 clutter_actor_remove_action (ClutterActor  *self,
13711                              ClutterAction *action)
13712 {
13713   ClutterActorPrivate *priv;
13714
13715   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13716   g_return_if_fail (CLUTTER_IS_ACTION (action));
13717
13718   priv = self->priv;
13719
13720   if (priv->actions == NULL)
13721     return;
13722
13723   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13724
13725   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13726 }
13727
13728 /**
13729  * clutter_actor_remove_action_by_name:
13730  * @self: a #ClutterActor
13731  * @name: the name of the action to remove
13732  *
13733  * Removes the #ClutterAction with the given name from the list
13734  * of actions applied to @self
13735  *
13736  * Since: 1.4
13737  */
13738 void
13739 clutter_actor_remove_action_by_name (ClutterActor *self,
13740                                      const gchar  *name)
13741 {
13742   ClutterActorPrivate *priv;
13743   ClutterActorMeta *meta;
13744
13745   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13746   g_return_if_fail (name != NULL);
13747
13748   priv = self->priv;
13749
13750   if (priv->actions == NULL)
13751     return;
13752
13753   meta = _clutter_meta_group_get_meta (priv->actions, name);
13754   if (meta == NULL)
13755     return;
13756
13757   _clutter_meta_group_remove_meta (priv->actions, meta);
13758
13759   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13760 }
13761
13762 /**
13763  * clutter_actor_get_actions:
13764  * @self: a #ClutterActor
13765  *
13766  * Retrieves the list of actions applied to @self
13767  *
13768  * Return value: (transfer container) (element-type Clutter.Action): a copy
13769  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13770  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13771  *   allocated by the returned #GList
13772  *
13773  * Since: 1.4
13774  */
13775 GList *
13776 clutter_actor_get_actions (ClutterActor *self)
13777 {
13778   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13779
13780   if (self->priv->actions == NULL)
13781     return NULL;
13782
13783   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13784 }
13785
13786 /**
13787  * clutter_actor_get_action:
13788  * @self: a #ClutterActor
13789  * @name: the name of the action to retrieve
13790  *
13791  * Retrieves the #ClutterAction with the given name in the list
13792  * of actions applied to @self
13793  *
13794  * Return value: (transfer none): a #ClutterAction for the given
13795  *   name, or %NULL. The returned #ClutterAction is owned by the
13796  *   actor and it should not be unreferenced directly
13797  *
13798  * Since: 1.4
13799  */
13800 ClutterAction *
13801 clutter_actor_get_action (ClutterActor *self,
13802                           const gchar  *name)
13803 {
13804   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13805   g_return_val_if_fail (name != NULL, NULL);
13806
13807   if (self->priv->actions == NULL)
13808     return NULL;
13809
13810   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13811 }
13812
13813 /**
13814  * clutter_actor_clear_actions:
13815  * @self: a #ClutterActor
13816  *
13817  * Clears the list of actions applied to @self
13818  *
13819  * Since: 1.4
13820  */
13821 void
13822 clutter_actor_clear_actions (ClutterActor *self)
13823 {
13824   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13825
13826   if (self->priv->actions == NULL)
13827     return;
13828
13829   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13830 }
13831
13832 /**
13833  * clutter_actor_add_constraint:
13834  * @self: a #ClutterActor
13835  * @constraint: a #ClutterConstraint
13836  *
13837  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13838  * to @self
13839  *
13840  * The #ClutterActor will hold a reference on the @constraint until
13841  * either clutter_actor_remove_constraint() or
13842  * clutter_actor_clear_constraints() is called.
13843  *
13844  * Since: 1.4
13845  */
13846 void
13847 clutter_actor_add_constraint (ClutterActor      *self,
13848                               ClutterConstraint *constraint)
13849 {
13850   ClutterActorPrivate *priv;
13851
13852   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13853   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13854
13855   priv = self->priv;
13856
13857   if (priv->constraints == NULL)
13858     {
13859       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13860       priv->constraints->actor = self;
13861     }
13862
13863   _clutter_meta_group_add_meta (priv->constraints,
13864                                 CLUTTER_ACTOR_META (constraint));
13865   clutter_actor_queue_relayout (self);
13866
13867   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13868 }
13869
13870 /**
13871  * clutter_actor_add_constraint_with_name:
13872  * @self: a #ClutterActor
13873  * @name: the name to set on the constraint
13874  * @constraint: a #ClutterConstraint
13875  *
13876  * A convenience function for setting the name of a #ClutterConstraint
13877  * while adding it to the list of constraints applied to @self
13878  *
13879  * This function is the logical equivalent of:
13880  *
13881  * |[
13882  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13883  *   clutter_actor_add_constraint (self, constraint);
13884  * ]|
13885  *
13886  * Since: 1.4
13887  */
13888 void
13889 clutter_actor_add_constraint_with_name (ClutterActor      *self,
13890                                         const gchar       *name,
13891                                         ClutterConstraint *constraint)
13892 {
13893   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13894   g_return_if_fail (name != NULL);
13895   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13896
13897   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13898   clutter_actor_add_constraint (self, constraint);
13899 }
13900
13901 /**
13902  * clutter_actor_remove_constraint:
13903  * @self: a #ClutterActor
13904  * @constraint: a #ClutterConstraint
13905  *
13906  * Removes @constraint from the list of constraints applied to @self
13907  *
13908  * The reference held by @self on the #ClutterConstraint will be released
13909  *
13910  * Since: 1.4
13911  */
13912 void
13913 clutter_actor_remove_constraint (ClutterActor      *self,
13914                                  ClutterConstraint *constraint)
13915 {
13916   ClutterActorPrivate *priv;
13917
13918   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13919   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13920
13921   priv = self->priv;
13922
13923   if (priv->constraints == NULL)
13924     return;
13925
13926   _clutter_meta_group_remove_meta (priv->constraints,
13927                                    CLUTTER_ACTOR_META (constraint));
13928   clutter_actor_queue_relayout (self);
13929
13930   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13931 }
13932
13933 /**
13934  * clutter_actor_remove_constraint_by_name:
13935  * @self: a #ClutterActor
13936  * @name: the name of the constraint to remove
13937  *
13938  * Removes the #ClutterConstraint with the given name from the list
13939  * of constraints applied to @self
13940  *
13941  * Since: 1.4
13942  */
13943 void
13944 clutter_actor_remove_constraint_by_name (ClutterActor *self,
13945                                          const gchar  *name)
13946 {
13947   ClutterActorPrivate *priv;
13948   ClutterActorMeta *meta;
13949
13950   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13951   g_return_if_fail (name != NULL);
13952
13953   priv = self->priv;
13954
13955   if (priv->constraints == NULL)
13956     return;
13957
13958   meta = _clutter_meta_group_get_meta (priv->constraints, name);
13959   if (meta == NULL)
13960     return;
13961
13962   _clutter_meta_group_remove_meta (priv->constraints, meta);
13963   clutter_actor_queue_relayout (self);
13964 }
13965
13966 /**
13967  * clutter_actor_get_constraints:
13968  * @self: a #ClutterActor
13969  *
13970  * Retrieves the list of constraints applied to @self
13971  *
13972  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
13973  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
13974  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13975  *   allocated by the returned #GList
13976  *
13977  * Since: 1.4
13978  */
13979 GList *
13980 clutter_actor_get_constraints (ClutterActor *self)
13981 {
13982   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13983
13984   if (self->priv->constraints == NULL)
13985     return NULL;
13986
13987   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
13988 }
13989
13990 /**
13991  * clutter_actor_get_constraint:
13992  * @self: a #ClutterActor
13993  * @name: the name of the constraint to retrieve
13994  *
13995  * Retrieves the #ClutterConstraint with the given name in the list
13996  * of constraints applied to @self
13997  *
13998  * Return value: (transfer none): a #ClutterConstraint for the given
13999  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14000  *   actor and it should not be unreferenced directly
14001  *
14002  * Since: 1.4
14003  */
14004 ClutterConstraint *
14005 clutter_actor_get_constraint (ClutterActor *self,
14006                               const gchar  *name)
14007 {
14008   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14009   g_return_val_if_fail (name != NULL, NULL);
14010
14011   if (self->priv->constraints == NULL)
14012     return NULL;
14013
14014   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14015 }
14016
14017 /**
14018  * clutter_actor_clear_constraints:
14019  * @self: a #ClutterActor
14020  *
14021  * Clears the list of constraints applied to @self
14022  *
14023  * Since: 1.4
14024  */
14025 void
14026 clutter_actor_clear_constraints (ClutterActor *self)
14027 {
14028   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14029
14030   if (self->priv->constraints == NULL)
14031     return;
14032
14033   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14034
14035   clutter_actor_queue_relayout (self);
14036 }
14037
14038 /**
14039  * clutter_actor_set_clip_to_allocation:
14040  * @self: a #ClutterActor
14041  * @clip_set: %TRUE to apply a clip tracking the allocation
14042  *
14043  * Sets whether @self should be clipped to the same size as its
14044  * allocation
14045  *
14046  * Since: 1.4
14047  */
14048 void
14049 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14050                                       gboolean      clip_set)
14051 {
14052   ClutterActorPrivate *priv;
14053
14054   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14055
14056   clip_set = !!clip_set;
14057
14058   priv = self->priv;
14059
14060   if (priv->clip_to_allocation != clip_set)
14061     {
14062       priv->clip_to_allocation = clip_set;
14063
14064       clutter_actor_queue_redraw (self);
14065
14066       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14067     }
14068 }
14069
14070 /**
14071  * clutter_actor_get_clip_to_allocation:
14072  * @self: a #ClutterActor
14073  *
14074  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14075  *
14076  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14077  *
14078  * Since: 1.4
14079  */
14080 gboolean
14081 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14082 {
14083   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14084
14085   return self->priv->clip_to_allocation;
14086 }
14087
14088 /**
14089  * clutter_actor_add_effect:
14090  * @self: a #ClutterActor
14091  * @effect: a #ClutterEffect
14092  *
14093  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14094  *
14095  * The #ClutterActor will hold a reference on the @effect until either
14096  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14097  * called.
14098  *
14099  * Since: 1.4
14100  */
14101 void
14102 clutter_actor_add_effect (ClutterActor  *self,
14103                           ClutterEffect *effect)
14104 {
14105   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14106   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14107
14108   _clutter_actor_add_effect_internal (self, effect);
14109
14110   clutter_actor_queue_redraw (self);
14111
14112   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14113 }
14114
14115 /**
14116  * clutter_actor_add_effect_with_name:
14117  * @self: a #ClutterActor
14118  * @name: the name to set on the effect
14119  * @effect: a #ClutterEffect
14120  *
14121  * A convenience function for setting the name of a #ClutterEffect
14122  * while adding it to the list of effectss applied to @self
14123  *
14124  * This function is the logical equivalent of:
14125  *
14126  * |[
14127  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14128  *   clutter_actor_add_effect (self, effect);
14129  * ]|
14130  *
14131  * Since: 1.4
14132  */
14133 void
14134 clutter_actor_add_effect_with_name (ClutterActor  *self,
14135                                     const gchar   *name,
14136                                     ClutterEffect *effect)
14137 {
14138   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14139   g_return_if_fail (name != NULL);
14140   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14141
14142   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14143   clutter_actor_add_effect (self, effect);
14144 }
14145
14146 /**
14147  * clutter_actor_remove_effect:
14148  * @self: a #ClutterActor
14149  * @effect: a #ClutterEffect
14150  *
14151  * Removes @effect from the list of effects applied to @self
14152  *
14153  * The reference held by @self on the #ClutterEffect will be released
14154  *
14155  * Since: 1.4
14156  */
14157 void
14158 clutter_actor_remove_effect (ClutterActor  *self,
14159                              ClutterEffect *effect)
14160 {
14161   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14162   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14163
14164   _clutter_actor_remove_effect_internal (self, effect);
14165
14166   clutter_actor_queue_redraw (self);
14167
14168   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14169 }
14170
14171 /**
14172  * clutter_actor_remove_effect_by_name:
14173  * @self: a #ClutterActor
14174  * @name: the name of the effect to remove
14175  *
14176  * Removes the #ClutterEffect with the given name from the list
14177  * of effects applied to @self
14178  *
14179  * Since: 1.4
14180  */
14181 void
14182 clutter_actor_remove_effect_by_name (ClutterActor *self,
14183                                      const gchar  *name)
14184 {
14185   ClutterActorPrivate *priv;
14186   ClutterActorMeta *meta;
14187
14188   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14189   g_return_if_fail (name != NULL);
14190
14191   priv = self->priv;
14192
14193   if (priv->effects == NULL)
14194     return;
14195
14196   meta = _clutter_meta_group_get_meta (priv->effects, name);
14197   if (meta == NULL)
14198     return;
14199
14200   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14201 }
14202
14203 /**
14204  * clutter_actor_get_effects:
14205  * @self: a #ClutterActor
14206  *
14207  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14208  *
14209  * Return value: (transfer container) (element-type Clutter.Effect): a list
14210  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14211  *   list are owned by Clutter and they should not be freed. You should
14212  *   free the returned list using g_list_free() when done
14213  *
14214  * Since: 1.4
14215  */
14216 GList *
14217 clutter_actor_get_effects (ClutterActor *self)
14218 {
14219   ClutterActorPrivate *priv;
14220
14221   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14222
14223   priv = self->priv;
14224
14225   if (priv->effects == NULL)
14226     return NULL;
14227
14228   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14229 }
14230
14231 /**
14232  * clutter_actor_get_effect:
14233  * @self: a #ClutterActor
14234  * @name: the name of the effect to retrieve
14235  *
14236  * Retrieves the #ClutterEffect with the given name in the list
14237  * of effects applied to @self
14238  *
14239  * Return value: (transfer none): a #ClutterEffect for the given
14240  *   name, or %NULL. The returned #ClutterEffect is owned by the
14241  *   actor and it should not be unreferenced directly
14242  *
14243  * Since: 1.4
14244  */
14245 ClutterEffect *
14246 clutter_actor_get_effect (ClutterActor *self,
14247                           const gchar  *name)
14248 {
14249   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14250   g_return_val_if_fail (name != NULL, NULL);
14251
14252   if (self->priv->effects == NULL)
14253     return NULL;
14254
14255   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14256 }
14257
14258 /**
14259  * clutter_actor_clear_effects:
14260  * @self: a #ClutterActor
14261  *
14262  * Clears the list of effects applied to @self
14263  *
14264  * Since: 1.4
14265  */
14266 void
14267 clutter_actor_clear_effects (ClutterActor *self)
14268 {
14269   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14270
14271   if (self->priv->effects == NULL)
14272     return;
14273
14274   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14275
14276   clutter_actor_queue_redraw (self);
14277 }
14278
14279 /**
14280  * clutter_actor_has_key_focus:
14281  * @self: a #ClutterActor
14282  *
14283  * Checks whether @self is the #ClutterActor that has key focus
14284  *
14285  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14286  *
14287  * Since: 1.4
14288  */
14289 gboolean
14290 clutter_actor_has_key_focus (ClutterActor *self)
14291 {
14292   ClutterActor *stage;
14293
14294   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14295
14296   stage = _clutter_actor_get_stage_internal (self);
14297   if (stage == NULL)
14298     return FALSE;
14299
14300   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14301 }
14302
14303 static gboolean
14304 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14305                                       ClutterPaintVolume *pv)
14306 {
14307   ClutterActorPrivate *priv = self->priv;
14308
14309   /* Actors are only expected to report a valid paint volume
14310    * while they have a valid allocation. */
14311   if (G_UNLIKELY (priv->needs_allocation))
14312     {
14313       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14314                     "Actor needs allocation",
14315                     _clutter_actor_get_debug_name (self));
14316       return FALSE;
14317     }
14318
14319   /* Check if there are any handlers connected to the paint
14320    * signal. If there are then all bets are off for what the paint
14321    * volume for this actor might possibly be!
14322    *
14323    * XXX: It's expected that this is going to end up being quite a
14324    * costly check to have to do here, but we haven't come up with
14325    * another solution that can reliably catch paint signal handlers at
14326    * the right time to either avoid artefacts due to invalid stage
14327    * clipping or due to incorrect culling.
14328    *
14329    * Previously we checked in clutter_actor_paint(), but at that time
14330    * we may already be using a stage clip that could be derived from
14331    * an invalid paint-volume. We used to try and handle that by
14332    * queuing a follow up, unclipped, redraw but still the previous
14333    * checking wasn't enough to catch invalid volumes involved in
14334    * culling (considering that containers may derive their volume from
14335    * children that haven't yet been painted)
14336    *
14337    * Longer term, improved solutions could be:
14338    * - Disallow painting in the paint signal, only allow using it
14339    *   for tracking when paints happen. We can add another API that
14340    *   allows monkey patching the paint of arbitrary actors but in a
14341    *   more controlled way and that also supports modifying the
14342    *   paint-volume.
14343    * - If we could be notified somehow when signal handlers are
14344    *   connected we wouldn't have to poll for handlers like this.
14345    */
14346   if (g_signal_has_handler_pending (self,
14347                                     actor_signals[PAINT],
14348                                     0,
14349                                     TRUE))
14350     {
14351       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14352                     "Actor has \"paint\" signal handlers",
14353                     _clutter_actor_get_debug_name (self));
14354       return FALSE;
14355     }
14356
14357   _clutter_paint_volume_init_static (pv, self);
14358
14359   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14360     {
14361       clutter_paint_volume_free (pv);
14362       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14363                     "Actor failed to report a volume",
14364                     _clutter_actor_get_debug_name (self));
14365       return FALSE;
14366     }
14367
14368   /* since effects can modify the paint volume, we allow them to actually
14369    * do this by making get_paint_volume() "context sensitive"
14370    */
14371   if (priv->effects != NULL)
14372     {
14373       if (priv->current_effect != NULL)
14374         {
14375           const GList *effects, *l;
14376
14377           /* if we are being called from within the paint sequence of
14378            * an actor, get the paint volume up to the current effect
14379            */
14380           effects = _clutter_meta_group_peek_metas (priv->effects);
14381           for (l = effects;
14382                l != NULL || (l != NULL && l->data != priv->current_effect);
14383                l = l->next)
14384             {
14385               if (!_clutter_effect_get_paint_volume (l->data, pv))
14386                 {
14387                   clutter_paint_volume_free (pv);
14388                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14389                                 "Effect (%s) failed to report a volume",
14390                                 _clutter_actor_get_debug_name (self),
14391                                 _clutter_actor_meta_get_debug_name (l->data));
14392                   return FALSE;
14393                 }
14394             }
14395         }
14396       else
14397         {
14398           const GList *effects, *l;
14399
14400           /* otherwise, get the cumulative volume */
14401           effects = _clutter_meta_group_peek_metas (priv->effects);
14402           for (l = effects; l != NULL; l = l->next)
14403             if (!_clutter_effect_get_paint_volume (l->data, pv))
14404               {
14405                 clutter_paint_volume_free (pv);
14406                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14407                               "Effect (%s) failed to report a volume",
14408                               _clutter_actor_get_debug_name (self),
14409                               _clutter_actor_meta_get_debug_name (l->data));
14410                 return FALSE;
14411               }
14412         }
14413     }
14414
14415   return TRUE;
14416 }
14417
14418 /* The public clutter_actor_get_paint_volume API returns a const
14419  * pointer since we return a pointer directly to the cached
14420  * PaintVolume associated with the actor and don't want the user to
14421  * inadvertently modify it, but for internal uses we sometimes need
14422  * access to the same PaintVolume but need to apply some book-keeping
14423  * modifications to it so we don't want a const pointer.
14424  */
14425 static ClutterPaintVolume *
14426 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14427 {
14428   ClutterActorPrivate *priv;
14429
14430   priv = self->priv;
14431
14432   if (priv->paint_volume_valid)
14433     clutter_paint_volume_free (&priv->paint_volume);
14434
14435   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14436     {
14437       priv->paint_volume_valid = TRUE;
14438       return &priv->paint_volume;
14439     }
14440   else
14441     {
14442       priv->paint_volume_valid = FALSE;
14443       return NULL;
14444     }
14445 }
14446
14447 /**
14448  * clutter_actor_get_paint_volume:
14449  * @self: a #ClutterActor
14450  *
14451  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14452  * when a paint volume can't be determined.
14453  *
14454  * The paint volume is defined as the 3D space occupied by an actor
14455  * when being painted.
14456  *
14457  * This function will call the <function>get_paint_volume()</function>
14458  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14459  * should not usually care about overriding the default implementation,
14460  * unless they are, for instance: painting outside their allocation, or
14461  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14462  * 3D depth).
14463  *
14464  * <note>2D actors overriding <function>get_paint_volume()</function>
14465  * ensure their volume has a depth of 0. (This will be true so long as
14466  * you don't call clutter_paint_volume_set_depth().)</note>
14467  *
14468  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14469  *   or %NULL if no volume could be determined.
14470  *
14471  * Since: 1.6
14472  */
14473 const ClutterPaintVolume *
14474 clutter_actor_get_paint_volume (ClutterActor *self)
14475 {
14476   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14477
14478   return _clutter_actor_get_paint_volume_mutable (self);
14479 }
14480
14481 /**
14482  * clutter_actor_get_transformed_paint_volume:
14483  * @self: a #ClutterActor
14484  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14485  *    (or %NULL for the stage)
14486  *
14487  * Retrieves the 3D paint volume of an actor like
14488  * clutter_actor_get_paint_volume() does (Please refer to the
14489  * documentation of clutter_actor_get_paint_volume() for more
14490  * details.) and it additionally transforms the paint volume into the
14491  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14492  * is passed for @relative_to_ancestor)
14493  *
14494  * This can be used by containers that base their paint volume on
14495  * the volume of their children. Such containers can query the
14496  * transformed paint volume of all of its children and union them
14497  * together using clutter_paint_volume_union().
14498  *
14499  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14500  *   or %NULL if no volume could be determined.
14501  *
14502  * Since: 1.6
14503  */
14504 const ClutterPaintVolume *
14505 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14506                                             ClutterActor *relative_to_ancestor)
14507 {
14508   const ClutterPaintVolume *volume;
14509   ClutterActor *stage;
14510   ClutterPaintVolume *transformed_volume;
14511
14512   stage = _clutter_actor_get_stage_internal (self);
14513   if (G_UNLIKELY (stage == NULL))
14514     return NULL;
14515
14516   if (relative_to_ancestor == NULL)
14517     relative_to_ancestor = stage;
14518
14519   volume = clutter_actor_get_paint_volume (self);
14520   if (volume == NULL)
14521     return NULL;
14522
14523   transformed_volume =
14524     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14525
14526   _clutter_paint_volume_copy_static (volume, transformed_volume);
14527
14528   _clutter_paint_volume_transform_relative (transformed_volume,
14529                                             relative_to_ancestor);
14530
14531   return transformed_volume;
14532 }
14533
14534 /**
14535  * clutter_actor_get_paint_box:
14536  * @self: a #ClutterActor
14537  * @box: (out): return location for a #ClutterActorBox
14538  *
14539  * Retrieves the paint volume of the passed #ClutterActor, and
14540  * transforms it into a 2D bounding box in stage coordinates.
14541  *
14542  * This function is useful to determine the on screen area occupied by
14543  * the actor. The box is only an approximation and may often be
14544  * considerably larger due to the optimizations used to calculate the
14545  * box. The box is never smaller though, so it can reliably be used
14546  * for culling.
14547  *
14548  * There are times when a 2D paint box can't be determined, e.g.
14549  * because the actor isn't yet parented under a stage or because
14550  * the actor is unable to determine a paint volume.
14551  *
14552  * Return value: %TRUE if a 2D paint box could be determined, else
14553  * %FALSE.
14554  *
14555  * Since: 1.6
14556  */
14557 gboolean
14558 clutter_actor_get_paint_box (ClutterActor    *self,
14559                              ClutterActorBox *box)
14560 {
14561   ClutterActor *stage;
14562   ClutterPaintVolume *pv;
14563
14564   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14565   g_return_val_if_fail (box != NULL, FALSE);
14566
14567   stage = _clutter_actor_get_stage_internal (self);
14568   if (G_UNLIKELY (!stage))
14569     return FALSE;
14570
14571   pv = _clutter_actor_get_paint_volume_mutable (self);
14572   if (G_UNLIKELY (!pv))
14573     return FALSE;
14574
14575   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14576
14577   return TRUE;
14578 }
14579
14580 /**
14581  * clutter_actor_has_overlaps:
14582  * @self: A #ClutterActor
14583  *
14584  * Asks the actor's implementation whether it may contain overlapping
14585  * primitives.
14586  *
14587  * For example; Clutter may use this to determine whether the painting
14588  * should be redirected to an offscreen buffer to correctly implement
14589  * the opacity property.
14590  *
14591  * Custom actors can override the default response by implementing the
14592  * #ClutterActor <function>has_overlaps</function> virtual function. See
14593  * clutter_actor_set_offscreen_redirect() for more information.
14594  *
14595  * Return value: %TRUE if the actor may have overlapping primitives, and
14596  *   %FALSE otherwise
14597  *
14598  * Since: 1.8
14599  */
14600 gboolean
14601 clutter_actor_has_overlaps (ClutterActor *self)
14602 {
14603   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14604
14605   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14606 }
14607
14608 /**
14609  * clutter_actor_has_effects:
14610  * @self: A #ClutterActor
14611  *
14612  * Returns whether the actor has any effects applied.
14613  *
14614  * Return value: %TRUE if the actor has any effects,
14615  *   %FALSE otherwise
14616  *
14617  * Since: 1.10
14618  */
14619 gboolean
14620 clutter_actor_has_effects (ClutterActor *self)
14621 {
14622   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14623
14624   if (self->priv->effects == NULL)
14625     return FALSE;
14626
14627   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14628 }
14629
14630 /**
14631  * clutter_actor_has_constraints:
14632  * @self: A #ClutterActor
14633  *
14634  * Returns whether the actor has any constraints applied.
14635  *
14636  * Return value: %TRUE if the actor has any constraints,
14637  *   %FALSE otherwise
14638  *
14639  * Since: 1.10
14640  */
14641 gboolean
14642 clutter_actor_has_constraints (ClutterActor *self)
14643 {
14644   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14645
14646   return self->priv->constraints != NULL;
14647 }
14648
14649 /**
14650  * clutter_actor_has_actions:
14651  * @self: A #ClutterActor
14652  *
14653  * Returns whether the actor has any actions applied.
14654  *
14655  * Return value: %TRUE if the actor has any actions,
14656  *   %FALSE otherwise
14657  *
14658  * Since: 1.10
14659  */
14660 gboolean
14661 clutter_actor_has_actions (ClutterActor *self)
14662 {
14663   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14664
14665   return self->priv->actions != NULL;
14666 }
14667
14668 /**
14669  * clutter_actor_get_n_children:
14670  * @self: a #ClutterActor
14671  *
14672  * Retrieves the number of children of @self.
14673  *
14674  * Return value: the number of children of an actor
14675  *
14676  * Since: 1.10
14677  */
14678 gint
14679 clutter_actor_get_n_children (ClutterActor *self)
14680 {
14681   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14682
14683   return self->priv->n_children;
14684 }
14685
14686 /**
14687  * clutter_actor_get_child_at_index:
14688  * @self: a #ClutterActor
14689  * @index_: the position in the list of children
14690  *
14691  * Retrieves the actor at the given @index_ inside the list of
14692  * children of @self.
14693  *
14694  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14695  *
14696  * Since: 1.10
14697  */
14698 ClutterActor *
14699 clutter_actor_get_child_at_index (ClutterActor *self,
14700                                   gint          index_)
14701 {
14702   ClutterActor *iter;
14703   int i;
14704
14705   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14706   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14707
14708   for (iter = self->priv->first_child, i = 0;
14709        iter != NULL && i < index_;
14710        iter = iter->priv->next_sibling, i += 1)
14711     ;
14712
14713   return iter;
14714 }
14715
14716 /*< private >
14717  * _clutter_actor_foreach_child:
14718  * @actor: The actor whos children you want to iterate
14719  * @callback: The function to call for each child
14720  * @user_data: Private data to pass to @callback
14721  *
14722  * Calls a given @callback once for each child of the specified @actor and
14723  * passing the @user_data pointer each time.
14724  *
14725  * Return value: returns %TRUE if all children were iterated, else
14726  *    %FALSE if a callback broke out of iteration early.
14727  */
14728 gboolean
14729 _clutter_actor_foreach_child (ClutterActor           *self,
14730                               ClutterForeachCallback  callback,
14731                               gpointer                user_data)
14732 {
14733   ClutterActorPrivate *priv = self->priv;
14734   ClutterActor *iter;
14735   gboolean cont;
14736
14737   for (cont = TRUE, iter = priv->first_child;
14738        cont && iter != NULL;
14739        iter = iter->priv->next_sibling)
14740     {
14741       cont = callback (iter, user_data);
14742     }
14743
14744   return cont;
14745 }
14746
14747 /* For debugging purposes this gives us a simple way to print out
14748  * the scenegraph e.g in gdb using:
14749  * [|
14750  *   _clutter_actor_traverse (stage,
14751  *                            0,
14752  *                            _clutter_debug_print_actor_cb,
14753  *                            NULL,
14754  *                            NULL);
14755  * |]
14756  */
14757 ClutterActorTraverseVisitFlags
14758 _clutter_debug_print_actor_cb (ClutterActor *actor,
14759                                int depth,
14760                                void *user_data)
14761 {
14762   g_print ("%*s%s:%p\n",
14763            depth * 2, "",
14764            _clutter_actor_get_debug_name (actor),
14765            actor);
14766
14767   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14768 }
14769
14770 static void
14771 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14772                                  ClutterTraverseCallback callback,
14773                                  gpointer                user_data)
14774 {
14775   GQueue *queue = g_queue_new ();
14776   ClutterActor dummy;
14777   int current_depth = 0;
14778
14779   g_queue_push_tail (queue, actor);
14780   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14781
14782   while ((actor = g_queue_pop_head (queue)))
14783     {
14784       ClutterActorTraverseVisitFlags flags;
14785
14786       if (actor == &dummy)
14787         {
14788           current_depth++;
14789           g_queue_push_tail (queue, &dummy);
14790           continue;
14791         }
14792
14793       flags = callback (actor, current_depth, user_data);
14794       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14795         break;
14796       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14797         {
14798           ClutterActor *iter;
14799
14800           for (iter = actor->priv->first_child;
14801                iter != NULL;
14802                iter = iter->priv->next_sibling)
14803             {
14804               g_queue_push_tail (queue, iter);
14805             }
14806         }
14807     }
14808
14809   g_queue_free (queue);
14810 }
14811
14812 static ClutterActorTraverseVisitFlags
14813 _clutter_actor_traverse_depth (ClutterActor           *actor,
14814                                ClutterTraverseCallback before_children_callback,
14815                                ClutterTraverseCallback after_children_callback,
14816                                int                     current_depth,
14817                                gpointer                user_data)
14818 {
14819   ClutterActorTraverseVisitFlags flags;
14820
14821   flags = before_children_callback (actor, current_depth, user_data);
14822   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14823     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14824
14825   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14826     {
14827       ClutterActor *iter;
14828
14829       for (iter = actor->priv->first_child;
14830            iter != NULL;
14831            iter = iter->priv->next_sibling)
14832         {
14833           flags = _clutter_actor_traverse_depth (iter,
14834                                                  before_children_callback,
14835                                                  after_children_callback,
14836                                                  current_depth + 1,
14837                                                  user_data);
14838
14839           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14840             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14841         }
14842     }
14843
14844   if (after_children_callback)
14845     return after_children_callback (actor, current_depth, user_data);
14846   else
14847     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14848 }
14849
14850 /* _clutter_actor_traverse:
14851  * @actor: The actor to start traversing the graph from
14852  * @flags: These flags may affect how the traversal is done
14853  * @before_children_callback: A function to call before visiting the
14854  *   children of the current actor.
14855  * @after_children_callback: A function to call after visiting the
14856  *   children of the current actor. (Ignored if
14857  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14858  * @user_data: The private data to pass to the callbacks
14859  *
14860  * Traverses the scenegraph starting at the specified @actor and
14861  * descending through all its children and its children's children.
14862  * For each actor traversed @before_children_callback and
14863  * @after_children_callback are called with the specified
14864  * @user_data, before and after visiting that actor's children.
14865  *
14866  * The callbacks can return flags that affect the ongoing traversal
14867  * such as by skipping over an actors children or bailing out of
14868  * any further traversing.
14869  */
14870 void
14871 _clutter_actor_traverse (ClutterActor              *actor,
14872                          ClutterActorTraverseFlags  flags,
14873                          ClutterTraverseCallback    before_children_callback,
14874                          ClutterTraverseCallback    after_children_callback,
14875                          gpointer                   user_data)
14876 {
14877   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
14878     _clutter_actor_traverse_breadth (actor,
14879                                      before_children_callback,
14880                                      user_data);
14881   else /* DEPTH_FIRST */
14882     _clutter_actor_traverse_depth (actor,
14883                                    before_children_callback,
14884                                    after_children_callback,
14885                                    0, /* start depth */
14886                                    user_data);
14887 }
14888
14889 static void
14890 on_layout_manager_changed (ClutterLayoutManager *manager,
14891                            ClutterActor         *self)
14892 {
14893   clutter_actor_queue_relayout (self);
14894 }
14895
14896 /**
14897  * clutter_actor_set_layout_manager:
14898  * @self: a #ClutterActor
14899  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
14900  *
14901  * Sets the #ClutterLayoutManager delegate object that will be used to
14902  * lay out the children of @self.
14903  *
14904  * The #ClutterActor will take a reference on the passed @manager which
14905  * will be released either when the layout manager is removed, or when
14906  * the actor is destroyed.
14907  *
14908  * Since: 1.10
14909  */
14910 void
14911 clutter_actor_set_layout_manager (ClutterActor         *self,
14912                                   ClutterLayoutManager *manager)
14913 {
14914   ClutterActorPrivate *priv;
14915
14916   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14917   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
14918
14919   priv = self->priv;
14920
14921   if (priv->layout_manager != NULL)
14922     {
14923       g_signal_handlers_disconnect_by_func (priv->layout_manager,
14924                                             G_CALLBACK (on_layout_manager_changed),
14925                                             self);
14926       clutter_layout_manager_set_container (priv->layout_manager, NULL);
14927       g_object_unref (priv->layout_manager);
14928     }
14929
14930   priv->layout_manager = manager;
14931
14932   if (priv->layout_manager != NULL)
14933     {
14934       g_object_ref_sink (priv->layout_manager);
14935       clutter_layout_manager_set_container (priv->layout_manager,
14936                                             CLUTTER_CONTAINER (self));
14937       g_signal_connect (priv->layout_manager, "layout-changed",
14938                         G_CALLBACK (on_layout_manager_changed),
14939                         self);
14940     }
14941
14942   clutter_actor_queue_relayout (self);
14943
14944   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
14945 }
14946
14947 /**
14948  * clutter_actor_get_layout_manager:
14949  * @self: a #ClutterActor
14950  *
14951  * Retrieves the #ClutterLayoutManager used by @self.
14952  *
14953  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
14954  *   or %NULL
14955  *
14956  * Since: 1.10
14957  */
14958 ClutterLayoutManager *
14959 clutter_actor_get_layout_manager (ClutterActor *self)
14960 {
14961   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14962
14963   return self->priv->layout_manager;
14964 }
14965
14966 static const ClutterLayoutInfo default_layout_info = {
14967   0.f,                          /* fixed-x */
14968   0.f,                          /* fixed-y */
14969   { 0, 0, 0, 0 },               /* margin */
14970   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
14971   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
14972   0.f, 0.f,                     /* min_width, natural_width */
14973   0.f, 0.f,                     /* natual_width, natural_height */
14974 };
14975
14976 static void
14977 layout_info_free (gpointer data)
14978 {
14979   if (G_LIKELY (data != NULL))
14980     g_slice_free (ClutterLayoutInfo, data);
14981 }
14982
14983 /*< private >
14984  * _clutter_actor_get_layout_info:
14985  * @self: a #ClutterActor
14986  *
14987  * Retrieves a pointer to the ClutterLayoutInfo structure.
14988  *
14989  * If the actor does not have a ClutterLayoutInfo associated to it, one
14990  * will be created and initialized to the default values.
14991  *
14992  * This function should be used for setters.
14993  *
14994  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
14995  * instead.
14996  *
14997  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
14998  */
14999 ClutterLayoutInfo *
15000 _clutter_actor_get_layout_info (ClutterActor *self)
15001 {
15002   ClutterLayoutInfo *retval;
15003
15004   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15005   if (retval == NULL)
15006     {
15007       retval = g_slice_new (ClutterLayoutInfo);
15008
15009       *retval = default_layout_info;
15010
15011       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15012                                retval,
15013                                layout_info_free);
15014     }
15015
15016   return retval;
15017 }
15018
15019 /*< private >
15020  * _clutter_actor_get_layout_info_or_defaults:
15021  * @self: a #ClutterActor
15022  *
15023  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15024  *
15025  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15026  * then the default structure will be returned.
15027  *
15028  * This function should only be used for getters.
15029  *
15030  * Return value: a const pointer to the ClutterLayoutInfo structure
15031  */
15032 const ClutterLayoutInfo *
15033 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15034 {
15035   const ClutterLayoutInfo *info;
15036
15037   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15038   if (info == NULL)
15039     return &default_layout_info;
15040
15041   return info;
15042 }
15043
15044 /**
15045  * clutter_actor_set_x_align:
15046  * @self: a #ClutterActor
15047  * @x_align: the horizontal alignment policy
15048  *
15049  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15050  * actor received extra horizontal space.
15051  *
15052  * See also the #ClutterActor:x-align property.
15053  *
15054  * Since: 1.10
15055  */
15056 void
15057 clutter_actor_set_x_align (ClutterActor      *self,
15058                            ClutterActorAlign  x_align)
15059 {
15060   ClutterLayoutInfo *info;
15061
15062   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15063
15064   info = _clutter_actor_get_layout_info (self);
15065
15066   if (info->x_align != x_align)
15067     {
15068       info->x_align = x_align;
15069
15070       clutter_actor_queue_relayout (self);
15071
15072       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15073     }
15074 }
15075
15076 /**
15077  * clutter_actor_get_x_align:
15078  * @self: a #ClutterActor
15079  *
15080  * Retrieves the horizontal alignment policy set using
15081  * clutter_actor_set_x_align().
15082  *
15083  * Return value: the horizontal alignment policy.
15084  *
15085  * Since: 1.10
15086  */
15087 ClutterActorAlign
15088 clutter_actor_get_x_align (ClutterActor *self)
15089 {
15090   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15091
15092   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15093 }
15094
15095 /**
15096  * clutter_actor_set_y_align:
15097  * @self: a #ClutterActor
15098  * @y_align: the vertical alignment policy
15099  *
15100  * Sets the vertical alignment policy of a #ClutterActor, in case the
15101  * actor received extra vertical space.
15102  *
15103  * See also the #ClutterActor:y-align property.
15104  *
15105  * Since: 1.10
15106  */
15107 void
15108 clutter_actor_set_y_align (ClutterActor      *self,
15109                            ClutterActorAlign  y_align)
15110 {
15111   ClutterLayoutInfo *info;
15112
15113   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15114
15115   info = _clutter_actor_get_layout_info (self);
15116
15117   if (info->y_align != y_align)
15118     {
15119       info->y_align = y_align;
15120
15121       clutter_actor_queue_relayout (self);
15122
15123       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15124     }
15125 }
15126
15127 /**
15128  * clutter_actor_get_y_align:
15129  * @self: a #ClutterActor
15130  *
15131  * Retrieves the vertical alignment policy set using
15132  * clutter_actor_set_y_align().
15133  *
15134  * Return value: the vertical alignment policy.
15135  *
15136  * Since: 1.10
15137  */
15138 ClutterActorAlign
15139 clutter_actor_get_y_align (ClutterActor *self)
15140 {
15141   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15142
15143   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15144 }
15145
15146
15147 /**
15148  * clutter_margin_new:
15149  *
15150  * Creates a new #ClutterMargin.
15151  *
15152  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15153  *   clutter_margin_free() to free the resources associated with it when
15154  *   done.
15155  *
15156  * Since: 1.10
15157  */
15158 ClutterMargin *
15159 clutter_margin_new (void)
15160 {
15161   return g_slice_new0 (ClutterMargin);
15162 }
15163
15164 /**
15165  * clutter_margin_copy:
15166  * @margin_: a #ClutterMargin
15167  *
15168  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15169  * the newly created structure.
15170  *
15171  * Return value: (transfer full): a copy of the #ClutterMargin.
15172  *
15173  * Since: 1.10
15174  */
15175 ClutterMargin *
15176 clutter_margin_copy (const ClutterMargin *margin_)
15177 {
15178   if (G_LIKELY (margin_ != NULL))
15179     return g_slice_dup (ClutterMargin, margin_);
15180
15181   return NULL;
15182 }
15183
15184 /**
15185  * clutter_margin_free:
15186  * @margin_: a #ClutterMargin
15187  *
15188  * Frees the resources allocated by clutter_margin_new() and
15189  * clutter_margin_copy().
15190  *
15191  * Since: 1.10
15192  */
15193 void
15194 clutter_margin_free (ClutterMargin *margin_)
15195 {
15196   if (G_LIKELY (margin_ != NULL))
15197     g_slice_free (ClutterMargin, margin_);
15198 }
15199
15200 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15201                      clutter_margin_copy,
15202                      clutter_margin_free)
15203
15204 /**
15205  * clutter_actor_set_margin:
15206  * @self: a #ClutterActor
15207  * @margin: a #ClutterMargin
15208  *
15209  * Sets all the components of the margin of a #ClutterActor.
15210  *
15211  * Since: 1.10
15212  */
15213 void
15214 clutter_actor_set_margin (ClutterActor        *self,
15215                           const ClutterMargin *margin)
15216 {
15217   ClutterLayoutInfo *info;
15218   gboolean changed;
15219   GObject *obj;
15220
15221   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15222   g_return_if_fail (margin != NULL);
15223
15224   obj = G_OBJECT (self);
15225   changed = FALSE;
15226
15227   g_object_freeze_notify (obj);
15228
15229   info = _clutter_actor_get_layout_info (self);
15230
15231   if (info->margin.top != margin->top)
15232     {
15233       info->margin.top = margin->top;
15234       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15235       changed = TRUE;
15236     }
15237
15238   if (info->margin.right != margin->right)
15239     {
15240       info->margin.right = margin->right;
15241       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15242       changed = TRUE;
15243     }
15244
15245   if (info->margin.bottom != margin->bottom)
15246     {
15247       info->margin.bottom = margin->bottom;
15248       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15249       changed = TRUE;
15250     }
15251
15252   if (info->margin.left != margin->left)
15253     {
15254       info->margin.left = margin->left;
15255       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15256       changed = TRUE;
15257     }
15258
15259   if (changed)
15260     clutter_actor_queue_relayout (self);
15261
15262   g_object_thaw_notify (obj);
15263 }
15264
15265 /**
15266  * clutter_actor_get_margin:
15267  * @self: a #ClutterActor
15268  * @margin: (out caller-allocates): return location for a #ClutterMargin
15269  *
15270  * Retrieves all the components of the margin of a #ClutterActor.
15271  *
15272  * Since: 1.10
15273  */
15274 void
15275 clutter_actor_get_margin (ClutterActor  *self,
15276                           ClutterMargin *margin)
15277 {
15278   const ClutterLayoutInfo *info;
15279
15280   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15281   g_return_if_fail (margin != NULL);
15282
15283   info = _clutter_actor_get_layout_info_or_defaults (self);
15284
15285   *margin = info->margin;
15286 }
15287
15288 /**
15289  * clutter_actor_set_margin_top:
15290  * @self: a #ClutterActor
15291  * @margin: the top margin
15292  *
15293  * Sets the margin from the top of a #ClutterActor.
15294  *
15295  * Since: 1.10
15296  */
15297 void
15298 clutter_actor_set_margin_top (ClutterActor *self,
15299                               gfloat        margin)
15300 {
15301   ClutterLayoutInfo *info;
15302
15303   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15304   g_return_if_fail (margin >= 0.f);
15305
15306   info = _clutter_actor_get_layout_info (self);
15307
15308   if (info->margin.top == margin)
15309     return;
15310
15311   info->margin.top = margin;
15312
15313   clutter_actor_queue_relayout (self);
15314
15315   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15316 }
15317
15318 /**
15319  * clutter_actor_get_margin_top:
15320  * @self: a #ClutterActor
15321  *
15322  * Retrieves the top margin of a #ClutterActor.
15323  *
15324  * Return value: the top margin
15325  *
15326  * Since: 1.10
15327  */
15328 gfloat
15329 clutter_actor_get_margin_top (ClutterActor *self)
15330 {
15331   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15332
15333   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15334 }
15335
15336 /**
15337  * clutter_actor_set_margin_bottom:
15338  * @self: a #ClutterActor
15339  * @margin: the bottom margin
15340  *
15341  * Sets the margin from the bottom of a #ClutterActor.
15342  *
15343  * Since: 1.10
15344  */
15345 void
15346 clutter_actor_set_margin_bottom (ClutterActor *self,
15347                                  gfloat        margin)
15348 {
15349   ClutterLayoutInfo *info;
15350
15351   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15352   g_return_if_fail (margin >= 0.f);
15353
15354   info = _clutter_actor_get_layout_info (self);
15355
15356   if (info->margin.bottom == margin)
15357     return;
15358
15359   info->margin.bottom = margin;
15360
15361   clutter_actor_queue_relayout (self);
15362
15363   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15364 }
15365
15366 /**
15367  * clutter_actor_get_margin_bottom:
15368  * @self: a #ClutterActor
15369  *
15370  * Retrieves the bottom margin of a #ClutterActor.
15371  *
15372  * Return value: the bottom margin
15373  *
15374  * Since: 1.10
15375  */
15376 gfloat
15377 clutter_actor_get_margin_bottom (ClutterActor *self)
15378 {
15379   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15380
15381   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15382 }
15383
15384 /**
15385  * clutter_actor_set_margin_left:
15386  * @self: a #ClutterActor
15387  * @margin: the left margin
15388  *
15389  * Sets the margin from the left of a #ClutterActor.
15390  *
15391  * Since: 1.10
15392  */
15393 void
15394 clutter_actor_set_margin_left (ClutterActor *self,
15395                                gfloat        margin)
15396 {
15397   ClutterLayoutInfo *info;
15398
15399   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15400   g_return_if_fail (margin >= 0.f);
15401
15402   info = _clutter_actor_get_layout_info (self);
15403
15404   if (info->margin.left == margin)
15405     return;
15406
15407   info->margin.left = margin;
15408
15409   clutter_actor_queue_relayout (self);
15410
15411   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15412 }
15413
15414 /**
15415  * clutter_actor_get_margin_left:
15416  * @self: a #ClutterActor
15417  *
15418  * Retrieves the left margin of a #ClutterActor.
15419  *
15420  * Return value: the left margin
15421  *
15422  * Since: 1.10
15423  */
15424 gfloat
15425 clutter_actor_get_margin_left (ClutterActor *self)
15426 {
15427   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15428
15429   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15430 }
15431
15432 /**
15433  * clutter_actor_set_margin_right:
15434  * @self: a #ClutterActor
15435  * @margin: the right margin
15436  *
15437  * Sets the margin from the right of a #ClutterActor.
15438  *
15439  * Since: 1.10
15440  */
15441 void
15442 clutter_actor_set_margin_right (ClutterActor *self,
15443                                 gfloat        margin)
15444 {
15445   ClutterLayoutInfo *info;
15446
15447   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15448   g_return_if_fail (margin >= 0.f);
15449
15450   info = _clutter_actor_get_layout_info (self);
15451
15452   if (info->margin.right == margin)
15453     return;
15454
15455   info->margin.right = margin;
15456
15457   clutter_actor_queue_relayout (self);
15458
15459   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15460 }
15461
15462 /**
15463  * clutter_actor_get_margin_right:
15464  * @self: a #ClutterActor
15465  *
15466  * Retrieves the right margin of a #ClutterActor.
15467  *
15468  * Return value: the right margin
15469  *
15470  * Since: 1.10
15471  */
15472 gfloat
15473 clutter_actor_get_margin_right (ClutterActor *self)
15474 {
15475   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15476
15477   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15478 }
15479
15480 /**
15481  * clutter_actor_set_background_color:
15482  * @self: a #ClutterActor
15483  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15484  *  set color
15485  *
15486  * Sets the background color of a #ClutterActor.
15487  *
15488  * The background color will be used to cover the whole allocation of the
15489  * actor. The default background color of an actor is transparent.
15490  *
15491  * To check whether an actor has a background color, you can use the
15492  * #ClutterActor:background-color-set actor property.
15493  *
15494  * Since: 1.10
15495  */
15496 void
15497 clutter_actor_set_background_color (ClutterActor       *self,
15498                                     const ClutterColor *color)
15499 {
15500   ClutterActorPrivate *priv;
15501
15502   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15503
15504   priv = self->priv;
15505
15506   if (color == NULL)
15507     {
15508       priv->bg_color_set = FALSE;
15509       g_object_notify_by_pspec (G_OBJECT (self),
15510                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15511       return;
15512     }
15513
15514   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15515     return;
15516
15517   priv->bg_color = *color;
15518   priv->bg_color_set = TRUE;
15519
15520   clutter_actor_queue_redraw (self);
15521
15522   g_object_notify_by_pspec (G_OBJECT (self),
15523                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15524   g_object_notify_by_pspec (G_OBJECT (self),
15525                             obj_props[PROP_BACKGROUND_COLOR]);
15526 }
15527
15528 /**
15529  * clutter_actor_get_background_color:
15530  * @self: a #ClutterActor
15531  * @color: (out caller-allocates): return location for a #ClutterColor
15532  *
15533  * Retrieves the color set using clutter_actor_set_background_color().
15534  *
15535  * Since: 1.10
15536  */
15537 void
15538 clutter_actor_get_background_color (ClutterActor *self,
15539                                     ClutterColor *color)
15540 {
15541   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15542   g_return_if_fail (color != NULL);
15543
15544   *color = self->priv->bg_color;
15545 }
15546
15547 /**
15548  * clutter_actor_get_previous_sibling:
15549  * @self: a #ClutterActor
15550  *
15551  * Retrieves the sibling of @self that comes before it in the list
15552  * of children of @self's parent.
15553  *
15554  * The returned pointer is only valid until the scene graph changes; it
15555  * is not safe to modify the list of children of @self while iterating
15556  * it.
15557  *
15558  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15559  *
15560  * Since: 1.10
15561  */
15562 ClutterActor *
15563 clutter_actor_get_previous_sibling (ClutterActor *self)
15564 {
15565   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15566
15567   return self->priv->prev_sibling;
15568 }
15569
15570 /**
15571  * clutter_actor_get_next_sibling:
15572  * @self: a #ClutterActor
15573  *
15574  * Retrieves the sibling of @self that comes after it in the list
15575  * of children of @self's parent.
15576  *
15577  * The returned pointer is only valid until the scene graph changes; it
15578  * is not safe to modify the list of children of @self while iterating
15579  * it.
15580  *
15581  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15582  *
15583  * Since: 1.10
15584  */
15585 ClutterActor *
15586 clutter_actor_get_next_sibling (ClutterActor *self)
15587 {
15588   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15589
15590   return self->priv->next_sibling;
15591 }
15592
15593 /**
15594  * clutter_actor_get_first_child:
15595  * @self: a #ClutterActor
15596  *
15597  * Retrieves the first child of @self.
15598  *
15599  * The returned pointer is only valid until the scene graph changes; it
15600  * is not safe to modify the list of children of @self while iterating
15601  * it.
15602  *
15603  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15604  *
15605  * Since: 1.10
15606  */
15607 ClutterActor *
15608 clutter_actor_get_first_child (ClutterActor *self)
15609 {
15610   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15611
15612   return self->priv->first_child;
15613 }
15614
15615 /**
15616  * clutter_actor_get_last_child:
15617  * @self: a #ClutterActor
15618  *
15619  * Retrieves the last child of @self.
15620  *
15621  * The returned pointer is only valid until the scene graph changes; it
15622  * is not safe to modify the list of children of @self while iterating
15623  * it.
15624  *
15625  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15626  *
15627  * Since: 1.10
15628  */
15629 ClutterActor *
15630 clutter_actor_get_last_child (ClutterActor *self)
15631 {
15632   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15633
15634   return self->priv->last_child;
15635 }
15636
15637 /* easy way to have properly named fields instead of the dummy ones
15638  * we use in the public structure
15639  */
15640 typedef struct _RealActorIter
15641 {
15642   ClutterActor *root;           /* dummy1 */
15643   ClutterActor *current;        /* dummy2 */
15644   gpointer padding_1;           /* dummy3 */
15645   gint age;                     /* dummy4 */
15646   gpointer padding_2;           /* dummy5 */
15647 } RealActorIter;
15648
15649 /**
15650  * clutter_actor_iter_init:
15651  * @iter: a #ClutterActorIter
15652  * @root: a #ClutterActor
15653  *
15654  * Initializes a #ClutterActorIter, which can then be used to iterate
15655  * efficiently over a section of the scene graph, and associates it
15656  * with @root.
15657  *
15658  * Modifying the scene graph section that contains @root will invalidate
15659  * the iterator.
15660  *
15661  * |[
15662  *   ClutterActorIter iter;
15663  *   ClutterActor *child;
15664  *
15665  *   clutter_actor_iter_init (&iter, container);
15666  *   while (clutter_actor_iter_next (&iter, &child))
15667  *     {
15668  *       /&ast; do something with child &ast;/
15669  *     }
15670  * ]|
15671  *
15672  * Since: 1.10
15673  */
15674 void
15675 clutter_actor_iter_init (ClutterActorIter *iter,
15676                          ClutterActor     *root)
15677 {
15678   RealActorIter *ri = (RealActorIter *) iter;
15679
15680   g_return_if_fail (iter != NULL);
15681   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15682
15683   ri->root = root;
15684   ri->current = NULL;
15685   ri->age = root->priv->age;
15686 }
15687
15688 /**
15689  * clutter_actor_iter_next:
15690  * @iter: a #ClutterActorIter
15691  * @child: (out): return location for a #ClutterActor
15692  *
15693  * Advances the @iter and retrieves the next child of the root #ClutterActor
15694  * that was used to initialize the #ClutterActorIterator.
15695  *
15696  * If the iterator can advance, this function returns %TRUE and sets the
15697  * @child argument.
15698  *
15699  * If the iterator cannot advance, this function returns %FALSE, and
15700  * the contents of @child are undefined.
15701  *
15702  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15703  *
15704  * Since: 1.10
15705  */
15706 gboolean
15707 clutter_actor_iter_next (ClutterActorIter  *iter,
15708                          ClutterActor     **child)
15709 {
15710   RealActorIter *ri = (RealActorIter *) iter;
15711
15712   g_return_val_if_fail (iter != NULL, FALSE);
15713   g_return_val_if_fail (ri->root != NULL, FALSE);
15714 #ifndef G_DISABLE_ASSERT
15715   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15716 #endif
15717
15718   if (ri->current == NULL)
15719     ri->current = ri->root->priv->first_child;
15720   else
15721     ri->current = ri->current->priv->next_sibling;
15722
15723   if (child != NULL)
15724     *child = ri->current;
15725
15726   return ri->current != NULL;
15727 }
15728
15729 /**
15730  * clutter_actor_iter_next:
15731  * @iter: a #ClutterActorIter
15732  * @child: (out): return location for a #ClutterActor
15733  *
15734  * Advances the @iter and retrieves the previous child of the root
15735  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15736  *
15737  * If the iterator can advance, this function returns %TRUE and sets the
15738  * @child argument.
15739  *
15740  * If the iterator cannot advance, this function returns %FALSE, and
15741  * the contents of @child are undefined.
15742  *
15743  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15744  *
15745  * Since: 1.10
15746  */
15747 gboolean
15748 clutter_actor_iter_prev (ClutterActorIter  *iter,
15749                          ClutterActor     **child)
15750 {
15751   RealActorIter *ri = (RealActorIter *) iter;
15752
15753   g_return_val_if_fail (iter != NULL, FALSE);
15754   g_return_val_if_fail (ri->root != NULL, FALSE);
15755 #ifndef G_DISABLE_ASSERT
15756   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15757 #endif
15758
15759   if (ri->current == NULL)
15760     ri->current = ri->root->priv->last_child;
15761   else
15762     ri->current = ri->current->priv->prev_sibling;
15763
15764   if (child != NULL)
15765     *child = ri->current;
15766
15767   return ri->current != NULL;
15768 }
15769
15770 /**
15771  * clutter_actor_iter_remove:
15772  * @iter: a #ClutterActorIter
15773  *
15774  * Safely removes the #ClutterActor currently pointer to by the iterator
15775  * from its parent.
15776  *
15777  * This function can only be called after clutter_actor_iter_next() or
15778  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15779  * than once for the same actor.
15780  *
15781  * This function will call clutter_actor_remove_child() internally.
15782  *
15783  * Since: 1.10
15784  */
15785 void
15786 clutter_actor_iter_remove (ClutterActorIter *iter)
15787 {
15788   RealActorIter *ri = (RealActorIter *) iter;
15789   ClutterActor *cur;
15790
15791   g_return_if_fail (iter != NULL);
15792   g_return_if_fail (ri->root != NULL);
15793 #ifndef G_DISABLE_ASSERT
15794   g_return_if_fail (ri->age == ri->root->priv->age);
15795 #endif
15796   g_return_if_fail (ri->current != NULL);
15797
15798   cur = ri->current;
15799
15800   if (cur != NULL)
15801     {
15802       ri->current = cur->priv->prev_sibling;
15803
15804       clutter_actor_remove_child_internal (ri->root, cur,
15805                                            REMOVE_CHILD_DEFAULT_FLAGS);
15806
15807       ri->age += 1;
15808     }
15809 }
15810
15811 /**
15812  * clutter_actor_iter_destroy:
15813  * @iter: a #ClutterActorIter
15814  *
15815  * Safely destroys the #ClutterActor currently pointer to by the iterator
15816  * from its parent.
15817  *
15818  * This function can only be called after clutter_actor_iter_next() or
15819  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15820  * than once for the same actor.
15821  *
15822  * This function will call clutter_actor_destroy() internally.
15823  *
15824  * Since: 1.10
15825  */
15826 void
15827 clutter_actor_iter_destroy (ClutterActorIter *iter)
15828 {
15829   RealActorIter *ri = (RealActorIter *) iter;
15830   ClutterActor *cur;
15831
15832   g_return_if_fail (iter != NULL);
15833   g_return_if_fail (ri->root != NULL);
15834 #ifndef G_DISABLE_ASSERT
15835   g_return_if_fail (ri->age == ri->root->priv->age);
15836 #endif
15837   g_return_if_fail (ri->current != NULL);
15838
15839   cur = ri->current;
15840
15841   if (cur != NULL)
15842     {
15843       ri->current = cur->priv->prev_sibling;
15844
15845       clutter_actor_destroy (cur);
15846
15847       ri->age += 1;
15848     }
15849 }