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