Fix compiler warning
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="bin-layout">
113  *     <title>Actors</title>
114  *     <graphic fileref="test-actor.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  */
243
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
327
328 #include "clutter-actor-private.h"
329
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-main.h"
342 #include "clutter-marshal.h"
343 #include "clutter-flatten-effect.h"
344 #include "clutter-paint-volume-private.h"
345 #include "clutter-private.h"
346 #include "clutter-profile.h"
347 #include "clutter-scriptable.h"
348 #include "clutter-script-private.h"
349 #include "clutter-stage-private.h"
350 #include "clutter-units.h"
351
352 #include "deprecated/clutter-behaviour.h"
353 #include "deprecated/clutter-container.h"
354
355 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
356 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
357
358 /* Internal enum used to control mapped state update.  This is a hint
359  * which indicates when to do something other than just enforce
360  * invariants.
361  */
362 typedef enum {
363   MAP_STATE_CHECK,           /* just enforce invariants. */
364   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
365                               * used when about to unparent.
366                               */
367   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
368                               * used to set mapped on toplevels.
369                               */
370   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
371                               * used just before unmapping parent.
372                               */
373 } MapStateChange;
374
375 /* 3 entries should be a good compromise, few layout managers
376  * will ask for 3 different preferred size in each allocation cycle */
377 #define N_CACHED_SIZE_REQUESTS 3
378
379 struct _ClutterActorPrivate
380 {
381   /* request mode */
382   ClutterRequestMode request_mode;
383
384   /* our cached size requests for different width / height */
385   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
386   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
387
388   /* An age of 0 means the entry is not set */
389   guint cached_height_age;
390   guint cached_width_age;
391
392   /* the bounding box of the actor, relative to the parent's
393    * allocation
394    */
395   ClutterActorBox allocation;
396   ClutterAllocationFlags allocation_flags;
397
398   /* depth */
399   gfloat z;
400
401   /* clip, in actor coordinates */
402   cairo_rectangle_t clip;
403
404   /* the cached transformation matrix; see apply_transform() */
405   CoglMatrix transform;
406
407   guint8 opacity;
408   gint opacity_override;
409
410   ClutterOffscreenRedirect offscreen_redirect;
411
412   /* This is an internal effect used to implement the
413      offscreen-redirect property */
414   ClutterEffect *flatten_effect;
415
416   /* scene graph */
417   ClutterActor *parent;
418   ClutterActor *prev_sibling;
419   ClutterActor *next_sibling;
420   ClutterActor *first_child;
421   ClutterActor *last_child;
422
423   gint n_children;
424
425   /* tracks whenever the children of an actor are changed; the
426    * age is incremented by 1 whenever an actor is added or
427    * removed. the age is not incremented when the first or the
428    * last child pointers are changed, or when grandchildren of
429    * an actor are changed.
430    */
431   gint age;
432
433   gchar *name; /* a non-unique name, used for debugging */
434   guint32 id; /* unique id, used for backward compatibility */
435
436   gint32 pick_id; /* per-stage unique id, used for picking */
437
438   /* a back-pointer to the Pango context that we can use
439    * to create pre-configured PangoLayout
440    */
441   PangoContext *pango_context;
442
443   /* the text direction configured for this child - either by
444    * application code, or by the actor's parent
445    */
446   ClutterTextDirection text_direction;
447
448   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
449   gint internal_child;
450
451   /* meta classes */
452   ClutterMetaGroup *actions;
453   ClutterMetaGroup *constraints;
454   ClutterMetaGroup *effects;
455
456   /* delegate object used to allocate the children of this actor */
457   ClutterLayoutManager *layout_manager;
458
459   /* used when painting, to update the paint volume */
460   ClutterEffect *current_effect;
461
462   /* This is used to store an effect which needs to be redrawn. A
463      redraw can be queued to start from a particular effect. This is
464      used by parametrised effects that can cache an image of the
465      actor. If a parameter of the effect changes then it only needs to
466      redraw the cached image, not the actual actor. The pointer is
467      only valid if is_dirty == TRUE. If the pointer is NULL then the
468      whole actor is dirty. */
469   ClutterEffect *effect_to_redraw;
470
471   /* This is used when painting effects to implement the
472      clutter_actor_continue_paint() function. It points to the node in
473      the list of effects that is next in the chain */
474   const GList *next_effect_to_paint;
475
476   ClutterPaintVolume paint_volume;
477
478   /* NB: This volume isn't relative to this actor, it is in eye
479    * coordinates so that it can remain valid after the actor changes.
480    */
481   ClutterPaintVolume last_paint_volume;
482
483   ClutterStageQueueRedrawEntry *queue_redraw_entry;
484
485   ClutterColor bg_color;
486
487   /* bitfields */
488
489   /* fixed position and sizes */
490   guint position_set                : 1;
491   guint min_width_set               : 1;
492   guint min_height_set              : 1;
493   guint natural_width_set           : 1;
494   guint natural_height_set          : 1;
495   /* cached request is invalid (implies allocation is too) */
496   guint needs_width_request         : 1;
497   /* cached request is invalid (implies allocation is too) */
498   guint needs_height_request        : 1;
499   /* cached allocation is invalid (request has changed, probably) */
500   guint needs_allocation            : 1;
501   guint show_on_set_parent          : 1;
502   guint has_clip                    : 1;
503   guint clip_to_allocation          : 1;
504   guint enable_model_view_transform : 1;
505   guint enable_paint_unmapped       : 1;
506   guint has_pointer                 : 1;
507   guint propagated_one_redraw       : 1;
508   guint paint_volume_valid          : 1;
509   guint last_paint_volume_valid     : 1;
510   guint in_clone_paint              : 1;
511   guint transform_valid             : 1;
512   /* This is TRUE if anything has queued a redraw since we were last
513      painted. In this case effect_to_redraw will point to an effect
514      the redraw was queued from or it will be NULL if the redraw was
515      queued without an effect. */
516   guint is_dirty                    : 1;
517   guint bg_color_set                : 1;
518 };
519
520 enum
521 {
522   PROP_0,
523
524   PROP_NAME,
525
526   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
527    * when set they force a size request, when gotten they
528    * get the allocation if the allocation is valid, and the
529    * request otherwise
530    */
531   PROP_X,
532   PROP_Y,
533   PROP_WIDTH,
534   PROP_HEIGHT,
535
536   /* Then the rest of these size-related properties are the "actual"
537    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
538    */
539   PROP_FIXED_X,
540   PROP_FIXED_Y,
541
542   PROP_FIXED_POSITION_SET,
543
544   PROP_MIN_WIDTH,
545   PROP_MIN_WIDTH_SET,
546
547   PROP_MIN_HEIGHT,
548   PROP_MIN_HEIGHT_SET,
549
550   PROP_NATURAL_WIDTH,
551   PROP_NATURAL_WIDTH_SET,
552
553   PROP_NATURAL_HEIGHT,
554   PROP_NATURAL_HEIGHT_SET,
555
556   PROP_REQUEST_MODE,
557
558   /* Allocation properties are read-only */
559   PROP_ALLOCATION,
560
561   PROP_DEPTH,
562
563   PROP_CLIP,
564   PROP_HAS_CLIP,
565   PROP_CLIP_TO_ALLOCATION,
566
567   PROP_OPACITY,
568
569   PROP_OFFSCREEN_REDIRECT,
570
571   PROP_VISIBLE,
572   PROP_MAPPED,
573   PROP_REALIZED,
574   PROP_REACTIVE,
575
576   PROP_SCALE_X,
577   PROP_SCALE_Y,
578   PROP_SCALE_CENTER_X,
579   PROP_SCALE_CENTER_Y,
580   PROP_SCALE_GRAVITY,
581
582   PROP_ROTATION_ANGLE_X,
583   PROP_ROTATION_ANGLE_Y,
584   PROP_ROTATION_ANGLE_Z,
585   PROP_ROTATION_CENTER_X,
586   PROP_ROTATION_CENTER_Y,
587   PROP_ROTATION_CENTER_Z,
588   /* This property only makes sense for the z rotation because the
589      others would depend on the actor having a size along the
590      z-axis */
591   PROP_ROTATION_CENTER_Z_GRAVITY,
592
593   PROP_ANCHOR_X,
594   PROP_ANCHOR_Y,
595   PROP_ANCHOR_GRAVITY,
596
597   PROP_SHOW_ON_SET_PARENT,
598
599   PROP_TEXT_DIRECTION,
600   PROP_HAS_POINTER,
601
602   PROP_ACTIONS,
603   PROP_CONSTRAINTS,
604   PROP_EFFECT,
605
606   PROP_LAYOUT_MANAGER,
607
608   PROP_X_ALIGN,
609   PROP_Y_ALIGN,
610   PROP_MARGIN_TOP,
611   PROP_MARGIN_BOTTOM,
612   PROP_MARGIN_LEFT,
613   PROP_MARGIN_RIGHT,
614
615   PROP_BACKGROUND_COLOR,
616   PROP_BACKGROUND_COLOR_SET,
617
618   PROP_FIRST_CHILD,
619   PROP_LAST_CHILD,
620
621   PROP_LAST
622 };
623
624 static GParamSpec *obj_props[PROP_LAST];
625
626 enum
627 {
628   SHOW,
629   HIDE,
630   DESTROY,
631   PARENT_SET,
632   KEY_FOCUS_IN,
633   KEY_FOCUS_OUT,
634   PAINT,
635   PICK,
636   REALIZE,
637   UNREALIZE,
638   QUEUE_REDRAW,
639   QUEUE_RELAYOUT,
640   EVENT,
641   CAPTURED_EVENT,
642   BUTTON_PRESS_EVENT,
643   BUTTON_RELEASE_EVENT,
644   SCROLL_EVENT,
645   KEY_PRESS_EVENT,
646   KEY_RELEASE_EVENT,
647   MOTION_EVENT,
648   ENTER_EVENT,
649   LEAVE_EVENT,
650   ALLOCATION_CHANGED,
651
652   LAST_SIGNAL
653 };
654
655 static guint actor_signals[LAST_SIGNAL] = { 0, };
656
657 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
658 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
659 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
660 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
661
662 /* These setters are all static for now, maybe they should be in the
663  * public API, but they are perhaps obscure enough to leave only as
664  * properties
665  */
666 static void clutter_actor_set_min_width          (ClutterActor *self,
667                                                   gfloat        min_width);
668 static void clutter_actor_set_min_height         (ClutterActor *self,
669                                                   gfloat        min_height);
670 static void clutter_actor_set_natural_width      (ClutterActor *self,
671                                                   gfloat        natural_width);
672 static void clutter_actor_set_natural_height     (ClutterActor *self,
673                                                   gfloat        natural_height);
674 static void clutter_actor_set_min_width_set      (ClutterActor *self,
675                                                   gboolean      use_min_width);
676 static void clutter_actor_set_min_height_set     (ClutterActor *self,
677                                                   gboolean      use_min_height);
678 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
679                                                   gboolean  use_natural_width);
680 static void clutter_actor_set_natural_height_set (ClutterActor *self,
681                                                   gboolean  use_natural_height);
682 static void clutter_actor_update_map_state       (ClutterActor  *self,
683                                                   MapStateChange change);
684 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
685
686 /* Helper routines for managing anchor coords */
687 static void clutter_anchor_coord_get_units (ClutterActor      *self,
688                                             const AnchorCoord *coord,
689                                             gfloat            *x,
690                                             gfloat            *y,
691                                             gfloat            *z);
692 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
693                                             gfloat             x,
694                                             gfloat             y,
695                                             gfloat             z);
696
697 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
698 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
699                                                         ClutterGravity     gravity);
700
701 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
702
703 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
704
705 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
706                                                                ClutterActor *ancestor,
707                                                                CoglMatrix *matrix);
708
709 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
710
711 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
712
713 static void on_layout_manager_changed (ClutterLayoutManager *manager,
714                                        ClutterActor         *self);
715
716 /* Helper macro which translates by the anchor coord, applies the
717    given transformation and then translates back */
718 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
719   gfloat _tx, _ty, _tz;                                                \
720   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
721   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
722   { _transform; }                                                      \
723   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
724
725 static GQuark quark_shader_data = 0;
726 static GQuark quark_actor_layout_info = 0;
727 static GQuark quark_actor_transform_info = 0;
728
729 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
730                          clutter_actor,
731                          G_TYPE_INITIALLY_UNOWNED,
732                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
733                                                 clutter_container_iface_init)
734                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
735                                                 clutter_scriptable_iface_init)
736                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
737                                                 clutter_animatable_iface_init)
738                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
739                                                 atk_implementor_iface_init));
740
741 /*< private >
742  * clutter_actor_get_debug_name:
743  * @actor: a #ClutterActor
744  *
745  * Retrieves a printable name of @actor for debugging messages
746  *
747  * Return value: a string with a printable name
748  */
749 const gchar *
750 _clutter_actor_get_debug_name (ClutterActor *actor)
751 {
752   return actor->priv->name != NULL ? actor->priv->name
753                                    : G_OBJECT_TYPE_NAME (actor);
754 }
755
756 #ifdef CLUTTER_ENABLE_DEBUG
757 /* XXX - this is for debugging only, remove once working (or leave
758  * in only in some debug mode). Should leave it for a little while
759  * until we're confident in the new map/realize/visible handling.
760  */
761 static inline void
762 clutter_actor_verify_map_state (ClutterActor *self)
763 {
764   ClutterActorPrivate *priv = self->priv;
765
766   if (CLUTTER_ACTOR_IS_REALIZED (self))
767     {
768       /* all bets are off during reparent when we're potentially realized,
769        * but should not be according to invariants
770        */
771       if (!CLUTTER_ACTOR_IN_REPARENT (self))
772         {
773           if (priv->parent == NULL)
774             {
775               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
776                 {
777                 }
778               else
779                 g_warning ("Realized non-toplevel actor '%s' should "
780                            "have a parent",
781                            _clutter_actor_get_debug_name (self));
782             }
783           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
784             {
785               g_warning ("Realized actor %s has an unrealized parent %s",
786                          _clutter_actor_get_debug_name (self),
787                          _clutter_actor_get_debug_name (priv->parent));
788             }
789         }
790     }
791
792   if (CLUTTER_ACTOR_IS_MAPPED (self))
793     {
794       if (!CLUTTER_ACTOR_IS_REALIZED (self))
795         g_warning ("Actor '%s' is mapped but not realized",
796                    _clutter_actor_get_debug_name (self));
797
798       /* remaining bets are off during reparent when we're potentially
799        * mapped, but should not be according to invariants
800        */
801       if (!CLUTTER_ACTOR_IN_REPARENT (self))
802         {
803           if (priv->parent == NULL)
804             {
805               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
806                 {
807                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
808                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
809                     {
810                       g_warning ("Toplevel actor '%s' is mapped "
811                                  "but not visible",
812                                  _clutter_actor_get_debug_name (self));
813                     }
814                 }
815               else
816                 {
817                   g_warning ("Mapped actor '%s' should have a parent",
818                              _clutter_actor_get_debug_name (self));
819                 }
820             }
821           else
822             {
823               ClutterActor *iter = self;
824
825               /* check for the enable_paint_unmapped flag on the actor
826                * and parents; if the flag is enabled at any point of this
827                * branch of the scene graph then all the later checks
828                * become pointless
829                */
830               while (iter != NULL)
831                 {
832                   if (iter->priv->enable_paint_unmapped)
833                     return;
834
835                   iter = iter->priv->parent;
836                 }
837
838               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
839                 {
840                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
841                              "is not visible",
842                              _clutter_actor_get_debug_name (self),
843                              _clutter_actor_get_debug_name (priv->parent));
844                 }
845
846               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
847                 {
848                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
849                              "is not realized",
850                              _clutter_actor_get_debug_name (self),
851                              _clutter_actor_get_debug_name (priv->parent));
852                 }
853
854               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
855                 {
856                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
857                     g_warning ("Actor '%s' is mapped but its non-toplevel "
858                                "parent '%s' is not mapped",
859                                _clutter_actor_get_debug_name (self),
860                                _clutter_actor_get_debug_name (priv->parent));
861                 }
862             }
863         }
864     }
865 }
866
867 #endif /* CLUTTER_ENABLE_DEBUG */
868
869 static void
870 clutter_actor_set_mapped (ClutterActor *self,
871                           gboolean      mapped)
872 {
873   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
874     return;
875
876   if (mapped)
877     {
878       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
879       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
880     }
881   else
882     {
883       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
884       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
885     }
886 }
887
888 /* this function updates the mapped and realized states according to
889  * invariants, in the appropriate order.
890  */
891 static void
892 clutter_actor_update_map_state (ClutterActor  *self,
893                                 MapStateChange change)
894 {
895   gboolean was_mapped;
896
897   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
898
899   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
900     {
901       /* the mapped flag on top-level actors must be set by the
902        * per-backend implementation because it might be asynchronous.
903        *
904        * That is, the MAPPED flag on toplevels currently tracks the X
905        * server mapped-ness of the window, while the expected behavior
906        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
907        * This creates some weird complexity by breaking the invariant
908        * that if we're visible and all ancestors shown then we are
909        * also mapped - instead, we are mapped if all ancestors
910        * _possibly excepting_ the stage are mapped. The stage
911        * will map/unmap for example when it is minimized or
912        * moved to another workspace.
913        *
914        * So, the only invariant on the stage is that if visible it
915        * should be realized, and that it has to be visible to be
916        * mapped.
917        */
918       if (CLUTTER_ACTOR_IS_VISIBLE (self))
919         clutter_actor_realize (self);
920
921       switch (change)
922         {
923         case MAP_STATE_CHECK:
924           break;
925
926         case MAP_STATE_MAKE_MAPPED:
927           g_assert (!was_mapped);
928           clutter_actor_set_mapped (self, TRUE);
929           break;
930
931         case MAP_STATE_MAKE_UNMAPPED:
932           g_assert (was_mapped);
933           clutter_actor_set_mapped (self, FALSE);
934           break;
935
936         case MAP_STATE_MAKE_UNREALIZED:
937           /* we only use MAKE_UNREALIZED in unparent,
938            * and unparenting a stage isn't possible.
939            * If someone wants to just unrealize a stage
940            * then clutter_actor_unrealize() doesn't
941            * go through this codepath.
942            */
943           g_warning ("Trying to force unrealize stage is not allowed");
944           break;
945         }
946
947       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
948           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
949           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
950         {
951           g_warning ("Clutter toplevel of type '%s' is not visible, but "
952                      "it is somehow still mapped",
953                      _clutter_actor_get_debug_name (self));
954         }
955     }
956   else
957     {
958       ClutterActorPrivate *priv = self->priv;
959       ClutterActor *parent = priv->parent;
960       gboolean should_be_mapped;
961       gboolean may_be_realized;
962       gboolean must_be_realized;
963
964       should_be_mapped = FALSE;
965       may_be_realized = TRUE;
966       must_be_realized = FALSE;
967
968       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
969         {
970           may_be_realized = FALSE;
971         }
972       else
973         {
974           /* Maintain invariant that if parent is mapped, and we are
975            * visible, then we are mapped ...  unless parent is a
976            * stage, in which case we map regardless of parent's map
977            * state but do require stage to be visible and realized.
978            *
979            * If parent is realized, that does not force us to be
980            * realized; but if parent is unrealized, that does force
981            * us to be unrealized.
982            *
983            * The reason we don't force children to realize with
984            * parents is _clutter_actor_rerealize(); if we require that
985            * a realized parent means children are realized, then to
986            * unrealize an actor we would have to unrealize its
987            * parents, which would end up meaning unrealizing and
988            * hiding the entire stage. So we allow unrealizing a
989            * child (as long as that child is not mapped) while that
990            * child still has a realized parent.
991            *
992            * Also, if we unrealize from leaf nodes to root, and
993            * realize from root to leaf, the invariants are never
994            * violated if we allow children to be unrealized
995            * while parents are realized.
996            *
997            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
998            * to force us to unmap, even though parent is still
999            * mapped. This is because we're unmapping from leaf nodes
1000            * up to root nodes.
1001            */
1002           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1003               change != MAP_STATE_MAKE_UNMAPPED)
1004             {
1005               gboolean parent_is_visible_realized_toplevel;
1006
1007               parent_is_visible_realized_toplevel =
1008                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1009                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1010                  CLUTTER_ACTOR_IS_REALIZED (parent));
1011
1012               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1013                   parent_is_visible_realized_toplevel)
1014                 {
1015                   must_be_realized = TRUE;
1016                   should_be_mapped = TRUE;
1017                 }
1018             }
1019
1020           /* if the actor has been set to be painted even if unmapped
1021            * then we should map it and check for realization as well;
1022            * this is an override for the branch of the scene graph
1023            * which begins with this node
1024            */
1025           if (priv->enable_paint_unmapped)
1026             {
1027               if (priv->parent == NULL)
1028                 g_warning ("Attempting to map an unparented actor '%s'",
1029                            _clutter_actor_get_debug_name (self));
1030
1031               should_be_mapped = TRUE;
1032               must_be_realized = TRUE;
1033             }
1034
1035           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1036             may_be_realized = FALSE;
1037         }
1038
1039       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1040         {
1041           if (parent == NULL)
1042             g_warning ("Attempting to map a child that does not "
1043                        "meet the necessary invariants: the actor '%s' "
1044                        "has no parent",
1045                        _clutter_actor_get_debug_name (self));
1046           else
1047             g_warning ("Attempting to map a child that does not "
1048                        "meet the necessary invariants: the actor '%s' "
1049                        "is parented to an unmapped actor '%s'",
1050                        _clutter_actor_get_debug_name (self),
1051                        _clutter_actor_get_debug_name (priv->parent));
1052         }
1053
1054       /* If in reparent, we temporarily suspend unmap and unrealize.
1055        *
1056        * We want to go in the order "realize, map" and "unmap, unrealize"
1057        */
1058
1059       /* Unmap */
1060       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1061         clutter_actor_set_mapped (self, FALSE);
1062
1063       /* Realize */
1064       if (must_be_realized)
1065         clutter_actor_realize (self);
1066
1067       /* if we must be realized then we may be, presumably */
1068       g_assert (!(must_be_realized && !may_be_realized));
1069
1070       /* Unrealize */
1071       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1072         clutter_actor_unrealize_not_hiding (self);
1073
1074       /* Map */
1075       if (should_be_mapped)
1076         {
1077           if (!must_be_realized)
1078             g_warning ("Somehow we think actor '%s' should be mapped but "
1079                        "not realized, which isn't allowed",
1080                        _clutter_actor_get_debug_name (self));
1081
1082           /* realization is allowed to fail (though I don't know what
1083            * an app is supposed to do about that - shouldn't it just
1084            * be a g_error? anyway, we have to avoid mapping if this
1085            * happens)
1086            */
1087           if (CLUTTER_ACTOR_IS_REALIZED (self))
1088             clutter_actor_set_mapped (self, TRUE);
1089         }
1090     }
1091
1092 #ifdef CLUTTER_ENABLE_DEBUG
1093   /* check all invariants were kept */
1094   clutter_actor_verify_map_state (self);
1095 #endif
1096 }
1097
1098 static void
1099 clutter_actor_real_map (ClutterActor *self)
1100 {
1101   ClutterActorPrivate *priv = self->priv;
1102   ClutterActor *stage, *iter;
1103
1104   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1105
1106   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1107                 _clutter_actor_get_debug_name (self));
1108
1109   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1110
1111   stage = _clutter_actor_get_stage_internal (self);
1112   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1113
1114   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1115                 priv->pick_id,
1116                 _clutter_actor_get_debug_name (self));
1117
1118   /* notify on parent mapped before potentially mapping
1119    * children, so apps see a top-down notification.
1120    */
1121   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1122
1123   for (iter = self->priv->first_child;
1124        iter != NULL;
1125        iter = iter->priv->next_sibling)
1126     {
1127       clutter_actor_map (iter);
1128     }
1129 }
1130
1131 /**
1132  * clutter_actor_map:
1133  * @self: A #ClutterActor
1134  *
1135  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1136  * and realizes its children if they are visible. Does nothing if the
1137  * actor is not visible.
1138  *
1139  * Calling this function is strongly disencouraged: the default
1140  * implementation of #ClutterActorClass.map() will map all the children
1141  * of an actor when mapping its parent.
1142  *
1143  * When overriding map, it is mandatory to chain up to the parent
1144  * implementation.
1145  *
1146  * Since: 1.0
1147  */
1148 void
1149 clutter_actor_map (ClutterActor *self)
1150 {
1151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1152
1153   if (CLUTTER_ACTOR_IS_MAPPED (self))
1154     return;
1155
1156   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1157     return;
1158
1159   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1160 }
1161
1162 static void
1163 clutter_actor_real_unmap (ClutterActor *self)
1164 {
1165   ClutterActorPrivate *priv = self->priv;
1166   ClutterActor *iter;
1167
1168   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1169
1170   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1171                 _clutter_actor_get_debug_name (self));
1172
1173   for (iter = self->priv->first_child;
1174        iter != NULL;
1175        iter = iter->priv->next_sibling)
1176     {
1177       clutter_actor_unmap (iter);
1178     }
1179
1180   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1181
1182   /* clear the contents of the last paint volume, so that hiding + moving +
1183    * showing will not result in the wrong area being repainted
1184    */
1185   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1186   priv->last_paint_volume_valid = TRUE;
1187
1188   /* notify on parent mapped after potentially unmapping
1189    * children, so apps see a bottom-up notification.
1190    */
1191   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1192
1193   /* relinquish keyboard focus if we were unmapped while owning it */
1194   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1195     {
1196       ClutterStage *stage;
1197
1198       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1199
1200       if (stage != NULL)
1201         _clutter_stage_release_pick_id (stage, priv->pick_id);
1202
1203       priv->pick_id = -1;
1204
1205       if (stage != NULL &&
1206           clutter_stage_get_key_focus (stage) == self)
1207         {
1208           clutter_stage_set_key_focus (stage, NULL);
1209         }
1210     }
1211 }
1212
1213 /**
1214  * clutter_actor_unmap:
1215  * @self: A #ClutterActor
1216  *
1217  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1218  * unmaps its children if they were mapped.
1219  *
1220  * Calling this function is not encouraged: the default #ClutterActor
1221  * implementation of #ClutterActorClass.unmap() will also unmap any
1222  * eventual children by default when their parent is unmapped.
1223  *
1224  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1225  * chain up to the parent implementation.
1226  *
1227  * <note>It is important to note that the implementation of the
1228  * #ClutterActorClass.unmap() virtual function may be called after
1229  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1230  * implementation, but it is guaranteed to be called before the
1231  * #GObjectClass.finalize() implementation.</note>
1232  *
1233  * Since: 1.0
1234  */
1235 void
1236 clutter_actor_unmap (ClutterActor *self)
1237 {
1238   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1239
1240   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1241     return;
1242
1243   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1244 }
1245
1246 static void
1247 clutter_actor_real_show (ClutterActor *self)
1248 {
1249   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1250     {
1251       ClutterActorPrivate *priv = self->priv;
1252
1253       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1254
1255       /* we notify on the "visible" flag in the clutter_actor_show()
1256        * wrapper so the entire show signal emission completes first
1257        * (?)
1258        */
1259       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1260
1261       /* we queue a relayout unless the actor is inside a
1262        * container that explicitly told us not to
1263        */
1264       if (priv->parent != NULL &&
1265           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1266         {
1267           /* While an actor is hidden the parent may not have
1268            * allocated/requested so we need to start from scratch
1269            * and avoid the short-circuiting in
1270            * clutter_actor_queue_relayout().
1271            */
1272           priv->needs_width_request  = FALSE;
1273           priv->needs_height_request = FALSE;
1274           priv->needs_allocation     = FALSE;
1275           clutter_actor_queue_relayout (self);
1276         }
1277     }
1278 }
1279
1280 static inline void
1281 set_show_on_set_parent (ClutterActor *self,
1282                         gboolean      set_show)
1283 {
1284   ClutterActorPrivate *priv = self->priv;
1285
1286   set_show = !!set_show;
1287
1288   if (priv->show_on_set_parent == set_show)
1289     return;
1290
1291   if (priv->parent == NULL)
1292     {
1293       priv->show_on_set_parent = set_show;
1294       g_object_notify_by_pspec (G_OBJECT (self),
1295                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1296     }
1297 }
1298
1299 /**
1300  * clutter_actor_show:
1301  * @self: A #ClutterActor
1302  *
1303  * Flags an actor to be displayed. An actor that isn't shown will not
1304  * be rendered on the stage.
1305  *
1306  * Actors are visible by default.
1307  *
1308  * If this function is called on an actor without a parent, the
1309  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1310  * effect.
1311  */
1312 void
1313 clutter_actor_show (ClutterActor *self)
1314 {
1315   ClutterActorPrivate *priv;
1316
1317   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1318
1319   /* simple optimization */
1320   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1321     {
1322       /* we still need to set the :show-on-set-parent property, in
1323        * case show() is called on an unparented actor
1324        */
1325       set_show_on_set_parent (self, TRUE);
1326       return;
1327     }
1328
1329 #ifdef CLUTTER_ENABLE_DEBUG
1330   clutter_actor_verify_map_state (self);
1331 #endif
1332
1333   priv = self->priv;
1334
1335   g_object_freeze_notify (G_OBJECT (self));
1336
1337   set_show_on_set_parent (self, TRUE);
1338
1339   g_signal_emit (self, actor_signals[SHOW], 0);
1340   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1341
1342   if (priv->parent != NULL)
1343     clutter_actor_queue_redraw (priv->parent);
1344
1345   g_object_thaw_notify (G_OBJECT (self));
1346 }
1347
1348 /**
1349  * clutter_actor_show_all:
1350  * @self: a #ClutterActor
1351  *
1352  * Calls clutter_actor_show() on all children of an actor (if any).
1353  *
1354  * Since: 0.2
1355  *
1356  * Deprecated: 1.10: Actors are visible by default
1357  */
1358 void
1359 clutter_actor_show_all (ClutterActor *self)
1360 {
1361   ClutterActorClass *klass;
1362
1363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1364
1365   klass = CLUTTER_ACTOR_GET_CLASS (self);
1366   if (klass->show_all)
1367     klass->show_all (self);
1368 }
1369
1370 static void
1371 clutter_actor_real_hide (ClutterActor *self)
1372 {
1373   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1374     {
1375       ClutterActorPrivate *priv = self->priv;
1376
1377       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1378
1379       /* we notify on the "visible" flag in the clutter_actor_hide()
1380        * wrapper so the entire hide signal emission completes first
1381        * (?)
1382        */
1383       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1384
1385       /* we queue a relayout unless the actor is inside a
1386        * container that explicitly told us not to
1387        */
1388       if (priv->parent != NULL &&
1389           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1390         clutter_actor_queue_relayout (priv->parent);
1391     }
1392 }
1393
1394 /**
1395  * clutter_actor_hide:
1396  * @self: A #ClutterActor
1397  *
1398  * Flags an actor to be hidden. A hidden actor will not be
1399  * rendered on the stage.
1400  *
1401  * Actors are visible by default.
1402  *
1403  * If this function is called on an actor without a parent, the
1404  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1405  * as a side-effect.
1406  */
1407 void
1408 clutter_actor_hide (ClutterActor *self)
1409 {
1410   ClutterActorPrivate *priv;
1411
1412   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1413
1414   /* simple optimization */
1415   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1416     {
1417       /* we still need to set the :show-on-set-parent property, in
1418        * case hide() is called on an unparented actor
1419        */
1420       set_show_on_set_parent (self, FALSE);
1421       return;
1422     }
1423
1424 #ifdef CLUTTER_ENABLE_DEBUG
1425   clutter_actor_verify_map_state (self);
1426 #endif
1427
1428   priv = self->priv;
1429
1430   g_object_freeze_notify (G_OBJECT (self));
1431
1432   set_show_on_set_parent (self, FALSE);
1433
1434   g_signal_emit (self, actor_signals[HIDE], 0);
1435   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1436
1437   if (priv->parent != NULL)
1438     clutter_actor_queue_redraw (priv->parent);
1439
1440   g_object_thaw_notify (G_OBJECT (self));
1441 }
1442
1443 /**
1444  * clutter_actor_hide_all:
1445  * @self: a #ClutterActor
1446  *
1447  * Calls clutter_actor_hide() on all child actors (if any).
1448  *
1449  * Since: 0.2
1450  *
1451  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1452  *   prevent its children from being painted as well.
1453  */
1454 void
1455 clutter_actor_hide_all (ClutterActor *self)
1456 {
1457   ClutterActorClass *klass;
1458
1459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1460
1461   klass = CLUTTER_ACTOR_GET_CLASS (self);
1462   if (klass->hide_all)
1463     klass->hide_all (self);
1464 }
1465
1466 /**
1467  * clutter_actor_realize:
1468  * @self: A #ClutterActor
1469  *
1470  * Realization informs the actor that it is attached to a stage. It
1471  * can use this to allocate resources if it wanted to delay allocation
1472  * until it would be rendered. However it is perfectly acceptable for
1473  * an actor to create resources before being realized because Clutter
1474  * only ever has a single rendering context so that actor is free to
1475  * be moved from one stage to another.
1476  *
1477  * This function does nothing if the actor is already realized.
1478  *
1479  * Because a realized actor must have realized parent actors, calling
1480  * clutter_actor_realize() will also realize all parents of the actor.
1481  *
1482  * This function does not realize child actors, except in the special
1483  * case that realizing the stage, when the stage is visible, will
1484  * suddenly map (and thus realize) the children of the stage.
1485  **/
1486 void
1487 clutter_actor_realize (ClutterActor *self)
1488 {
1489   ClutterActorPrivate *priv;
1490
1491   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1492
1493   priv = self->priv;
1494
1495 #ifdef CLUTTER_ENABLE_DEBUG
1496   clutter_actor_verify_map_state (self);
1497 #endif
1498
1499   if (CLUTTER_ACTOR_IS_REALIZED (self))
1500     return;
1501
1502   /* To be realized, our parent actors must be realized first.
1503    * This will only succeed if we're inside a toplevel.
1504    */
1505   if (priv->parent != NULL)
1506     clutter_actor_realize (priv->parent);
1507
1508   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1509     {
1510       /* toplevels can be realized at any time */
1511     }
1512   else
1513     {
1514       /* "Fail" the realization if parent is missing or unrealized;
1515        * this should really be a g_warning() not some kind of runtime
1516        * failure; how can an app possibly recover? Instead it's a bug
1517        * in the app and the app should get an explanatory warning so
1518        * someone can fix it. But for now it's too hard to fix this
1519        * because e.g. ClutterTexture needs reworking.
1520        */
1521       if (priv->parent == NULL ||
1522           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1523         return;
1524     }
1525
1526   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1527
1528   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1529   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1530
1531   g_signal_emit (self, actor_signals[REALIZE], 0);
1532
1533   /* Stage actor is allowed to unset the realized flag again in its
1534    * default signal handler, though that is a pathological situation.
1535    */
1536
1537   /* If realization "failed" we'll have to update child state. */
1538   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1539 }
1540
1541 static void
1542 clutter_actor_real_unrealize (ClutterActor *self)
1543 {
1544   /* we must be unmapped (implying our children are also unmapped) */
1545   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1546 }
1547
1548 /**
1549  * clutter_actor_unrealize:
1550  * @self: A #ClutterActor
1551  *
1552  * Unrealization informs the actor that it may be being destroyed or
1553  * moved to another stage. The actor may want to destroy any
1554  * underlying graphics resources at this point. However it is
1555  * perfectly acceptable for it to retain the resources until the actor
1556  * is destroyed because Clutter only ever uses a single rendering
1557  * context and all of the graphics resources are valid on any stage.
1558  *
1559  * Because mapped actors must be realized, actors may not be
1560  * unrealized if they are mapped. This function hides the actor to be
1561  * sure it isn't mapped, an application-visible side effect that you
1562  * may not be expecting.
1563  *
1564  * This function should not be called by application code.
1565  */
1566 void
1567 clutter_actor_unrealize (ClutterActor *self)
1568 {
1569   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1570   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1571
1572 /* This function should not really be in the public API, because
1573  * there isn't a good reason to call it. ClutterActor will already
1574  * unrealize things for you when it's important to do so.
1575  *
1576  * If you were using clutter_actor_unrealize() in a dispose
1577  * implementation, then don't, just chain up to ClutterActor's
1578  * dispose.
1579  *
1580  * If you were using clutter_actor_unrealize() to implement
1581  * unrealizing children of your container, then don't, ClutterActor
1582  * will already take care of that.
1583  *
1584  * If you were using clutter_actor_unrealize() to re-realize to
1585  * create your resources in a different way, then use
1586  * _clutter_actor_rerealize() (inside Clutter) or just call your
1587  * code that recreates your resources directly (outside Clutter).
1588  */
1589
1590 #ifdef CLUTTER_ENABLE_DEBUG
1591   clutter_actor_verify_map_state (self);
1592 #endif
1593
1594   clutter_actor_hide (self);
1595
1596   clutter_actor_unrealize_not_hiding (self);
1597 }
1598
1599 static ClutterActorTraverseVisitFlags
1600 unrealize_actor_before_children_cb (ClutterActor *self,
1601                                     int depth,
1602                                     void *user_data)
1603 {
1604   /* If an actor is already unrealized we know its children have also
1605    * already been unrealized... */
1606   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1607     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1608
1609   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1610
1611   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1612 }
1613
1614 static ClutterActorTraverseVisitFlags
1615 unrealize_actor_after_children_cb (ClutterActor *self,
1616                                    int depth,
1617                                    void *user_data)
1618 {
1619   /* We want to unset the realized flag only _after_
1620    * child actors are unrealized, to maintain invariants.
1621    */
1622   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1623   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1624   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1625 }
1626
1627 /*
1628  * clutter_actor_unrealize_not_hiding:
1629  * @self: A #ClutterActor
1630  *
1631  * Unrealization informs the actor that it may be being destroyed or
1632  * moved to another stage. The actor may want to destroy any
1633  * underlying graphics resources at this point. However it is
1634  * perfectly acceptable for it to retain the resources until the actor
1635  * is destroyed because Clutter only ever uses a single rendering
1636  * context and all of the graphics resources are valid on any stage.
1637  *
1638  * Because mapped actors must be realized, actors may not be
1639  * unrealized if they are mapped. You must hide the actor or one of
1640  * its parents before attempting to unrealize.
1641  *
1642  * This function is separate from clutter_actor_unrealize() because it
1643  * does not automatically hide the actor.
1644  * Actors need not be hidden to be unrealized, they just need to
1645  * be unmapped. In fact we don't want to mess up the application's
1646  * setting of the "visible" flag, so hiding is very undesirable.
1647  *
1648  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1649  * backward compatibility.
1650  */
1651 static void
1652 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1653 {
1654   _clutter_actor_traverse (self,
1655                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1656                            unrealize_actor_before_children_cb,
1657                            unrealize_actor_after_children_cb,
1658                            NULL);
1659 }
1660
1661 /*
1662  * _clutter_actor_rerealize:
1663  * @self: A #ClutterActor
1664  * @callback: Function to call while unrealized
1665  * @data: data for callback
1666  *
1667  * If an actor is already unrealized, this just calls the callback.
1668  *
1669  * If it is realized, it unrealizes temporarily, calls the callback,
1670  * and then re-realizes the actor.
1671  *
1672  * As a side effect, leaves all children of the actor unrealized if
1673  * the actor was realized but not showing.  This is because when we
1674  * unrealize the actor temporarily we must unrealize its children
1675  * (e.g. children of a stage can't be realized if stage window is
1676  * gone). And we aren't clever enough to save the realization state of
1677  * all children. In most cases this should not matter, because
1678  * the children will automatically realize when they next become mapped.
1679  */
1680 void
1681 _clutter_actor_rerealize (ClutterActor    *self,
1682                           ClutterCallback  callback,
1683                           void            *data)
1684 {
1685   gboolean was_mapped;
1686   gboolean was_showing;
1687   gboolean was_realized;
1688
1689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1690
1691 #ifdef CLUTTER_ENABLE_DEBUG
1692   clutter_actor_verify_map_state (self);
1693 #endif
1694
1695   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1696   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1697   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1698
1699   /* Must be unmapped to unrealize. Note we only have to hide this
1700    * actor if it was mapped (if all parents were showing).  If actor
1701    * is merely visible (but not mapped), then that's fine, we can
1702    * leave it visible.
1703    */
1704   if (was_mapped)
1705     clutter_actor_hide (self);
1706
1707   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1708
1709   /* unrealize self and all children */
1710   clutter_actor_unrealize_not_hiding (self);
1711
1712   if (callback != NULL)
1713     {
1714       (* callback) (self, data);
1715     }
1716
1717   if (was_showing)
1718     clutter_actor_show (self); /* will realize only if mapping implies it */
1719   else if (was_realized)
1720     clutter_actor_realize (self); /* realize self and all parents */
1721 }
1722
1723 static void
1724 clutter_actor_real_pick (ClutterActor       *self,
1725                          const ClutterColor *color)
1726 {
1727   /* the default implementation is just to paint a rectangle
1728    * with the same size of the actor using the passed color
1729    */
1730   if (clutter_actor_should_pick_paint (self))
1731     {
1732       ClutterActorBox box = { 0, };
1733       float width, height;
1734
1735       clutter_actor_get_allocation_box (self, &box);
1736
1737       width = box.x2 - box.x1;
1738       height = box.y2 - box.y1;
1739
1740       cogl_set_source_color4ub (color->red,
1741                                 color->green,
1742                                 color->blue,
1743                                 color->alpha);
1744
1745       cogl_rectangle (0, 0, width, height);
1746     }
1747
1748   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1749    * with existing container classes that override the pick() virtual
1750    * and chain up to the default implementation - otherwise we'll end up
1751    * painting our children twice.
1752    *
1753    * this has to go away for 2.0; hopefully along the pick() itself.
1754    */
1755   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1756     {
1757       ClutterActor *iter;
1758
1759       for (iter = self->priv->first_child;
1760            iter != NULL;
1761            iter = iter->priv->next_sibling)
1762         clutter_actor_paint (iter);
1763     }
1764 }
1765
1766 /**
1767  * clutter_actor_should_pick_paint:
1768  * @self: A #ClutterActor
1769  *
1770  * Should be called inside the implementation of the
1771  * #ClutterActor::pick virtual function in order to check whether
1772  * the actor should paint itself in pick mode or not.
1773  *
1774  * This function should never be called directly by applications.
1775  *
1776  * Return value: %TRUE if the actor should paint its silhouette,
1777  *   %FALSE otherwise
1778  */
1779 gboolean
1780 clutter_actor_should_pick_paint (ClutterActor *self)
1781 {
1782   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1783
1784   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1785       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1786        CLUTTER_ACTOR_IS_REACTIVE (self)))
1787     return TRUE;
1788
1789   return FALSE;
1790 }
1791
1792 static void
1793 clutter_actor_real_get_preferred_width (ClutterActor *self,
1794                                         gfloat        for_height,
1795                                         gfloat       *min_width_p,
1796                                         gfloat       *natural_width_p)
1797 {
1798   ClutterActorPrivate *priv = self->priv;
1799
1800   if (priv->n_children != 0 &&
1801       priv->layout_manager != NULL)
1802     {
1803       ClutterContainer *container = CLUTTER_CONTAINER (self);
1804
1805       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1806                     "for the preferred width",
1807                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1808                     priv->layout_manager);
1809
1810       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1811                                                   container,
1812                                                   for_height,
1813                                                   min_width_p,
1814                                                   natural_width_p);
1815
1816       return;
1817     }
1818
1819   /* Default implementation is always 0x0, usually an actor
1820    * using this default is relying on someone to set the
1821    * request manually
1822    */
1823   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1824
1825   if (min_width_p)
1826     *min_width_p = 0;
1827
1828   if (natural_width_p)
1829     *natural_width_p = 0;
1830 }
1831
1832 static void
1833 clutter_actor_real_get_preferred_height (ClutterActor *self,
1834                                          gfloat        for_width,
1835                                          gfloat       *min_height_p,
1836                                          gfloat       *natural_height_p)
1837 {
1838   ClutterActorPrivate *priv = self->priv;
1839
1840   if (priv->n_children != 0 &&
1841       priv->layout_manager != NULL)
1842     {
1843       ClutterContainer *container = CLUTTER_CONTAINER (self);
1844
1845       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1846                     "for the preferred height",
1847                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1848                     priv->layout_manager);
1849
1850       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1851                                                    container,
1852                                                    for_width,
1853                                                    min_height_p,
1854                                                    natural_height_p);
1855
1856       return;
1857     }
1858   /* Default implementation is always 0x0, usually an actor
1859    * using this default is relying on someone to set the
1860    * request manually
1861    */
1862   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1863
1864   if (min_height_p)
1865     *min_height_p = 0;
1866
1867   if (natural_height_p)
1868     *natural_height_p = 0;
1869 }
1870
1871 static void
1872 clutter_actor_store_old_geometry (ClutterActor    *self,
1873                                   ClutterActorBox *box)
1874 {
1875   *box = self->priv->allocation;
1876 }
1877
1878 static inline void
1879 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1880                                           const ClutterActorBox *old)
1881 {
1882   ClutterActorPrivate *priv = self->priv;
1883   GObject *obj = G_OBJECT (self);
1884
1885   g_object_freeze_notify (obj);
1886
1887   /* to avoid excessive requisition or allocation cycles we
1888    * use the cached values.
1889    *
1890    * - if we don't have an allocation we assume that we need
1891    *   to notify anyway
1892    * - if we don't have a width or a height request we notify
1893    *   width and height
1894    * - if we have a valid allocation then we check the old
1895    *   bounding box with the current allocation and we notify
1896    *   the changes
1897    */
1898   if (priv->needs_allocation)
1899     {
1900       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1901       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1904     }
1905   else if (priv->needs_width_request || priv->needs_height_request)
1906     {
1907       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1908       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1909     }
1910   else
1911     {
1912       gfloat xu, yu;
1913       gfloat widthu, heightu;
1914
1915       xu = priv->allocation.x1;
1916       yu = priv->allocation.y1;
1917       widthu = priv->allocation.x2 - priv->allocation.x1;
1918       heightu = priv->allocation.y2 - priv->allocation.y1;
1919
1920       if (xu != old->x1)
1921         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1922
1923       if (yu != old->y1)
1924         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1925
1926       if (widthu != (old->x2 - old->x1))
1927         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1928
1929       if (heightu != (old->y2 - old->y1))
1930         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1931     }
1932
1933   g_object_thaw_notify (obj);
1934 }
1935
1936 /*< private >
1937  * clutter_actor_set_allocation_internal:
1938  * @self: a #ClutterActor
1939  * @box: a #ClutterActorBox
1940  * @flags: allocation flags
1941  *
1942  * Stores the allocation of @self.
1943  *
1944  * This function only performs basic storage and property notification.
1945  *
1946  * This function should be called by clutter_actor_set_allocation()
1947  * and by the default implementation of #ClutterActorClass.allocate().
1948  *
1949  * Return value: %TRUE if the allocation of the #ClutterActor has been
1950  *   changed, and %FALSE otherwise
1951  */
1952 static inline gboolean
1953 clutter_actor_set_allocation_internal (ClutterActor           *self,
1954                                        const ClutterActorBox  *box,
1955                                        ClutterAllocationFlags  flags)
1956 {
1957   ClutterActorPrivate *priv = self->priv;
1958   GObject *obj;
1959   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1960   gboolean flags_changed;
1961   gboolean retval;
1962   ClutterActorBox old_alloc = { 0, };
1963
1964   obj = G_OBJECT (self);
1965
1966   g_object_freeze_notify (obj);
1967
1968   clutter_actor_store_old_geometry (self, &old_alloc);
1969
1970   x1_changed = priv->allocation.x1 != box->x1;
1971   y1_changed = priv->allocation.y1 != box->y1;
1972   x2_changed = priv->allocation.x2 != box->x2;
1973   y2_changed = priv->allocation.y2 != box->y2;
1974
1975   flags_changed = priv->allocation_flags != flags;
1976
1977   priv->allocation = *box;
1978   priv->allocation_flags = flags;
1979
1980   /* allocation is authoritative */
1981   priv->needs_width_request = FALSE;
1982   priv->needs_height_request = FALSE;
1983   priv->needs_allocation = FALSE;
1984
1985   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1986     {
1987       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1988                     _clutter_actor_get_debug_name (self));
1989
1990       priv->transform_valid = FALSE;
1991
1992       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1993
1994       retval = TRUE;
1995     }
1996   else
1997     retval = FALSE;
1998
1999   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2000
2001   g_object_thaw_notify (obj);
2002
2003   return retval;
2004 }
2005
2006 static void clutter_actor_real_allocate (ClutterActor           *self,
2007                                          const ClutterActorBox  *box,
2008                                          ClutterAllocationFlags  flags);
2009
2010 static inline void
2011 clutter_actor_maybe_layout_children (ClutterActor           *self,
2012                                      const ClutterActorBox  *allocation,
2013                                      ClutterAllocationFlags  flags)
2014 {
2015   ClutterActorPrivate *priv = self->priv;
2016
2017   /* this is going to be a bit hard to follow, so let's put an explanation
2018    * here.
2019    *
2020    * we want ClutterActor to have a default layout manager if the actor was
2021    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2022    *
2023    * we also want any subclass of ClutterActor that does not override the
2024    * ::allocate() virtual function to delegate to a layout manager.
2025    *
2026    * finally, we want to allow people subclassing ClutterActor and overriding
2027    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2028    *
2029    * on the other hand, we want existing actor subclasses overriding the
2030    * ::allocate() virtual function and chaining up to the parent's
2031    * implementation to continue working without allocating their children
2032    * twice, or without entering an allocation loop.
2033    *
2034    * for the first two points, we check if the class of the actor is
2035    * overridding the ::allocate() virtual function; if it isn't, then we
2036    * follow through with checking whether we have children and a layout
2037    * manager, and eventually calling clutter_layout_manager_allocate().
2038    *
2039    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2040    * allocation flags that we got passed, and if it is present, we continue
2041    * with the check above.
2042    *
2043    * if neither of these two checks yields a positive result, we just
2044    * assume that the ::allocate() virtual function that resulted in this
2045    * function being called will also allocate the children of the actor.
2046    */
2047
2048   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2049     goto check_layout;
2050
2051   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2052     goto check_layout;
2053
2054   return;
2055
2056 check_layout:
2057   if (priv->n_children != 0 &&
2058       priv->layout_manager != NULL)
2059     {
2060       ClutterContainer *container = CLUTTER_CONTAINER (self);
2061       ClutterAllocationFlags children_flags;
2062       ClutterActorBox children_box;
2063
2064       /* normalize the box passed to the layout manager */
2065       children_box.x1 = children_box.y1 = 0.f;
2066       children_box.x2 = (allocation->x2 - allocation->x1);
2067       children_box.y2 = (allocation->y2 - allocation->y1);
2068
2069       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2070        * the actor's children, since it refers only to the current
2071        * actor's allocation.
2072        */
2073       children_flags = flags;
2074       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2075
2076       CLUTTER_NOTE (LAYOUT,
2077                     "Allocating %d children of %s "
2078                     "at { %.2f, %.2f - %.2f x %.2f } "
2079                     "using %s",
2080                     priv->n_children,
2081                     _clutter_actor_get_debug_name (self),
2082                     allocation->x1,
2083                     allocation->y1,
2084                     (allocation->x2 - allocation->x1),
2085                     (allocation->y2 - allocation->y1),
2086                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2087
2088       clutter_layout_manager_allocate (priv->layout_manager,
2089                                        container,
2090                                        &children_box,
2091                                        children_flags);
2092     }
2093 }
2094
2095 static void
2096 clutter_actor_real_allocate (ClutterActor           *self,
2097                              const ClutterActorBox  *box,
2098                              ClutterAllocationFlags  flags)
2099 {
2100   ClutterActorPrivate *priv = self->priv;
2101   gboolean changed;
2102
2103   g_object_freeze_notify (G_OBJECT (self));
2104
2105   changed = clutter_actor_set_allocation_internal (self, box, flags);
2106
2107   /* we allocate our children before we notify changes in our geometry,
2108    * so that people connecting to properties will be able to get valid
2109    * data out of the sub-tree of the scene graph that has this actor at
2110    * the root.
2111    */
2112   clutter_actor_maybe_layout_children (self, box, flags);
2113
2114   if (changed)
2115     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2116                    &priv->allocation,
2117                    priv->allocation_flags);
2118
2119   g_object_thaw_notify (G_OBJECT (self));
2120 }
2121
2122 static void
2123 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2124                                     ClutterActor *origin)
2125 {
2126   /* no point in queuing a redraw on a destroyed actor */
2127   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2128     return;
2129
2130   /* NB: We can't bail out early here if the actor is hidden in case
2131    * the actor bas been cloned. In this case the clone will need to
2132    * receive the signal so it can queue its own redraw.
2133    */
2134
2135   /* calls klass->queue_redraw in default handler */
2136   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2137 }
2138
2139 static void
2140 clutter_actor_real_queue_redraw (ClutterActor *self,
2141                                  ClutterActor *origin)
2142 {
2143   ClutterActor *parent;
2144
2145   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2146                 _clutter_actor_get_debug_name (self),
2147                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2148                                : "same actor");
2149
2150   /* no point in queuing a redraw on a destroyed actor */
2151   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2152     return;
2153
2154   /* If the queue redraw is coming from a child then the actor has
2155      become dirty and any queued effect is no longer valid */
2156   if (self != origin)
2157     {
2158       self->priv->is_dirty = TRUE;
2159       self->priv->effect_to_redraw = NULL;
2160     }
2161
2162   /* If the actor isn't visible, we still had to emit the signal
2163    * to allow for a ClutterClone, but the appearance of the parent
2164    * won't change so we don't have to propagate up the hierarchy.
2165    */
2166   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2167     return;
2168
2169   /* Although we could determine here that a full stage redraw
2170    * has already been queued and immediately bail out, we actually
2171    * guarantee that we will propagate a queue-redraw signal to our
2172    * parent at least once so that it's possible to implement a
2173    * container that tracks which of its children have queued a
2174    * redraw.
2175    */
2176   if (self->priv->propagated_one_redraw)
2177     {
2178       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2179       if (stage != NULL &&
2180           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2181         return;
2182     }
2183
2184   self->priv->propagated_one_redraw = TRUE;
2185
2186   /* notify parents, if they are all visible eventually we'll
2187    * queue redraw on the stage, which queues the redraw idle.
2188    */
2189   parent = clutter_actor_get_parent (self);
2190   if (parent != NULL)
2191     {
2192       /* this will go up recursively */
2193       _clutter_actor_signal_queue_redraw (parent, origin);
2194     }
2195 }
2196
2197 static void
2198 clutter_actor_real_queue_relayout (ClutterActor *self)
2199 {
2200   ClutterActorPrivate *priv = self->priv;
2201
2202   /* no point in queueing a redraw on a destroyed actor */
2203   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2204     return;
2205
2206   priv->needs_width_request  = TRUE;
2207   priv->needs_height_request = TRUE;
2208   priv->needs_allocation     = TRUE;
2209
2210   /* reset the cached size requests */
2211   memset (priv->width_requests, 0,
2212           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2213   memset (priv->height_requests, 0,
2214           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2215
2216   /* We need to go all the way up the hierarchy */
2217   if (priv->parent != NULL)
2218     _clutter_actor_queue_only_relayout (priv->parent);
2219 }
2220
2221 /**
2222  * clutter_actor_apply_relative_transform_to_point:
2223  * @self: A #ClutterActor
2224  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2225  *   default #ClutterStage
2226  * @point: A point as #ClutterVertex
2227  * @vertex: (out caller-allocates): The translated #ClutterVertex
2228  *
2229  * Transforms @point in coordinates relative to the actor into
2230  * ancestor-relative coordinates using the relevant transform
2231  * stack (i.e. scale, rotation, etc).
2232  *
2233  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2234  * this case, the coordinates returned will be the coordinates on
2235  * the stage before the projection is applied. This is different from
2236  * the behaviour of clutter_actor_apply_transform_to_point().
2237  *
2238  * Since: 0.6
2239  */
2240 void
2241 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2242                                                  ClutterActor        *ancestor,
2243                                                  const ClutterVertex *point,
2244                                                  ClutterVertex       *vertex)
2245 {
2246   gfloat w;
2247   CoglMatrix matrix;
2248
2249   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2250   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2251   g_return_if_fail (point != NULL);
2252   g_return_if_fail (vertex != NULL);
2253
2254   *vertex = *point;
2255   w = 1.0;
2256
2257   if (ancestor == NULL)
2258     ancestor = _clutter_actor_get_stage_internal (self);
2259
2260   if (ancestor == NULL)
2261     {
2262       *vertex = *point;
2263       return;
2264     }
2265
2266   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2267   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2268 }
2269
2270 static gboolean
2271 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2272                                          const ClutterVertex *vertices_in,
2273                                          ClutterVertex *vertices_out,
2274                                          int n_vertices)
2275 {
2276   ClutterActor *stage;
2277   CoglMatrix modelview;
2278   CoglMatrix projection;
2279   float viewport[4];
2280
2281   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2282
2283   stage = _clutter_actor_get_stage_internal (self);
2284
2285   /* We really can't do anything meaningful in this case so don't try
2286    * to do any transform */
2287   if (stage == NULL)
2288     return FALSE;
2289
2290   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2291    * that gets us to stage coordinates, we want to go all the way to eye
2292    * coordinates */
2293   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2294
2295   /* Fetch the projection and viewport */
2296   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2297   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2298                                &viewport[0],
2299                                &viewport[1],
2300                                &viewport[2],
2301                                &viewport[3]);
2302
2303   _clutter_util_fully_transform_vertices (&modelview,
2304                                           &projection,
2305                                           viewport,
2306                                           vertices_in,
2307                                           vertices_out,
2308                                           n_vertices);
2309
2310   return TRUE;
2311 }
2312
2313 /**
2314  * clutter_actor_apply_transform_to_point:
2315  * @self: A #ClutterActor
2316  * @point: A point as #ClutterVertex
2317  * @vertex: (out caller-allocates): The translated #ClutterVertex
2318  *
2319  * Transforms @point in coordinates relative to the actor
2320  * into screen-relative coordinates with the current actor
2321  * transformation (i.e. scale, rotation, etc)
2322  *
2323  * Since: 0.4
2324  **/
2325 void
2326 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2327                                         const ClutterVertex *point,
2328                                         ClutterVertex       *vertex)
2329 {
2330   g_return_if_fail (point != NULL);
2331   g_return_if_fail (vertex != NULL);
2332   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2333 }
2334
2335 /*
2336  * _clutter_actor_get_relative_transformation_matrix:
2337  * @self: The actor whose coordinate space you want to transform from.
2338  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2339  *            or %NULL if you want to transform all the way to eye coordinates.
2340  * @matrix: A #CoglMatrix to store the transformation
2341  *
2342  * This gets a transformation @matrix that will transform coordinates from the
2343  * coordinate space of @self into the coordinate space of @ancestor.
2344  *
2345  * For example if you need a matrix that can transform the local actor
2346  * coordinates of @self into stage coordinates you would pass the actor's stage
2347  * pointer as the @ancestor.
2348  *
2349  * If you pass %NULL then the transformation will take you all the way through
2350  * to eye coordinates. This can be useful if you want to extract the entire
2351  * modelview transform that Clutter applies before applying the projection
2352  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2353  * using cogl_set_modelview_matrix() for example then you would want a matrix
2354  * that transforms into eye coordinates.
2355  *
2356  * <note><para>This function explicitly initializes the given @matrix. If you just
2357  * want clutter to multiply a relative transformation with an existing matrix
2358  * you can use clutter_actor_apply_relative_transformation_matrix()
2359  * instead.</para></note>
2360  *
2361  */
2362 /* XXX: We should consider caching the stage relative modelview along with
2363  * the actor itself */
2364 static void
2365 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2366                                                    ClutterActor *ancestor,
2367                                                    CoglMatrix *matrix)
2368 {
2369   cogl_matrix_init_identity (matrix);
2370
2371   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2372 }
2373
2374 /* Project the given @box into stage window coordinates, writing the
2375  * transformed vertices to @verts[]. */
2376 static gboolean
2377 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2378                                           const ClutterActorBox *box,
2379                                           ClutterVertex          verts[])
2380 {
2381   ClutterVertex box_vertices[4];
2382
2383   box_vertices[0].x = box->x1;
2384   box_vertices[0].y = box->y1;
2385   box_vertices[0].z = 0;
2386   box_vertices[1].x = box->x2;
2387   box_vertices[1].y = box->y1;
2388   box_vertices[1].z = 0;
2389   box_vertices[2].x = box->x1;
2390   box_vertices[2].y = box->y2;
2391   box_vertices[2].z = 0;
2392   box_vertices[3].x = box->x2;
2393   box_vertices[3].y = box->y2;
2394   box_vertices[3].z = 0;
2395
2396   return
2397     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2398 }
2399
2400 /**
2401  * clutter_actor_get_allocation_vertices:
2402  * @self: A #ClutterActor
2403  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2404  *   against, or %NULL to use the #ClutterStage
2405  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2406  *   location for an array of 4 #ClutterVertex in which to store the result
2407  *
2408  * Calculates the transformed coordinates of the four corners of the
2409  * actor in the plane of @ancestor. The returned vertices relate to
2410  * the #ClutterActorBox coordinates as follows:
2411  * <itemizedlist>
2412  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2413  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2414  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2415  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2416  * </itemizedlist>
2417  *
2418  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2419  * this case, the coordinates returned will be the coordinates on
2420  * the stage before the projection is applied. This is different from
2421  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2422  *
2423  * Since: 0.6
2424  */
2425 void
2426 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2427                                        ClutterActor  *ancestor,
2428                                        ClutterVertex  verts[])
2429 {
2430   ClutterActorPrivate *priv;
2431   ClutterActorBox box;
2432   ClutterVertex vertices[4];
2433   CoglMatrix modelview;
2434
2435   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2436   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2437
2438   if (ancestor == NULL)
2439     ancestor = _clutter_actor_get_stage_internal (self);
2440
2441   /* Fallback to a NOP transform if the actor isn't parented under a
2442    * stage. */
2443   if (ancestor == NULL)
2444     ancestor = self;
2445
2446   priv = self->priv;
2447
2448   /* if the actor needs to be allocated we force a relayout, so that
2449    * we will have valid values to use in the transformations */
2450   if (priv->needs_allocation)
2451     {
2452       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2453       if (stage)
2454         _clutter_stage_maybe_relayout (stage);
2455       else
2456         {
2457           box.x1 = box.y1 = 0;
2458           /* The result isn't really meaningful in this case but at
2459            * least try to do something *vaguely* reasonable... */
2460           clutter_actor_get_size (self, &box.x2, &box.y2);
2461         }
2462     }
2463
2464   clutter_actor_get_allocation_box (self, &box);
2465
2466   vertices[0].x = box.x1;
2467   vertices[0].y = box.y1;
2468   vertices[0].z = 0;
2469   vertices[1].x = box.x2;
2470   vertices[1].y = box.y1;
2471   vertices[1].z = 0;
2472   vertices[2].x = box.x1;
2473   vertices[2].y = box.y2;
2474   vertices[2].z = 0;
2475   vertices[3].x = box.x2;
2476   vertices[3].y = box.y2;
2477   vertices[3].z = 0;
2478
2479   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2480                                                      &modelview);
2481
2482   cogl_matrix_transform_points (&modelview,
2483                                 3,
2484                                 sizeof (ClutterVertex),
2485                                 vertices,
2486                                 sizeof (ClutterVertex),
2487                                 vertices,
2488                                 4);
2489 }
2490
2491 /**
2492  * clutter_actor_get_abs_allocation_vertices:
2493  * @self: A #ClutterActor
2494  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2495  *   of 4 #ClutterVertex where to store the result.
2496  *
2497  * Calculates the transformed screen coordinates of the four corners of
2498  * the actor; the returned vertices relate to the #ClutterActorBox
2499  * coordinates  as follows:
2500  * <itemizedlist>
2501  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2502  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2503  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2504  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2505  * </itemizedlist>
2506  *
2507  * Since: 0.4
2508  */
2509 void
2510 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2511                                            ClutterVertex  verts[])
2512 {
2513   ClutterActorPrivate *priv;
2514   ClutterActorBox actor_space_allocation;
2515
2516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2517
2518   priv = self->priv;
2519
2520   /* if the actor needs to be allocated we force a relayout, so that
2521    * the actor allocation box will be valid for
2522    * _clutter_actor_transform_and_project_box()
2523    */
2524   if (priv->needs_allocation)
2525     {
2526       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2527       /* There's nothing meaningful we can do now */
2528       if (!stage)
2529         return;
2530
2531       _clutter_stage_maybe_relayout (stage);
2532     }
2533
2534   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2535    * own coordinate space... */
2536   actor_space_allocation.x1 = 0;
2537   actor_space_allocation.y1 = 0;
2538   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2539   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2540   _clutter_actor_transform_and_project_box (self,
2541                                             &actor_space_allocation,
2542                                             verts);
2543 }
2544
2545 static void
2546 clutter_actor_real_apply_transform (ClutterActor *self,
2547                                     CoglMatrix   *matrix)
2548 {
2549   ClutterActorPrivate *priv = self->priv;
2550
2551   if (!priv->transform_valid)
2552     {
2553       CoglMatrix *transform = &priv->transform;
2554       const ClutterTransformInfo *info;
2555
2556       info = _clutter_actor_get_transform_info_or_defaults (self);
2557
2558       cogl_matrix_init_identity (transform);
2559
2560       cogl_matrix_translate (transform,
2561                              priv->allocation.x1,
2562                              priv->allocation.y1,
2563                              0.0);
2564
2565       if (priv->z)
2566         cogl_matrix_translate (transform, 0, 0, priv->z);
2567
2568       /*
2569        * because the rotation involves translations, we must scale
2570        * before applying the rotations (if we apply the scale after
2571        * the rotations, the translations included in the rotation are
2572        * not scaled and so the entire object will move on the screen
2573        * as a result of rotating it).
2574        */
2575       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2576         {
2577           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2578                                         &info->scale_center,
2579                                         cogl_matrix_scale (transform,
2580                                                            info->scale_x,
2581                                                            info->scale_y,
2582                                                            1.0));
2583         }
2584
2585       if (info->rz_angle)
2586         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2587                                       &info->rz_center,
2588                                       cogl_matrix_rotate (transform,
2589                                                           info->rz_angle,
2590                                                           0, 0, 1.0));
2591
2592       if (info->ry_angle)
2593         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2594                                       &info->ry_center,
2595                                       cogl_matrix_rotate (transform,
2596                                                           info->ry_angle,
2597                                                           0, 1.0, 0));
2598
2599       if (info->rx_angle)
2600         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2601                                       &info->rx_center,
2602                                       cogl_matrix_rotate (transform,
2603                                                           info->rx_angle,
2604                                                           1.0, 0, 0));
2605
2606       if (!clutter_anchor_coord_is_zero (&info->anchor))
2607         {
2608           gfloat x, y, z;
2609
2610           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2611           cogl_matrix_translate (transform, -x, -y, -z);
2612         }
2613
2614       priv->transform_valid = TRUE;
2615     }
2616
2617   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2618 }
2619
2620 /* Applies the transforms associated with this actor to the given
2621  * matrix. */
2622 void
2623 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2624                                           CoglMatrix *matrix)
2625 {
2626   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2627 }
2628
2629 /*
2630  * clutter_actor_apply_relative_transformation_matrix:
2631  * @self: The actor whose coordinate space you want to transform from.
2632  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2633  *            or %NULL if you want to transform all the way to eye coordinates.
2634  * @matrix: A #CoglMatrix to apply the transformation too.
2635  *
2636  * This multiplies a transform with @matrix that will transform coordinates
2637  * from the coordinate space of @self into the coordinate space of @ancestor.
2638  *
2639  * For example if you need a matrix that can transform the local actor
2640  * coordinates of @self into stage coordinates you would pass the actor's stage
2641  * pointer as the @ancestor.
2642  *
2643  * If you pass %NULL then the transformation will take you all the way through
2644  * to eye coordinates. This can be useful if you want to extract the entire
2645  * modelview transform that Clutter applies before applying the projection
2646  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2647  * using cogl_set_modelview_matrix() for example then you would want a matrix
2648  * that transforms into eye coordinates.
2649  *
2650  * <note>This function doesn't initialize the given @matrix, it simply
2651  * multiplies the requested transformation matrix with the existing contents of
2652  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2653  * before calling this function, or you can use
2654  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2655  */
2656 void
2657 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2658                                                      ClutterActor *ancestor,
2659                                                      CoglMatrix *matrix)
2660 {
2661   ClutterActor *parent;
2662
2663   /* Note we terminate before ever calling stage->apply_transform()
2664    * since that would conceptually be relative to the underlying
2665    * window OpenGL coordinates so we'd need a special @ancestor
2666    * value to represent the fake parent of the stage. */
2667   if (self == ancestor)
2668     return;
2669
2670   parent = clutter_actor_get_parent (self);
2671
2672   if (parent != NULL)
2673     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2674                                                          matrix);
2675
2676   _clutter_actor_apply_modelview_transform (self, matrix);
2677 }
2678
2679 static void
2680 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2681                                        ClutterPaintVolume *pv,
2682                                        const char *label,
2683                                        const CoglColor *color)
2684 {
2685   static CoglPipeline *outline = NULL;
2686   CoglPrimitive *prim;
2687   ClutterVertex line_ends[12 * 2];
2688   int n_vertices;
2689   CoglContext *ctx =
2690     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2691   /* XXX: at some point we'll query this from the stage but we can't
2692    * do that until the osx backend uses Cogl natively. */
2693   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2694
2695   if (outline == NULL)
2696     outline = cogl_pipeline_new (ctx);
2697
2698   _clutter_paint_volume_complete (pv);
2699
2700   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2701
2702   /* Front face */
2703   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2704   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2705   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2706   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2707
2708   if (!pv->is_2d)
2709     {
2710       /* Back face */
2711       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2712       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2713       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2714       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2715
2716       /* Lines connecting front face to back face */
2717       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2718       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2719       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2720       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2721     }
2722
2723   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2724                                 n_vertices,
2725                                 (CoglVertexP3 *)line_ends);
2726
2727   cogl_pipeline_set_color (outline, color);
2728   cogl_framebuffer_draw_primitive (fb, outline, prim);
2729   cogl_object_unref (prim);
2730
2731   if (label)
2732     {
2733       PangoLayout *layout;
2734       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2735       pango_layout_set_text (layout, label, -1);
2736       cogl_pango_render_layout (layout,
2737                                 pv->vertices[0].x,
2738                                 pv->vertices[0].y,
2739                                 color,
2740                                 0);
2741       g_object_unref (layout);
2742     }
2743 }
2744
2745 static void
2746 _clutter_actor_draw_paint_volume (ClutterActor *self)
2747 {
2748   ClutterPaintVolume *pv;
2749   CoglColor color;
2750
2751   pv = _clutter_actor_get_paint_volume_mutable (self);
2752   if (!pv)
2753     {
2754       gfloat width, height;
2755       ClutterPaintVolume fake_pv;
2756
2757       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2758       _clutter_paint_volume_init_static (&fake_pv, stage);
2759
2760       clutter_actor_get_size (self, &width, &height);
2761       clutter_paint_volume_set_width (&fake_pv, width);
2762       clutter_paint_volume_set_height (&fake_pv, height);
2763
2764       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2765       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2766                                              _clutter_actor_get_debug_name (self),
2767                                              &color);
2768
2769       clutter_paint_volume_free (&fake_pv);
2770     }
2771   else
2772     {
2773       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2774       _clutter_actor_draw_paint_volume_full (self, pv,
2775                                              _clutter_actor_get_debug_name (self),
2776                                              &color);
2777     }
2778 }
2779
2780 static void
2781 _clutter_actor_paint_cull_result (ClutterActor *self,
2782                                   gboolean success,
2783                                   ClutterCullResult result)
2784 {
2785   ClutterPaintVolume *pv;
2786   CoglColor color;
2787
2788   if (success)
2789     {
2790       if (result == CLUTTER_CULL_RESULT_IN)
2791         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2792       else if (result == CLUTTER_CULL_RESULT_OUT)
2793         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2794       else
2795         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2796     }
2797   else
2798     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2799
2800   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2801     _clutter_actor_draw_paint_volume_full (self, pv,
2802                                            _clutter_actor_get_debug_name (self),
2803                                            &color);
2804   else
2805     {
2806       PangoLayout *layout;
2807       char *label =
2808         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2809       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2810       cogl_set_source_color (&color);
2811
2812       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2813       pango_layout_set_text (layout, label, -1);
2814       cogl_pango_render_layout (layout,
2815                                 0,
2816                                 0,
2817                                 &color,
2818                                 0);
2819       g_free (label);
2820       g_object_unref (layout);
2821     }
2822 }
2823
2824 static int clone_paint_level = 0;
2825
2826 void
2827 _clutter_actor_push_clone_paint (void)
2828 {
2829   clone_paint_level++;
2830 }
2831
2832 void
2833 _clutter_actor_pop_clone_paint (void)
2834 {
2835   clone_paint_level--;
2836 }
2837
2838 static gboolean
2839 in_clone_paint (void)
2840 {
2841   return clone_paint_level > 0;
2842 }
2843
2844 /* Returns TRUE if the actor can be ignored */
2845 /* FIXME: we should return a ClutterCullResult, and
2846  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2847  * means there's no point in trying to cull descendants of the current
2848  * node. */
2849 static gboolean
2850 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2851 {
2852   ClutterActorPrivate *priv = self->priv;
2853   ClutterActor *stage;
2854   const ClutterPlane *stage_clip;
2855
2856   if (!priv->last_paint_volume_valid)
2857     {
2858       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2859                     "->last_paint_volume_valid == FALSE",
2860                     _clutter_actor_get_debug_name (self));
2861       return FALSE;
2862     }
2863
2864   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2865     return FALSE;
2866
2867   stage = _clutter_actor_get_stage_internal (self);
2868   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2869   if (G_UNLIKELY (!stage_clip))
2870     {
2871       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2872                     "No stage clip set",
2873                     _clutter_actor_get_debug_name (self));
2874       return FALSE;
2875     }
2876
2877   if (cogl_get_draw_framebuffer () !=
2878       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2879     {
2880       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2881                     "Current framebuffer doesn't correspond to stage",
2882                     _clutter_actor_get_debug_name (self));
2883       return FALSE;
2884     }
2885
2886   *result_out =
2887     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2888   return TRUE;
2889 }
2890
2891 static void
2892 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2893 {
2894   ClutterActorPrivate *priv = self->priv;
2895   const ClutterPaintVolume *pv;
2896
2897   if (priv->last_paint_volume_valid)
2898     {
2899       clutter_paint_volume_free (&priv->last_paint_volume);
2900       priv->last_paint_volume_valid = FALSE;
2901     }
2902
2903   pv = clutter_actor_get_paint_volume (self);
2904   if (!pv)
2905     {
2906       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2907                     "Actor failed to report a paint volume",
2908                     _clutter_actor_get_debug_name (self));
2909       return;
2910     }
2911
2912   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2913
2914   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2915                                             NULL); /* eye coordinates */
2916
2917   priv->last_paint_volume_valid = TRUE;
2918 }
2919
2920 static inline gboolean
2921 actor_has_shader_data (ClutterActor *self)
2922 {
2923   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2924 }
2925
2926 guint32
2927 _clutter_actor_get_pick_id (ClutterActor *self)
2928 {
2929   if (self->priv->pick_id < 0)
2930     return 0;
2931
2932   return self->priv->pick_id;
2933 }
2934
2935 /* This is the same as clutter_actor_add_effect except that it doesn't
2936    queue a redraw and it doesn't notify on the effect property */
2937 static void
2938 _clutter_actor_add_effect_internal (ClutterActor  *self,
2939                                     ClutterEffect *effect)
2940 {
2941   ClutterActorPrivate *priv = self->priv;
2942
2943   if (priv->effects == NULL)
2944     {
2945       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2946       priv->effects->actor = self;
2947     }
2948
2949   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2950 }
2951
2952 /* This is the same as clutter_actor_remove_effect except that it doesn't
2953    queue a redraw and it doesn't notify on the effect property */
2954 static void
2955 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2956                                        ClutterEffect *effect)
2957 {
2958   ClutterActorPrivate *priv = self->priv;
2959
2960   if (priv->effects == NULL)
2961     return;
2962
2963   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2964 }
2965
2966 static gboolean
2967 needs_flatten_effect (ClutterActor *self)
2968 {
2969   ClutterActorPrivate *priv = self->priv;
2970
2971   if (G_UNLIKELY (clutter_paint_debug_flags &
2972                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2973     return FALSE;
2974
2975   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2976     return TRUE;
2977   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2978     {
2979       if (clutter_actor_get_paint_opacity (self) < 255 &&
2980           clutter_actor_has_overlaps (self))
2981         return TRUE;
2982     }
2983
2984   return FALSE;
2985 }
2986
2987 static void
2988 add_or_remove_flatten_effect (ClutterActor *self)
2989 {
2990   ClutterActorPrivate *priv = self->priv;
2991
2992   /* Add or remove the flatten effect depending on the
2993      offscreen-redirect property. */
2994   if (needs_flatten_effect (self))
2995     {
2996       if (priv->flatten_effect == NULL)
2997         {
2998           ClutterActorMeta *actor_meta;
2999           gint priority;
3000
3001           priv->flatten_effect = _clutter_flatten_effect_new ();
3002           /* Keep a reference to the effect so that we can queue
3003              redraws from it */
3004           g_object_ref_sink (priv->flatten_effect);
3005
3006           /* Set the priority of the effect to high so that it will
3007              always be applied to the actor first. It uses an internal
3008              priority so that it won't be visible to applications */
3009           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3010           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3011           _clutter_actor_meta_set_priority (actor_meta, priority);
3012
3013           /* This will add the effect without queueing a redraw */
3014           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3015         }
3016     }
3017   else
3018     {
3019       if (priv->flatten_effect != NULL)
3020         {
3021           /* Destroy the effect so that it will lose its fbo cache of
3022              the actor */
3023           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3024           g_object_unref (priv->flatten_effect);
3025           priv->flatten_effect = NULL;
3026         }
3027     }
3028 }
3029
3030 static void
3031 clutter_actor_real_paint (ClutterActor *actor)
3032 {
3033   ClutterActorPrivate *priv = actor->priv;
3034   ClutterActor *iter;
3035
3036   /* paint the background color, if set */
3037   if (priv->bg_color_set)
3038     {
3039       float width, height;
3040       guint8 real_alpha;
3041
3042       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3043
3044       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3045                  * priv->bg_color.alpha
3046                  / 255;
3047
3048       cogl_set_source_color4ub (priv->bg_color.red,
3049                                 priv->bg_color.green,
3050                                 priv->bg_color.blue,
3051                                 real_alpha);
3052
3053       cogl_rectangle (0, 0, width, height);
3054     }
3055
3056   for (iter = priv->first_child;
3057        iter != NULL;
3058        iter = iter->priv->next_sibling)
3059     {
3060       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3061                     _clutter_actor_get_debug_name (iter),
3062                     _clutter_actor_get_debug_name (actor),
3063                     iter->priv->allocation.x1,
3064                     iter->priv->allocation.y1,
3065                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3066                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3067
3068       clutter_actor_paint (iter);
3069     }
3070 }
3071
3072 /**
3073  * clutter_actor_paint:
3074  * @self: A #ClutterActor
3075  *
3076  * Renders the actor to display.
3077  *
3078  * This function should not be called directly by applications.
3079  * Call clutter_actor_queue_redraw() to queue paints, instead.
3080  *
3081  * This function is context-aware, and will either cause a
3082  * regular paint or a pick paint.
3083  *
3084  * This function will emit the #ClutterActor::paint signal or
3085  * the #ClutterActor::pick signal, depending on the context.
3086  *
3087  * This function does not paint the actor if the actor is set to 0,
3088  * unless it is performing a pick paint.
3089  */
3090 void
3091 clutter_actor_paint (ClutterActor *self)
3092 {
3093   ClutterActorPrivate *priv;
3094   ClutterPickMode pick_mode;
3095   gboolean clip_set = FALSE;
3096   gboolean shader_applied = FALSE;
3097
3098   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3099                           "Actor real-paint counter",
3100                           "Increments each time any actor is painted",
3101                           0 /* no application private data */);
3102   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3103                           "Actor pick-paint counter",
3104                           "Increments each time any actor is painted "
3105                           "for picking",
3106                           0 /* no application private data */);
3107
3108   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3109
3110   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3111     return;
3112
3113   priv = self->priv;
3114
3115   pick_mode = _clutter_context_get_pick_mode ();
3116
3117   if (pick_mode == CLUTTER_PICK_NONE)
3118     priv->propagated_one_redraw = FALSE;
3119
3120   /* It's an important optimization that we consider painting of
3121    * actors with 0 opacity to be a NOP... */
3122   if (pick_mode == CLUTTER_PICK_NONE &&
3123       /* ignore top-levels, since they might be transparent */
3124       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3125       /* Use the override opacity if its been set */
3126       ((priv->opacity_override >= 0) ?
3127        priv->opacity_override : priv->opacity) == 0)
3128     return;
3129
3130   /* if we aren't paintable (not in a toplevel with all
3131    * parents paintable) then do nothing.
3132    */
3133   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3134     return;
3135
3136   /* mark that we are in the paint process */
3137   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3138
3139   cogl_push_matrix();
3140
3141   if (priv->enable_model_view_transform)
3142     {
3143       CoglMatrix matrix;
3144
3145       /* XXX: It could be better to cache the modelview with the actor
3146        * instead of progressively building up the transformations on
3147        * the matrix stack every time we paint. */
3148       cogl_get_modelview_matrix (&matrix);
3149       _clutter_actor_apply_modelview_transform (self, &matrix);
3150
3151 #ifdef CLUTTER_ENABLE_DEBUG
3152       /* Catch when out-of-band transforms have been made by actors not as part
3153        * of an apply_transform vfunc... */
3154       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3155         {
3156           CoglMatrix expected_matrix;
3157
3158           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3159                                                              &expected_matrix);
3160
3161           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3162             {
3163               GString *buf = g_string_sized_new (1024);
3164               ClutterActor *parent;
3165
3166               parent = self;
3167               while (parent != NULL)
3168                 {
3169                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3170
3171                   if (parent->priv->parent != NULL)
3172                     g_string_append (buf, "->");
3173
3174                   parent = parent->priv->parent;
3175                 }
3176
3177               g_warning ("Unexpected transform found when painting actor "
3178                          "\"%s\". This will be caused by one of the actor's "
3179                          "ancestors (%s) using the Cogl API directly to transform "
3180                          "children instead of using ::apply_transform().",
3181                          _clutter_actor_get_debug_name (self),
3182                          buf->str);
3183
3184               g_string_free (buf, TRUE);
3185             }
3186         }
3187 #endif /* CLUTTER_ENABLE_DEBUG */
3188
3189       cogl_set_modelview_matrix (&matrix);
3190     }
3191
3192   if (priv->has_clip)
3193     {
3194       cogl_clip_push_rectangle (priv->clip.x,
3195                                 priv->clip.y,
3196                                 priv->clip.x + priv->clip.width,
3197                                 priv->clip.y + priv->clip.height);
3198       clip_set = TRUE;
3199     }
3200   else if (priv->clip_to_allocation)
3201     {
3202       gfloat width, height;
3203
3204       width  = priv->allocation.x2 - priv->allocation.x1;
3205       height = priv->allocation.y2 - priv->allocation.y1;
3206
3207       cogl_clip_push_rectangle (0, 0, width, height);
3208       clip_set = TRUE;
3209     }
3210
3211   if (pick_mode == CLUTTER_PICK_NONE)
3212     {
3213       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3214
3215       /* We check whether we need to add the flatten effect before
3216          each paint so that we can avoid having a mechanism for
3217          applications to notify when the value of the
3218          has_overlaps virtual changes. */
3219       add_or_remove_flatten_effect (self);
3220     }
3221   else
3222     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3223
3224   /* We save the current paint volume so that the next time the
3225    * actor queues a redraw we can constrain the redraw to just
3226    * cover the union of the new bounding box and the old.
3227    *
3228    * We also fetch the current paint volume to perform culling so
3229    * we can avoid painting actors outside the current clip region.
3230    *
3231    * If we are painting inside a clone, we should neither update
3232    * the paint volume or use it to cull painting, since the paint
3233    * box represents the location of the source actor on the
3234    * screen.
3235    *
3236    * XXX: We are starting to do a lot of vertex transforms on
3237    * the CPU in a typical paint, so at some point we should
3238    * audit these and consider caching some things.
3239    *
3240    * NB: We don't perform culling while picking at this point because
3241    * clutter-stage.c doesn't setup the clipping planes appropriately.
3242    *
3243    * NB: We don't want to update the last-paint-volume during picking
3244    * because the last-paint-volume is used to determine the old screen
3245    * space location of an actor that has moved so we can know the
3246    * minimal region to redraw to clear an old view of the actor. If we
3247    * update this during picking then by the time we come around to
3248    * paint then the last-paint-volume would likely represent the new
3249    * actor position not the old.
3250    */
3251   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3252     {
3253       gboolean success;
3254       /* annoyingly gcc warns if uninitialized even though
3255        * the initialization is redundant :-( */
3256       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3257
3258       if (G_LIKELY ((clutter_paint_debug_flags &
3259                      (CLUTTER_DEBUG_DISABLE_CULLING |
3260                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3261                     (CLUTTER_DEBUG_DISABLE_CULLING |
3262                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3263         _clutter_actor_update_last_paint_volume (self);
3264
3265       success = cull_actor (self, &result);
3266
3267       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3268         _clutter_actor_paint_cull_result (self, success, result);
3269       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3270         goto done;
3271     }
3272
3273   if (priv->effects == NULL)
3274     {
3275       if (pick_mode == CLUTTER_PICK_NONE &&
3276           actor_has_shader_data (self))
3277         {
3278           _clutter_actor_shader_pre_paint (self, FALSE);
3279           shader_applied = TRUE;
3280         }
3281
3282       priv->next_effect_to_paint = NULL;
3283     }
3284   else
3285     priv->next_effect_to_paint =
3286       _clutter_meta_group_peek_metas (priv->effects);
3287
3288   clutter_actor_continue_paint (self);
3289
3290   if (shader_applied)
3291     _clutter_actor_shader_post_paint (self);
3292
3293   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3294                   pick_mode == CLUTTER_PICK_NONE))
3295     _clutter_actor_draw_paint_volume (self);
3296
3297 done:
3298   /* If we make it here then the actor has run through a complete
3299      paint run including all the effects so it's no longer dirty */
3300   if (pick_mode == CLUTTER_PICK_NONE)
3301     priv->is_dirty = FALSE;
3302
3303   if (clip_set)
3304     cogl_clip_pop();
3305
3306   cogl_pop_matrix();
3307
3308   /* paint sequence complete */
3309   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3310 }
3311
3312 /**
3313  * clutter_actor_continue_paint:
3314  * @self: A #ClutterActor
3315  *
3316  * Run the next stage of the paint sequence. This function should only
3317  * be called within the implementation of the ‘run’ virtual of a
3318  * #ClutterEffect. It will cause the run method of the next effect to
3319  * be applied, or it will paint the actual actor if the current effect
3320  * is the last effect in the chain.
3321  *
3322  * Since: 1.8
3323  */
3324 void
3325 clutter_actor_continue_paint (ClutterActor *self)
3326 {
3327   ClutterActorPrivate *priv;
3328
3329   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3330   /* This should only be called from with in the ‘run’ implementation
3331      of a ClutterEffect */
3332   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3333
3334   priv = self->priv;
3335
3336   /* Skip any effects that are disabled */
3337   while (priv->next_effect_to_paint &&
3338          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3339     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3340
3341   /* If this has come from the last effect then we'll just paint the
3342      actual actor */
3343   if (priv->next_effect_to_paint == NULL)
3344     {
3345       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3346         {
3347           g_signal_emit (self, actor_signals[PAINT], 0);
3348         }
3349       else
3350         {
3351           ClutterColor col = { 0, };
3352
3353           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3354
3355           /* Actor will then paint silhouette of itself in supplied
3356            * color.  See clutter_stage_get_actor_at_pos() for where
3357            * picking is enabled.
3358            */
3359           g_signal_emit (self, actor_signals[PICK], 0, &col);
3360         }
3361     }
3362   else
3363     {
3364       ClutterEffect *old_current_effect;
3365       ClutterEffectPaintFlags run_flags = 0;
3366
3367       /* Cache the current effect so that we can put it back before
3368          returning */
3369       old_current_effect = priv->current_effect;
3370
3371       priv->current_effect = priv->next_effect_to_paint->data;
3372       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3373
3374       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3375         {
3376           if (priv->is_dirty)
3377             {
3378               /* If there's an effect queued with this redraw then all
3379                  effects up to that one will be considered dirty. It
3380                  is expected the queued effect will paint the cached
3381                  image and not call clutter_actor_continue_paint again
3382                  (although it should work ok if it does) */
3383               if (priv->effect_to_redraw == NULL ||
3384                   priv->current_effect != priv->effect_to_redraw)
3385                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3386             }
3387
3388           _clutter_effect_paint (priv->current_effect, run_flags);
3389         }
3390       else
3391         {
3392           /* We can't determine when an actor has been modified since
3393              its last pick so lets just assume it has always been
3394              modified */
3395           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3396
3397           _clutter_effect_pick (priv->current_effect, run_flags);
3398         }
3399
3400       priv->current_effect = old_current_effect;
3401     }
3402 }
3403
3404 static ClutterActorTraverseVisitFlags
3405 invalidate_queue_redraw_entry (ClutterActor *self,
3406                                int           depth,
3407                                gpointer      user_data)
3408 {
3409   ClutterActorPrivate *priv = self->priv;
3410
3411   if (priv->queue_redraw_entry != NULL)
3412     {
3413       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3414       priv->queue_redraw_entry = NULL;
3415     }
3416
3417   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3418 }
3419
3420 static inline void
3421 remove_child (ClutterActor *self,
3422               ClutterActor *child)
3423 {
3424   ClutterActor *prev_sibling, *next_sibling;
3425
3426   prev_sibling = child->priv->prev_sibling;
3427   next_sibling = child->priv->next_sibling;
3428
3429   if (prev_sibling != NULL)
3430     prev_sibling->priv->next_sibling = next_sibling;
3431
3432   if (next_sibling != NULL)
3433     next_sibling->priv->prev_sibling = prev_sibling;
3434
3435   if (self->priv->first_child == child)
3436     self->priv->first_child = next_sibling;
3437
3438   if (self->priv->last_child == child)
3439     self->priv->last_child = prev_sibling;
3440
3441   child->priv->parent = NULL;
3442   child->priv->prev_sibling = NULL;
3443   child->priv->next_sibling = NULL;
3444 }
3445
3446 typedef enum {
3447   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3448   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3449   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3450   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3451   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3452   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3453
3454   /* default flags for public API */
3455   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3456                                     REMOVE_CHILD_EMIT_PARENT_SET |
3457                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3458                                     REMOVE_CHILD_CHECK_STATE |
3459                                     REMOVE_CHILD_FLUSH_QUEUE |
3460                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3461
3462   /* flags for legacy/deprecated API */
3463   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3464                                     REMOVE_CHILD_FLUSH_QUEUE |
3465                                     REMOVE_CHILD_EMIT_PARENT_SET |
3466                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3467 } ClutterActorRemoveChildFlags;
3468
3469 /*< private >
3470  * clutter_actor_remove_child_internal:
3471  * @self: a #ClutterActor
3472  * @child: the child of @self that has to be removed
3473  * @flags: control the removal operations
3474  *
3475  * Removes @child from the list of children of @self.
3476  */
3477 static void
3478 clutter_actor_remove_child_internal (ClutterActor                 *self,
3479                                      ClutterActor                 *child,
3480                                      ClutterActorRemoveChildFlags  flags)
3481 {
3482   ClutterActor *old_first, *old_last;
3483   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3484   gboolean flush_queue;
3485   gboolean notify_first_last;
3486   gboolean was_mapped;
3487
3488   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3489   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3490   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3491   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3492   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3493   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3494
3495   g_object_freeze_notify (G_OBJECT (self));
3496
3497   if (destroy_meta)
3498     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3499
3500   if (check_state)
3501     {
3502       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3503
3504       /* we need to unrealize *before* we set parent_actor to NULL,
3505        * because in an unrealize method actors are dissociating from the
3506        * stage, which means they need to be able to
3507        * clutter_actor_get_stage().
3508        *
3509        * yhis should unmap and unrealize, unless we're reparenting.
3510        */
3511       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3512     }
3513   else
3514     was_mapped = FALSE;
3515
3516   if (flush_queue)
3517     {
3518       /* We take this opportunity to invalidate any queue redraw entry
3519        * associated with the actor and descendants since we won't be able to
3520        * determine the appropriate stage after this.
3521        *
3522        * we do this after we updated the mapped state because actors might
3523        * end up queueing redraws inside their mapped/unmapped virtual
3524        * functions, and if we invalidate the redraw entry we could end up
3525        * with an inconsistent state and weird memory corruption. see
3526        * bugs:
3527        *
3528        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3529        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3530        */
3531       _clutter_actor_traverse (child,
3532                                0,
3533                                invalidate_queue_redraw_entry,
3534                                NULL,
3535                                NULL);
3536     }
3537
3538   old_first = self->priv->first_child;
3539   old_last = self->priv->last_child;
3540
3541   remove_child (self, child);
3542
3543   self->priv->n_children -= 1;
3544
3545   self->priv->age += 1;
3546
3547   /* clutter_actor_reparent() will emit ::parent-set for us */
3548   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3549     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3550
3551   /* if the child was mapped then we need to relayout ourselves to account
3552    * for the removed child
3553    */
3554   if (was_mapped)
3555     clutter_actor_queue_relayout (self);
3556
3557   /* we need to emit the signal before dropping the reference */
3558   if (emit_actor_removed)
3559     g_signal_emit_by_name (self, "actor-removed", child);
3560
3561   if (notify_first_last)
3562     {
3563       if (old_first != self->priv->first_child)
3564         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3565
3566       if (old_last != self->priv->last_child)
3567         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3568     }
3569
3570   g_object_thaw_notify (G_OBJECT (self));
3571
3572   /* remove the reference we acquired in clutter_actor_add_child() */
3573   g_object_unref (child);
3574 }
3575
3576 static const ClutterTransformInfo default_transform_info = {
3577   0.0, { 0, },          /* rotation-x */
3578   0.0, { 0, },          /* rotation-y */
3579   0.0, { 0, },          /* rotation-z */
3580
3581   1.0, 1.0, { 0, },     /* scale */
3582
3583   { 0, },               /* anchor */
3584 };
3585
3586 /*< private >
3587  * _clutter_actor_get_transform_info_or_defaults:
3588  * @self: a #ClutterActor
3589  *
3590  * Retrieves the ClutterTransformInfo structure associated to an actor.
3591  *
3592  * If the actor does not have a ClutterTransformInfo structure associated
3593  * to it, then the default structure will be returned.
3594  *
3595  * This function should only be used for getters.
3596  *
3597  * Return value: a const pointer to the ClutterTransformInfo structure
3598  */
3599 const ClutterTransformInfo *
3600 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3601 {
3602   ClutterTransformInfo *info;
3603
3604   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3605   if (info != NULL)
3606     return info;
3607
3608   return &default_transform_info;
3609 }
3610
3611 static void
3612 clutter_transform_info_free (gpointer data)
3613 {
3614   if (data != NULL)
3615     g_slice_free (ClutterTransformInfo, data);
3616 }
3617
3618 /*< private >
3619  * _clutter_actor_get_transform_info:
3620  * @self: a #ClutterActor
3621  *
3622  * Retrieves a pointer to the ClutterTransformInfo structure.
3623  *
3624  * If the actor does not have a ClutterTransformInfo associated to it, one
3625  * will be created and initialized to the default values.
3626  *
3627  * This function should be used for setters.
3628  *
3629  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3630  * instead.
3631  *
3632  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3633  *   structure
3634  */
3635 ClutterTransformInfo *
3636 _clutter_actor_get_transform_info (ClutterActor *self)
3637 {
3638   ClutterTransformInfo *info;
3639
3640   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3641   if (info == NULL)
3642     {
3643       info = g_slice_new (ClutterTransformInfo);
3644
3645       *info = default_transform_info;
3646
3647       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3648                                info,
3649                                clutter_transform_info_free);
3650     }
3651
3652   return info;
3653 }
3654
3655 /*< private >
3656  * clutter_actor_set_rotation_angle_internal:
3657  * @self: a #ClutterActor
3658  * @axis: the axis of the angle to change
3659  * @angle: the angle of rotation
3660  *
3661  * Sets the rotation angle on the given axis without affecting the
3662  * rotation center point.
3663  */
3664 static inline void
3665 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3666                                            ClutterRotateAxis  axis,
3667                                            gdouble            angle)
3668 {
3669   GObject *obj = G_OBJECT (self);
3670   ClutterTransformInfo *info;
3671
3672   info = _clutter_actor_get_transform_info (self);
3673
3674   g_object_freeze_notify (obj);
3675
3676   switch (axis)
3677     {
3678     case CLUTTER_X_AXIS:
3679       info->rx_angle = angle;
3680       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3681       break;
3682
3683     case CLUTTER_Y_AXIS:
3684       info->ry_angle = angle;
3685       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3686       break;
3687
3688     case CLUTTER_Z_AXIS:
3689       info->rz_angle = angle;
3690       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3691       break;
3692     }
3693
3694   self->priv->transform_valid = FALSE;
3695
3696   g_object_thaw_notify (obj);
3697
3698   clutter_actor_queue_redraw (self);
3699 }
3700
3701 /*< private >
3702  * clutter_actor_set_rotation_center_internal:
3703  * @self: a #ClutterActor
3704  * @axis: the axis of the center to change
3705  * @center: the coordinates of the rotation center
3706  *
3707  * Sets the rotation center on the given axis without affecting the
3708  * rotation angle.
3709  */
3710 static inline void
3711 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3712                                             ClutterRotateAxis    axis,
3713                                             const ClutterVertex *center)
3714 {
3715   GObject *obj = G_OBJECT (self);
3716   ClutterTransformInfo *info;
3717   ClutterVertex v = { 0, 0, 0 };
3718
3719   info = _clutter_actor_get_transform_info (self);
3720
3721   if (center != NULL)
3722     v = *center;
3723
3724   g_object_freeze_notify (obj);
3725
3726   switch (axis)
3727     {
3728     case CLUTTER_X_AXIS:
3729       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3730       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3731       break;
3732
3733     case CLUTTER_Y_AXIS:
3734       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3735       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3736       break;
3737
3738     case CLUTTER_Z_AXIS:
3739       /* if the previously set rotation center was fractional, then
3740        * setting explicit coordinates will have to notify the
3741        * :rotation-center-z-gravity property as well
3742        */
3743       if (info->rz_center.is_fractional)
3744         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3745
3746       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3747       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3748       break;
3749     }
3750
3751   self->priv->transform_valid = FALSE;
3752
3753   g_object_thaw_notify (obj);
3754
3755   clutter_actor_queue_redraw (self);
3756 }
3757
3758 static inline void
3759 clutter_actor_set_scale_factor (ClutterActor      *self,
3760                                 ClutterRotateAxis  axis,
3761                                 gdouble            factor)
3762 {
3763   GObject *obj = G_OBJECT (self);
3764   ClutterTransformInfo *info;
3765
3766   info = _clutter_actor_get_transform_info (self);
3767
3768   g_object_freeze_notify (obj);
3769
3770   switch (axis)
3771     {
3772     case CLUTTER_X_AXIS:
3773       info->scale_x = factor;
3774       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3775       break;
3776
3777     case CLUTTER_Y_AXIS:
3778       info->scale_y = factor;
3779       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3780       break;
3781
3782     default:
3783       g_assert_not_reached ();
3784     }
3785
3786   self->priv->transform_valid = FALSE;
3787
3788   clutter_actor_queue_redraw (self);
3789
3790   g_object_thaw_notify (obj);
3791 }
3792
3793 static inline void
3794 clutter_actor_set_scale_center (ClutterActor      *self,
3795                                 ClutterRotateAxis  axis,
3796                                 gfloat             coord)
3797 {
3798   GObject *obj = G_OBJECT (self);
3799   ClutterTransformInfo *info;
3800   gfloat center_x, center_y;
3801
3802   info = _clutter_actor_get_transform_info (self);
3803
3804   g_object_freeze_notify (obj);
3805
3806   /* get the current scale center coordinates */
3807   clutter_anchor_coord_get_units (self, &info->scale_center,
3808                                   &center_x,
3809                                   &center_y,
3810                                   NULL);
3811
3812   /* we need to notify this too, because setting explicit coordinates will
3813    * change the gravity as a side effect
3814    */
3815   if (info->scale_center.is_fractional)
3816     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3817
3818   switch (axis)
3819     {
3820     case CLUTTER_X_AXIS:
3821       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3822       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3823       break;
3824
3825     case CLUTTER_Y_AXIS:
3826       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3827       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3828       break;
3829
3830     default:
3831       g_assert_not_reached ();
3832     }
3833
3834   self->priv->transform_valid = FALSE;
3835
3836   clutter_actor_queue_redraw (self);
3837
3838   g_object_thaw_notify (obj);
3839 }
3840
3841 static inline void
3842 clutter_actor_set_anchor_coord (ClutterActor      *self,
3843                                 ClutterRotateAxis  axis,
3844                                 gfloat             coord)
3845 {
3846   GObject *obj = G_OBJECT (self);
3847   ClutterTransformInfo *info;
3848   gfloat anchor_x, anchor_y;
3849
3850   info = _clutter_actor_get_transform_info (self);
3851
3852   g_object_freeze_notify (obj);
3853
3854   clutter_anchor_coord_get_units (self, &info->anchor,
3855                                   &anchor_x,
3856                                   &anchor_y,
3857                                   NULL);
3858
3859   if (info->anchor.is_fractional)
3860     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3861
3862   switch (axis)
3863     {
3864     case CLUTTER_X_AXIS:
3865       clutter_anchor_coord_set_units (&info->anchor,
3866                                       coord,
3867                                       anchor_y,
3868                                       0.0);
3869       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3870       break;
3871
3872     case CLUTTER_Y_AXIS:
3873       clutter_anchor_coord_set_units (&info->anchor,
3874                                       anchor_x,
3875                                       coord,
3876                                       0.0);
3877       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3878       break;
3879
3880     default:
3881       g_assert_not_reached ();
3882     }
3883
3884   self->priv->transform_valid = FALSE;
3885
3886   clutter_actor_queue_redraw (self);
3887
3888   g_object_thaw_notify (obj);
3889 }
3890
3891 static void
3892 clutter_actor_set_property (GObject      *object,
3893                             guint         prop_id,
3894                             const GValue *value,
3895                             GParamSpec   *pspec)
3896 {
3897   ClutterActor *actor = CLUTTER_ACTOR (object);
3898   ClutterActorPrivate *priv = actor->priv;
3899
3900   switch (prop_id)
3901     {
3902     case PROP_X:
3903       clutter_actor_set_x (actor, g_value_get_float (value));
3904       break;
3905
3906     case PROP_Y:
3907       clutter_actor_set_y (actor, g_value_get_float (value));
3908       break;
3909
3910     case PROP_WIDTH:
3911       clutter_actor_set_width (actor, g_value_get_float (value));
3912       break;
3913
3914     case PROP_HEIGHT:
3915       clutter_actor_set_height (actor, g_value_get_float (value));
3916       break;
3917
3918     case PROP_FIXED_X:
3919       clutter_actor_set_x (actor, g_value_get_float (value));
3920       break;
3921
3922     case PROP_FIXED_Y:
3923       clutter_actor_set_y (actor, g_value_get_float (value));
3924       break;
3925
3926     case PROP_FIXED_POSITION_SET:
3927       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3928       break;
3929
3930     case PROP_MIN_WIDTH:
3931       clutter_actor_set_min_width (actor, g_value_get_float (value));
3932       break;
3933
3934     case PROP_MIN_HEIGHT:
3935       clutter_actor_set_min_height (actor, g_value_get_float (value));
3936       break;
3937
3938     case PROP_NATURAL_WIDTH:
3939       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3940       break;
3941
3942     case PROP_NATURAL_HEIGHT:
3943       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3944       break;
3945
3946     case PROP_MIN_WIDTH_SET:
3947       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3948       break;
3949
3950     case PROP_MIN_HEIGHT_SET:
3951       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3952       break;
3953
3954     case PROP_NATURAL_WIDTH_SET:
3955       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3956       break;
3957
3958     case PROP_NATURAL_HEIGHT_SET:
3959       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3960       break;
3961
3962     case PROP_REQUEST_MODE:
3963       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3964       break;
3965
3966     case PROP_DEPTH:
3967       clutter_actor_set_depth (actor, g_value_get_float (value));
3968       break;
3969
3970     case PROP_OPACITY:
3971       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3972       break;
3973
3974     case PROP_OFFSCREEN_REDIRECT:
3975       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3976       break;
3977
3978     case PROP_NAME:
3979       clutter_actor_set_name (actor, g_value_get_string (value));
3980       break;
3981
3982     case PROP_VISIBLE:
3983       if (g_value_get_boolean (value) == TRUE)
3984         clutter_actor_show (actor);
3985       else
3986         clutter_actor_hide (actor);
3987       break;
3988
3989     case PROP_SCALE_X:
3990       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3991                                       g_value_get_double (value));
3992       break;
3993
3994     case PROP_SCALE_Y:
3995       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3996                                       g_value_get_double (value));
3997       break;
3998
3999     case PROP_SCALE_CENTER_X:
4000       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4001                                       g_value_get_float (value));
4002       break;
4003
4004     case PROP_SCALE_CENTER_Y:
4005       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4006                                       g_value_get_float (value));
4007       break;
4008
4009     case PROP_SCALE_GRAVITY:
4010       {
4011         const ClutterTransformInfo *info;
4012         ClutterGravity gravity;
4013
4014         info = _clutter_actor_get_transform_info_or_defaults (actor);
4015         gravity = g_value_get_enum (value);
4016
4017         clutter_actor_set_scale_with_gravity (actor,
4018                                               info->scale_x,
4019                                               info->scale_y,
4020                                               gravity);
4021       }
4022       break;
4023
4024     case PROP_CLIP:
4025       {
4026         const ClutterGeometry *geom = g_value_get_boxed (value);
4027
4028         clutter_actor_set_clip (actor,
4029                                 geom->x, geom->y,
4030                                 geom->width, geom->height);
4031       }
4032       break;
4033
4034     case PROP_CLIP_TO_ALLOCATION:
4035       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4036       break;
4037
4038     case PROP_REACTIVE:
4039       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4040       break;
4041
4042     case PROP_ROTATION_ANGLE_X:
4043       clutter_actor_set_rotation_angle_internal (actor,
4044                                                  CLUTTER_X_AXIS,
4045                                                  g_value_get_double (value));
4046       break;
4047
4048     case PROP_ROTATION_ANGLE_Y:
4049       clutter_actor_set_rotation_angle_internal (actor,
4050                                                  CLUTTER_Y_AXIS,
4051                                                  g_value_get_double (value));
4052       break;
4053
4054     case PROP_ROTATION_ANGLE_Z:
4055       clutter_actor_set_rotation_angle_internal (actor,
4056                                                  CLUTTER_Z_AXIS,
4057                                                  g_value_get_double (value));
4058       break;
4059
4060     case PROP_ROTATION_CENTER_X:
4061       clutter_actor_set_rotation_center_internal (actor,
4062                                                   CLUTTER_X_AXIS,
4063                                                   g_value_get_boxed (value));
4064       break;
4065
4066     case PROP_ROTATION_CENTER_Y:
4067       clutter_actor_set_rotation_center_internal (actor,
4068                                                   CLUTTER_Y_AXIS,
4069                                                   g_value_get_boxed (value));
4070       break;
4071
4072     case PROP_ROTATION_CENTER_Z:
4073       clutter_actor_set_rotation_center_internal (actor,
4074                                                   CLUTTER_Z_AXIS,
4075                                                   g_value_get_boxed (value));
4076       break;
4077
4078     case PROP_ROTATION_CENTER_Z_GRAVITY:
4079       {
4080         const ClutterTransformInfo *info;
4081
4082         info = _clutter_actor_get_transform_info_or_defaults (actor);
4083         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4084                                                    g_value_get_enum (value));
4085       }
4086       break;
4087
4088     case PROP_ANCHOR_X:
4089       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4090                                       g_value_get_float (value));
4091       break;
4092
4093     case PROP_ANCHOR_Y:
4094       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4095                                       g_value_get_float (value));
4096       break;
4097
4098     case PROP_ANCHOR_GRAVITY:
4099       clutter_actor_set_anchor_point_from_gravity (actor,
4100                                                    g_value_get_enum (value));
4101       break;
4102
4103     case PROP_SHOW_ON_SET_PARENT:
4104       priv->show_on_set_parent = g_value_get_boolean (value);
4105       break;
4106
4107     case PROP_TEXT_DIRECTION:
4108       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4109       break;
4110
4111     case PROP_ACTIONS:
4112       clutter_actor_add_action (actor, g_value_get_object (value));
4113       break;
4114
4115     case PROP_CONSTRAINTS:
4116       clutter_actor_add_constraint (actor, g_value_get_object (value));
4117       break;
4118
4119     case PROP_EFFECT:
4120       clutter_actor_add_effect (actor, g_value_get_object (value));
4121       break;
4122
4123     case PROP_LAYOUT_MANAGER:
4124       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4125       break;
4126
4127     case PROP_X_ALIGN:
4128       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4129       break;
4130
4131     case PROP_Y_ALIGN:
4132       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4133       break;
4134
4135     case PROP_MARGIN_TOP:
4136       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4137       break;
4138
4139     case PROP_MARGIN_BOTTOM:
4140       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4141       break;
4142
4143     case PROP_MARGIN_LEFT:
4144       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4145       break;
4146
4147     case PROP_MARGIN_RIGHT:
4148       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4149       break;
4150
4151     case PROP_BACKGROUND_COLOR:
4152       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4153       break;
4154
4155     default:
4156       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4157       break;
4158     }
4159 }
4160
4161 static void
4162 clutter_actor_get_property (GObject    *object,
4163                             guint       prop_id,
4164                             GValue     *value,
4165                             GParamSpec *pspec)
4166 {
4167   ClutterActor *actor = CLUTTER_ACTOR (object);
4168   ClutterActorPrivate *priv = actor->priv;
4169
4170   switch (prop_id)
4171     {
4172     case PROP_X:
4173       g_value_set_float (value, clutter_actor_get_x (actor));
4174       break;
4175
4176     case PROP_Y:
4177       g_value_set_float (value, clutter_actor_get_y (actor));
4178       break;
4179
4180     case PROP_WIDTH:
4181       g_value_set_float (value, clutter_actor_get_width (actor));
4182       break;
4183
4184     case PROP_HEIGHT:
4185       g_value_set_float (value, clutter_actor_get_height (actor));
4186       break;
4187
4188     case PROP_FIXED_X:
4189       {
4190         const ClutterLayoutInfo *info;
4191
4192         info = _clutter_actor_get_layout_info_or_defaults (actor);
4193         g_value_set_float (value, info->fixed_x);
4194       }
4195       break;
4196
4197     case PROP_FIXED_Y:
4198       {
4199         const ClutterLayoutInfo *info;
4200
4201         info = _clutter_actor_get_layout_info_or_defaults (actor);
4202         g_value_set_float (value, info->fixed_y);
4203       }
4204       break;
4205
4206     case PROP_FIXED_POSITION_SET:
4207       g_value_set_boolean (value, priv->position_set);
4208       break;
4209
4210     case PROP_MIN_WIDTH:
4211       {
4212         const ClutterLayoutInfo *info;
4213
4214         info = _clutter_actor_get_layout_info_or_defaults (actor);
4215         g_value_set_float (value, info->min_width);
4216       }
4217       break;
4218
4219     case PROP_MIN_HEIGHT:
4220       {
4221         const ClutterLayoutInfo *info;
4222
4223         info = _clutter_actor_get_layout_info_or_defaults (actor);
4224         g_value_set_float (value, info->min_height);
4225       }
4226       break;
4227
4228     case PROP_NATURAL_WIDTH:
4229       {
4230         const ClutterLayoutInfo *info;
4231
4232         info = _clutter_actor_get_layout_info_or_defaults (actor);
4233         g_value_set_float (value, info->natural_width);
4234       }
4235       break;
4236
4237     case PROP_NATURAL_HEIGHT:
4238       {
4239         const ClutterLayoutInfo *info;
4240
4241         info = _clutter_actor_get_layout_info_or_defaults (actor);
4242         g_value_set_float (value, info->natural_height);
4243       }
4244       break;
4245
4246     case PROP_MIN_WIDTH_SET:
4247       g_value_set_boolean (value, priv->min_width_set);
4248       break;
4249
4250     case PROP_MIN_HEIGHT_SET:
4251       g_value_set_boolean (value, priv->min_height_set);
4252       break;
4253
4254     case PROP_NATURAL_WIDTH_SET:
4255       g_value_set_boolean (value, priv->natural_width_set);
4256       break;
4257
4258     case PROP_NATURAL_HEIGHT_SET:
4259       g_value_set_boolean (value, priv->natural_height_set);
4260       break;
4261
4262     case PROP_REQUEST_MODE:
4263       g_value_set_enum (value, priv->request_mode);
4264       break;
4265
4266     case PROP_ALLOCATION:
4267       g_value_set_boxed (value, &priv->allocation);
4268       break;
4269
4270     case PROP_DEPTH:
4271       g_value_set_float (value, clutter_actor_get_depth (actor));
4272       break;
4273
4274     case PROP_OPACITY:
4275       g_value_set_uint (value, priv->opacity);
4276       break;
4277
4278     case PROP_OFFSCREEN_REDIRECT:
4279       g_value_set_enum (value, priv->offscreen_redirect);
4280       break;
4281
4282     case PROP_NAME:
4283       g_value_set_string (value, priv->name);
4284       break;
4285
4286     case PROP_VISIBLE:
4287       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4288       break;
4289
4290     case PROP_MAPPED:
4291       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4292       break;
4293
4294     case PROP_REALIZED:
4295       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4296       break;
4297
4298     case PROP_HAS_CLIP:
4299       g_value_set_boolean (value, priv->has_clip);
4300       break;
4301
4302     case PROP_CLIP:
4303       {
4304         ClutterGeometry clip;
4305
4306         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4307         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4308         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4309         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4310
4311         g_value_set_boxed (value, &clip);
4312       }
4313       break;
4314
4315     case PROP_CLIP_TO_ALLOCATION:
4316       g_value_set_boolean (value, priv->clip_to_allocation);
4317       break;
4318
4319     case PROP_SCALE_X:
4320       {
4321         const ClutterTransformInfo *info;
4322
4323         info = _clutter_actor_get_transform_info_or_defaults (actor);
4324         g_value_set_double (value, info->scale_x);
4325       }
4326       break;
4327
4328     case PROP_SCALE_Y:
4329       {
4330         const ClutterTransformInfo *info;
4331
4332         info = _clutter_actor_get_transform_info_or_defaults (actor);
4333         g_value_set_double (value, info->scale_y);
4334       }
4335       break;
4336
4337     case PROP_SCALE_CENTER_X:
4338       {
4339         gfloat center;
4340
4341         clutter_actor_get_scale_center (actor, &center, NULL);
4342
4343         g_value_set_float (value, center);
4344       }
4345       break;
4346
4347     case PROP_SCALE_CENTER_Y:
4348       {
4349         gfloat center;
4350
4351         clutter_actor_get_scale_center (actor, NULL, &center);
4352
4353         g_value_set_float (value, center);
4354       }
4355       break;
4356
4357     case PROP_SCALE_GRAVITY:
4358       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4359       break;
4360
4361     case PROP_REACTIVE:
4362       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4363       break;
4364
4365     case PROP_ROTATION_ANGLE_X:
4366       {
4367         const ClutterTransformInfo *info;
4368
4369         info = _clutter_actor_get_transform_info_or_defaults (actor);
4370         g_value_set_double (value, info->rx_angle);
4371       }
4372       break;
4373
4374     case PROP_ROTATION_ANGLE_Y:
4375       {
4376         const ClutterTransformInfo *info;
4377
4378         info = _clutter_actor_get_transform_info_or_defaults (actor);
4379         g_value_set_double (value, info->ry_angle);
4380       }
4381       break;
4382
4383     case PROP_ROTATION_ANGLE_Z:
4384       {
4385         const ClutterTransformInfo *info;
4386
4387         info = _clutter_actor_get_transform_info_or_defaults (actor);
4388         g_value_set_double (value, info->rz_angle);
4389       }
4390       break;
4391
4392     case PROP_ROTATION_CENTER_X:
4393       {
4394         ClutterVertex center;
4395
4396         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4397                                     &center.x,
4398                                     &center.y,
4399                                     &center.z);
4400
4401         g_value_set_boxed (value, &center);
4402       }
4403       break;
4404
4405     case PROP_ROTATION_CENTER_Y:
4406       {
4407         ClutterVertex center;
4408
4409         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4410                                     &center.x,
4411                                     &center.y,
4412                                     &center.z);
4413
4414         g_value_set_boxed (value, &center);
4415       }
4416       break;
4417
4418     case PROP_ROTATION_CENTER_Z:
4419       {
4420         ClutterVertex center;
4421
4422         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4423                                     &center.x,
4424                                     &center.y,
4425                                     &center.z);
4426
4427         g_value_set_boxed (value, &center);
4428       }
4429       break;
4430
4431     case PROP_ROTATION_CENTER_Z_GRAVITY:
4432       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4433       break;
4434
4435     case PROP_ANCHOR_X:
4436       {
4437         const ClutterTransformInfo *info;
4438         gfloat anchor_x;
4439
4440         info = _clutter_actor_get_transform_info_or_defaults (actor);
4441         clutter_anchor_coord_get_units (actor, &info->anchor,
4442                                         &anchor_x,
4443                                         NULL,
4444                                         NULL);
4445         g_value_set_float (value, anchor_x);
4446       }
4447       break;
4448
4449     case PROP_ANCHOR_Y:
4450       {
4451         const ClutterTransformInfo *info;
4452         gfloat anchor_y;
4453
4454         info = _clutter_actor_get_transform_info_or_defaults (actor);
4455         clutter_anchor_coord_get_units (actor, &info->anchor,
4456                                         NULL,
4457                                         &anchor_y,
4458                                         NULL);
4459         g_value_set_float (value, anchor_y);
4460       }
4461       break;
4462
4463     case PROP_ANCHOR_GRAVITY:
4464       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4465       break;
4466
4467     case PROP_SHOW_ON_SET_PARENT:
4468       g_value_set_boolean (value, priv->show_on_set_parent);
4469       break;
4470
4471     case PROP_TEXT_DIRECTION:
4472       g_value_set_enum (value, priv->text_direction);
4473       break;
4474
4475     case PROP_HAS_POINTER:
4476       g_value_set_boolean (value, priv->has_pointer);
4477       break;
4478
4479     case PROP_LAYOUT_MANAGER:
4480       g_value_set_object (value, priv->layout_manager);
4481       break;
4482
4483     case PROP_X_ALIGN:
4484       {
4485         const ClutterLayoutInfo *info;
4486
4487         info = _clutter_actor_get_layout_info_or_defaults (actor);
4488         g_value_set_enum (value, info->x_align);
4489       }
4490       break;
4491
4492     case PROP_Y_ALIGN:
4493       {
4494         const ClutterLayoutInfo *info;
4495
4496         info = _clutter_actor_get_layout_info_or_defaults (actor);
4497         g_value_set_enum (value, info->y_align);
4498       }
4499       break;
4500
4501     case PROP_MARGIN_TOP:
4502       {
4503         const ClutterLayoutInfo *info;
4504
4505         info = _clutter_actor_get_layout_info_or_defaults (actor);
4506         g_value_set_float (value, info->margin.top);
4507       }
4508       break;
4509
4510     case PROP_MARGIN_BOTTOM:
4511       {
4512         const ClutterLayoutInfo *info;
4513
4514         info = _clutter_actor_get_layout_info_or_defaults (actor);
4515         g_value_set_float (value, info->margin.bottom);
4516       }
4517       break;
4518
4519     case PROP_MARGIN_LEFT:
4520       {
4521         const ClutterLayoutInfo *info;
4522
4523         info = _clutter_actor_get_layout_info_or_defaults (actor);
4524         g_value_set_float (value, info->margin.left);
4525       }
4526       break;
4527
4528     case PROP_MARGIN_RIGHT:
4529       {
4530         const ClutterLayoutInfo *info;
4531
4532         info = _clutter_actor_get_layout_info_or_defaults (actor);
4533         g_value_set_float (value, info->margin.right);
4534       }
4535       break;
4536
4537     case PROP_BACKGROUND_COLOR_SET:
4538       g_value_set_boolean (value, priv->bg_color_set);
4539       break;
4540
4541     case PROP_BACKGROUND_COLOR:
4542       g_value_set_boxed (value, &priv->bg_color);
4543       break;
4544
4545     case PROP_FIRST_CHILD:
4546       g_value_set_object (value, priv->first_child);
4547       break;
4548
4549     case PROP_LAST_CHILD:
4550       g_value_set_object (value, priv->last_child);
4551       break;
4552
4553     default:
4554       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4555       break;
4556     }
4557 }
4558
4559 static void
4560 clutter_actor_dispose (GObject *object)
4561 {
4562   ClutterActor *self = CLUTTER_ACTOR (object);
4563   ClutterActorPrivate *priv = self->priv;
4564
4565   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4566                 priv->id,
4567                 g_type_name (G_OBJECT_TYPE (self)),
4568                 object->ref_count);
4569
4570   g_signal_emit (self, actor_signals[DESTROY], 0);
4571
4572   /* avoid recursing when called from clutter_actor_destroy() */
4573   if (priv->parent != NULL)
4574     {
4575       ClutterActor *parent = priv->parent;
4576
4577       /* go through the Container implementation unless this
4578        * is an internal child and has been marked as such.
4579        *
4580        * removing the actor from its parent will reset the
4581        * realized and mapped states.
4582        */
4583       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4584         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4585       else
4586         clutter_actor_remove_child_internal (parent, self,
4587                                              REMOVE_CHILD_LEGACY_FLAGS);
4588     }
4589
4590   /* parent must be gone at this point */
4591   g_assert (priv->parent == NULL);
4592
4593   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4594     {
4595       /* can't be mapped or realized with no parent */
4596       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4597       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4598     }
4599
4600   g_clear_object (&priv->pango_context);
4601   g_clear_object (&priv->actions);
4602   g_clear_object (&priv->constraints);
4603   g_clear_object (&priv->effects);
4604   g_clear_object (&priv->flatten_effect);
4605
4606   if (priv->layout_manager != NULL)
4607     {
4608       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4609       g_object_unref (priv->layout_manager);
4610       priv->layout_manager = NULL;
4611     }
4612
4613   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4614 }
4615
4616 static void
4617 clutter_actor_finalize (GObject *object)
4618 {
4619   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4620
4621   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4622                 priv->name != NULL ? priv->name : "<none>",
4623                 priv->id,
4624                 g_type_name (G_OBJECT_TYPE (object)));
4625
4626   _clutter_context_release_id (priv->id);
4627
4628   g_free (priv->name);
4629
4630   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4631 }
4632
4633
4634 /**
4635  * clutter_actor_get_accessible:
4636  * @self: a #ClutterActor
4637  *
4638  * Returns the accessible object that describes the actor to an
4639  * assistive technology.
4640  *
4641  * If no class-specific #AtkObject implementation is available for the
4642  * actor instance in question, it will inherit an #AtkObject
4643  * implementation from the first ancestor class for which such an
4644  * implementation is defined.
4645  *
4646  * The documentation of the <ulink
4647  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4648  * library contains more information about accessible objects and
4649  * their uses.
4650  *
4651  * Returns: (transfer none): the #AtkObject associated with @actor
4652  */
4653 AtkObject *
4654 clutter_actor_get_accessible (ClutterActor *self)
4655 {
4656   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4657
4658   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4659 }
4660
4661 static AtkObject *
4662 clutter_actor_real_get_accessible (ClutterActor *actor)
4663 {
4664   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4665 }
4666
4667 static AtkObject *
4668 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4669 {
4670   AtkObject *accessible;
4671
4672   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4673   if (accessible != NULL)
4674     g_object_ref (accessible);
4675
4676   return accessible;
4677 }
4678
4679 static void
4680 atk_implementor_iface_init (AtkImplementorIface *iface)
4681 {
4682   iface->ref_accessible = _clutter_actor_ref_accessible;
4683 }
4684
4685 static gboolean
4686 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4687                                      ClutterPaintVolume *volume)
4688 {
4689   ClutterActorPrivate *priv = self->priv;
4690   ClutterActor *child;
4691   ClutterActorClass *klass;
4692   gboolean res;
4693
4694   klass = CLUTTER_ACTOR_GET_CLASS (self);
4695
4696   /* XXX - this thoroughly sucks, but we don't want to penalize users
4697    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4698    * redraw. This should go away in 2.0.
4699    */
4700   if (klass->paint == clutter_actor_real_paint &&
4701       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4702     {
4703       res = TRUE;
4704     }
4705   else
4706     {
4707       /* this is the default return value: we cannot know if a class
4708        * is going to paint outside its allocation, so we take the
4709        * conservative approach.
4710        */
4711       res = FALSE;
4712     }
4713
4714   /* we start from the allocation */
4715   clutter_paint_volume_set_width (volume,
4716                                   priv->allocation.x2 - priv->allocation.x1);
4717   clutter_paint_volume_set_height (volume,
4718                                    priv->allocation.y2 - priv->allocation.y1);
4719
4720   /* if the actor has a clip set then we have a pretty definite
4721    * size for the paint volume: the actor cannot possibly paint
4722    * outside the clip region.
4723    */
4724   if (priv->clip_to_allocation)
4725     {
4726       /* the allocation has already been set, so we just flip the
4727        * return value
4728        */
4729       res = TRUE;
4730     }
4731   else
4732     {
4733       if (priv->has_clip &&
4734           priv->clip.width >= 0 &&
4735           priv->clip.height >= 0)
4736         {
4737           ClutterVertex origin;
4738
4739           origin.x = priv->clip.x;
4740           origin.y = priv->clip.y;
4741           origin.z = 0;
4742
4743           clutter_paint_volume_set_origin (volume, &origin);
4744           clutter_paint_volume_set_width (volume, priv->clip.width);
4745           clutter_paint_volume_set_height (volume, priv->clip.height);
4746
4747           res = TRUE;
4748         }
4749
4750       /* if we don't have children we just bail out here... */
4751       if (priv->n_children == 0)
4752         return res;
4753
4754       /* ...but if we have children then we ask for their paint volume in
4755        * our coordinates. if any of our children replies that it doesn't
4756        * have a paint volume, we bail out
4757        */
4758       for (child = priv->first_child;
4759            child != NULL;
4760            child = child->priv->next_sibling)
4761         {
4762           const ClutterPaintVolume *child_volume;
4763
4764           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4765           if (child_volume == NULL)
4766             {
4767               res = FALSE;
4768               break;
4769             }
4770
4771           clutter_paint_volume_union (volume, child_volume);
4772           res = TRUE;
4773         }
4774     }
4775
4776   return res;
4777 }
4778
4779 static gboolean
4780 clutter_actor_real_has_overlaps (ClutterActor *self)
4781 {
4782   /* By default we'll assume that all actors need an offscreen redirect to get
4783    * the correct opacity. Actors such as ClutterTexture that would never need
4784    * an offscreen redirect can override this to return FALSE. */
4785   return TRUE;
4786 }
4787
4788 static void
4789 clutter_actor_real_destroy (ClutterActor *actor)
4790 {
4791   ClutterActorIter iter;
4792
4793   clutter_actor_iter_init (&iter, actor);
4794   while (clutter_actor_iter_next (&iter, NULL))
4795     clutter_actor_iter_destroy (&iter);
4796 }
4797
4798 static GObject *
4799 clutter_actor_constructor (GType gtype,
4800                            guint n_props,
4801                            GObjectConstructParam *props)
4802 {
4803   GObjectClass *gobject_class;
4804   ClutterActor *self;
4805   GObject *retval;
4806
4807   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4808   retval = gobject_class->constructor (gtype, n_props, props);
4809   self = CLUTTER_ACTOR (retval);
4810
4811   if (self->priv->layout_manager == NULL)
4812     {
4813       ClutterLayoutManager *default_layout;
4814
4815       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4816
4817       default_layout = clutter_fixed_layout_new ();
4818       clutter_actor_set_layout_manager (self, default_layout);
4819     }
4820
4821   return retval;
4822 }
4823
4824 static void
4825 clutter_actor_class_init (ClutterActorClass *klass)
4826 {
4827   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4828
4829   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4830   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4831   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4832
4833   object_class->constructor = clutter_actor_constructor;
4834   object_class->set_property = clutter_actor_set_property;
4835   object_class->get_property = clutter_actor_get_property;
4836   object_class->dispose = clutter_actor_dispose;
4837   object_class->finalize = clutter_actor_finalize;
4838
4839   klass->show = clutter_actor_real_show;
4840   klass->show_all = clutter_actor_show;
4841   klass->hide = clutter_actor_real_hide;
4842   klass->hide_all = clutter_actor_hide;
4843   klass->map = clutter_actor_real_map;
4844   klass->unmap = clutter_actor_real_unmap;
4845   klass->unrealize = clutter_actor_real_unrealize;
4846   klass->pick = clutter_actor_real_pick;
4847   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4848   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4849   klass->allocate = clutter_actor_real_allocate;
4850   klass->queue_redraw = clutter_actor_real_queue_redraw;
4851   klass->queue_relayout = clutter_actor_real_queue_relayout;
4852   klass->apply_transform = clutter_actor_real_apply_transform;
4853   klass->get_accessible = clutter_actor_real_get_accessible;
4854   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4855   klass->has_overlaps = clutter_actor_real_has_overlaps;
4856   klass->paint = clutter_actor_real_paint;
4857   klass->destroy = clutter_actor_real_destroy;
4858
4859   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4860
4861   /**
4862    * ClutterActor:x:
4863    *
4864    * X coordinate of the actor in pixels. If written, forces a fixed
4865    * position for the actor. If read, returns the fixed position if any,
4866    * otherwise the allocation if available, otherwise 0.
4867    */
4868   obj_props[PROP_X] =
4869     g_param_spec_float ("x",
4870                         P_("X coordinate"),
4871                         P_("X coordinate of the actor"),
4872                         -G_MAXFLOAT, G_MAXFLOAT,
4873                         0.0,
4874                         CLUTTER_PARAM_READWRITE);
4875
4876   /**
4877    * ClutterActor:y:
4878    *
4879    * Y coordinate of the actor in pixels. If written, forces a fixed
4880    * position for the actor.  If read, returns the fixed position if
4881    * any, otherwise the allocation if available, otherwise 0.
4882    */
4883   obj_props[PROP_Y] =
4884     g_param_spec_float ("y",
4885                         P_("Y coordinate"),
4886                         P_("Y coordinate of the actor"),
4887                         -G_MAXFLOAT, G_MAXFLOAT,
4888                         0.0,
4889                         CLUTTER_PARAM_READWRITE);
4890
4891   /**
4892    * ClutterActor:width:
4893    *
4894    * Width of the actor (in pixels). If written, forces the minimum and
4895    * natural size request of the actor to the given width. If read, returns
4896    * the allocated width if available, otherwise the width request.
4897    */
4898   obj_props[PROP_WIDTH] =
4899     g_param_spec_float ("width",
4900                         P_("Width"),
4901                         P_("Width of the actor"),
4902                         0.0, G_MAXFLOAT,
4903                         0.0,
4904                         CLUTTER_PARAM_READWRITE);
4905
4906   /**
4907    * ClutterActor:height:
4908    *
4909    * Height of the actor (in pixels).  If written, forces the minimum and
4910    * natural size request of the actor to the given height. If read, returns
4911    * the allocated height if available, otherwise the height request.
4912    */
4913   obj_props[PROP_HEIGHT] =
4914     g_param_spec_float ("height",
4915                         P_("Height"),
4916                         P_("Height of the actor"),
4917                         0.0, G_MAXFLOAT,
4918                         0.0,
4919                         CLUTTER_PARAM_READWRITE);
4920
4921   /**
4922    * ClutterActor:fixed-x:
4923    *
4924    * The fixed X position of the actor in pixels.
4925    *
4926    * Writing this property sets #ClutterActor:fixed-position-set
4927    * property as well, as a side effect
4928    *
4929    * Since: 0.8
4930    */
4931   obj_props[PROP_FIXED_X] =
4932     g_param_spec_float ("fixed-x",
4933                         P_("Fixed X"),
4934                         P_("Forced X position of the actor"),
4935                         -G_MAXFLOAT, G_MAXFLOAT,
4936                         0.0,
4937                         CLUTTER_PARAM_READWRITE);
4938
4939   /**
4940    * ClutterActor:fixed-y:
4941    *
4942    * The fixed Y position of the actor in pixels.
4943    *
4944    * Writing this property sets the #ClutterActor:fixed-position-set
4945    * property as well, as a side effect
4946    *
4947    * Since: 0.8
4948    */
4949   obj_props[PROP_FIXED_Y] =
4950     g_param_spec_float ("fixed-y",
4951                         P_("Fixed Y"),
4952                         P_("Forced Y position of the actor"),
4953                         -G_MAXFLOAT, G_MAXFLOAT,
4954                         0,
4955                         CLUTTER_PARAM_READWRITE);
4956
4957   /**
4958    * ClutterActor:fixed-position-set:
4959    *
4960    * This flag controls whether the #ClutterActor:fixed-x and
4961    * #ClutterActor:fixed-y properties are used
4962    *
4963    * Since: 0.8
4964    */
4965   obj_props[PROP_FIXED_POSITION_SET] =
4966     g_param_spec_boolean ("fixed-position-set",
4967                           P_("Fixed position set"),
4968                           P_("Whether to use fixed positioning for the actor"),
4969                           FALSE,
4970                           CLUTTER_PARAM_READWRITE);
4971
4972   /**
4973    * ClutterActor:min-width:
4974    *
4975    * A forced minimum width request for the actor, in pixels
4976    *
4977    * Writing this property sets the #ClutterActor:min-width-set property
4978    * as well, as a side effect.
4979    *
4980    *This property overrides the usual width request of the actor.
4981    *
4982    * Since: 0.8
4983    */
4984   obj_props[PROP_MIN_WIDTH] =
4985     g_param_spec_float ("min-width",
4986                         P_("Min Width"),
4987                         P_("Forced minimum width request for the actor"),
4988                         0.0, G_MAXFLOAT,
4989                         0.0,
4990                         CLUTTER_PARAM_READWRITE);
4991
4992   /**
4993    * ClutterActor:min-height:
4994    *
4995    * A forced minimum height request for the actor, in pixels
4996    *
4997    * Writing this property sets the #ClutterActor:min-height-set property
4998    * as well, as a side effect. This property overrides the usual height
4999    * request of the actor.
5000    *
5001    * Since: 0.8
5002    */
5003   obj_props[PROP_MIN_HEIGHT] =
5004     g_param_spec_float ("min-height",
5005                         P_("Min Height"),
5006                         P_("Forced minimum height request for the actor"),
5007                         0.0, G_MAXFLOAT,
5008                         0.0,
5009                         CLUTTER_PARAM_READWRITE);
5010
5011   /**
5012    * ClutterActor:natural-width:
5013    *
5014    * A forced natural width request for the actor, in pixels
5015    *
5016    * Writing this property sets the #ClutterActor:natural-width-set
5017    * property as well, as a side effect. This property overrides the
5018    * usual width request of the actor
5019    *
5020    * Since: 0.8
5021    */
5022   obj_props[PROP_NATURAL_WIDTH] =
5023     g_param_spec_float ("natural-width",
5024                         P_("Natural Width"),
5025                         P_("Forced natural width request for the actor"),
5026                         0.0, G_MAXFLOAT,
5027                         0.0,
5028                         CLUTTER_PARAM_READWRITE);
5029
5030   /**
5031    * ClutterActor:natural-height:
5032    *
5033    * A forced natural height request for the actor, in pixels
5034    *
5035    * Writing this property sets the #ClutterActor:natural-height-set
5036    * property as well, as a side effect. This property overrides the
5037    * usual height request of the actor
5038    *
5039    * Since: 0.8
5040    */
5041   obj_props[PROP_NATURAL_HEIGHT] =
5042     g_param_spec_float ("natural-height",
5043                         P_("Natural Height"),
5044                         P_("Forced natural height request for the actor"),
5045                         0.0, G_MAXFLOAT,
5046                         0.0,
5047                         CLUTTER_PARAM_READWRITE);
5048
5049   /**
5050    * ClutterActor:min-width-set:
5051    *
5052    * This flag controls whether the #ClutterActor:min-width property
5053    * is used
5054    *
5055    * Since: 0.8
5056    */
5057   obj_props[PROP_MIN_WIDTH_SET] =
5058     g_param_spec_boolean ("min-width-set",
5059                           P_("Minimum width set"),
5060                           P_("Whether to use the min-width property"),
5061                           FALSE,
5062                           CLUTTER_PARAM_READWRITE);
5063
5064   /**
5065    * ClutterActor:min-height-set:
5066    *
5067    * This flag controls whether the #ClutterActor:min-height property
5068    * is used
5069    *
5070    * Since: 0.8
5071    */
5072   obj_props[PROP_MIN_HEIGHT_SET] =
5073     g_param_spec_boolean ("min-height-set",
5074                           P_("Minimum height set"),
5075                           P_("Whether to use the min-height property"),
5076                           FALSE,
5077                           CLUTTER_PARAM_READWRITE);
5078
5079   /**
5080    * ClutterActor:natural-width-set:
5081    *
5082    * This flag controls whether the #ClutterActor:natural-width property
5083    * is used
5084    *
5085    * Since: 0.8
5086    */
5087   obj_props[PROP_NATURAL_WIDTH_SET] =
5088     g_param_spec_boolean ("natural-width-set",
5089                           P_("Natural width set"),
5090                           P_("Whether to use the natural-width property"),
5091                           FALSE,
5092                           CLUTTER_PARAM_READWRITE);
5093
5094   /**
5095    * ClutterActor:natural-height-set:
5096    *
5097    * This flag controls whether the #ClutterActor:natural-height property
5098    * is used
5099    *
5100    * Since: 0.8
5101    */
5102   obj_props[PROP_NATURAL_HEIGHT_SET] =
5103     g_param_spec_boolean ("natural-height-set",
5104                           P_("Natural height set"),
5105                           P_("Whether to use the natural-height property"),
5106                           FALSE,
5107                           CLUTTER_PARAM_READWRITE);
5108
5109   /**
5110    * ClutterActor:allocation:
5111    *
5112    * The allocation for the actor, in pixels
5113    *
5114    * This is property is read-only, but you might monitor it to know when an
5115    * actor moves or resizes
5116    *
5117    * Since: 0.8
5118    */
5119   obj_props[PROP_ALLOCATION] =
5120     g_param_spec_boxed ("allocation",
5121                         P_("Allocation"),
5122                         P_("The actor's allocation"),
5123                         CLUTTER_TYPE_ACTOR_BOX,
5124                         CLUTTER_PARAM_READABLE);
5125
5126   /**
5127    * ClutterActor:request-mode:
5128    *
5129    * Request mode for the #ClutterActor. The request mode determines the
5130    * type of geometry management used by the actor, either height for width
5131    * (the default) or width for height.
5132    *
5133    * For actors implementing height for width, the parent container should get
5134    * the preferred width first, and then the preferred height for that width.
5135    *
5136    * For actors implementing width for height, the parent container should get
5137    * the preferred height first, and then the preferred width for that height.
5138    *
5139    * For instance:
5140    *
5141    * |[
5142    *   ClutterRequestMode mode;
5143    *   gfloat natural_width, min_width;
5144    *   gfloat natural_height, min_height;
5145    *
5146    *   mode = clutter_actor_get_request_mode (child);
5147    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5148    *     {
5149    *       clutter_actor_get_preferred_width (child, -1,
5150    *                                          &amp;min_width,
5151    *                                          &amp;natural_width);
5152    *       clutter_actor_get_preferred_height (child, natural_width,
5153    *                                           &amp;min_height,
5154    *                                           &amp;natural_height);
5155    *     }
5156    *   else
5157    *     {
5158    *       clutter_actor_get_preferred_height (child, -1,
5159    *                                           &amp;min_height,
5160    *                                           &amp;natural_height);
5161    *       clutter_actor_get_preferred_width (child, natural_height,
5162    *                                          &amp;min_width,
5163    *                                          &amp;natural_width);
5164    *     }
5165    * ]|
5166    *
5167    * will retrieve the minimum and natural width and height depending on the
5168    * preferred request mode of the #ClutterActor "child".
5169    *
5170    * The clutter_actor_get_preferred_size() function will implement this
5171    * check for you.
5172    *
5173    * Since: 0.8
5174    */
5175   obj_props[PROP_REQUEST_MODE] =
5176     g_param_spec_enum ("request-mode",
5177                        P_("Request Mode"),
5178                        P_("The actor's request mode"),
5179                        CLUTTER_TYPE_REQUEST_MODE,
5180                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5181                        CLUTTER_PARAM_READWRITE);
5182
5183   /**
5184    * ClutterActor:depth:
5185    *
5186    * The position of the actor on the Z axis
5187    *
5188    * Since: 0.6
5189    */
5190   obj_props[PROP_DEPTH] =
5191     g_param_spec_float ("depth",
5192                         P_("Depth"),
5193                         P_("Position on the Z axis"),
5194                         -G_MAXFLOAT, G_MAXFLOAT,
5195                         0.0,
5196                         CLUTTER_PARAM_READWRITE);
5197
5198   /**
5199    * ClutterActor:opacity:
5200    *
5201    * Opacity of an actor, between 0 (fully transparent) and
5202    * 255 (fully opaque)
5203    */
5204   obj_props[PROP_OPACITY] =
5205     g_param_spec_uint ("opacity",
5206                        P_("Opacity"),
5207                        P_("Opacity of an actor"),
5208                        0, 255,
5209                        255,
5210                        CLUTTER_PARAM_READWRITE);
5211
5212   /**
5213    * ClutterActor:offscreen-redirect:
5214    *
5215    * Determines the conditions in which the actor will be redirected
5216    * to an offscreen framebuffer while being painted. For example this
5217    * can be used to cache an actor in a framebuffer or for improved
5218    * handling of transparent actors. See
5219    * clutter_actor_set_offscreen_redirect() for details.
5220    *
5221    * Since: 1.8
5222    */
5223   obj_props[PROP_OFFSCREEN_REDIRECT] =
5224     g_param_spec_flags ("offscreen-redirect",
5225                         P_("Offscreen redirect"),
5226                         P_("Flags controlling when to flatten the actor into a single image"),
5227                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5228                         0,
5229                         CLUTTER_PARAM_READWRITE);
5230
5231   /**
5232    * ClutterActor:visible:
5233    *
5234    * Whether the actor is set to be visible or not
5235    *
5236    * See also #ClutterActor:mapped
5237    */
5238   obj_props[PROP_VISIBLE] =
5239     g_param_spec_boolean ("visible",
5240                           P_("Visible"),
5241                           P_("Whether the actor is visible or not"),
5242                           FALSE,
5243                           CLUTTER_PARAM_READWRITE);
5244
5245   /**
5246    * ClutterActor:mapped:
5247    *
5248    * Whether the actor is mapped (will be painted when the stage
5249    * to which it belongs is mapped)
5250    *
5251    * Since: 1.0
5252    */
5253   obj_props[PROP_MAPPED] =
5254     g_param_spec_boolean ("mapped",
5255                           P_("Mapped"),
5256                           P_("Whether the actor will be painted"),
5257                           FALSE,
5258                           CLUTTER_PARAM_READABLE);
5259
5260   /**
5261    * ClutterActor:realized:
5262    *
5263    * Whether the actor has been realized
5264    *
5265    * Since: 1.0
5266    */
5267   obj_props[PROP_REALIZED] =
5268     g_param_spec_boolean ("realized",
5269                           P_("Realized"),
5270                           P_("Whether the actor has been realized"),
5271                           FALSE,
5272                           CLUTTER_PARAM_READABLE);
5273
5274   /**
5275    * ClutterActor:reactive:
5276    *
5277    * Whether the actor is reactive to events or not
5278    *
5279    * Only reactive actors will emit event-related signals
5280    *
5281    * Since: 0.6
5282    */
5283   obj_props[PROP_REACTIVE] =
5284     g_param_spec_boolean ("reactive",
5285                           P_("Reactive"),
5286                           P_("Whether the actor is reactive to events"),
5287                           FALSE,
5288                           CLUTTER_PARAM_READWRITE);
5289
5290   /**
5291    * ClutterActor:has-clip:
5292    *
5293    * Whether the actor has the #ClutterActor:clip property set or not
5294    */
5295   obj_props[PROP_HAS_CLIP] =
5296     g_param_spec_boolean ("has-clip",
5297                           P_("Has Clip"),
5298                           P_("Whether the actor has a clip set"),
5299                           FALSE,
5300                           CLUTTER_PARAM_READABLE);
5301
5302   /**
5303    * ClutterActor:clip:
5304    *
5305    * The clip region for the actor, in actor-relative coordinates
5306    *
5307    * Every part of the actor outside the clip region will not be
5308    * painted
5309    */
5310   obj_props[PROP_CLIP] =
5311     g_param_spec_boxed ("clip",
5312                         P_("Clip"),
5313                         P_("The clip region for the actor"),
5314                         CLUTTER_TYPE_GEOMETRY,
5315                         CLUTTER_PARAM_READWRITE);
5316
5317   /**
5318    * ClutterActor:name:
5319    *
5320    * The name of the actor
5321    *
5322    * Since: 0.2
5323    */
5324   obj_props[PROP_NAME] =
5325     g_param_spec_string ("name",
5326                          P_("Name"),
5327                          P_("Name of the actor"),
5328                          NULL,
5329                          CLUTTER_PARAM_READWRITE);
5330
5331   /**
5332    * ClutterActor:scale-x:
5333    *
5334    * The horizontal scale of the actor
5335    *
5336    * Since: 0.6
5337    */
5338   obj_props[PROP_SCALE_X] =
5339     g_param_spec_double ("scale-x",
5340                          P_("Scale X"),
5341                          P_("Scale factor on the X axis"),
5342                          0.0, G_MAXDOUBLE,
5343                          1.0,
5344                          CLUTTER_PARAM_READWRITE);
5345
5346   /**
5347    * ClutterActor:scale-y:
5348    *
5349    * The vertical scale of the actor
5350    *
5351    * Since: 0.6
5352    */
5353   obj_props[PROP_SCALE_Y] =
5354     g_param_spec_double ("scale-y",
5355                          P_("Scale Y"),
5356                          P_("Scale factor on the Y axis"),
5357                          0.0, G_MAXDOUBLE,
5358                          1.0,
5359                          CLUTTER_PARAM_READWRITE);
5360
5361   /**
5362    * ClutterActor:scale-center-x:
5363    *
5364    * The horizontal center point for scaling
5365    *
5366    * Since: 1.0
5367    */
5368   obj_props[PROP_SCALE_CENTER_X] =
5369     g_param_spec_float ("scale-center-x",
5370                         P_("Scale Center X"),
5371                         P_("Horizontal scale center"),
5372                         -G_MAXFLOAT, G_MAXFLOAT,
5373                         0.0,
5374                         CLUTTER_PARAM_READWRITE);
5375
5376   /**
5377    * ClutterActor:scale-center-y:
5378    *
5379    * The vertical center point for scaling
5380    *
5381    * Since: 1.0
5382    */
5383   obj_props[PROP_SCALE_CENTER_Y] =
5384     g_param_spec_float ("scale-center-y",
5385                         P_("Scale Center Y"),
5386                         P_("Vertical scale center"),
5387                         -G_MAXFLOAT, G_MAXFLOAT,
5388                         0.0,
5389                         CLUTTER_PARAM_READWRITE);
5390
5391   /**
5392    * ClutterActor:scale-gravity:
5393    *
5394    * The center point for scaling expressed as a #ClutterGravity
5395    *
5396    * Since: 1.0
5397    */
5398   obj_props[PROP_SCALE_GRAVITY] =
5399     g_param_spec_enum ("scale-gravity",
5400                        P_("Scale Gravity"),
5401                        P_("The center of scaling"),
5402                        CLUTTER_TYPE_GRAVITY,
5403                        CLUTTER_GRAVITY_NONE,
5404                        CLUTTER_PARAM_READWRITE);
5405
5406   /**
5407    * ClutterActor:rotation-angle-x:
5408    *
5409    * The rotation angle on the X axis
5410    *
5411    * Since: 0.6
5412    */
5413   obj_props[PROP_ROTATION_ANGLE_X] =
5414     g_param_spec_double ("rotation-angle-x",
5415                          P_("Rotation Angle X"),
5416                          P_("The rotation angle on the X axis"),
5417                          -G_MAXDOUBLE, G_MAXDOUBLE,
5418                          0.0,
5419                          CLUTTER_PARAM_READWRITE);
5420
5421   /**
5422    * ClutterActor:rotation-angle-y:
5423    *
5424    * The rotation angle on the Y axis
5425    *
5426    * Since: 0.6
5427    */
5428   obj_props[PROP_ROTATION_ANGLE_Y] =
5429     g_param_spec_double ("rotation-angle-y",
5430                          P_("Rotation Angle Y"),
5431                          P_("The rotation angle on the Y axis"),
5432                          -G_MAXDOUBLE, G_MAXDOUBLE,
5433                          0.0,
5434                          CLUTTER_PARAM_READWRITE);
5435
5436   /**
5437    * ClutterActor:rotation-angle-z:
5438    *
5439    * The rotation angle on the Z axis
5440    *
5441    * Since: 0.6
5442    */
5443   obj_props[PROP_ROTATION_ANGLE_Z] =
5444     g_param_spec_double ("rotation-angle-z",
5445                          P_("Rotation Angle Z"),
5446                          P_("The rotation angle on the Z axis"),
5447                          -G_MAXDOUBLE, G_MAXDOUBLE,
5448                          0.0,
5449                          CLUTTER_PARAM_READWRITE);
5450
5451   /**
5452    * ClutterActor:rotation-center-x:
5453    *
5454    * The rotation center on the X axis.
5455    *
5456    * Since: 0.6
5457    */
5458   obj_props[PROP_ROTATION_CENTER_X] =
5459     g_param_spec_boxed ("rotation-center-x",
5460                         P_("Rotation Center X"),
5461                         P_("The rotation center on the X axis"),
5462                         CLUTTER_TYPE_VERTEX,
5463                         CLUTTER_PARAM_READWRITE);
5464
5465   /**
5466    * ClutterActor:rotation-center-y:
5467    *
5468    * The rotation center on the Y axis.
5469    *
5470    * Since: 0.6
5471    */
5472   obj_props[PROP_ROTATION_CENTER_Y] =
5473     g_param_spec_boxed ("rotation-center-y",
5474                         P_("Rotation Center Y"),
5475                         P_("The rotation center on the Y axis"),
5476                         CLUTTER_TYPE_VERTEX,
5477                         CLUTTER_PARAM_READWRITE);
5478
5479   /**
5480    * ClutterActor:rotation-center-z:
5481    *
5482    * The rotation center on the Z axis.
5483    *
5484    * Since: 0.6
5485    */
5486   obj_props[PROP_ROTATION_CENTER_Z] =
5487     g_param_spec_boxed ("rotation-center-z",
5488                         P_("Rotation Center Z"),
5489                         P_("The rotation center on the Z axis"),
5490                         CLUTTER_TYPE_VERTEX,
5491                         CLUTTER_PARAM_READWRITE);
5492
5493   /**
5494    * ClutterActor:rotation-center-z-gravity:
5495    *
5496    * The rotation center on the Z axis expressed as a #ClutterGravity.
5497    *
5498    * Since: 1.0
5499    */
5500   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5501     g_param_spec_enum ("rotation-center-z-gravity",
5502                        P_("Rotation Center Z Gravity"),
5503                        P_("Center point for rotation around the Z axis"),
5504                        CLUTTER_TYPE_GRAVITY,
5505                        CLUTTER_GRAVITY_NONE,
5506                        CLUTTER_PARAM_READWRITE);
5507
5508   /**
5509    * ClutterActor:anchor-x:
5510    *
5511    * The X coordinate of an actor's anchor point, relative to
5512    * the actor coordinate space, in pixels
5513    *
5514    * Since: 0.8
5515    */
5516   obj_props[PROP_ANCHOR_X] =
5517     g_param_spec_float ("anchor-x",
5518                         P_("Anchor X"),
5519                         P_("X coordinate of the anchor point"),
5520                         -G_MAXFLOAT, G_MAXFLOAT,
5521                         0,
5522                         CLUTTER_PARAM_READWRITE);
5523
5524   /**
5525    * ClutterActor:anchor-y:
5526    *
5527    * The Y coordinate of an actor's anchor point, relative to
5528    * the actor coordinate space, in pixels
5529    *
5530    * Since: 0.8
5531    */
5532   obj_props[PROP_ANCHOR_Y] =
5533     g_param_spec_float ("anchor-y",
5534                         P_("Anchor Y"),
5535                         P_("Y coordinate of the anchor point"),
5536                         -G_MAXFLOAT, G_MAXFLOAT,
5537                         0,
5538                         CLUTTER_PARAM_READWRITE);
5539
5540   /**
5541    * ClutterActor:anchor-gravity:
5542    *
5543    * The anchor point expressed as a #ClutterGravity
5544    *
5545    * Since: 1.0
5546    */
5547   obj_props[PROP_ANCHOR_GRAVITY] =
5548     g_param_spec_enum ("anchor-gravity",
5549                        P_("Anchor Gravity"),
5550                        P_("The anchor point as a ClutterGravity"),
5551                        CLUTTER_TYPE_GRAVITY,
5552                        CLUTTER_GRAVITY_NONE,
5553                        CLUTTER_PARAM_READWRITE);
5554
5555   /**
5556    * ClutterActor:show-on-set-parent:
5557    *
5558    * If %TRUE, the actor is automatically shown when parented.
5559    *
5560    * Calling clutter_actor_hide() on an actor which has not been
5561    * parented will set this property to %FALSE as a side effect.
5562    *
5563    * Since: 0.8
5564    */
5565   obj_props[PROP_SHOW_ON_SET_PARENT] =
5566     g_param_spec_boolean ("show-on-set-parent",
5567                           P_("Show on set parent"),
5568                           P_("Whether the actor is shown when parented"),
5569                           TRUE,
5570                           CLUTTER_PARAM_READWRITE);
5571
5572   /**
5573    * ClutterActor:clip-to-allocation:
5574    *
5575    * Whether the clip region should track the allocated area
5576    * of the actor.
5577    *
5578    * This property is ignored if a clip area has been explicitly
5579    * set using clutter_actor_set_clip().
5580    *
5581    * Since: 1.0
5582    */
5583   obj_props[PROP_CLIP_TO_ALLOCATION] =
5584     g_param_spec_boolean ("clip-to-allocation",
5585                           P_("Clip to Allocation"),
5586                           P_("Sets the clip region to track the actor's allocation"),
5587                           FALSE,
5588                           CLUTTER_PARAM_READWRITE);
5589
5590   /**
5591    * ClutterActor:text-direction:
5592    *
5593    * The direction of the text inside a #ClutterActor.
5594    *
5595    * Since: 1.0
5596    */
5597   obj_props[PROP_TEXT_DIRECTION] =
5598     g_param_spec_enum ("text-direction",
5599                        P_("Text Direction"),
5600                        P_("Direction of the text"),
5601                        CLUTTER_TYPE_TEXT_DIRECTION,
5602                        CLUTTER_TEXT_DIRECTION_LTR,
5603                        CLUTTER_PARAM_READWRITE);
5604
5605   /**
5606    * ClutterActor:has-pointer:
5607    *
5608    * Whether the actor contains the pointer of a #ClutterInputDevice
5609    * or not.
5610    *
5611    * Since: 1.2
5612    */
5613   obj_props[PROP_HAS_POINTER] =
5614     g_param_spec_boolean ("has-pointer",
5615                           P_("Has Pointer"),
5616                           P_("Whether the actor contains the pointer of an input device"),
5617                           FALSE,
5618                           CLUTTER_PARAM_READABLE);
5619
5620   /**
5621    * ClutterActor:actions:
5622    *
5623    * Adds a #ClutterAction to the actor
5624    *
5625    * Since: 1.4
5626    */
5627   obj_props[PROP_ACTIONS] =
5628     g_param_spec_object ("actions",
5629                          P_("Actions"),
5630                          P_("Adds an action to the actor"),
5631                          CLUTTER_TYPE_ACTION,
5632                          CLUTTER_PARAM_WRITABLE);
5633
5634   /**
5635    * ClutterActor:constraints:
5636    *
5637    * Adds a #ClutterConstraint to the actor
5638    *
5639    * Since: 1.4
5640    */
5641   obj_props[PROP_CONSTRAINTS] =
5642     g_param_spec_object ("constraints",
5643                          P_("Constraints"),
5644                          P_("Adds a constraint to the actor"),
5645                          CLUTTER_TYPE_CONSTRAINT,
5646                          CLUTTER_PARAM_WRITABLE);
5647
5648   /**
5649    * ClutterActor:effect:
5650    *
5651    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5652    *
5653    * Since: 1.4
5654    */
5655   obj_props[PROP_EFFECT] =
5656     g_param_spec_object ("effect",
5657                          P_("Effect"),
5658                          P_("Add an effect to be applied on the actor"),
5659                          CLUTTER_TYPE_EFFECT,
5660                          CLUTTER_PARAM_WRITABLE);
5661
5662   /**
5663    * ClutterActor:layout-manager:
5664    *
5665    * A delegate object for controlling the layout of the children of
5666    * an actor.
5667    *
5668    * Since: 1.10
5669    */
5670   obj_props[PROP_LAYOUT_MANAGER] =
5671     g_param_spec_object ("layout-manager",
5672                          P_("Layout Manager"),
5673                          P_("The object controlling the layout of an actor's children"),
5674                          CLUTTER_TYPE_LAYOUT_MANAGER,
5675                          CLUTTER_PARAM_READWRITE);
5676
5677
5678   /**
5679    * ClutterActor:x-align:
5680    *
5681    * The alignment of an actor on the X axis, if the actor has been given
5682    * extra space for its allocation.
5683    *
5684    * Since: 1.10
5685    */
5686   obj_props[PROP_X_ALIGN] =
5687     g_param_spec_enum ("x-align",
5688                        P_("X Alignment"),
5689                        P_("The alignment of the actor on the X axis within its allocation"),
5690                        CLUTTER_TYPE_ACTOR_ALIGN,
5691                        CLUTTER_ACTOR_ALIGN_FILL,
5692                        CLUTTER_PARAM_READWRITE);
5693
5694   /**
5695    * ClutterActor:y-align:
5696    *
5697    * The alignment of an actor on the Y axis, if the actor has been given
5698    * extra space for its allocation.
5699    *
5700    * Since: 1.10
5701    */
5702   obj_props[PROP_Y_ALIGN] =
5703     g_param_spec_enum ("y-align",
5704                        P_("Y Alignment"),
5705                        P_("The alignment of the actor on the Y axis within its allocation"),
5706                        CLUTTER_TYPE_ACTOR_ALIGN,
5707                        CLUTTER_ACTOR_ALIGN_FILL,
5708                        CLUTTER_PARAM_READWRITE);
5709
5710   /**
5711    * ClutterActor:margin-top:
5712    *
5713    * The margin (in pixels) from the top of the actor.
5714    *
5715    * This property adds a margin to the actor's preferred size; the margin
5716    * will be automatically taken into account when allocating the actor.
5717    *
5718    * Since: 1.10
5719    */
5720   obj_props[PROP_MARGIN_TOP] =
5721     g_param_spec_float ("margin-top",
5722                         P_("Margin Top"),
5723                         P_("Extra space at the top"),
5724                         0.0, G_MAXFLOAT,
5725                         0.0,
5726                         CLUTTER_PARAM_READWRITE);
5727
5728   /**
5729    * ClutterActor:margin-bottom:
5730    *
5731    * The margin (in pixels) from the bottom of the actor.
5732    *
5733    * This property adds a margin to the actor's preferred size; the margin
5734    * will be automatically taken into account when allocating the actor.
5735    *
5736    * Since: 1.10
5737    */
5738   obj_props[PROP_MARGIN_BOTTOM] =
5739     g_param_spec_float ("margin-bottom",
5740                         P_("Margin Bottom"),
5741                         P_("Extra space at the bottom"),
5742                         0.0, G_MAXFLOAT,
5743                         0.0,
5744                         CLUTTER_PARAM_READWRITE);
5745
5746   /**
5747    * ClutterActor:margin-left:
5748    *
5749    * The margin (in pixels) from the left of the actor.
5750    *
5751    * This property adds a margin to the actor's preferred size; the margin
5752    * will be automatically taken into account when allocating the actor.
5753    *
5754    * Since: 1.10
5755    */
5756   obj_props[PROP_MARGIN_LEFT] =
5757     g_param_spec_float ("margin-left",
5758                         P_("Margin Left"),
5759                         P_("Extra space at the left"),
5760                         0.0, G_MAXFLOAT,
5761                         0.0,
5762                         CLUTTER_PARAM_READWRITE);
5763
5764   /**
5765    * ClutterActor:margin-right:
5766    *
5767    * The margin (in pixels) from the right of the actor.
5768    *
5769    * This property adds a margin to the actor's preferred size; the margin
5770    * will be automatically taken into account when allocating the actor.
5771    *
5772    * Since: 1.10
5773    */
5774   obj_props[PROP_MARGIN_RIGHT] =
5775     g_param_spec_float ("margin-right",
5776                         P_("Margin Right"),
5777                         P_("Extra space at the right"),
5778                         0.0, G_MAXFLOAT,
5779                         0.0,
5780                         CLUTTER_PARAM_READWRITE);
5781
5782   /**
5783    * ClutterActor:background-color-set:
5784    *
5785    * Whether the #ClutterActor:background-color property has been set.
5786    *
5787    * Since: 1.10
5788    */
5789   obj_props[PROP_BACKGROUND_COLOR_SET] =
5790     g_param_spec_boolean ("background-color-set",
5791                           P_("Background Color Set"),
5792                           P_("Whether the background color is set"),
5793                           FALSE,
5794                           CLUTTER_PARAM_READABLE);
5795
5796   /**
5797    * ClutterActor:background-color:
5798    *
5799    * Paints a solid fill of the actor's allocation using the specified
5800    * color.
5801    *
5802    * Since: 1.10
5803    */
5804   obj_props[PROP_BACKGROUND_COLOR] =
5805     clutter_param_spec_color ("background-color",
5806                               P_("Background color"),
5807                               P_("The actor's background color"),
5808                               CLUTTER_COLOR_Transparent,
5809                               CLUTTER_PARAM_READWRITE);
5810
5811   /**
5812    * ClutterActor:first-child:
5813    *
5814    * The actor's first child.
5815    *
5816    * Since: 1.10
5817    */
5818   obj_props[PROP_FIRST_CHILD] =
5819     g_param_spec_object ("first-child",
5820                          P_("First Child"),
5821                          P_("The actor's first child"),
5822                          CLUTTER_TYPE_ACTOR,
5823                          CLUTTER_PARAM_READABLE);
5824
5825   /**
5826    * ClutterActor:last-child:
5827    *
5828    * The actor's last child.
5829    *
5830    * Since: 1.10
5831    */
5832   obj_props[PROP_LAST_CHILD] =
5833     g_param_spec_object ("last-child",
5834                          P_("Last Child"),
5835                          P_("The actor's last child"),
5836                          CLUTTER_TYPE_ACTOR,
5837                          CLUTTER_PARAM_READABLE);
5838
5839   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5840
5841   /**
5842    * ClutterActor::destroy:
5843    * @actor: the #ClutterActor which emitted the signal
5844    *
5845    * The ::destroy signal notifies that all references held on the
5846    * actor which emitted it should be released.
5847    *
5848    * The ::destroy signal should be used by all holders of a reference
5849    * on @actor.
5850    *
5851    * This signal might result in the finalization of the #ClutterActor
5852    * if all references are released.
5853    *
5854    * Composite actors and actors implementing the #ClutterContainer
5855    * interface should override the default implementation of the
5856    * class handler of this signal and call clutter_actor_destroy() on
5857    * their children. When overriding the default class handler, it is
5858    * required to chain up to the parent's implementation.
5859    *
5860    * Since: 0.2
5861    */
5862   actor_signals[DESTROY] =
5863     g_signal_new (I_("destroy"),
5864                   G_TYPE_FROM_CLASS (object_class),
5865                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5866                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5867                   NULL, NULL,
5868                   _clutter_marshal_VOID__VOID,
5869                   G_TYPE_NONE, 0);
5870   /**
5871    * ClutterActor::show:
5872    * @actor: the object which received the signal
5873    *
5874    * The ::show signal is emitted when an actor is visible and
5875    * rendered on the stage.
5876    *
5877    * Since: 0.2
5878    */
5879   actor_signals[SHOW] =
5880     g_signal_new (I_("show"),
5881                   G_TYPE_FROM_CLASS (object_class),
5882                   G_SIGNAL_RUN_FIRST,
5883                   G_STRUCT_OFFSET (ClutterActorClass, show),
5884                   NULL, NULL,
5885                   _clutter_marshal_VOID__VOID,
5886                   G_TYPE_NONE, 0);
5887   /**
5888    * ClutterActor::hide:
5889    * @actor: the object which received the signal
5890    *
5891    * The ::hide signal is emitted when an actor is no longer rendered
5892    * on the stage.
5893    *
5894    * Since: 0.2
5895    */
5896   actor_signals[HIDE] =
5897     g_signal_new (I_("hide"),
5898                   G_TYPE_FROM_CLASS (object_class),
5899                   G_SIGNAL_RUN_FIRST,
5900                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5901                   NULL, NULL,
5902                   _clutter_marshal_VOID__VOID,
5903                   G_TYPE_NONE, 0);
5904   /**
5905    * ClutterActor::parent-set:
5906    * @actor: the object which received the signal
5907    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5908    *
5909    * This signal is emitted when the parent of the actor changes.
5910    *
5911    * Since: 0.2
5912    */
5913   actor_signals[PARENT_SET] =
5914     g_signal_new (I_("parent-set"),
5915                   G_TYPE_FROM_CLASS (object_class),
5916                   G_SIGNAL_RUN_LAST,
5917                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5918                   NULL, NULL,
5919                   _clutter_marshal_VOID__OBJECT,
5920                   G_TYPE_NONE, 1,
5921                   CLUTTER_TYPE_ACTOR);
5922
5923   /**
5924    * ClutterActor::queue-redraw:
5925    * @actor: the actor we're bubbling the redraw request through
5926    * @origin: the actor which initiated the redraw request
5927    *
5928    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5929    * is called on @origin.
5930    *
5931    * The default implementation for #ClutterActor chains up to the
5932    * parent actor and queues a redraw on the parent, thus "bubbling"
5933    * the redraw queue up through the actor graph. The default
5934    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5935    * in a main loop idle handler.
5936    *
5937    * Note that the @origin actor may be the stage, or a container; it
5938    * does not have to be a leaf node in the actor graph.
5939    *
5940    * Toolkits embedding a #ClutterStage which require a redraw and
5941    * relayout cycle can stop the emission of this signal using the
5942    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
5943    * themselves, like:
5944    *
5945    * |[
5946    *   static void
5947    *   on_redraw_complete (gpointer data)
5948    *   {
5949    *     ClutterStage *stage = data;
5950    *
5951    *     /&ast; execute the Clutter drawing pipeline &ast;/
5952    *     clutter_stage_ensure_redraw (stage);
5953    *   }
5954    *
5955    *   static void
5956    *   on_stage_queue_redraw (ClutterStage *stage)
5957    *   {
5958    *     /&ast; this prevents the default handler to run &ast;/
5959    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
5960    *
5961    *     /&ast; queue a redraw with the host toolkit and call
5962    *      &ast; a function when the redraw has been completed
5963    *      &ast;/
5964    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
5965    *   }
5966    * ]|
5967    *
5968    * <note><para>This signal is emitted before the Clutter paint
5969    * pipeline is executed. If you want to know when the pipeline has
5970    * been completed you should connect to the ::paint signal on the
5971    * Stage with g_signal_connect_after().</para></note>
5972    *
5973    * Since: 1.0
5974    */
5975   actor_signals[QUEUE_REDRAW] =
5976     g_signal_new (I_("queue-redraw"),
5977                   G_TYPE_FROM_CLASS (object_class),
5978                   G_SIGNAL_RUN_LAST,
5979                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
5980                   NULL, NULL,
5981                   _clutter_marshal_VOID__OBJECT,
5982                   G_TYPE_NONE, 1,
5983                   CLUTTER_TYPE_ACTOR);
5984
5985   /**
5986    * ClutterActor::queue-relayout
5987    * @actor: the actor being queued for relayout
5988    *
5989    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
5990    * is called on an actor.
5991    *
5992    * The default implementation for #ClutterActor chains up to the
5993    * parent actor and queues a relayout on the parent, thus "bubbling"
5994    * the relayout queue up through the actor graph.
5995    *
5996    * The main purpose of this signal is to allow relayout to be propagated
5997    * properly in the procense of #ClutterClone actors. Applications will
5998    * not normally need to connect to this signal.
5999    *
6000    * Since: 1.2
6001    */
6002   actor_signals[QUEUE_RELAYOUT] =
6003     g_signal_new (I_("queue-relayout"),
6004                   G_TYPE_FROM_CLASS (object_class),
6005                   G_SIGNAL_RUN_LAST,
6006                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6007                   NULL, NULL,
6008                   _clutter_marshal_VOID__VOID,
6009                   G_TYPE_NONE, 0);
6010
6011   /**
6012    * ClutterActor::event:
6013    * @actor: the actor which received the event
6014    * @event: a #ClutterEvent
6015    *
6016    * The ::event signal is emitted each time an event is received
6017    * by the @actor. This signal will be emitted on every actor,
6018    * following the hierarchy chain, until it reaches the top-level
6019    * container (the #ClutterStage).
6020    *
6021    * Return value: %TRUE if the event has been handled by the actor,
6022    *   or %FALSE to continue the emission.
6023    *
6024    * Since: 0.6
6025    */
6026   actor_signals[EVENT] =
6027     g_signal_new (I_("event"),
6028                   G_TYPE_FROM_CLASS (object_class),
6029                   G_SIGNAL_RUN_LAST,
6030                   G_STRUCT_OFFSET (ClutterActorClass, event),
6031                   _clutter_boolean_handled_accumulator, NULL,
6032                   _clutter_marshal_BOOLEAN__BOXED,
6033                   G_TYPE_BOOLEAN, 1,
6034                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6035   /**
6036    * ClutterActor::button-press-event:
6037    * @actor: the actor which received the event
6038    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6039    *
6040    * The ::button-press-event signal is emitted each time a mouse button
6041    * is pressed on @actor.
6042    *
6043    * Return value: %TRUE if the event has been handled by the actor,
6044    *   or %FALSE to continue the emission.
6045    *
6046    * Since: 0.6
6047    */
6048   actor_signals[BUTTON_PRESS_EVENT] =
6049     g_signal_new (I_("button-press-event"),
6050                   G_TYPE_FROM_CLASS (object_class),
6051                   G_SIGNAL_RUN_LAST,
6052                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6053                   _clutter_boolean_handled_accumulator, NULL,
6054                   _clutter_marshal_BOOLEAN__BOXED,
6055                   G_TYPE_BOOLEAN, 1,
6056                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6057   /**
6058    * ClutterActor::button-release-event:
6059    * @actor: the actor which received the event
6060    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6061    *
6062    * The ::button-release-event signal is emitted each time a mouse button
6063    * is released on @actor.
6064    *
6065    * Return value: %TRUE if the event has been handled by the actor,
6066    *   or %FALSE to continue the emission.
6067    *
6068    * Since: 0.6
6069    */
6070   actor_signals[BUTTON_RELEASE_EVENT] =
6071     g_signal_new (I_("button-release-event"),
6072                   G_TYPE_FROM_CLASS (object_class),
6073                   G_SIGNAL_RUN_LAST,
6074                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6075                   _clutter_boolean_handled_accumulator, NULL,
6076                   _clutter_marshal_BOOLEAN__BOXED,
6077                   G_TYPE_BOOLEAN, 1,
6078                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6079   /**
6080    * ClutterActor::scroll-event:
6081    * @actor: the actor which received the event
6082    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6083    *
6084    * The ::scroll-event signal is emitted each time the mouse is
6085    * scrolled on @actor
6086    *
6087    * Return value: %TRUE if the event has been handled by the actor,
6088    *   or %FALSE to continue the emission.
6089    *
6090    * Since: 0.6
6091    */
6092   actor_signals[SCROLL_EVENT] =
6093     g_signal_new (I_("scroll-event"),
6094                   G_TYPE_FROM_CLASS (object_class),
6095                   G_SIGNAL_RUN_LAST,
6096                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6097                   _clutter_boolean_handled_accumulator, NULL,
6098                   _clutter_marshal_BOOLEAN__BOXED,
6099                   G_TYPE_BOOLEAN, 1,
6100                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6101   /**
6102    * ClutterActor::key-press-event:
6103    * @actor: the actor which received the event
6104    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6105    *
6106    * The ::key-press-event signal is emitted each time a keyboard button
6107    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6108    *
6109    * Return value: %TRUE if the event has been handled by the actor,
6110    *   or %FALSE to continue the emission.
6111    *
6112    * Since: 0.6
6113    */
6114   actor_signals[KEY_PRESS_EVENT] =
6115     g_signal_new (I_("key-press-event"),
6116                   G_TYPE_FROM_CLASS (object_class),
6117                   G_SIGNAL_RUN_LAST,
6118                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6119                   _clutter_boolean_handled_accumulator, NULL,
6120                   _clutter_marshal_BOOLEAN__BOXED,
6121                   G_TYPE_BOOLEAN, 1,
6122                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6123   /**
6124    * ClutterActor::key-release-event:
6125    * @actor: the actor which received the event
6126    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6127    *
6128    * The ::key-release-event signal is emitted each time a keyboard button
6129    * is released while @actor has key focus (see
6130    * clutter_stage_set_key_focus()).
6131    *
6132    * Return value: %TRUE if the event has been handled by the actor,
6133    *   or %FALSE to continue the emission.
6134    *
6135    * Since: 0.6
6136    */
6137   actor_signals[KEY_RELEASE_EVENT] =
6138     g_signal_new (I_("key-release-event"),
6139                   G_TYPE_FROM_CLASS (object_class),
6140                   G_SIGNAL_RUN_LAST,
6141                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6142                   _clutter_boolean_handled_accumulator, NULL,
6143                   _clutter_marshal_BOOLEAN__BOXED,
6144                   G_TYPE_BOOLEAN, 1,
6145                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6146   /**
6147    * ClutterActor::motion-event:
6148    * @actor: the actor which received the event
6149    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6150    *
6151    * The ::motion-event signal is emitted each time the mouse pointer is
6152    * moved over @actor.
6153    *
6154    * Return value: %TRUE if the event has been handled by the actor,
6155    *   or %FALSE to continue the emission.
6156    *
6157    * Since: 0.6
6158    */
6159   actor_signals[MOTION_EVENT] =
6160     g_signal_new (I_("motion-event"),
6161                   G_TYPE_FROM_CLASS (object_class),
6162                   G_SIGNAL_RUN_LAST,
6163                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6164                   _clutter_boolean_handled_accumulator, NULL,
6165                   _clutter_marshal_BOOLEAN__BOXED,
6166                   G_TYPE_BOOLEAN, 1,
6167                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6168
6169   /**
6170    * ClutterActor::key-focus-in:
6171    * @actor: the actor which now has key focus
6172    *
6173    * The ::key-focus-in signal is emitted when @actor receives key focus.
6174    *
6175    * Since: 0.6
6176    */
6177   actor_signals[KEY_FOCUS_IN] =
6178     g_signal_new (I_("key-focus-in"),
6179                   G_TYPE_FROM_CLASS (object_class),
6180                   G_SIGNAL_RUN_LAST,
6181                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6182                   NULL, NULL,
6183                   _clutter_marshal_VOID__VOID,
6184                   G_TYPE_NONE, 0);
6185
6186   /**
6187    * ClutterActor::key-focus-out:
6188    * @actor: the actor which now has key focus
6189    *
6190    * The ::key-focus-out signal is emitted when @actor loses key focus.
6191    *
6192    * Since: 0.6
6193    */
6194   actor_signals[KEY_FOCUS_OUT] =
6195     g_signal_new (I_("key-focus-out"),
6196                   G_TYPE_FROM_CLASS (object_class),
6197                   G_SIGNAL_RUN_LAST,
6198                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6199                   NULL, NULL,
6200                   _clutter_marshal_VOID__VOID,
6201                   G_TYPE_NONE, 0);
6202
6203   /**
6204    * ClutterActor::enter-event:
6205    * @actor: the actor which the pointer has entered.
6206    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6207    *
6208    * The ::enter-event signal is emitted when the pointer enters the @actor
6209    *
6210    * Return value: %TRUE if the event has been handled by the actor,
6211    *   or %FALSE to continue the emission.
6212    *
6213    * Since: 0.6
6214    */
6215   actor_signals[ENTER_EVENT] =
6216     g_signal_new (I_("enter-event"),
6217                   G_TYPE_FROM_CLASS (object_class),
6218                   G_SIGNAL_RUN_LAST,
6219                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6220                   _clutter_boolean_handled_accumulator, NULL,
6221                   _clutter_marshal_BOOLEAN__BOXED,
6222                   G_TYPE_BOOLEAN, 1,
6223                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6224
6225   /**
6226    * ClutterActor::leave-event:
6227    * @actor: the actor which the pointer has left
6228    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6229    *
6230    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6231    *
6232    * Return value: %TRUE if the event has been handled by the actor,
6233    *   or %FALSE to continue the emission.
6234    *
6235    * Since: 0.6
6236    */
6237   actor_signals[LEAVE_EVENT] =
6238     g_signal_new (I_("leave-event"),
6239                   G_TYPE_FROM_CLASS (object_class),
6240                   G_SIGNAL_RUN_LAST,
6241                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6242                   _clutter_boolean_handled_accumulator, NULL,
6243                   _clutter_marshal_BOOLEAN__BOXED,
6244                   G_TYPE_BOOLEAN, 1,
6245                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6246
6247   /**
6248    * ClutterActor::captured-event:
6249    * @actor: the actor which received the signal
6250    * @event: a #ClutterEvent
6251    *
6252    * The ::captured-event signal is emitted when an event is captured
6253    * by Clutter. This signal will be emitted starting from the top-level
6254    * container (the #ClutterStage) to the actor which received the event
6255    * going down the hierarchy. This signal can be used to intercept every
6256    * event before the specialized events (like
6257    * ClutterActor::button-press-event or ::key-released-event) are
6258    * emitted.
6259    *
6260    * Return value: %TRUE if the event has been handled by the actor,
6261    *   or %FALSE to continue the emission.
6262    *
6263    * Since: 0.6
6264    */
6265   actor_signals[CAPTURED_EVENT] =
6266     g_signal_new (I_("captured-event"),
6267                   G_TYPE_FROM_CLASS (object_class),
6268                   G_SIGNAL_RUN_LAST,
6269                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6270                   _clutter_boolean_handled_accumulator, NULL,
6271                   _clutter_marshal_BOOLEAN__BOXED,
6272                   G_TYPE_BOOLEAN, 1,
6273                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6274
6275   /**
6276    * ClutterActor::paint:
6277    * @actor: the #ClutterActor that received the signal
6278    *
6279    * The ::paint signal is emitted each time an actor is being painted.
6280    *
6281    * Subclasses of #ClutterActor should override the class signal handler
6282    * and paint themselves in that function.
6283    *
6284    * It is possible to connect a handler to the ::paint signal in order
6285    * to set up some custom aspect of a paint.
6286    *
6287    * Since: 0.8
6288    */
6289   actor_signals[PAINT] =
6290     g_signal_new (I_("paint"),
6291                   G_TYPE_FROM_CLASS (object_class),
6292                   G_SIGNAL_RUN_LAST,
6293                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6294                   NULL, NULL,
6295                   _clutter_marshal_VOID__VOID,
6296                   G_TYPE_NONE, 0);
6297   /**
6298    * ClutterActor::realize:
6299    * @actor: the #ClutterActor that received the signal
6300    *
6301    * The ::realize signal is emitted each time an actor is being
6302    * realized.
6303    *
6304    * Since: 0.8
6305    */
6306   actor_signals[REALIZE] =
6307     g_signal_new (I_("realize"),
6308                   G_TYPE_FROM_CLASS (object_class),
6309                   G_SIGNAL_RUN_LAST,
6310                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6311                   NULL, NULL,
6312                   _clutter_marshal_VOID__VOID,
6313                   G_TYPE_NONE, 0);
6314   /**
6315    * ClutterActor::unrealize:
6316    * @actor: the #ClutterActor that received the signal
6317    *
6318    * The ::unrealize signal is emitted each time an actor is being
6319    * unrealized.
6320    *
6321    * Since: 0.8
6322    */
6323   actor_signals[UNREALIZE] =
6324     g_signal_new (I_("unrealize"),
6325                   G_TYPE_FROM_CLASS (object_class),
6326                   G_SIGNAL_RUN_LAST,
6327                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6328                   NULL, NULL,
6329                   _clutter_marshal_VOID__VOID,
6330                   G_TYPE_NONE, 0);
6331
6332   /**
6333    * ClutterActor::pick:
6334    * @actor: the #ClutterActor that received the signal
6335    * @color: the #ClutterColor to be used when picking
6336    *
6337    * The ::pick signal is emitted each time an actor is being painted
6338    * in "pick mode". The pick mode is used to identify the actor during
6339    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6340    * The actor should paint its shape using the passed @pick_color.
6341    *
6342    * Subclasses of #ClutterActor should override the class signal handler
6343    * and paint themselves in that function.
6344    *
6345    * It is possible to connect a handler to the ::pick signal in order
6346    * to set up some custom aspect of a paint in pick mode.
6347    *
6348    * Since: 1.0
6349    */
6350   actor_signals[PICK] =
6351     g_signal_new (I_("pick"),
6352                   G_TYPE_FROM_CLASS (object_class),
6353                   G_SIGNAL_RUN_LAST,
6354                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6355                   NULL, NULL,
6356                   _clutter_marshal_VOID__BOXED,
6357                   G_TYPE_NONE, 1,
6358                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6359
6360   /**
6361    * ClutterActor::allocation-changed:
6362    * @actor: the #ClutterActor that emitted the signal
6363    * @box: a #ClutterActorBox with the new allocation
6364    * @flags: #ClutterAllocationFlags for the allocation
6365    *
6366    * The ::allocation-changed signal is emitted when the
6367    * #ClutterActor:allocation property changes. Usually, application
6368    * code should just use the notifications for the :allocation property
6369    * but if you want to track the allocation flags as well, for instance
6370    * to know whether the absolute origin of @actor changed, then you might
6371    * want use this signal instead.
6372    *
6373    * Since: 1.0
6374    */
6375   actor_signals[ALLOCATION_CHANGED] =
6376     g_signal_new (I_("allocation-changed"),
6377                   G_TYPE_FROM_CLASS (object_class),
6378                   G_SIGNAL_RUN_LAST,
6379                   0,
6380                   NULL, NULL,
6381                   _clutter_marshal_VOID__BOXED_FLAGS,
6382                   G_TYPE_NONE, 2,
6383                   CLUTTER_TYPE_ACTOR_BOX,
6384                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6385 }
6386
6387 static void
6388 clutter_actor_init (ClutterActor *self)
6389 {
6390   ClutterActorPrivate *priv;
6391
6392   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6393
6394   priv->id = _clutter_context_acquire_id (self);
6395   priv->pick_id = -1;
6396
6397   priv->opacity = 0xff;
6398   priv->show_on_set_parent = TRUE;
6399
6400   priv->needs_width_request = TRUE;
6401   priv->needs_height_request = TRUE;
6402   priv->needs_allocation = TRUE;
6403
6404   priv->cached_width_age = 1;
6405   priv->cached_height_age = 1;
6406
6407   priv->opacity_override = -1;
6408   priv->enable_model_view_transform = TRUE;
6409
6410   /* Initialize an empty paint volume to start with */
6411   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6412   priv->last_paint_volume_valid = TRUE;
6413
6414   priv->transform_valid = FALSE;
6415 }
6416
6417 /**
6418  * clutter_actor_new:
6419  *
6420  * Creates a new #ClutterActor.
6421  *
6422  * A newly created actor has a floating reference, which will be sunk
6423  * when it is added to another actor.
6424  *
6425  * Return value: (transfer full): the newly created #ClutterActor
6426  *
6427  * Since: 1.10
6428  */
6429 ClutterActor *
6430 clutter_actor_new (void)
6431 {
6432   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6433 }
6434
6435 /**
6436  * clutter_actor_destroy:
6437  * @self: a #ClutterActor
6438  *
6439  * Destroys an actor.  When an actor is destroyed, it will break any
6440  * references it holds to other objects.  If the actor is inside a
6441  * container, the actor will be removed.
6442  *
6443  * When you destroy a container, its children will be destroyed as well.
6444  *
6445  * Note: you cannot destroy the #ClutterStage returned by
6446  * clutter_stage_get_default().
6447  */
6448 void
6449 clutter_actor_destroy (ClutterActor *self)
6450 {
6451   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6452
6453   g_object_ref (self);
6454
6455   /* avoid recursion while destroying */
6456   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6457     {
6458       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6459
6460       g_object_run_dispose (G_OBJECT (self));
6461
6462       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6463     }
6464
6465   g_object_unref (self);
6466 }
6467
6468 void
6469 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6470                                     ClutterPaintVolume *clip)
6471 {
6472   ClutterActorPrivate *priv = self->priv;
6473   ClutterPaintVolume *pv;
6474   gboolean clipped;
6475
6476   /* If we've been explicitly passed a clip volume then there's
6477    * nothing more to calculate, but otherwise the only thing we know
6478    * is that the change is constrained to the given actor.
6479    *
6480    * The idea is that if we know the paint volume for where the actor
6481    * was last drawn (in eye coordinates) and we also have the paint
6482    * volume for where it will be drawn next (in actor coordinates)
6483    * then if we queue a redraw for both these volumes that will cover
6484    * everything that needs to be redrawn to clear the old view and
6485    * show the latest view of the actor.
6486    *
6487    * Don't clip this redraw if we don't know what position we had for
6488    * the previous redraw since we don't know where to set the clip so
6489    * it will clear the actor as it is currently.
6490    */
6491   if (clip)
6492     {
6493       _clutter_actor_set_queue_redraw_clip (self, clip);
6494       clipped = TRUE;
6495     }
6496   else if (G_LIKELY (priv->last_paint_volume_valid))
6497     {
6498       pv = _clutter_actor_get_paint_volume_mutable (self);
6499       if (pv)
6500         {
6501           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6502
6503           /* make sure we redraw the actors old position... */
6504           _clutter_actor_set_queue_redraw_clip (stage,
6505                                                 &priv->last_paint_volume);
6506           _clutter_actor_signal_queue_redraw (stage, stage);
6507           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6508
6509           /* XXX: Ideally the redraw signal would take a clip volume
6510            * argument, but that would be an ABI break. Until we can
6511            * break the ABI we pass the argument out-of-band
6512            */
6513
6514           /* setup the clip for the actors new position... */
6515           _clutter_actor_set_queue_redraw_clip (self, pv);
6516           clipped = TRUE;
6517         }
6518       else
6519         clipped = FALSE;
6520     }
6521   else
6522     clipped = FALSE;
6523
6524   _clutter_actor_signal_queue_redraw (self, self);
6525
6526   /* Just in case anyone is manually firing redraw signals without
6527    * using the public queue_redraw() API we are careful to ensure that
6528    * our out-of-band clip member is cleared before returning...
6529    *
6530    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6531    */
6532   if (G_LIKELY (clipped))
6533     _clutter_actor_set_queue_redraw_clip (self, NULL);
6534
6535   priv->queue_redraw_entry = NULL;
6536 }
6537
6538 static void
6539 _clutter_actor_get_allocation_clip (ClutterActor *self,
6540                                     ClutterActorBox *clip)
6541 {
6542   ClutterActorBox allocation;
6543
6544   /* XXX: we don't care if we get an out of date allocation here
6545    * because clutter_actor_queue_redraw_with_clip knows to ignore
6546    * the clip if the actor's allocation is invalid.
6547    *
6548    * This is noted because clutter_actor_get_allocation_box does some
6549    * unnecessary work to support buggy code with a comment suggesting
6550    * that it could be changed later which would be good for this use
6551    * case!
6552    */
6553   clutter_actor_get_allocation_box (self, &allocation);
6554
6555   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6556    * actor's own coordinate space but the allocation is in parent
6557    * coordinates */
6558   clip->x1 = 0;
6559   clip->y1 = 0;
6560   clip->x2 = allocation.x2 - allocation.x1;
6561   clip->y2 = allocation.y2 - allocation.y1;
6562 }
6563
6564 void
6565 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6566                                   ClutterRedrawFlags  flags,
6567                                   ClutterPaintVolume *volume,
6568                                   ClutterEffect      *effect)
6569 {
6570   ClutterActorPrivate *priv = self->priv;
6571   ClutterPaintVolume allocation_pv;
6572   ClutterPaintVolume *pv;
6573   gboolean should_free_pv;
6574   ClutterActor *stage;
6575
6576   /* Here's an outline of the actor queue redraw mechanism:
6577    *
6578    * The process starts in one of the following two functions which
6579    * are wrappers for this function:
6580    * clutter_actor_queue_redraw
6581    * _clutter_actor_queue_redraw_with_clip
6582    *
6583    * additionally, an effect can queue a redraw by wrapping this
6584    * function in clutter_effect_queue_rerun
6585    *
6586    * This functions queues an entry in a list associated with the
6587    * stage which is a list of actors that queued a redraw while
6588    * updating the timelines, performing layouting and processing other
6589    * mainloop sources before the next paint starts.
6590    *
6591    * We aim to minimize the processing done at this point because
6592    * there is a good chance other events will happen while updating
6593    * the scenegraph that would invalidate any expensive work we might
6594    * otherwise try to do here. For example we don't try and resolve
6595    * the screen space bounding box of an actor at this stage so as to
6596    * minimize how much of the screen redraw because it's possible
6597    * something else will happen which will force a full redraw anyway.
6598    *
6599    * When all updates are complete and we come to paint the stage then
6600    * we iterate this list and actually emit the "queue-redraw" signals
6601    * for each of the listed actors which will bubble up to the stage
6602    * for each actor and at that point we will transform the actors
6603    * paint volume into screen coordinates to determine the clip region
6604    * for what needs to be redrawn in the next paint.
6605    *
6606    * Besides minimizing redundant work another reason for this
6607    * deferred design is that it's more likely we will be able to
6608    * determine the paint volume of an actor once we've finished
6609    * updating the scenegraph because its allocation should be up to
6610    * date. NB: If we can't determine an actors paint volume then we
6611    * can't automatically queue a clipped redraw which can make a big
6612    * difference to performance.
6613    *
6614    * So the control flow goes like this:
6615    * One of clutter_actor_queue_redraw,
6616    *        _clutter_actor_queue_redraw_with_clip
6617    *     or clutter_effect_queue_rerun
6618    *
6619    * then control moves to:
6620    *   _clutter_stage_queue_actor_redraw
6621    *
6622    * later during _clutter_stage_do_update, once relayouting is done
6623    * and the scenegraph has been updated we will call:
6624    * _clutter_stage_finish_queue_redraws
6625    *
6626    * _clutter_stage_finish_queue_redraws will call
6627    * _clutter_actor_finish_queue_redraw for each listed actor.
6628    * Note: actors *are* allowed to queue further redraws during this
6629    * process (considering clone actors or texture_new_from_actor which
6630    * respond to their source queueing a redraw by queuing a redraw
6631    * themselves). We repeat the process until the list is empty.
6632    *
6633    * This will result in the "queue-redraw" signal being fired for
6634    * each actor which will pass control to the default signal handler:
6635    * clutter_actor_real_queue_redraw
6636    *
6637    * This will bubble up to the stages handler:
6638    * clutter_stage_real_queue_redraw
6639    *
6640    * clutter_stage_real_queue_redraw will transform the actors paint
6641    * volume into screen space and add it as a clip region for the next
6642    * paint.
6643    */
6644
6645   /* ignore queueing a redraw for actors being destroyed */
6646   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6647     return;
6648
6649   stage = _clutter_actor_get_stage_internal (self);
6650
6651   /* Ignore queueing a redraw for actors not descended from a stage */
6652   if (stage == NULL)
6653     return;
6654
6655   /* ignore queueing a redraw on stages that are being destroyed */
6656   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6657     return;
6658
6659   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6660     {
6661       ClutterActorBox allocation_clip;
6662       ClutterVertex origin;
6663
6664       /* If the actor doesn't have a valid allocation then we will
6665        * queue a full stage redraw. */
6666       if (priv->needs_allocation)
6667         {
6668           /* NB: NULL denotes an undefined clip which will result in a
6669            * full redraw... */
6670           _clutter_actor_set_queue_redraw_clip (self, NULL);
6671           _clutter_actor_signal_queue_redraw (self, self);
6672           return;
6673         }
6674
6675       _clutter_paint_volume_init_static (&allocation_pv, self);
6676       pv = &allocation_pv;
6677
6678       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6679
6680       origin.x = allocation_clip.x1;
6681       origin.y = allocation_clip.y1;
6682       origin.z = 0;
6683       clutter_paint_volume_set_origin (pv, &origin);
6684       clutter_paint_volume_set_width (pv,
6685                                       allocation_clip.x2 - allocation_clip.x1);
6686       clutter_paint_volume_set_height (pv,
6687                                        allocation_clip.y2 -
6688                                        allocation_clip.y1);
6689       should_free_pv = TRUE;
6690     }
6691   else
6692     {
6693       pv = volume;
6694       should_free_pv = FALSE;
6695     }
6696
6697   self->priv->queue_redraw_entry =
6698     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6699                                        priv->queue_redraw_entry,
6700                                        self,
6701                                        pv);
6702
6703   if (should_free_pv)
6704     clutter_paint_volume_free (pv);
6705
6706   /* If this is the first redraw queued then we can directly use the
6707      effect parameter */
6708   if (!priv->is_dirty)
6709     priv->effect_to_redraw = effect;
6710   /* Otherwise we need to merge it with the existing effect parameter */
6711   else if (effect != NULL)
6712     {
6713       /* If there's already an effect then we need to use whichever is
6714          later in the chain of actors. Otherwise a full redraw has
6715          already been queued on the actor so we need to ignore the
6716          effect parameter */
6717       if (priv->effect_to_redraw != NULL)
6718         {
6719           if (priv->effects == NULL)
6720             g_warning ("Redraw queued with an effect that is "
6721                        "not applied to the actor");
6722           else
6723             {
6724               const GList *l;
6725
6726               for (l = _clutter_meta_group_peek_metas (priv->effects);
6727                    l != NULL;
6728                    l = l->next)
6729                 {
6730                   if (l->data == priv->effect_to_redraw ||
6731                       l->data == effect)
6732                     priv->effect_to_redraw = l->data;
6733                 }
6734             }
6735         }
6736     }
6737   else
6738     {
6739       /* If no effect is specified then we need to redraw the whole
6740          actor */
6741       priv->effect_to_redraw = NULL;
6742     }
6743
6744   priv->is_dirty = TRUE;
6745 }
6746
6747 /**
6748  * clutter_actor_queue_redraw:
6749  * @self: A #ClutterActor
6750  *
6751  * Queues up a redraw of an actor and any children. The redraw occurs
6752  * once the main loop becomes idle (after the current batch of events
6753  * has been processed, roughly).
6754  *
6755  * Applications rarely need to call this, as redraws are handled
6756  * automatically by modification functions.
6757  *
6758  * This function will not do anything if @self is not visible, or
6759  * if the actor is inside an invisible part of the scenegraph.
6760  *
6761  * Also be aware that painting is a NOP for actors with an opacity of
6762  * 0
6763  *
6764  * When you are implementing a custom actor you must queue a redraw
6765  * whenever some private state changes that will affect painting or
6766  * picking of your actor.
6767  */
6768 void
6769 clutter_actor_queue_redraw (ClutterActor *self)
6770 {
6771   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6772
6773   _clutter_actor_queue_redraw_full (self,
6774                                     0, /* flags */
6775                                     NULL, /* clip volume */
6776                                     NULL /* effect */);
6777 }
6778
6779 /*< private >
6780  * _clutter_actor_queue_redraw_with_clip:
6781  * @self: A #ClutterActor
6782  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6783  *   this queue redraw.
6784  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6785  *   redrawn or %NULL if you are just using a @flag to state your
6786  *   desired clipping.
6787  *
6788  * Queues up a clipped redraw of an actor and any children. The redraw
6789  * occurs once the main loop becomes idle (after the current batch of
6790  * events has been processed, roughly).
6791  *
6792  * If no flags are given the clip volume is defined by @volume
6793  * specified in actor coordinates and tells Clutter that only content
6794  * within this volume has been changed so Clutter can optionally
6795  * optimize the redraw.
6796  *
6797  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6798  * should be %NULL and this tells Clutter to use the actor's current
6799  * allocation as a clip box. This flag can only be used for 2D actors,
6800  * because any actor with depth may be projected outside its
6801  * allocation.
6802  *
6803  * Applications rarely need to call this, as redraws are handled
6804  * automatically by modification functions.
6805  *
6806  * This function will not do anything if @self is not visible, or if
6807  * the actor is inside an invisible part of the scenegraph.
6808  *
6809  * Also be aware that painting is a NOP for actors with an opacity of
6810  * 0
6811  *
6812  * When you are implementing a custom actor you must queue a redraw
6813  * whenever some private state changes that will affect painting or
6814  * picking of your actor.
6815  */
6816 void
6817 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6818                                        ClutterRedrawFlags  flags,
6819                                        ClutterPaintVolume *volume)
6820 {
6821   _clutter_actor_queue_redraw_full (self,
6822                                     flags, /* flags */
6823                                     volume, /* clip volume */
6824                                     NULL /* effect */);
6825 }
6826
6827 static void
6828 _clutter_actor_queue_only_relayout (ClutterActor *self)
6829 {
6830   ClutterActorPrivate *priv = self->priv;
6831
6832   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6833     return;
6834
6835   if (priv->needs_width_request &&
6836       priv->needs_height_request &&
6837       priv->needs_allocation)
6838     return; /* save some cpu cycles */
6839
6840 #if CLUTTER_ENABLE_DEBUG
6841   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6842     {
6843       g_warning ("The actor '%s' is currently inside an allocation "
6844                  "cycle; calling clutter_actor_queue_relayout() is "
6845                  "not recommended",
6846                  _clutter_actor_get_debug_name (self));
6847     }
6848 #endif /* CLUTTER_ENABLE_DEBUG */
6849
6850   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6851 }
6852
6853 /**
6854  * clutter_actor_queue_redraw_with_clip:
6855  * @self: a #ClutterActor
6856  * @clip: (allow-none): a rectangular clip region, or %NULL
6857  *
6858  * Queues a redraw on @self limited to a specific, actor-relative
6859  * rectangular area.
6860  *
6861  * If @clip is %NULL this function is equivalent to
6862  * clutter_actor_queue_redraw().
6863  *
6864  * Since: 1.10
6865  */
6866 void
6867 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6868                                       const cairo_rectangle_int_t *clip)
6869 {
6870   ClutterPaintVolume volume;
6871   ClutterVertex origin;
6872
6873   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6874
6875   if (clip == NULL)
6876     {
6877       clutter_actor_queue_redraw (self);
6878       return;
6879     }
6880
6881   _clutter_paint_volume_init_static (&volume, self);
6882
6883   origin.x = clip->x;
6884   origin.y = clip->y;
6885   origin.z = 0.0f;
6886
6887   clutter_paint_volume_set_origin (&volume, &origin);
6888   clutter_paint_volume_set_width (&volume, clip->width);
6889   clutter_paint_volume_set_height (&volume, clip->height);
6890
6891   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6892
6893   clutter_paint_volume_free (&volume);
6894 }
6895
6896 /**
6897  * clutter_actor_queue_relayout:
6898  * @self: A #ClutterActor
6899  *
6900  * Indicates that the actor's size request or other layout-affecting
6901  * properties may have changed. This function is used inside #ClutterActor
6902  * subclass implementations, not by applications directly.
6903  *
6904  * Queueing a new layout automatically queues a redraw as well.
6905  *
6906  * Since: 0.8
6907  */
6908 void
6909 clutter_actor_queue_relayout (ClutterActor *self)
6910 {
6911   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6912
6913   _clutter_actor_queue_only_relayout (self);
6914   clutter_actor_queue_redraw (self);
6915 }
6916
6917 /**
6918  * clutter_actor_get_preferred_size:
6919  * @self: a #ClutterActor
6920  * @min_width_p: (out) (allow-none): return location for the minimum
6921  *   width, or %NULL
6922  * @min_height_p: (out) (allow-none): return location for the minimum
6923  *   height, or %NULL
6924  * @natural_width_p: (out) (allow-none): return location for the natural
6925  *   width, or %NULL
6926  * @natural_height_p: (out) (allow-none): return location for the natural
6927  *   height, or %NULL
6928  *
6929  * Computes the preferred minimum and natural size of an actor, taking into
6930  * account the actor's geometry management (either height-for-width
6931  * or width-for-height).
6932  *
6933  * The width and height used to compute the preferred height and preferred
6934  * width are the actor's natural ones.
6935  *
6936  * If you need to control the height for the preferred width, or the width for
6937  * the preferred height, you should use clutter_actor_get_preferred_width()
6938  * and clutter_actor_get_preferred_height(), and check the actor's preferred
6939  * geometry management using the #ClutterActor:request-mode property.
6940  *
6941  * Since: 0.8
6942  */
6943 void
6944 clutter_actor_get_preferred_size (ClutterActor *self,
6945                                   gfloat       *min_width_p,
6946                                   gfloat       *min_height_p,
6947                                   gfloat       *natural_width_p,
6948                                   gfloat       *natural_height_p)
6949 {
6950   ClutterActorPrivate *priv;
6951   gfloat min_width, min_height;
6952   gfloat natural_width, natural_height;
6953
6954   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6955
6956   priv = self->priv;
6957
6958   min_width = min_height = 0;
6959   natural_width = natural_height = 0;
6960
6961   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
6962     {
6963       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
6964       clutter_actor_get_preferred_width (self, -1,
6965                                          &min_width,
6966                                          &natural_width);
6967       clutter_actor_get_preferred_height (self, natural_width,
6968                                           &min_height,
6969                                           &natural_height);
6970     }
6971   else
6972     {
6973       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
6974       clutter_actor_get_preferred_height (self, -1,
6975                                           &min_height,
6976                                           &natural_height);
6977       clutter_actor_get_preferred_width (self, natural_height,
6978                                          &min_width,
6979                                          &natural_width);
6980     }
6981
6982   if (min_width_p)
6983     *min_width_p = min_width;
6984
6985   if (min_height_p)
6986     *min_height_p = min_height;
6987
6988   if (natural_width_p)
6989     *natural_width_p = natural_width;
6990
6991   if (natural_height_p)
6992     *natural_height_p = natural_height;
6993 }
6994
6995 /*< private >
6996  * effective_align:
6997  * @align: a #ClutterActorAlign
6998  * @direction: a #ClutterTextDirection
6999  *
7000  * Retrieves the correct alignment depending on the text direction
7001  *
7002  * Return value: the effective alignment
7003  */
7004 static ClutterActorAlign
7005 effective_align (ClutterActorAlign    align,
7006                  ClutterTextDirection direction)
7007 {
7008   ClutterActorAlign res;
7009
7010   switch (align)
7011     {
7012     case CLUTTER_ACTOR_ALIGN_START:
7013       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7014           ? CLUTTER_ACTOR_ALIGN_END
7015           : CLUTTER_ACTOR_ALIGN_START;
7016       break;
7017
7018     case CLUTTER_ACTOR_ALIGN_END:
7019       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7020           ? CLUTTER_ACTOR_ALIGN_START
7021           : CLUTTER_ACTOR_ALIGN_END;
7022       break;
7023
7024     default:
7025       res = align;
7026       break;
7027     }
7028
7029   return res;
7030 }
7031
7032 static inline void
7033 adjust_for_margin (float  margin_start,
7034                    float  margin_end,
7035                    float *minimum_size,
7036                    float *natural_size,
7037                    float *allocated_start,
7038                    float *allocated_end)
7039 {
7040   *minimum_size -= (margin_start + margin_end);
7041   *natural_size -= (margin_start + margin_end);
7042   *allocated_start += margin_start;
7043   *allocated_end -= margin_end;
7044 }
7045
7046 static inline void
7047 adjust_for_alignment (ClutterActorAlign  alignment,
7048                       float              natural_size,
7049                       float             *allocated_start,
7050                       float             *allocated_end)
7051 {
7052   float allocated_size = *allocated_end - *allocated_start;
7053
7054   switch (alignment)
7055     {
7056     case CLUTTER_ACTOR_ALIGN_FILL:
7057       /* do nothing */
7058       break;
7059
7060     case CLUTTER_ACTOR_ALIGN_START:
7061       /* keep start */
7062       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7063       break;
7064
7065     case CLUTTER_ACTOR_ALIGN_END:
7066       if (allocated_size > natural_size)
7067         {
7068           *allocated_start += (allocated_size - natural_size);
7069           *allocated_end = *allocated_start + natural_size;
7070         }
7071       break;
7072
7073     case CLUTTER_ACTOR_ALIGN_CENTER:
7074       if (allocated_size > natural_size)
7075         {
7076           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7077           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7078         }
7079       break;
7080     }
7081 }
7082
7083 /*< private >
7084  * clutter_actor_adjust_width:
7085  * @self: a #ClutterActor
7086  * @minimum_width: (inout): the actor's preferred minimum width, which
7087  *   will be adjusted depending on the margin
7088  * @natural_width: (inout): the actor's preferred natural width, which
7089  *   will be adjusted depending on the margin
7090  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7091  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7092  *
7093  * Adjusts the preferred and allocated position and size of an actor,
7094  * depending on the margin and alignment properties.
7095  */
7096 static void
7097 clutter_actor_adjust_width (ClutterActor *self,
7098                             gfloat       *minimum_width,
7099                             gfloat       *natural_width,
7100                             gfloat       *adjusted_x1,
7101                             gfloat       *adjusted_x2)
7102 {
7103   ClutterTextDirection text_dir;
7104   const ClutterLayoutInfo *info;
7105
7106   info = _clutter_actor_get_layout_info_or_defaults (self);
7107   text_dir = clutter_actor_get_text_direction (self);
7108
7109   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7110
7111   /* this will tweak natural_width to remove the margin, so that
7112    * adjust_for_alignment() will use the correct size
7113    */
7114   adjust_for_margin (info->margin.left, info->margin.right,
7115                      minimum_width, natural_width,
7116                      adjusted_x1, adjusted_x2);
7117
7118   adjust_for_alignment (effective_align (info->x_align, text_dir),
7119                         *natural_width,
7120                         adjusted_x1, adjusted_x2);
7121 }
7122
7123 /*< private >
7124  * clutter_actor_adjust_height:
7125  * @self: a #ClutterActor
7126  * @minimum_height: (inout): the actor's preferred minimum height, which
7127  *   will be adjusted depending on the margin
7128  * @natural_height: (inout): the actor's preferred natural height, which
7129  *   will be adjusted depending on the margin
7130  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7131  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7132  *
7133  * Adjusts the preferred and allocated position and size of an actor,
7134  * depending on the margin and alignment properties.
7135  */
7136 static void
7137 clutter_actor_adjust_height (ClutterActor *self,
7138                              gfloat       *minimum_height,
7139                              gfloat       *natural_height,
7140                              gfloat       *adjusted_y1,
7141                              gfloat       *adjusted_y2)
7142 {
7143   const ClutterLayoutInfo *info;
7144
7145   info = _clutter_actor_get_layout_info_or_defaults (self);
7146
7147   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7148
7149   /* this will tweak natural_height to remove the margin, so that
7150    * adjust_for_alignment() will use the correct size
7151    */
7152   adjust_for_margin (info->margin.top, info->margin.bottom,
7153                      minimum_height, natural_height,
7154                      adjusted_y1,
7155                      adjusted_y2);
7156
7157   /* we don't use effective_align() here, because text direction
7158    * only affects the horizontal axis
7159    */
7160   adjust_for_alignment (info->y_align,
7161                         *natural_height,
7162                         adjusted_y1,
7163                         adjusted_y2);
7164
7165 }
7166
7167 /* looks for a cached size request for this for_size. If not
7168  * found, returns the oldest entry so it can be overwritten */
7169 static gboolean
7170 _clutter_actor_get_cached_size_request (gfloat         for_size,
7171                                         SizeRequest   *cached_size_requests,
7172                                         SizeRequest  **result)
7173 {
7174   guint i;
7175
7176   *result = &cached_size_requests[0];
7177
7178   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7179     {
7180       SizeRequest *sr;
7181
7182       sr = &cached_size_requests[i];
7183
7184       if (sr->age > 0 &&
7185           sr->for_size == for_size)
7186         {
7187           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7188           *result = sr;
7189           return TRUE;
7190         }
7191       else if (sr->age < (*result)->age)
7192         {
7193           *result = sr;
7194         }
7195     }
7196
7197   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7198
7199   return FALSE;
7200 }
7201
7202 /**
7203  * clutter_actor_get_preferred_width:
7204  * @self: A #ClutterActor
7205  * @for_height: available height when computing the preferred width,
7206  *   or a negative value to indicate that no height is defined
7207  * @min_width_p: (out) (allow-none): return location for minimum width,
7208  *   or %NULL
7209  * @natural_width_p: (out) (allow-none): return location for the natural
7210  *   width, or %NULL
7211  *
7212  * Computes the requested minimum and natural widths for an actor,
7213  * optionally depending on the specified height, or if they are
7214  * already computed, returns the cached values.
7215  *
7216  * An actor may not get its request - depending on the layout
7217  * manager that's in effect.
7218  *
7219  * A request should not incorporate the actor's scale or anchor point;
7220  * those transformations do not affect layout, only rendering.
7221  *
7222  * Since: 0.8
7223  */
7224 void
7225 clutter_actor_get_preferred_width (ClutterActor *self,
7226                                    gfloat        for_height,
7227                                    gfloat       *min_width_p,
7228                                    gfloat       *natural_width_p)
7229 {
7230   float request_min_width, request_natural_width;
7231   SizeRequest *cached_size_request;
7232   const ClutterLayoutInfo *info;
7233   ClutterActorPrivate *priv;
7234   gboolean found_in_cache;
7235
7236   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7237
7238   priv = self->priv;
7239
7240   info = _clutter_actor_get_layout_info_or_defaults (self);
7241
7242   /* we shortcircuit the case of a fixed size set using set_width() */
7243   if (priv->min_width_set && priv->natural_width_set)
7244     {
7245       if (min_width_p != NULL)
7246         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7247
7248       if (natural_width_p != NULL)
7249         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7250
7251       return;
7252     }
7253
7254   /* the remaining cases are:
7255    *
7256    *   - either min_width or natural_width have been set
7257    *   - neither min_width or natural_width have been set
7258    *
7259    * in both cases, we go through the cache (and through the actor in case
7260    * of cache misses) and determine the authoritative value depending on
7261    * the *_set flags.
7262    */
7263
7264   if (!priv->needs_width_request)
7265     {
7266       found_in_cache =
7267         _clutter_actor_get_cached_size_request (for_height,
7268                                                 priv->width_requests,
7269                                                 &cached_size_request);
7270     }
7271   else
7272     {
7273       /* if the actor needs a width request we use the first slot */
7274       found_in_cache = FALSE;
7275       cached_size_request = &priv->width_requests[0];
7276     }
7277
7278   if (!found_in_cache)
7279     {
7280       gfloat minimum_width, natural_width;
7281       ClutterActorClass *klass;
7282
7283       minimum_width = natural_width = 0;
7284
7285       /* adjust for the margin */
7286       if (for_height >= 0)
7287         {
7288           for_height -= (info->margin.top + info->margin.bottom);
7289           if (for_height < 0)
7290             for_height = 0;
7291         }
7292
7293       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7294
7295       klass = CLUTTER_ACTOR_GET_CLASS (self);
7296       klass->get_preferred_width (self, for_height,
7297                                   &minimum_width,
7298                                   &natural_width);
7299
7300       /* adjust for the margin */
7301       minimum_width += (info->margin.left + info->margin.right);
7302       natural_width += (info->margin.left + info->margin.right);
7303
7304       /* Due to accumulated float errors, it's better not to warn
7305        * on this, but just fix it.
7306        */
7307       if (natural_width < minimum_width)
7308         natural_width = minimum_width;
7309
7310       cached_size_request->min_size = minimum_width;
7311       cached_size_request->natural_size = natural_width;
7312       cached_size_request->for_size = for_height;
7313       cached_size_request->age = priv->cached_width_age;
7314
7315       priv->cached_width_age += 1;
7316       priv->needs_width_request = FALSE;
7317     }
7318
7319   if (!priv->min_width_set)
7320     request_min_width = cached_size_request->min_size;
7321   else
7322     request_min_width = info->min_width;
7323
7324   if (!priv->natural_width_set)
7325     request_natural_width = cached_size_request->natural_size;
7326   else
7327     request_natural_width = info->natural_width;
7328
7329   if (min_width_p)
7330     *min_width_p = request_min_width;
7331
7332   if (natural_width_p)
7333     *natural_width_p = request_natural_width;
7334 }
7335
7336 /**
7337  * clutter_actor_get_preferred_height:
7338  * @self: A #ClutterActor
7339  * @for_width: available width to assume in computing desired height,
7340  *   or a negative value to indicate that no width is defined
7341  * @min_height_p: (out) (allow-none): return location for minimum height,
7342  *   or %NULL
7343  * @natural_height_p: (out) (allow-none): return location for natural
7344  *   height, or %NULL
7345  *
7346  * Computes the requested minimum and natural heights for an actor,
7347  * or if they are already computed, returns the cached values.
7348  *
7349  * An actor may not get its request - depending on the layout
7350  * manager that's in effect.
7351  *
7352  * A request should not incorporate the actor's scale or anchor point;
7353  * those transformations do not affect layout, only rendering.
7354  *
7355  * Since: 0.8
7356  */
7357 void
7358 clutter_actor_get_preferred_height (ClutterActor *self,
7359                                     gfloat        for_width,
7360                                     gfloat       *min_height_p,
7361                                     gfloat       *natural_height_p)
7362 {
7363   float request_min_height, request_natural_height;
7364   SizeRequest *cached_size_request;
7365   const ClutterLayoutInfo *info;
7366   ClutterActorPrivate *priv;
7367   gboolean found_in_cache;
7368
7369   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7370
7371   priv = self->priv;
7372
7373   info = _clutter_actor_get_layout_info_or_defaults (self);
7374
7375   /* we shortcircuit the case of a fixed size set using set_height() */
7376   if (priv->min_height_set && priv->natural_height_set)
7377     {
7378       if (min_height_p != NULL)
7379         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7380
7381       if (natural_height_p != NULL)
7382         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7383
7384       return;
7385     }
7386
7387   /* the remaining cases are:
7388    *
7389    *   - either min_height or natural_height have been set
7390    *   - neither min_height or natural_height have been set
7391    *
7392    * in both cases, we go through the cache (and through the actor in case
7393    * of cache misses) and determine the authoritative value depending on
7394    * the *_set flags.
7395    */
7396
7397   if (!priv->needs_height_request)
7398     {
7399       found_in_cache =
7400         _clutter_actor_get_cached_size_request (for_width,
7401                                                 priv->height_requests,
7402                                                 &cached_size_request);
7403     }
7404   else
7405     {
7406       found_in_cache = FALSE;
7407       cached_size_request = &priv->height_requests[0];
7408     }
7409
7410   if (!found_in_cache)
7411     {
7412       gfloat minimum_height, natural_height;
7413       ClutterActorClass *klass;
7414
7415       minimum_height = natural_height = 0;
7416
7417       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7418
7419       /* adjust for margin */
7420       if (for_width >= 0)
7421         {
7422           for_width -= (info->margin.left + info->margin.right);
7423           if (for_width < 0)
7424             for_width = 0;
7425         }
7426
7427       klass = CLUTTER_ACTOR_GET_CLASS (self);
7428       klass->get_preferred_height (self, for_width,
7429                                    &minimum_height,
7430                                    &natural_height);
7431
7432       /* adjust for margin */
7433       minimum_height += (info->margin.top + info->margin.bottom);
7434       natural_height += (info->margin.top + info->margin.bottom);
7435
7436       /* Due to accumulated float errors, it's better not to warn
7437        * on this, but just fix it.
7438        */
7439       if (natural_height < minimum_height)
7440         natural_height = minimum_height;
7441
7442       cached_size_request->min_size = minimum_height;
7443       cached_size_request->natural_size = natural_height;
7444       cached_size_request->for_size = for_width;
7445       cached_size_request->age = priv->cached_height_age;
7446
7447       priv->cached_height_age += 1;
7448       priv->needs_height_request = FALSE;
7449     }
7450
7451   if (!priv->min_height_set)
7452     request_min_height = cached_size_request->min_size;
7453   else
7454     request_min_height = info->min_height;
7455
7456   if (!priv->natural_height_set)
7457     request_natural_height = cached_size_request->natural_size;
7458   else
7459     request_natural_height = info->natural_height;
7460
7461   if (min_height_p)
7462     *min_height_p = request_min_height;
7463
7464   if (natural_height_p)
7465     *natural_height_p = request_natural_height;
7466 }
7467
7468 /**
7469  * clutter_actor_get_allocation_box:
7470  * @self: A #ClutterActor
7471  * @box: (out): the function fills this in with the actor's allocation
7472  *
7473  * Gets the layout box an actor has been assigned. The allocation can
7474  * only be assumed valid inside a paint() method; anywhere else, it
7475  * may be out-of-date.
7476  *
7477  * An allocation does not incorporate the actor's scale or anchor point;
7478  * those transformations do not affect layout, only rendering.
7479  *
7480  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7481  * of functions inside the implementation of the get_preferred_width()
7482  * or get_preferred_height() virtual functions.</note>
7483  *
7484  * Since: 0.8
7485  */
7486 void
7487 clutter_actor_get_allocation_box (ClutterActor    *self,
7488                                   ClutterActorBox *box)
7489 {
7490   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7491
7492   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7493    * which limits calling get_allocation to inside paint() basically; or
7494    * we can 2) force a layout, which could be expensive if someone calls
7495    * get_allocation somewhere silly; or we can 3) just return the latest
7496    * value, allowing it to be out-of-date, and assume people know what
7497    * they are doing.
7498    *
7499    * The least-surprises approach that keeps existing code working is
7500    * likely to be 2). People can end up doing some inefficient things,
7501    * though, and in general code that requires 2) is probably broken.
7502    */
7503
7504   /* this implements 2) */
7505   if (G_UNLIKELY (self->priv->needs_allocation))
7506     {
7507       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7508
7509       /* do not queue a relayout on an unparented actor */
7510       if (stage)
7511         _clutter_stage_maybe_relayout (stage);
7512     }
7513
7514   /* commenting out the code above and just keeping this assigment
7515    * implements 3)
7516    */
7517   *box = self->priv->allocation;
7518 }
7519
7520 /**
7521  * clutter_actor_get_allocation_geometry:
7522  * @self: A #ClutterActor
7523  * @geom: (out): allocation geometry in pixels
7524  *
7525  * Gets the layout box an actor has been assigned.  The allocation can
7526  * only be assumed valid inside a paint() method; anywhere else, it
7527  * may be out-of-date.
7528  *
7529  * An allocation does not incorporate the actor's scale or anchor point;
7530  * those transformations do not affect layout, only rendering.
7531  *
7532  * The returned rectangle is in pixels.
7533  *
7534  * Since: 0.8
7535  */
7536 void
7537 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7538                                        ClutterGeometry *geom)
7539 {
7540   ClutterActorBox box;
7541
7542   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7543   g_return_if_fail (geom != NULL);
7544
7545   clutter_actor_get_allocation_box (self, &box);
7546
7547   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7548   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7549   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7550   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7551 }
7552
7553 static void
7554 clutter_actor_update_constraints (ClutterActor    *self,
7555                                   ClutterActorBox *allocation)
7556 {
7557   ClutterActorPrivate *priv = self->priv;
7558   const GList *constraints, *l;
7559
7560   if (priv->constraints == NULL)
7561     return;
7562
7563   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7564   for (l = constraints; l != NULL; l = l->next)
7565     {
7566       ClutterConstraint *constraint = l->data;
7567       ClutterActorMeta *meta = l->data;
7568
7569       if (clutter_actor_meta_get_enabled (meta))
7570         {
7571           _clutter_constraint_update_allocation (constraint,
7572                                                  self,
7573                                                  allocation);
7574         }
7575     }
7576 }
7577
7578 /*< private >
7579  * clutter_actor_adjust_allocation:
7580  * @self: a #ClutterActor
7581  * @allocation: (inout): the allocation to adjust
7582  *
7583  * Adjusts the passed allocation box taking into account the actor's
7584  * layout information, like alignment, expansion, and margin.
7585  */
7586 static void
7587 clutter_actor_adjust_allocation (ClutterActor    *self,
7588                                  ClutterActorBox *allocation)
7589 {
7590   ClutterActorBox adj_allocation;
7591   float alloc_width, alloc_height;
7592   float min_width, min_height;
7593   float nat_width, nat_height;
7594   ClutterRequestMode req_mode;
7595
7596   adj_allocation = *allocation;
7597
7598   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7599
7600   /* we want to hit the cache, so we use the public API */
7601   req_mode = clutter_actor_get_request_mode (self);
7602
7603   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7604     {
7605       clutter_actor_get_preferred_width (self, -1,
7606                                          &min_width,
7607                                          &nat_width);
7608       clutter_actor_get_preferred_height (self, alloc_width,
7609                                           &min_height,
7610                                           &nat_height);
7611     }
7612   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7613     {
7614       clutter_actor_get_preferred_height (self, -1,
7615                                           &min_height,
7616                                           &nat_height);
7617       clutter_actor_get_preferred_height (self, alloc_height,
7618                                           &min_width,
7619                                           &nat_width);
7620     }
7621
7622 #ifdef CLUTTER_ENABLE_DEBUG
7623   /* warn about underallocations */
7624   if (_clutter_diagnostic_enabled () &&
7625       (floorf (min_width - alloc_width) > 0 ||
7626        floorf (min_height - alloc_height) > 0))
7627     {
7628       ClutterActor *parent = clutter_actor_get_parent (self);
7629
7630       /* the only actors that are allowed to be underallocated are the Stage,
7631        * as it doesn't have an implicit size, and Actors that specifically
7632        * told us that they want to opt-out from layout control mechanisms
7633        * through the NO_LAYOUT escape hatch.
7634        */
7635       if (parent != NULL &&
7636           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7637         {
7638           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7639                      "of %.2f x %.2f from its parent actor '%s', but its "
7640                      "requested minimum size is of %.2f x %.2f",
7641                      _clutter_actor_get_debug_name (self),
7642                      alloc_width, alloc_height,
7643                      _clutter_actor_get_debug_name (parent),
7644                      min_width, min_height);
7645         }
7646     }
7647 #endif
7648
7649   clutter_actor_adjust_width (self,
7650                               &min_width,
7651                               &nat_width,
7652                               &adj_allocation.x1,
7653                               &adj_allocation.x2);
7654
7655   clutter_actor_adjust_height (self,
7656                                &min_height,
7657                                &nat_height,
7658                                &adj_allocation.y1,
7659                                &adj_allocation.y2);
7660
7661   /* we maintain the invariant that an allocation cannot be adjusted
7662    * to be outside the parent-given box
7663    */
7664   if (adj_allocation.x1 < allocation->x1 ||
7665       adj_allocation.y1 < allocation->y1 ||
7666       adj_allocation.x2 > allocation->x2 ||
7667       adj_allocation.y2 > allocation->y2)
7668     {
7669       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7670                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7671                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7672                  _clutter_actor_get_debug_name (self),
7673                  adj_allocation.x1, adj_allocation.y1,
7674                  adj_allocation.x2 - adj_allocation.x1,
7675                  adj_allocation.y2 - adj_allocation.y1,
7676                  allocation->x1, allocation->y1,
7677                  allocation->x2 - allocation->x1,
7678                  allocation->y2 - allocation->y1);
7679       return;
7680     }
7681
7682   *allocation = adj_allocation;
7683 }
7684
7685 /**
7686  * clutter_actor_allocate:
7687  * @self: A #ClutterActor
7688  * @box: new allocation of the actor, in parent-relative coordinates
7689  * @flags: flags that control the allocation
7690  *
7691  * Called by the parent of an actor to assign the actor its size.
7692  * Should never be called by applications (except when implementing
7693  * a container or layout manager).
7694  *
7695  * Actors can know from their allocation box whether they have moved
7696  * with respect to their parent actor. The @flags parameter describes
7697  * additional information about the allocation, for instance whether
7698  * the parent has moved with respect to the stage, for example because
7699  * a grandparent's origin has moved.
7700  *
7701  * Since: 0.8
7702  */
7703 void
7704 clutter_actor_allocate (ClutterActor           *self,
7705                         const ClutterActorBox  *box,
7706                         ClutterAllocationFlags  flags)
7707 {
7708   ClutterActorPrivate *priv;
7709   ClutterActorClass *klass;
7710   ClutterActorBox old_allocation, real_allocation;
7711   gboolean origin_changed, child_moved, size_changed;
7712   gboolean stage_allocation_changed;
7713
7714   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7715   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7716     {
7717       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7718                  "which isn't a descendent of the stage!\n",
7719                  self, _clutter_actor_get_debug_name (self));
7720       return;
7721     }
7722
7723   priv = self->priv;
7724
7725   old_allocation = priv->allocation;
7726   real_allocation = *box;
7727
7728   /* constraints are allowed to modify the allocation only here; we do
7729    * this prior to all the other checks so that we can bail out if the
7730    * allocation did not change
7731    */
7732   clutter_actor_update_constraints (self, &real_allocation);
7733
7734   /* adjust the allocation depending on the align/margin properties */
7735   clutter_actor_adjust_allocation (self, &real_allocation);
7736
7737   if (real_allocation.x2 < real_allocation.x1 ||
7738       real_allocation.y2 < real_allocation.y1)
7739     {
7740       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7741                  _clutter_actor_get_debug_name (self),
7742                  real_allocation.x2 - real_allocation.x1,
7743                  real_allocation.y2 - real_allocation.y1);
7744     }
7745
7746   /* we allow 0-sized actors, but not negative-sized ones */
7747   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7748   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7749
7750   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7751
7752   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7753                  real_allocation.y1 != old_allocation.y1);
7754
7755   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7756                   real_allocation.y2 != old_allocation.y2);
7757
7758   if (origin_changed || child_moved || size_changed)
7759     stage_allocation_changed = TRUE;
7760   else
7761     stage_allocation_changed = FALSE;
7762
7763   /* If we get an allocation "out of the blue"
7764    * (we did not queue relayout), then we want to
7765    * ignore it. But if we have needs_allocation set,
7766    * we want to guarantee that allocate() virtual
7767    * method is always called, i.e. that queue_relayout()
7768    * always results in an allocate() invocation on
7769    * an actor.
7770    *
7771    * The optimization here is to avoid re-allocating
7772    * actors that did not queue relayout and were
7773    * not moved.
7774    */
7775   if (!priv->needs_allocation && !stage_allocation_changed)
7776     {
7777       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7778       return;
7779     }
7780
7781   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7782    * clutter_actor_allocate(), it indicates whether the parent has its
7783    * absolute origin moved; when passed in to ClutterActor::allocate()
7784    * virtual method though, it indicates whether the child has its
7785    * absolute origin moved.  So we set it when child_moved is TRUE
7786    */
7787   if (child_moved)
7788     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7789
7790   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7791
7792   klass = CLUTTER_ACTOR_GET_CLASS (self);
7793   klass->allocate (self, &real_allocation, flags);
7794
7795   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7796
7797   if (stage_allocation_changed)
7798     clutter_actor_queue_redraw (self);
7799 }
7800
7801 /**
7802  * clutter_actor_set_allocation:
7803  * @self: a #ClutterActor
7804  * @box: a #ClutterActorBox
7805  * @flags: allocation flags
7806  *
7807  * Stores the allocation of @self as defined by @box.
7808  *
7809  * This function can only be called from within the implementation of
7810  * the #ClutterActorClass.allocate() virtual function.
7811  *
7812  * The allocation should have been adjusted to take into account constraints,
7813  * alignment, and margin properties. If you are implementing a #ClutterActor
7814  * subclass that provides its own layout management policy for its children
7815  * instead of using a #ClutterLayoutManager delegate, you should not call
7816  * this function on the children of @self; instead, you should call
7817  * clutter_actor_allocate(), which will adjust the allocation box for
7818  * you.
7819  *
7820  * This function should only be used by subclasses of #ClutterActor
7821  * that wish to store their allocation but cannot chain up to the
7822  * parent's implementation; the default implementation of the
7823  * #ClutterActorClass.allocate() virtual function will call this
7824  * function.
7825  *
7826  * It is important to note that, while chaining up was the recommended
7827  * behaviour for #ClutterActor subclasses prior to the introduction of
7828  * this function, it is recommended to call clutter_actor_set_allocation()
7829  * instead.
7830  *
7831  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7832  * to handle the allocation of its children, this function will call
7833  * the clutter_layout_manager_allocate() function only if the
7834  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7835  * expected that the subclass will call clutter_layout_manager_allocate()
7836  * by itself. For instance, the following code:
7837  *
7838  * |[
7839  * static void
7840  * my_actor_allocate (ClutterActor *actor,
7841  *                    const ClutterActorBox *allocation,
7842  *                    ClutterAllocationFlags flags)
7843  * {
7844  *   ClutterActorBox new_alloc;
7845  *   ClutterAllocationFlags new_flags;
7846  *
7847  *   adjust_allocation (allocation, &amp;new_alloc);
7848  *
7849  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7850  *
7851  *   /&ast; this will use the layout manager set on the actor &ast;/
7852  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7853  * }
7854  * ]|
7855  *
7856  * is equivalent to this:
7857  *
7858  * |[
7859  * static void
7860  * my_actor_allocate (ClutterActor *actor,
7861  *                    const ClutterActorBox *allocation,
7862  *                    ClutterAllocationFlags flags)
7863  * {
7864  *   ClutterLayoutManager *layout;
7865  *   ClutterActorBox new_alloc;
7866  *
7867  *   adjust_allocation (allocation, &amp;new_alloc);
7868  *
7869  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7870  *
7871  *   layout = clutter_actor_get_layout_manager (actor);
7872  *   clutter_layout_manager_allocate (layout,
7873  *                                    CLUTTER_CONTAINER (actor),
7874  *                                    &amp;new_alloc,
7875  *                                    flags);
7876  * }
7877  * ]|
7878  *
7879  * Since: 1.10
7880  */
7881 void
7882 clutter_actor_set_allocation (ClutterActor           *self,
7883                               const ClutterActorBox  *box,
7884                               ClutterAllocationFlags  flags)
7885 {
7886   ClutterActorPrivate *priv;
7887   gboolean changed;
7888
7889   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7890   g_return_if_fail (box != NULL);
7891
7892   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7893     {
7894       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7895                   "can only be called from within the implementation of "
7896                   "the ClutterActor::allocate() virtual function.");
7897       return;
7898     }
7899
7900   priv = self->priv;
7901
7902   g_object_freeze_notify (G_OBJECT (self));
7903
7904   changed = clutter_actor_set_allocation_internal (self, box, flags);
7905
7906   /* we allocate our children before we notify changes in our geometry,
7907    * so that people connecting to properties will be able to get valid
7908    * data out of the sub-tree of the scene graph that has this actor at
7909    * the root.
7910    */
7911   clutter_actor_maybe_layout_children (self, box, flags);
7912
7913   if (changed)
7914     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7915                    &priv->allocation,
7916                    priv->allocation_flags);
7917
7918   g_object_thaw_notify (G_OBJECT (self));
7919 }
7920
7921 /**
7922  * clutter_actor_set_geometry:
7923  * @self: A #ClutterActor
7924  * @geometry: A #ClutterGeometry
7925  *
7926  * Sets the actor's fixed position and forces its minimum and natural
7927  * size, in pixels. This means the untransformed actor will have the
7928  * given geometry. This is the same as calling clutter_actor_set_position()
7929  * and clutter_actor_set_size().
7930  *
7931  * Deprecated: 1.10: Use clutter_actor_set_position() and
7932  *   clutter_actor_set_size() instead.
7933  */
7934 void
7935 clutter_actor_set_geometry (ClutterActor          *self,
7936                             const ClutterGeometry *geometry)
7937 {
7938   g_object_freeze_notify (G_OBJECT (self));
7939
7940   clutter_actor_set_position (self, geometry->x, geometry->y);
7941   clutter_actor_set_size (self, geometry->width, geometry->height);
7942
7943   g_object_thaw_notify (G_OBJECT (self));
7944 }
7945
7946 /**
7947  * clutter_actor_get_geometry:
7948  * @self: A #ClutterActor
7949  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
7950  *
7951  * Gets the size and position of an actor relative to its parent
7952  * actor. This is the same as calling clutter_actor_get_position() and
7953  * clutter_actor_get_size(). It tries to "do what you mean" and get the
7954  * requested size and position if the actor's allocation is invalid.
7955  *
7956  * Deprecated: 1.10: Use clutter_actor_get_position() and
7957  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
7958  *   instead.
7959  */
7960 void
7961 clutter_actor_get_geometry (ClutterActor    *self,
7962                             ClutterGeometry *geometry)
7963 {
7964   gfloat x, y, width, height;
7965
7966   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7967   g_return_if_fail (geometry != NULL);
7968
7969   clutter_actor_get_position (self, &x, &y);
7970   clutter_actor_get_size (self, &width, &height);
7971
7972   geometry->x = (int) x;
7973   geometry->y = (int) y;
7974   geometry->width = (int) width;
7975   geometry->height = (int) height;
7976 }
7977
7978 /**
7979  * clutter_actor_set_position:
7980  * @self: A #ClutterActor
7981  * @x: New left position of actor in pixels.
7982  * @y: New top position of actor in pixels.
7983  *
7984  * Sets the actor's fixed position in pixels relative to any parent
7985  * actor.
7986  *
7987  * If a layout manager is in use, this position will override the
7988  * layout manager and force a fixed position.
7989  */
7990 void
7991 clutter_actor_set_position (ClutterActor *self,
7992                             gfloat        x,
7993                             gfloat        y)
7994 {
7995   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7996
7997   g_object_freeze_notify (G_OBJECT (self));
7998
7999   clutter_actor_set_x (self, x);
8000   clutter_actor_set_y (self, y);
8001
8002   g_object_thaw_notify (G_OBJECT (self));
8003 }
8004
8005 /**
8006  * clutter_actor_get_fixed_position_set:
8007  * @self: A #ClutterActor
8008  *
8009  * Checks whether an actor has a fixed position set (and will thus be
8010  * unaffected by any layout manager).
8011  *
8012  * Return value: %TRUE if the fixed position is set on the actor
8013  *
8014  * Since: 0.8
8015  */
8016 gboolean
8017 clutter_actor_get_fixed_position_set (ClutterActor *self)
8018 {
8019   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8020
8021   return self->priv->position_set;
8022 }
8023
8024 /**
8025  * clutter_actor_set_fixed_position_set:
8026  * @self: A #ClutterActor
8027  * @is_set: whether to use fixed position
8028  *
8029  * Sets whether an actor has a fixed position set (and will thus be
8030  * unaffected by any layout manager).
8031  *
8032  * Since: 0.8
8033  */
8034 void
8035 clutter_actor_set_fixed_position_set (ClutterActor *self,
8036                                       gboolean      is_set)
8037 {
8038   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8039
8040   if (self->priv->position_set == (is_set != FALSE))
8041     return;
8042
8043   self->priv->position_set = is_set != FALSE;
8044   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8045
8046   clutter_actor_queue_relayout (self);
8047 }
8048
8049 /**
8050  * clutter_actor_move_by:
8051  * @self: A #ClutterActor
8052  * @dx: Distance to move Actor on X axis.
8053  * @dy: Distance to move Actor on Y axis.
8054  *
8055  * Moves an actor by the specified distance relative to its current
8056  * position in pixels.
8057  *
8058  * This function modifies the fixed position of an actor and thus removes
8059  * it from any layout management. Another way to move an actor is with an
8060  * anchor point, see clutter_actor_set_anchor_point().
8061  *
8062  * Since: 0.2
8063  */
8064 void
8065 clutter_actor_move_by (ClutterActor *self,
8066                        gfloat        dx,
8067                        gfloat        dy)
8068 {
8069   const ClutterLayoutInfo *info;
8070   gfloat x, y;
8071
8072   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8073
8074   info = _clutter_actor_get_layout_info_or_defaults (self);
8075   x = info->fixed_x;
8076   y = info->fixed_y;
8077
8078   clutter_actor_set_position (self, x + dx, y + dy);
8079 }
8080
8081 static void
8082 clutter_actor_set_min_width (ClutterActor *self,
8083                              gfloat        min_width)
8084 {
8085   ClutterActorPrivate *priv = self->priv;
8086   ClutterActorBox old = { 0, };
8087   ClutterLayoutInfo *info;
8088
8089   /* if we are setting the size on a top-level actor and the
8090    * backend only supports static top-levels (e.g. framebuffers)
8091    * then we ignore the passed value and we override it with
8092    * the stage implementation's preferred size.
8093    */
8094   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8095       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8096     return;
8097
8098   info = _clutter_actor_get_layout_info (self);
8099
8100   if (priv->min_width_set && min_width == info->min_width)
8101     return;
8102
8103   g_object_freeze_notify (G_OBJECT (self));
8104
8105   clutter_actor_store_old_geometry (self, &old);
8106
8107   info->min_width = min_width;
8108   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8109   clutter_actor_set_min_width_set (self, TRUE);
8110
8111   clutter_actor_notify_if_geometry_changed (self, &old);
8112
8113   g_object_thaw_notify (G_OBJECT (self));
8114
8115   clutter_actor_queue_relayout (self);
8116 }
8117
8118 static void
8119 clutter_actor_set_min_height (ClutterActor *self,
8120                               gfloat        min_height)
8121
8122 {
8123   ClutterActorPrivate *priv = self->priv;
8124   ClutterActorBox old = { 0, };
8125   ClutterLayoutInfo *info;
8126
8127   /* if we are setting the size on a top-level actor and the
8128    * backend only supports static top-levels (e.g. framebuffers)
8129    * then we ignore the passed value and we override it with
8130    * the stage implementation's preferred size.
8131    */
8132   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8133       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8134     return;
8135
8136   info = _clutter_actor_get_layout_info (self);
8137
8138   if (priv->min_height_set && min_height == info->min_height)
8139     return;
8140
8141   g_object_freeze_notify (G_OBJECT (self));
8142
8143   clutter_actor_store_old_geometry (self, &old);
8144
8145   info->min_height = min_height;
8146   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8147   clutter_actor_set_min_height_set (self, TRUE);
8148
8149   clutter_actor_notify_if_geometry_changed (self, &old);
8150
8151   g_object_thaw_notify (G_OBJECT (self));
8152
8153   clutter_actor_queue_relayout (self);
8154 }
8155
8156 static void
8157 clutter_actor_set_natural_width (ClutterActor *self,
8158                                  gfloat        natural_width)
8159 {
8160   ClutterActorPrivate *priv = self->priv;
8161   ClutterActorBox old = { 0, };
8162   ClutterLayoutInfo *info;
8163
8164   /* if we are setting the size on a top-level actor and the
8165    * backend only supports static top-levels (e.g. framebuffers)
8166    * then we ignore the passed value and we override it with
8167    * the stage implementation's preferred size.
8168    */
8169   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8170       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8171     return;
8172
8173   info = _clutter_actor_get_layout_info (self);
8174
8175   if (priv->natural_width_set && natural_width == info->natural_width)
8176     return;
8177
8178   g_object_freeze_notify (G_OBJECT (self));
8179
8180   clutter_actor_store_old_geometry (self, &old);
8181
8182   info->natural_width = natural_width;
8183   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8184   clutter_actor_set_natural_width_set (self, TRUE);
8185
8186   clutter_actor_notify_if_geometry_changed (self, &old);
8187
8188   g_object_thaw_notify (G_OBJECT (self));
8189
8190   clutter_actor_queue_relayout (self);
8191 }
8192
8193 static void
8194 clutter_actor_set_natural_height (ClutterActor *self,
8195                                   gfloat        natural_height)
8196 {
8197   ClutterActorPrivate *priv = self->priv;
8198   ClutterActorBox old = { 0, };
8199   ClutterLayoutInfo *info;
8200
8201   /* if we are setting the size on a top-level actor and the
8202    * backend only supports static top-levels (e.g. framebuffers)
8203    * then we ignore the passed value and we override it with
8204    * the stage implementation's preferred size.
8205    */
8206   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8207       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8208     return;
8209
8210   info = _clutter_actor_get_layout_info (self);
8211
8212   if (priv->natural_height_set && natural_height == info->natural_height)
8213     return;
8214
8215   g_object_freeze_notify (G_OBJECT (self));
8216
8217   clutter_actor_store_old_geometry (self, &old);
8218
8219   info->natural_height = natural_height;
8220   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8221   clutter_actor_set_natural_height_set (self, TRUE);
8222
8223   clutter_actor_notify_if_geometry_changed (self, &old);
8224
8225   g_object_thaw_notify (G_OBJECT (self));
8226
8227   clutter_actor_queue_relayout (self);
8228 }
8229
8230 static void
8231 clutter_actor_set_min_width_set (ClutterActor *self,
8232                                  gboolean      use_min_width)
8233 {
8234   ClutterActorPrivate *priv = self->priv;
8235   ClutterActorBox old = { 0, };
8236
8237   if (priv->min_width_set == (use_min_width != FALSE))
8238     return;
8239
8240   clutter_actor_store_old_geometry (self, &old);
8241
8242   priv->min_width_set = use_min_width != FALSE;
8243   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8244
8245   clutter_actor_notify_if_geometry_changed (self, &old);
8246
8247   clutter_actor_queue_relayout (self);
8248 }
8249
8250 static void
8251 clutter_actor_set_min_height_set (ClutterActor *self,
8252                                   gboolean      use_min_height)
8253 {
8254   ClutterActorPrivate *priv = self->priv;
8255   ClutterActorBox old = { 0, };
8256
8257   if (priv->min_height_set == (use_min_height != FALSE))
8258     return;
8259
8260   clutter_actor_store_old_geometry (self, &old);
8261
8262   priv->min_height_set = use_min_height != FALSE;
8263   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8264
8265   clutter_actor_notify_if_geometry_changed (self, &old);
8266
8267   clutter_actor_queue_relayout (self);
8268 }
8269
8270 static void
8271 clutter_actor_set_natural_width_set (ClutterActor *self,
8272                                      gboolean      use_natural_width)
8273 {
8274   ClutterActorPrivate *priv = self->priv;
8275   ClutterActorBox old = { 0, };
8276
8277   if (priv->natural_width_set == (use_natural_width != FALSE))
8278     return;
8279
8280   clutter_actor_store_old_geometry (self, &old);
8281
8282   priv->natural_width_set = use_natural_width != FALSE;
8283   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8284
8285   clutter_actor_notify_if_geometry_changed (self, &old);
8286
8287   clutter_actor_queue_relayout (self);
8288 }
8289
8290 static void
8291 clutter_actor_set_natural_height_set (ClutterActor *self,
8292                                       gboolean      use_natural_height)
8293 {
8294   ClutterActorPrivate *priv = self->priv;
8295   ClutterActorBox old = { 0, };
8296
8297   if (priv->natural_height_set == (use_natural_height != FALSE))
8298     return;
8299
8300   clutter_actor_store_old_geometry (self, &old);
8301
8302   priv->natural_height_set = use_natural_height != FALSE;
8303   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8304
8305   clutter_actor_notify_if_geometry_changed (self, &old);
8306
8307   clutter_actor_queue_relayout (self);
8308 }
8309
8310 /**
8311  * clutter_actor_set_request_mode:
8312  * @self: a #ClutterActor
8313  * @mode: the request mode
8314  *
8315  * Sets the geometry request mode of @self.
8316  *
8317  * The @mode determines the order for invoking
8318  * clutter_actor_get_preferred_width() and
8319  * clutter_actor_get_preferred_height()
8320  *
8321  * Since: 1.2
8322  */
8323 void
8324 clutter_actor_set_request_mode (ClutterActor       *self,
8325                                 ClutterRequestMode  mode)
8326 {
8327   ClutterActorPrivate *priv;
8328
8329   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8330
8331   priv = self->priv;
8332
8333   if (priv->request_mode == mode)
8334     return;
8335
8336   priv->request_mode = mode;
8337
8338   priv->needs_width_request = TRUE;
8339   priv->needs_height_request = TRUE;
8340
8341   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8342
8343   clutter_actor_queue_relayout (self);
8344 }
8345
8346 /**
8347  * clutter_actor_get_request_mode:
8348  * @self: a #ClutterActor
8349  *
8350  * Retrieves the geometry request mode of @self
8351  *
8352  * Return value: the request mode for the actor
8353  *
8354  * Since: 1.2
8355  */
8356 ClutterRequestMode
8357 clutter_actor_get_request_mode (ClutterActor *self)
8358 {
8359   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8360                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8361
8362   return self->priv->request_mode;
8363 }
8364
8365 /* variant of set_width() without checks and without notification
8366  * freeze+thaw, for internal usage only
8367  */
8368 static inline void
8369 clutter_actor_set_width_internal (ClutterActor *self,
8370                                   gfloat        width)
8371 {
8372   if (width >= 0)
8373     {
8374       /* the Stage will use the :min-width to control the minimum
8375        * width to be resized to, so we should not be setting it
8376        * along with the :natural-width
8377        */
8378       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8379         clutter_actor_set_min_width (self, width);
8380
8381       clutter_actor_set_natural_width (self, width);
8382     }
8383   else
8384     {
8385       /* we only unset the :natural-width for the Stage */
8386       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8387         clutter_actor_set_min_width_set (self, FALSE);
8388
8389       clutter_actor_set_natural_width_set (self, FALSE);
8390     }
8391 }
8392
8393 /* variant of set_height() without checks and without notification
8394  * freeze+thaw, for internal usage only
8395  */
8396 static inline void
8397 clutter_actor_set_height_internal (ClutterActor *self,
8398                                    gfloat        height)
8399 {
8400   if (height >= 0)
8401     {
8402       /* see the comment above in set_width_internal() */
8403       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8404         clutter_actor_set_min_height (self, height);
8405
8406       clutter_actor_set_natural_height (self, height);
8407     }
8408   else
8409     {
8410       /* see the comment above in set_width_internal() */
8411       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8412         clutter_actor_set_min_height_set (self, FALSE);
8413
8414       clutter_actor_set_natural_height_set (self, FALSE);
8415     }
8416 }
8417
8418 /**
8419  * clutter_actor_set_size:
8420  * @self: A #ClutterActor
8421  * @width: New width of actor in pixels, or -1
8422  * @height: New height of actor in pixels, or -1
8423  *
8424  * Sets the actor's size request in pixels. This overrides any
8425  * "normal" size request the actor would have. For example
8426  * a text actor might normally request the size of the text;
8427  * this function would force a specific size instead.
8428  *
8429  * If @width and/or @height are -1 the actor will use its
8430  * "normal" size request instead of overriding it, i.e.
8431  * you can "unset" the size with -1.
8432  *
8433  * This function sets or unsets both the minimum and natural size.
8434  */
8435 void
8436 clutter_actor_set_size (ClutterActor *self,
8437                         gfloat        width,
8438                         gfloat        height)
8439 {
8440   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8441
8442   g_object_freeze_notify (G_OBJECT (self));
8443
8444   clutter_actor_set_width_internal (self, width);
8445   clutter_actor_set_height_internal (self, height);
8446
8447   g_object_thaw_notify (G_OBJECT (self));
8448 }
8449
8450 /**
8451  * clutter_actor_get_size:
8452  * @self: A #ClutterActor
8453  * @width: (out) (allow-none): return location for the width, or %NULL.
8454  * @height: (out) (allow-none): return location for the height, or %NULL.
8455  *
8456  * This function tries to "do what you mean" and return
8457  * the size an actor will have. If the actor has a valid
8458  * allocation, the allocation will be returned; otherwise,
8459  * the actors natural size request will be returned.
8460  *
8461  * If you care whether you get the request vs. the allocation, you
8462  * should probably call a different function like
8463  * clutter_actor_get_allocation_box() or
8464  * clutter_actor_get_preferred_width().
8465  *
8466  * Since: 0.2
8467  */
8468 void
8469 clutter_actor_get_size (ClutterActor *self,
8470                         gfloat       *width,
8471                         gfloat       *height)
8472 {
8473   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8474
8475   if (width)
8476     *width = clutter_actor_get_width (self);
8477
8478   if (height)
8479     *height = clutter_actor_get_height (self);
8480 }
8481
8482 /**
8483  * clutter_actor_get_position:
8484  * @self: a #ClutterActor
8485  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8486  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8487  *
8488  * This function tries to "do what you mean" and tell you where the
8489  * actor is, prior to any transformations. Retrieves the fixed
8490  * position of an actor in pixels, if one has been set; otherwise, if
8491  * the allocation is valid, returns the actor's allocated position;
8492  * otherwise, returns 0,0.
8493  *
8494  * The returned position is in pixels.
8495  *
8496  * Since: 0.6
8497  */
8498 void
8499 clutter_actor_get_position (ClutterActor *self,
8500                             gfloat       *x,
8501                             gfloat       *y)
8502 {
8503   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8504
8505   if (x)
8506     *x = clutter_actor_get_x (self);
8507
8508   if (y)
8509     *y = clutter_actor_get_y (self);
8510 }
8511
8512 /**
8513  * clutter_actor_get_transformed_position:
8514  * @self: A #ClutterActor
8515  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8516  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8517  *
8518  * Gets the absolute position of an actor, in pixels relative to the stage.
8519  *
8520  * Since: 0.8
8521  */
8522 void
8523 clutter_actor_get_transformed_position (ClutterActor *self,
8524                                         gfloat       *x,
8525                                         gfloat       *y)
8526 {
8527   ClutterVertex v1;
8528   ClutterVertex v2;
8529
8530   v1.x = v1.y = v1.z = 0;
8531   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8532
8533   if (x)
8534     *x = v2.x;
8535
8536   if (y)
8537     *y = v2.y;
8538 }
8539
8540 /**
8541  * clutter_actor_get_transformed_size:
8542  * @self: A #ClutterActor
8543  * @width: (out) (allow-none): return location for the width, or %NULL
8544  * @height: (out) (allow-none): return location for the height, or %NULL
8545  *
8546  * Gets the absolute size of an actor in pixels, taking into account the
8547  * scaling factors.
8548  *
8549  * If the actor has a valid allocation, the allocated size will be used.
8550  * If the actor has not a valid allocation then the preferred size will
8551  * be transformed and returned.
8552  *
8553  * If you want the transformed allocation, see
8554  * clutter_actor_get_abs_allocation_vertices() instead.
8555  *
8556  * <note>When the actor (or one of its ancestors) is rotated around the
8557  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8558  * as a generic quadrangle; in that case this function returns the size
8559  * of the smallest rectangle that encapsulates the entire quad. Please
8560  * note that in this case no assumptions can be made about the relative
8561  * position of this envelope to the absolute position of the actor, as
8562  * returned by clutter_actor_get_transformed_position(); if you need this
8563  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8564  * to get the coords of the actual quadrangle.</note>
8565  *
8566  * Since: 0.8
8567  */
8568 void
8569 clutter_actor_get_transformed_size (ClutterActor *self,
8570                                     gfloat       *width,
8571                                     gfloat       *height)
8572 {
8573   ClutterActorPrivate *priv;
8574   ClutterVertex v[4];
8575   gfloat x_min, x_max, y_min, y_max;
8576   gint i;
8577
8578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8579
8580   priv = self->priv;
8581
8582   /* if the actor hasn't been allocated yet, get the preferred
8583    * size and transform that
8584    */
8585   if (priv->needs_allocation)
8586     {
8587       gfloat natural_width, natural_height;
8588       ClutterActorBox box;
8589
8590       /* Make a fake allocation to transform.
8591        *
8592        * NB: _clutter_actor_transform_and_project_box expects a box in
8593        * the actor's coordinate space... */
8594
8595       box.x1 = 0;
8596       box.y1 = 0;
8597
8598       natural_width = natural_height = 0;
8599       clutter_actor_get_preferred_size (self, NULL, NULL,
8600                                         &natural_width,
8601                                         &natural_height);
8602
8603       box.x2 = natural_width;
8604       box.y2 = natural_height;
8605
8606       _clutter_actor_transform_and_project_box (self, &box, v);
8607     }
8608   else
8609     clutter_actor_get_abs_allocation_vertices (self, v);
8610
8611   x_min = x_max = v[0].x;
8612   y_min = y_max = v[0].y;
8613
8614   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8615     {
8616       if (v[i].x < x_min)
8617         x_min = v[i].x;
8618
8619       if (v[i].x > x_max)
8620         x_max = v[i].x;
8621
8622       if (v[i].y < y_min)
8623         y_min = v[i].y;
8624
8625       if (v[i].y > y_max)
8626         y_max = v[i].y;
8627     }
8628
8629   if (width)
8630     *width  = x_max - x_min;
8631
8632   if (height)
8633     *height = y_max - y_min;
8634 }
8635
8636 /**
8637  * clutter_actor_get_width:
8638  * @self: A #ClutterActor
8639  *
8640  * Retrieves the width of a #ClutterActor.
8641  *
8642  * If the actor has a valid allocation, this function will return the
8643  * width of the allocated area given to the actor.
8644  *
8645  * If the actor does not have a valid allocation, this function will
8646  * return the actor's natural width, that is the preferred width of
8647  * the actor.
8648  *
8649  * If you care whether you get the preferred width or the width that
8650  * has been assigned to the actor, you should probably call a different
8651  * function like clutter_actor_get_allocation_box() to retrieve the
8652  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8653  * preferred width.
8654  *
8655  * If an actor has a fixed width, for instance a width that has been
8656  * assigned using clutter_actor_set_width(), the width returned will
8657  * be the same value.
8658  *
8659  * Return value: the width of the actor, in pixels
8660  */
8661 gfloat
8662 clutter_actor_get_width (ClutterActor *self)
8663 {
8664   ClutterActorPrivate *priv;
8665
8666   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8667
8668   priv = self->priv;
8669
8670   if (priv->needs_allocation)
8671     {
8672       gfloat natural_width = 0;
8673
8674       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8675         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8676       else
8677         {
8678           gfloat natural_height = 0;
8679
8680           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8681           clutter_actor_get_preferred_width (self, natural_height,
8682                                              NULL,
8683                                              &natural_width);
8684         }
8685
8686       return natural_width;
8687     }
8688   else
8689     return priv->allocation.x2 - priv->allocation.x1;
8690 }
8691
8692 /**
8693  * clutter_actor_get_height:
8694  * @self: A #ClutterActor
8695  *
8696  * Retrieves the height of a #ClutterActor.
8697  *
8698  * If the actor has a valid allocation, this function will return the
8699  * height of the allocated area given to the actor.
8700  *
8701  * If the actor does not have a valid allocation, this function will
8702  * return the actor's natural height, that is the preferred height of
8703  * the actor.
8704  *
8705  * If you care whether you get the preferred height or the height that
8706  * has been assigned to the actor, you should probably call a different
8707  * function like clutter_actor_get_allocation_box() to retrieve the
8708  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8709  * preferred height.
8710  *
8711  * If an actor has a fixed height, for instance a height that has been
8712  * assigned using clutter_actor_set_height(), the height returned will
8713  * be the same value.
8714  *
8715  * Return value: the height of the actor, in pixels
8716  */
8717 gfloat
8718 clutter_actor_get_height (ClutterActor *self)
8719 {
8720   ClutterActorPrivate *priv;
8721
8722   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8723
8724   priv = self->priv;
8725
8726   if (priv->needs_allocation)
8727     {
8728       gfloat natural_height = 0;
8729
8730       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8731         {
8732           gfloat natural_width = 0;
8733
8734           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8735           clutter_actor_get_preferred_height (self, natural_width,
8736                                               NULL, &natural_height);
8737         }
8738       else
8739         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8740
8741       return natural_height;
8742     }
8743   else
8744     return priv->allocation.y2 - priv->allocation.y1;
8745 }
8746
8747 /**
8748  * clutter_actor_set_width:
8749  * @self: A #ClutterActor
8750  * @width: Requested new width for the actor, in pixels, or -1
8751  *
8752  * Forces a width on an actor, causing the actor's preferred width
8753  * and height (if any) to be ignored.
8754  *
8755  * If @width is -1 the actor will use its preferred width request
8756  * instead of overriding it, i.e. you can "unset" the width with -1.
8757  *
8758  * This function sets both the minimum and natural size of the actor.
8759  *
8760  * since: 0.2
8761  */
8762 void
8763 clutter_actor_set_width (ClutterActor *self,
8764                          gfloat        width)
8765 {
8766   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8767
8768   g_object_freeze_notify (G_OBJECT (self));
8769
8770   clutter_actor_set_width_internal (self, width);
8771
8772   g_object_thaw_notify (G_OBJECT (self));
8773 }
8774
8775 /**
8776  * clutter_actor_set_height:
8777  * @self: A #ClutterActor
8778  * @height: Requested new height for the actor, in pixels, or -1
8779  *
8780  * Forces a height on an actor, causing the actor's preferred width
8781  * and height (if any) to be ignored.
8782  *
8783  * If @height is -1 the actor will use its preferred height instead of
8784  * overriding it, i.e. you can "unset" the height with -1.
8785  *
8786  * This function sets both the minimum and natural size of the actor.
8787  *
8788  * since: 0.2
8789  */
8790 void
8791 clutter_actor_set_height (ClutterActor *self,
8792                           gfloat        height)
8793 {
8794   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8795
8796   g_object_freeze_notify (G_OBJECT (self));
8797
8798   clutter_actor_set_height_internal (self, height);
8799
8800   g_object_thaw_notify (G_OBJECT (self));
8801 }
8802
8803 /**
8804  * clutter_actor_set_x:
8805  * @self: a #ClutterActor
8806  * @x: the actor's position on the X axis
8807  *
8808  * Sets the actor's X coordinate, relative to its parent, in pixels.
8809  *
8810  * Overrides any layout manager and forces a fixed position for
8811  * the actor.
8812  *
8813  * Since: 0.6
8814  */
8815 void
8816 clutter_actor_set_x (ClutterActor *self,
8817                      gfloat        x)
8818 {
8819   ClutterActorBox old = { 0, };
8820   ClutterActorPrivate *priv;
8821   ClutterLayoutInfo *info;
8822
8823   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8824
8825   priv = self->priv;
8826
8827   info = _clutter_actor_get_layout_info (self);
8828
8829   if (priv->position_set && info->fixed_x == x)
8830     return;
8831
8832   clutter_actor_store_old_geometry (self, &old);
8833
8834   info->fixed_x = x;
8835   clutter_actor_set_fixed_position_set (self, TRUE);
8836
8837   clutter_actor_notify_if_geometry_changed (self, &old);
8838
8839   clutter_actor_queue_relayout (self);
8840 }
8841
8842 /**
8843  * clutter_actor_set_y:
8844  * @self: a #ClutterActor
8845  * @y: the actor's position on the Y axis
8846  *
8847  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8848  *
8849  * Overrides any layout manager and forces a fixed position for
8850  * the actor.
8851  *
8852  * Since: 0.6
8853  */
8854 void
8855 clutter_actor_set_y (ClutterActor *self,
8856                      gfloat        y)
8857 {
8858   ClutterActorBox old = { 0, };
8859   ClutterActorPrivate *priv;
8860   ClutterLayoutInfo *info;
8861
8862   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8863
8864   priv = self->priv;
8865
8866   info = _clutter_actor_get_layout_info (self);
8867
8868   if (priv->position_set && info->fixed_y == y)
8869     return;
8870
8871   clutter_actor_store_old_geometry (self, &old);
8872
8873   info->fixed_y = y;
8874   clutter_actor_set_fixed_position_set (self, TRUE);
8875
8876   clutter_actor_notify_if_geometry_changed (self, &old);
8877
8878   clutter_actor_queue_relayout (self);
8879 }
8880
8881 /**
8882  * clutter_actor_get_x:
8883  * @self: A #ClutterActor
8884  *
8885  * Retrieves the X coordinate of a #ClutterActor.
8886  *
8887  * This function tries to "do what you mean", by returning the
8888  * correct value depending on the actor's state.
8889  *
8890  * If the actor has a valid allocation, this function will return
8891  * the X coordinate of the origin of the allocation box.
8892  *
8893  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8894  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8895  * function will return that coordinate.
8896  *
8897  * If both the allocation and a fixed position are missing, this function
8898  * will return 0.
8899  *
8900  * Return value: the X coordinate, in pixels, ignoring any
8901  *   transformation (i.e. scaling, rotation)
8902  */
8903 gfloat
8904 clutter_actor_get_x (ClutterActor *self)
8905 {
8906   ClutterActorPrivate *priv;
8907
8908   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8909
8910   priv = self->priv;
8911
8912   if (priv->needs_allocation)
8913     {
8914       if (priv->position_set)
8915         {
8916           const ClutterLayoutInfo *info;
8917
8918           info = _clutter_actor_get_layout_info_or_defaults (self);
8919
8920           return info->fixed_x;
8921         }
8922       else
8923         return 0;
8924     }
8925   else
8926     return priv->allocation.x1;
8927 }
8928
8929 /**
8930  * clutter_actor_get_y:
8931  * @self: A #ClutterActor
8932  *
8933  * Retrieves the Y coordinate of a #ClutterActor.
8934  *
8935  * This function tries to "do what you mean", by returning the
8936  * correct value depending on the actor's state.
8937  *
8938  * If the actor has a valid allocation, this function will return
8939  * the Y coordinate of the origin of the allocation box.
8940  *
8941  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
8942  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8943  * function will return that coordinate.
8944  *
8945  * If both the allocation and a fixed position are missing, this function
8946  * will return 0.
8947  *
8948  * Return value: the Y coordinate, in pixels, ignoring any
8949  *   transformation (i.e. scaling, rotation)
8950  */
8951 gfloat
8952 clutter_actor_get_y (ClutterActor *self)
8953 {
8954   ClutterActorPrivate *priv;
8955
8956   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8957
8958   priv = self->priv;
8959
8960   if (priv->needs_allocation)
8961     {
8962       if (priv->position_set)
8963         {
8964           const ClutterLayoutInfo *info;
8965
8966           info = _clutter_actor_get_layout_info_or_defaults (self);
8967
8968           return info->fixed_y;
8969         }
8970       else
8971         return 0;
8972     }
8973   else
8974     return priv->allocation.y1;
8975 }
8976
8977 /**
8978  * clutter_actor_set_scale:
8979  * @self: A #ClutterActor
8980  * @scale_x: double factor to scale actor by horizontally.
8981  * @scale_y: double factor to scale actor by vertically.
8982  *
8983  * Scales an actor with the given factors. The scaling is relative to
8984  * the scale center and the anchor point. The scale center is
8985  * unchanged by this function and defaults to 0,0.
8986  *
8987  * Since: 0.2
8988  */
8989 void
8990 clutter_actor_set_scale (ClutterActor *self,
8991                          gdouble       scale_x,
8992                          gdouble       scale_y)
8993 {
8994   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8995
8996   g_object_freeze_notify (G_OBJECT (self));
8997
8998   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
8999   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9000
9001   g_object_thaw_notify (G_OBJECT (self));
9002 }
9003
9004 /**
9005  * clutter_actor_set_scale_full:
9006  * @self: A #ClutterActor
9007  * @scale_x: double factor to scale actor by horizontally.
9008  * @scale_y: double factor to scale actor by vertically.
9009  * @center_x: X coordinate of the center of the scale.
9010  * @center_y: Y coordinate of the center of the scale
9011  *
9012  * Scales an actor with the given factors around the given center
9013  * point. The center point is specified in pixels relative to the
9014  * anchor point (usually the top left corner of the actor).
9015  *
9016  * Since: 1.0
9017  */
9018 void
9019 clutter_actor_set_scale_full (ClutterActor *self,
9020                               gdouble       scale_x,
9021                               gdouble       scale_y,
9022                               gfloat        center_x,
9023                               gfloat        center_y)
9024 {
9025   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9026
9027   g_object_freeze_notify (G_OBJECT (self));
9028
9029   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9030   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9031   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9032   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9033
9034   g_object_thaw_notify (G_OBJECT (self));
9035 }
9036
9037 /**
9038  * clutter_actor_set_scale_with_gravity:
9039  * @self: A #ClutterActor
9040  * @scale_x: double factor to scale actor by horizontally.
9041  * @scale_y: double factor to scale actor by vertically.
9042  * @gravity: the location of the scale center expressed as a compass
9043  * direction.
9044  *
9045  * Scales an actor with the given factors around the given
9046  * center point. The center point is specified as one of the compass
9047  * directions in #ClutterGravity. For example, setting it to north
9048  * will cause the top of the actor to remain unchanged and the rest of
9049  * the actor to expand left, right and downwards.
9050  *
9051  * Since: 1.0
9052  */
9053 void
9054 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9055                                       gdouble         scale_x,
9056                                       gdouble         scale_y,
9057                                       ClutterGravity  gravity)
9058 {
9059   ClutterTransformInfo *info;
9060   GObject *obj;
9061
9062   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9063
9064   obj = G_OBJECT (self);
9065
9066   g_object_freeze_notify (obj);
9067
9068   info = _clutter_actor_get_transform_info (self);
9069   info->scale_x = scale_x;
9070   info->scale_y = scale_y;
9071
9072   if (gravity == CLUTTER_GRAVITY_NONE)
9073     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9074   else
9075     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9076
9077   self->priv->transform_valid = FALSE;
9078
9079   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9080   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9081   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9082   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9083   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9084
9085   clutter_actor_queue_redraw (self);
9086
9087   g_object_thaw_notify (obj);
9088 }
9089
9090 /**
9091  * clutter_actor_get_scale:
9092  * @self: A #ClutterActor
9093  * @scale_x: (out) (allow-none): Location to store horizonal
9094  *   scale factor, or %NULL.
9095  * @scale_y: (out) (allow-none): Location to store vertical
9096  *   scale factor, or %NULL.
9097  *
9098  * Retrieves an actors scale factors.
9099  *
9100  * Since: 0.2
9101  */
9102 void
9103 clutter_actor_get_scale (ClutterActor *self,
9104                          gdouble      *scale_x,
9105                          gdouble      *scale_y)
9106 {
9107   const ClutterTransformInfo *info;
9108
9109   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9110
9111   info = _clutter_actor_get_transform_info_or_defaults (self);
9112
9113   if (scale_x)
9114     *scale_x = info->scale_x;
9115
9116   if (scale_y)
9117     *scale_y = info->scale_y;
9118 }
9119
9120 /**
9121  * clutter_actor_get_scale_center:
9122  * @self: A #ClutterActor
9123  * @center_x: (out) (allow-none): Location to store the X position
9124  *   of the scale center, or %NULL.
9125  * @center_y: (out) (allow-none): Location to store the Y position
9126  *   of the scale center, or %NULL.
9127  *
9128  * Retrieves the scale center coordinate in pixels relative to the top
9129  * left corner of the actor. If the scale center was specified using a
9130  * #ClutterGravity this will calculate the pixel offset using the
9131  * current size of the actor.
9132  *
9133  * Since: 1.0
9134  */
9135 void
9136 clutter_actor_get_scale_center (ClutterActor *self,
9137                                 gfloat       *center_x,
9138                                 gfloat       *center_y)
9139 {
9140   const ClutterTransformInfo *info;
9141
9142   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9143
9144   info = _clutter_actor_get_transform_info_or_defaults (self);
9145
9146   clutter_anchor_coord_get_units (self, &info->scale_center,
9147                                   center_x,
9148                                   center_y,
9149                                   NULL);
9150 }
9151
9152 /**
9153  * clutter_actor_get_scale_gravity:
9154  * @self: A #ClutterActor
9155  *
9156  * Retrieves the scale center as a compass direction. If the scale
9157  * center was specified in pixels or units this will return
9158  * %CLUTTER_GRAVITY_NONE.
9159  *
9160  * Return value: the scale gravity
9161  *
9162  * Since: 1.0
9163  */
9164 ClutterGravity
9165 clutter_actor_get_scale_gravity (ClutterActor *self)
9166 {
9167   const ClutterTransformInfo *info;
9168
9169   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9170
9171   info = _clutter_actor_get_transform_info_or_defaults (self);
9172
9173   return clutter_anchor_coord_get_gravity (&info->scale_center);
9174 }
9175
9176 /**
9177  * clutter_actor_set_opacity:
9178  * @self: A #ClutterActor
9179  * @opacity: New opacity value for the actor.
9180  *
9181  * Sets the actor's opacity, with zero being completely transparent and
9182  * 255 (0xff) being fully opaque.
9183  */
9184 void
9185 clutter_actor_set_opacity (ClutterActor *self,
9186                            guint8        opacity)
9187 {
9188   ClutterActorPrivate *priv;
9189
9190   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9191
9192   priv = self->priv;
9193
9194   if (priv->opacity != opacity)
9195     {
9196       priv->opacity = opacity;
9197
9198       /* Queue a redraw from the flatten effect so that it can use
9199          its cached image if available instead of having to redraw the
9200          actual actor. If it doesn't end up using the FBO then the
9201          effect is still able to continue the paint anyway. If there
9202          is no flatten effect yet then this is equivalent to queueing
9203          a full redraw */
9204       _clutter_actor_queue_redraw_full (self,
9205                                         0, /* flags */
9206                                         NULL, /* clip */
9207                                         priv->flatten_effect);
9208
9209       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9210     }
9211 }
9212
9213 /*
9214  * clutter_actor_get_paint_opacity_internal:
9215  * @self: a #ClutterActor
9216  *
9217  * Retrieves the absolute opacity of the actor, as it appears on the stage
9218  *
9219  * This function does not do type checks
9220  *
9221  * Return value: the absolute opacity of the actor
9222  */
9223 static guint8
9224 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9225 {
9226   ClutterActorPrivate *priv = self->priv;
9227   ClutterActor *parent;
9228
9229   /* override the top-level opacity to always be 255; even in
9230    * case of ClutterStage:use-alpha being TRUE we want the rest
9231    * of the scene to be painted
9232    */
9233   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9234     return 255;
9235
9236   if (priv->opacity_override >= 0)
9237     return priv->opacity_override;
9238
9239   parent = priv->parent;
9240
9241   /* Factor in the actual actors opacity with parents */
9242   if (parent != NULL)
9243     {
9244       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9245
9246       if (opacity != 0xff)
9247         return (opacity * priv->opacity) / 0xff;
9248     }
9249
9250   return priv->opacity;
9251
9252 }
9253
9254 /**
9255  * clutter_actor_get_paint_opacity:
9256  * @self: A #ClutterActor
9257  *
9258  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9259  *
9260  * This function traverses the hierarchy chain and composites the opacity of
9261  * the actor with that of its parents.
9262  *
9263  * This function is intended for subclasses to use in the paint virtual
9264  * function, to paint themselves with the correct opacity.
9265  *
9266  * Return value: The actor opacity value.
9267  *
9268  * Since: 0.8
9269  */
9270 guint8
9271 clutter_actor_get_paint_opacity (ClutterActor *self)
9272 {
9273   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9274
9275   return clutter_actor_get_paint_opacity_internal (self);
9276 }
9277
9278 /**
9279  * clutter_actor_get_opacity:
9280  * @self: a #ClutterActor
9281  *
9282  * Retrieves the opacity value of an actor, as set by
9283  * clutter_actor_set_opacity().
9284  *
9285  * For retrieving the absolute opacity of the actor inside a paint
9286  * virtual function, see clutter_actor_get_paint_opacity().
9287  *
9288  * Return value: the opacity of the actor
9289  */
9290 guint8
9291 clutter_actor_get_opacity (ClutterActor *self)
9292 {
9293   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9294
9295   return self->priv->opacity;
9296 }
9297
9298 /**
9299  * clutter_actor_set_offscreen_redirect:
9300  * @self: A #ClutterActor
9301  * @redirect: New offscreen redirect flags for the actor.
9302  *
9303  * Defines the circumstances where the actor should be redirected into
9304  * an offscreen image. The offscreen image is used to flatten the
9305  * actor into a single image while painting for two main reasons.
9306  * Firstly, when the actor is painted a second time without any of its
9307  * contents changing it can simply repaint the cached image without
9308  * descending further down the actor hierarchy. Secondly, it will make
9309  * the opacity look correct even if there are overlapping primitives
9310  * in the actor.
9311  *
9312  * Caching the actor could in some cases be a performance win and in
9313  * some cases be a performance lose so it is important to determine
9314  * which value is right for an actor before modifying this value. For
9315  * example, there is never any reason to flatten an actor that is just
9316  * a single texture (such as a #ClutterTexture) because it is
9317  * effectively already cached in an image so the offscreen would be
9318  * redundant. Also if the actor contains primitives that are far apart
9319  * with a large transparent area in the middle (such as a large
9320  * CluterGroup with a small actor in the top left and a small actor in
9321  * the bottom right) then the cached image will contain the entire
9322  * image of the large area and the paint will waste time blending all
9323  * of the transparent pixels in the middle.
9324  *
9325  * The default method of implementing opacity on a container simply
9326  * forwards on the opacity to all of the children. If the children are
9327  * overlapping then it will appear as if they are two separate glassy
9328  * objects and there will be a break in the color where they
9329  * overlap. By redirecting to an offscreen buffer it will be as if the
9330  * two opaque objects are combined into one and then made transparent
9331  * which is usually what is expected.
9332  *
9333  * The image below demonstrates the difference between redirecting and
9334  * not. The image shows two Clutter groups, each containing a red and
9335  * a green rectangle which overlap. The opacity on the group is set to
9336  * 128 (which is 50%). When the offscreen redirect is not used, the
9337  * red rectangle can be seen through the blue rectangle as if the two
9338  * rectangles were separately transparent. When the redirect is used
9339  * the group as a whole is transparent instead so the red rectangle is
9340  * not visible where they overlap.
9341  *
9342  * <figure id="offscreen-redirect">
9343  *   <title>Sample of using an offscreen redirect for transparency</title>
9344  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9345  * </figure>
9346  *
9347  * The default value for this property is 0, so we effectively will
9348  * never redirect an actor offscreen by default. This means that there
9349  * are times that transparent actors may look glassy as described
9350  * above. The reason this is the default is because there is a
9351  * performance trade off between quality and performance here. In many
9352  * cases the default form of glassy opacity looks good enough, but if
9353  * it's not you will need to set the
9354  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9355  * redirection for opacity.
9356  *
9357  * Custom actors that don't contain any overlapping primitives are
9358  * recommended to override the has_overlaps() virtual to return %FALSE
9359  * for maximum efficiency.
9360  *
9361  * Since: 1.8
9362  */
9363 void
9364 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9365                                       ClutterOffscreenRedirect redirect)
9366 {
9367   ClutterActorPrivate *priv;
9368
9369   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9370
9371   priv = self->priv;
9372
9373   if (priv->offscreen_redirect != redirect)
9374     {
9375       priv->offscreen_redirect = redirect;
9376
9377       /* Queue a redraw from the effect so that it can use its cached
9378          image if available instead of having to redraw the actual
9379          actor. If it doesn't end up using the FBO then the effect is
9380          still able to continue the paint anyway. If there is no
9381          effect then this is equivalent to queuing a full redraw */
9382       _clutter_actor_queue_redraw_full (self,
9383                                         0, /* flags */
9384                                         NULL, /* clip */
9385                                         priv->flatten_effect);
9386
9387       g_object_notify_by_pspec (G_OBJECT (self),
9388                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9389     }
9390 }
9391
9392 /**
9393  * clutter_actor_get_offscreen_redirect:
9394  * @self: a #ClutterActor
9395  *
9396  * Retrieves whether to redirect the actor to an offscreen buffer, as
9397  * set by clutter_actor_set_offscreen_redirect().
9398  *
9399  * Return value: the value of the offscreen-redirect property of the actor
9400  *
9401  * Since: 1.8
9402  */
9403 ClutterOffscreenRedirect
9404 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9405 {
9406   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9407
9408   return self->priv->offscreen_redirect;
9409 }
9410
9411 /**
9412  * clutter_actor_set_name:
9413  * @self: A #ClutterActor
9414  * @name: Textual tag to apply to actor
9415  *
9416  * Sets the given name to @self. The name can be used to identify
9417  * a #ClutterActor.
9418  */
9419 void
9420 clutter_actor_set_name (ClutterActor *self,
9421                         const gchar  *name)
9422 {
9423   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9424
9425   g_free (self->priv->name);
9426   self->priv->name = g_strdup (name);
9427
9428   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9429 }
9430
9431 /**
9432  * clutter_actor_get_name:
9433  * @self: A #ClutterActor
9434  *
9435  * Retrieves the name of @self.
9436  *
9437  * Return value: the name of the actor, or %NULL. The returned string is
9438  *   owned by the actor and should not be modified or freed.
9439  */
9440 const gchar *
9441 clutter_actor_get_name (ClutterActor *self)
9442 {
9443   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9444
9445   return self->priv->name;
9446 }
9447
9448 /**
9449  * clutter_actor_get_gid:
9450  * @self: A #ClutterActor
9451  *
9452  * Retrieves the unique id for @self.
9453  *
9454  * Return value: Globally unique value for this object instance.
9455  *
9456  * Since: 0.6
9457  *
9458  * Deprecated: 1.8: The id is not used any longer.
9459  */
9460 guint32
9461 clutter_actor_get_gid (ClutterActor *self)
9462 {
9463   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9464
9465   return self->priv->id;
9466 }
9467
9468 /**
9469  * clutter_actor_set_depth:
9470  * @self: a #ClutterActor
9471  * @depth: Z co-ord
9472  *
9473  * Sets the Z coordinate of @self to @depth.
9474  *
9475  * The unit used by @depth is dependant on the perspective setup. See
9476  * also clutter_stage_set_perspective().
9477  */
9478 void
9479 clutter_actor_set_depth (ClutterActor *self,
9480                          gfloat        depth)
9481 {
9482   ClutterActorPrivate *priv;
9483
9484   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9485
9486   priv = self->priv;
9487
9488   if (priv->z != depth)
9489     {
9490       /* Sets Z value - XXX 2.0: should we invert? */
9491       priv->z = depth;
9492
9493       priv->transform_valid = FALSE;
9494
9495       /* FIXME - remove this crap; sadly, there are still containers
9496        * in Clutter that depend on this utter brain damage
9497        */
9498       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9499
9500       clutter_actor_queue_redraw (self);
9501
9502       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9503     }
9504 }
9505
9506 /**
9507  * clutter_actor_get_depth:
9508  * @self: a #ClutterActor
9509  *
9510  * Retrieves the depth of @self.
9511  *
9512  * Return value: the depth of the actor
9513  */
9514 gfloat
9515 clutter_actor_get_depth (ClutterActor *self)
9516 {
9517   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9518
9519   return self->priv->z;
9520 }
9521
9522 /**
9523  * clutter_actor_set_rotation:
9524  * @self: a #ClutterActor
9525  * @axis: the axis of rotation
9526  * @angle: the angle of rotation
9527  * @x: X coordinate of the rotation center
9528  * @y: Y coordinate of the rotation center
9529  * @z: Z coordinate of the rotation center
9530  *
9531  * Sets the rotation angle of @self around the given axis.
9532  *
9533  * The rotation center coordinates used depend on the value of @axis:
9534  * <itemizedlist>
9535  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9536  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9537  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9538  * </itemizedlist>
9539  *
9540  * The rotation coordinates are relative to the anchor point of the
9541  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9542  * point is set, the upper left corner is assumed as the origin.
9543  *
9544  * Since: 0.8
9545  */
9546 void
9547 clutter_actor_set_rotation (ClutterActor      *self,
9548                             ClutterRotateAxis  axis,
9549                             gdouble            angle,
9550                             gfloat             x,
9551                             gfloat             y,
9552                             gfloat             z)
9553 {
9554   ClutterVertex v;
9555
9556   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9557
9558   v.x = x;
9559   v.y = y;
9560   v.z = z;
9561
9562   g_object_freeze_notify (G_OBJECT (self));
9563
9564   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9565   clutter_actor_set_rotation_center_internal (self, axis, &v);
9566
9567   g_object_thaw_notify (G_OBJECT (self));
9568 }
9569
9570 /**
9571  * clutter_actor_set_z_rotation_from_gravity:
9572  * @self: a #ClutterActor
9573  * @angle: the angle of rotation
9574  * @gravity: the center point of the rotation
9575  *
9576  * Sets the rotation angle of @self around the Z axis using the center
9577  * point specified as a compass point. For example to rotate such that
9578  * the center of the actor remains static you can use
9579  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9580  * will move accordingly.
9581  *
9582  * Since: 1.0
9583  */
9584 void
9585 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9586                                            gdouble         angle,
9587                                            ClutterGravity  gravity)
9588 {
9589   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9590
9591   if (gravity == CLUTTER_GRAVITY_NONE)
9592     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9593   else
9594     {
9595       GObject *obj = G_OBJECT (self);
9596       ClutterTransformInfo *info;
9597
9598       info = _clutter_actor_get_transform_info (self);
9599
9600       g_object_freeze_notify (obj);
9601
9602       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9603
9604       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9605       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9606       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9607
9608       g_object_thaw_notify (obj);
9609     }
9610 }
9611
9612 /**
9613  * clutter_actor_get_rotation:
9614  * @self: a #ClutterActor
9615  * @axis: the axis of rotation
9616  * @x: (out): return value for the X coordinate of the center of rotation
9617  * @y: (out): return value for the Y coordinate of the center of rotation
9618  * @z: (out): return value for the Z coordinate of the center of rotation
9619  *
9620  * Retrieves the angle and center of rotation on the given axis,
9621  * set using clutter_actor_set_rotation().
9622  *
9623  * Return value: the angle of rotation
9624  *
9625  * Since: 0.8
9626  */
9627 gdouble
9628 clutter_actor_get_rotation (ClutterActor      *self,
9629                             ClutterRotateAxis  axis,
9630                             gfloat            *x,
9631                             gfloat            *y,
9632                             gfloat            *z)
9633 {
9634   const ClutterTransformInfo *info;
9635   const AnchorCoord *anchor_coord;
9636   gdouble retval = 0;
9637
9638   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9639
9640   info = _clutter_actor_get_transform_info_or_defaults (self);
9641
9642   switch (axis)
9643     {
9644     case CLUTTER_X_AXIS:
9645       anchor_coord = &info->rx_center;
9646       retval = info->rx_angle;
9647       break;
9648
9649     case CLUTTER_Y_AXIS:
9650       anchor_coord = &info->ry_center;
9651       retval = info->ry_angle;
9652       break;
9653
9654     case CLUTTER_Z_AXIS:
9655       anchor_coord = &info->rz_center;
9656       retval = info->rz_angle;
9657       break;
9658
9659     default:
9660       anchor_coord = NULL;
9661       retval = 0.0;
9662       break;
9663     }
9664
9665   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9666
9667   return retval;
9668 }
9669
9670 /**
9671  * clutter_actor_get_z_rotation_gravity:
9672  * @self: A #ClutterActor
9673  *
9674  * Retrieves the center for the rotation around the Z axis as a
9675  * compass direction. If the center was specified in pixels or units
9676  * this will return %CLUTTER_GRAVITY_NONE.
9677  *
9678  * Return value: the Z rotation center
9679  *
9680  * Since: 1.0
9681  */
9682 ClutterGravity
9683 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9684 {
9685   const ClutterTransformInfo *info;
9686
9687   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9688
9689   info = _clutter_actor_get_transform_info_or_defaults (self);
9690
9691   return clutter_anchor_coord_get_gravity (&info->rz_center);
9692 }
9693
9694 /**
9695  * clutter_actor_set_clip:
9696  * @self: A #ClutterActor
9697  * @xoff: X offset of the clip rectangle
9698  * @yoff: Y offset of the clip rectangle
9699  * @width: Width of the clip rectangle
9700  * @height: Height of the clip rectangle
9701  *
9702  * Sets clip area for @self. The clip area is always computed from the
9703  * upper left corner of the actor, even if the anchor point is set
9704  * otherwise.
9705  *
9706  * Since: 0.6
9707  */
9708 void
9709 clutter_actor_set_clip (ClutterActor *self,
9710                         gfloat        xoff,
9711                         gfloat        yoff,
9712                         gfloat        width,
9713                         gfloat        height)
9714 {
9715   ClutterActorPrivate *priv;
9716
9717   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9718
9719   priv = self->priv;
9720
9721   if (priv->has_clip &&
9722       priv->clip.x == xoff &&
9723       priv->clip.y == yoff &&
9724       priv->clip.width == width &&
9725       priv->clip.height == height)
9726     return;
9727
9728   priv->clip.x = xoff;
9729   priv->clip.y = yoff;
9730   priv->clip.width = width;
9731   priv->clip.height = height;
9732
9733   priv->has_clip = TRUE;
9734
9735   clutter_actor_queue_redraw (self);
9736
9737   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9738   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9739 }
9740
9741 /**
9742  * clutter_actor_remove_clip:
9743  * @self: A #ClutterActor
9744  *
9745  * Removes clip area from @self.
9746  */
9747 void
9748 clutter_actor_remove_clip (ClutterActor *self)
9749 {
9750   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9751
9752   if (!self->priv->has_clip)
9753     return;
9754
9755   self->priv->has_clip = FALSE;
9756
9757   clutter_actor_queue_redraw (self);
9758
9759   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9760 }
9761
9762 /**
9763  * clutter_actor_has_clip:
9764  * @self: a #ClutterActor
9765  *
9766  * Determines whether the actor has a clip area set or not.
9767  *
9768  * Return value: %TRUE if the actor has a clip area set.
9769  *
9770  * Since: 0.1.1
9771  */
9772 gboolean
9773 clutter_actor_has_clip (ClutterActor *self)
9774 {
9775   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9776
9777   return self->priv->has_clip;
9778 }
9779
9780 /**
9781  * clutter_actor_get_clip:
9782  * @self: a #ClutterActor
9783  * @xoff: (out) (allow-none): return location for the X offset of
9784  *   the clip rectangle, or %NULL
9785  * @yoff: (out) (allow-none): return location for the Y offset of
9786  *   the clip rectangle, or %NULL
9787  * @width: (out) (allow-none): return location for the width of
9788  *   the clip rectangle, or %NULL
9789  * @height: (out) (allow-none): return location for the height of
9790  *   the clip rectangle, or %NULL
9791  *
9792  * Gets the clip area for @self, if any is set
9793  *
9794  * Since: 0.6
9795  */
9796 void
9797 clutter_actor_get_clip (ClutterActor *self,
9798                         gfloat       *xoff,
9799                         gfloat       *yoff,
9800                         gfloat       *width,
9801                         gfloat       *height)
9802 {
9803   ClutterActorPrivate *priv;
9804
9805   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9806
9807   priv = self->priv;
9808
9809   if (!priv->has_clip)
9810     return;
9811
9812   if (xoff != NULL)
9813     *xoff = priv->clip.x;
9814
9815   if (yoff != NULL)
9816     *yoff = priv->clip.y;
9817
9818   if (width != NULL)
9819     *width = priv->clip.width;
9820
9821   if (height != NULL)
9822     *height = priv->clip.height;
9823 }
9824
9825 /**
9826  * clutter_actor_get_children:
9827  * @self: a #ClutterActor
9828  *
9829  * Retrieves the list of children of @self.
9830  *
9831  * Return value: (transfer container) (element-type ClutterActor): A newly
9832  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9833  *   done.
9834  *
9835  * Since: 1.10
9836  */
9837 GList *
9838 clutter_actor_get_children (ClutterActor *self)
9839 {
9840   ClutterActor *iter;
9841   GList *res;
9842
9843   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9844
9845   /* we walk the list backward so that we can use prepend(),
9846    * which is O(1)
9847    */
9848   for (iter = self->priv->last_child, res = NULL;
9849        iter != NULL;
9850        iter = iter->priv->prev_sibling)
9851     {
9852       res = g_list_prepend (res, iter);
9853     }
9854
9855   return res;
9856 }
9857
9858 /*< private >
9859  * insert_child_at_depth:
9860  * @self: a #ClutterActor
9861  * @child: a #ClutterActor
9862  *
9863  * Inserts @child inside the list of children held by @self, using
9864  * the depth as the insertion criteria.
9865  *
9866  * This sadly makes the insertion not O(1), but we can keep the
9867  * list sorted so that the painters algorithm we use for painting
9868  * the children will work correctly.
9869  */
9870 static void
9871 insert_child_at_depth (ClutterActor *self,
9872                        ClutterActor *child,
9873                        gpointer      dummy G_GNUC_UNUSED)
9874 {
9875   ClutterActor *iter;
9876
9877   child->priv->parent = self;
9878
9879   /* special-case the first child */
9880   if (self->priv->n_children == 0)
9881     {
9882       self->priv->first_child = child;
9883       self->priv->last_child = child;
9884
9885       child->priv->next_sibling = NULL;
9886       child->priv->prev_sibling = NULL;
9887
9888       return;
9889     }
9890
9891   /* Find the right place to insert the child so that it will still be
9892      sorted and the child will be after all of the actors at the same
9893      dept */
9894   for (iter = self->priv->first_child;
9895        iter != NULL;
9896        iter = iter->priv->next_sibling)
9897     {
9898       if (iter->priv->z > child->priv->z)
9899         break;
9900     }
9901
9902   if (iter != NULL)
9903     {
9904       ClutterActor *tmp = iter->priv->prev_sibling;
9905
9906       if (tmp != NULL)
9907         tmp->priv->next_sibling = child;
9908
9909       /* Insert the node before the found one */
9910       child->priv->prev_sibling = iter->priv->prev_sibling;
9911       child->priv->next_sibling = iter;
9912       iter->priv->prev_sibling = child;
9913     }
9914   else
9915     {
9916       ClutterActor *tmp = self->priv->last_child;
9917
9918       if (tmp != NULL)
9919         tmp->priv->next_sibling = child;
9920
9921       /* insert the node at the end of the list */
9922       child->priv->prev_sibling = self->priv->last_child;
9923       child->priv->next_sibling = NULL;
9924     }
9925
9926   if (child->priv->prev_sibling == NULL)
9927     self->priv->first_child = child;
9928
9929   if (child->priv->next_sibling == NULL)
9930     self->priv->last_child = child;
9931 }
9932
9933 static void
9934 insert_child_at_index (ClutterActor *self,
9935                        ClutterActor *child,
9936                        gpointer      data_)
9937 {
9938   gint index_ = GPOINTER_TO_INT (data_);
9939
9940   child->priv->parent = self;
9941
9942   if (index_ == 0)
9943     {
9944       ClutterActor *tmp = self->priv->first_child;
9945
9946       if (tmp != NULL)
9947         tmp->priv->prev_sibling = child;
9948
9949       child->priv->prev_sibling = NULL;
9950       child->priv->next_sibling = tmp;
9951     }
9952   else if (index_ < 0 || index_ >= self->priv->n_children)
9953     {
9954       ClutterActor *tmp = self->priv->last_child;
9955
9956       if (tmp != NULL)
9957         tmp->priv->next_sibling = child;
9958
9959       child->priv->prev_sibling = tmp;
9960       child->priv->next_sibling = NULL;
9961     }
9962   else
9963     {
9964       ClutterActor *iter;
9965       int i;
9966
9967       for (iter = self->priv->first_child, i = 0;
9968            iter != NULL;
9969            iter = iter->priv->next_sibling, i += 1)
9970         {
9971           if (index_ == i)
9972             {
9973               ClutterActor *tmp = iter->priv->prev_sibling;
9974
9975               child->priv->prev_sibling = tmp;
9976               child->priv->next_sibling = iter;
9977
9978               iter->priv->prev_sibling = child;
9979
9980               if (tmp != NULL)
9981                 tmp->priv->next_sibling = child;
9982
9983               break;
9984             }
9985         }
9986     }
9987
9988   if (child->priv->prev_sibling == NULL)
9989     self->priv->first_child = child;
9990
9991   if (child->priv->next_sibling == NULL)
9992     self->priv->last_child = child;
9993 }
9994
9995 static void
9996 insert_child_above (ClutterActor *self,
9997                     ClutterActor *child,
9998                     gpointer      data)
9999 {
10000   ClutterActor *sibling = data;
10001
10002   child->priv->parent = self;
10003
10004   if (sibling == NULL)
10005     sibling = self->priv->last_child;
10006
10007   child->priv->prev_sibling = sibling;
10008
10009   if (sibling != NULL)
10010     {
10011       ClutterActor *tmp = sibling->priv->next_sibling;
10012
10013       child->priv->next_sibling = tmp;
10014
10015       if (tmp != NULL)
10016         tmp->priv->prev_sibling = child;
10017
10018       sibling->priv->next_sibling = child;
10019     }
10020   else
10021     child->priv->next_sibling = NULL;
10022
10023   if (child->priv->prev_sibling == NULL)
10024     self->priv->first_child = child;
10025
10026   if (child->priv->next_sibling == NULL)
10027     self->priv->last_child = child;
10028 }
10029
10030 static void
10031 insert_child_below (ClutterActor *self,
10032                     ClutterActor *child,
10033                     gpointer      data)
10034 {
10035   ClutterActor *sibling = data;
10036
10037   child->priv->parent = self;
10038
10039   if (sibling == NULL)
10040     sibling = self->priv->first_child;
10041
10042   child->priv->next_sibling = sibling;
10043
10044   if (sibling != NULL)
10045     {
10046       ClutterActor *tmp = sibling->priv->prev_sibling;
10047
10048       child->priv->prev_sibling = tmp;
10049
10050       if (tmp != NULL)
10051         tmp->priv->next_sibling = child;
10052
10053       sibling->priv->prev_sibling = child;
10054     }
10055   else
10056     child->priv->prev_sibling = NULL;
10057
10058   if (child->priv->prev_sibling == NULL)
10059     self->priv->first_child = child;
10060
10061   if (child->priv->next_sibling == NULL)
10062     self->priv->last_child = child;
10063 }
10064
10065 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10066                                            ClutterActor *child,
10067                                            gpointer      data);
10068
10069 typedef enum {
10070   ADD_CHILD_CREATE_META       = 1 << 0,
10071   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10072   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10073   ADD_CHILD_CHECK_STATE       = 1 << 3,
10074   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10075
10076   /* default flags for public API */
10077   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10078                                ADD_CHILD_EMIT_PARENT_SET |
10079                                ADD_CHILD_EMIT_ACTOR_ADDED |
10080                                ADD_CHILD_CHECK_STATE |
10081                                ADD_CHILD_NOTIFY_FIRST_LAST,
10082
10083   /* flags for legacy/deprecated API */
10084   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10085                                ADD_CHILD_CHECK_STATE |
10086                                ADD_CHILD_NOTIFY_FIRST_LAST
10087 } ClutterActorAddChildFlags;
10088
10089 /*< private >
10090  * clutter_actor_add_child_internal:
10091  * @self: a #ClutterActor
10092  * @child: a #ClutterActor
10093  * @flags: control flags for actions
10094  * @add_func: delegate function
10095  * @data: (closure): data to pass to @add_func
10096  *
10097  * Adds @child to the list of children of @self.
10098  *
10099  * The actual insertion inside the list is delegated to @add_func: this
10100  * function will just set up the state, perform basic checks, and emit
10101  * signals.
10102  *
10103  * The @flags argument is used to perform additional operations.
10104  */
10105 static inline void
10106 clutter_actor_add_child_internal (ClutterActor              *self,
10107                                   ClutterActor              *child,
10108                                   ClutterActorAddChildFlags  flags,
10109                                   ClutterActorAddChildFunc   add_func,
10110                                   gpointer                   data)
10111 {
10112   ClutterTextDirection text_dir;
10113   gboolean create_meta;
10114   gboolean emit_parent_set, emit_actor_added;
10115   gboolean check_state;
10116   gboolean notify_first_last;
10117   ClutterActor *old_first_child, *old_last_child;
10118
10119   if (child->priv->parent != NULL)
10120     {
10121       g_warning ("Cannot set a parent on an actor which has a parent. "
10122                  "You must use clutter_actor_remove_child() first.");
10123       return;
10124     }
10125
10126   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10127     {
10128       g_warning ("Cannot set a parent on a toplevel actor\n");
10129       return;
10130     }
10131
10132   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10133     {
10134       g_warning ("Cannot set a parent currently being destroyed");
10135       return;
10136     }
10137
10138   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10139   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10140   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10141   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10142   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10143
10144   old_first_child = self->priv->first_child;
10145   old_last_child = self->priv->last_child;
10146
10147   g_object_freeze_notify (G_OBJECT (self));
10148
10149   if (create_meta)
10150     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10151
10152   g_object_ref_sink (child);
10153   child->priv->parent = NULL;
10154   child->priv->next_sibling = NULL;
10155   child->priv->prev_sibling = NULL;
10156
10157   /* delegate the actual insertion */
10158   add_func (self, child, data);
10159
10160   g_assert (child->priv->parent == self);
10161
10162   self->priv->n_children += 1;
10163
10164   self->priv->age += 1;
10165
10166   /* if push_internal() has been called then we automatically set
10167    * the flag on the actor
10168    */
10169   if (self->priv->internal_child)
10170     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10171
10172   /* clutter_actor_reparent() will emit ::parent-set for us */
10173   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10174     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10175
10176   if (check_state)
10177     {
10178       /* If parent is mapped or realized, we need to also be mapped or
10179        * realized once we're inside the parent.
10180        */
10181       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10182
10183       /* propagate the parent's text direction to the child */
10184       text_dir = clutter_actor_get_text_direction (self);
10185       clutter_actor_set_text_direction (child, text_dir);
10186     }
10187
10188   if (child->priv->show_on_set_parent)
10189     clutter_actor_show (child);
10190
10191   if (CLUTTER_ACTOR_IS_MAPPED (child))
10192     clutter_actor_queue_redraw (child);
10193
10194   /* maintain the invariant that if an actor needs layout,
10195    * its parents do as well
10196    */
10197   if (child->priv->needs_width_request ||
10198       child->priv->needs_height_request ||
10199       child->priv->needs_allocation)
10200     {
10201       /* we work around the short-circuiting we do
10202        * in clutter_actor_queue_relayout() since we
10203        * want to force a relayout
10204        */
10205       child->priv->needs_width_request = TRUE;
10206       child->priv->needs_height_request = TRUE;
10207       child->priv->needs_allocation = TRUE;
10208
10209       clutter_actor_queue_relayout (child->priv->parent);
10210     }
10211
10212   if (emit_actor_added)
10213     g_signal_emit_by_name (self, "actor-added", child);
10214
10215   if (notify_first_last)
10216     {
10217       if (old_first_child != self->priv->first_child)
10218         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10219
10220       if (old_last_child != self->priv->last_child)
10221         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10222     }
10223
10224   g_object_thaw_notify (G_OBJECT (self));
10225 }
10226
10227 /**
10228  * clutter_actor_add_child:
10229  * @self: a #ClutterActor
10230  * @child: a #ClutterActor
10231  *
10232  * Adds @child to the children of @self.
10233  *
10234  * This function will acquire a reference on @child that will only
10235  * be released when calling clutter_actor_remove_child().
10236  *
10237  * This function will take into consideration the #ClutterActor:depth
10238  * of @child, and will keep the list of children sorted.
10239  *
10240  * This function will emit the #ClutterContainer::actor-added signal
10241  * on @self.
10242  *
10243  * Since: 1.10
10244  */
10245 void
10246 clutter_actor_add_child (ClutterActor *self,
10247                          ClutterActor *child)
10248 {
10249   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10250   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10251   g_return_if_fail (self != child);
10252   g_return_if_fail (child->priv->parent == NULL);
10253
10254   clutter_actor_add_child_internal (self, child,
10255                                     ADD_CHILD_DEFAULT_FLAGS,
10256                                     insert_child_at_depth,
10257                                     NULL);
10258 }
10259
10260 /**
10261  * clutter_actor_insert_child_at_index:
10262  * @self: a #ClutterActor
10263  * @child: a #ClutterActor
10264  * @index_: the index
10265  *
10266  * Inserts @child into the list of children of @self, using the
10267  * given @index_. If @index_ is greater than the number of children
10268  * in @self, or is less than 0, then the new child is added at the end.
10269  *
10270  * This function will acquire a reference on @child that will only
10271  * be released when calling clutter_actor_remove_child().
10272  *
10273  * This function will not take into consideration the #ClutterActor:depth
10274  * of @child.
10275  *
10276  * This function will emit the #ClutterContainer::actor-added signal
10277  * on @self.
10278  *
10279  * Since: 1.10
10280  */
10281 void
10282 clutter_actor_insert_child_at_index (ClutterActor *self,
10283                                      ClutterActor *child,
10284                                      gint          index_)
10285 {
10286   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10287   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10288   g_return_if_fail (self != child);
10289   g_return_if_fail (child->priv->parent == NULL);
10290
10291   clutter_actor_add_child_internal (self, child,
10292                                     ADD_CHILD_DEFAULT_FLAGS,
10293                                     insert_child_at_index,
10294                                     GINT_TO_POINTER (index_));
10295 }
10296
10297 /**
10298  * clutter_actor_insert_child_above:
10299  * @self: a #ClutterActor
10300  * @child: a #ClutterActor
10301  * @sibling: (allow-none): a child of @self, or %NULL
10302  *
10303  * Inserts @child into the list of children of @self, above another
10304  * child of @self or, if @sibling is %NULL, above all the children
10305  * of @self.
10306  *
10307  * This function will acquire a reference on @child that will only
10308  * be released when calling clutter_actor_remove_child().
10309  *
10310  * This function will not take into consideration the #ClutterActor:depth
10311  * of @child.
10312  *
10313  * This function will emit the #ClutterContainer::actor-added signal
10314  * on @self.
10315  *
10316  * Since: 1.10
10317  */
10318 void
10319 clutter_actor_insert_child_above (ClutterActor *self,
10320                                   ClutterActor *child,
10321                                   ClutterActor *sibling)
10322 {
10323   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10324   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10325   g_return_if_fail (self != child);
10326   g_return_if_fail (child != sibling);
10327   g_return_if_fail (child->priv->parent == NULL);
10328   g_return_if_fail (sibling == NULL ||
10329                     (CLUTTER_IS_ACTOR (sibling) &&
10330                      sibling->priv->parent == self));
10331
10332   clutter_actor_add_child_internal (self, child,
10333                                     ADD_CHILD_DEFAULT_FLAGS,
10334                                     insert_child_above,
10335                                     sibling);
10336 }
10337
10338 /**
10339  * clutter_actor_insert_child_below:
10340  * @self: a #ClutterActor
10341  * @child: a #ClutterActor
10342  * @sibling: (allow-none): a child of @self, or %NULL
10343  *
10344  * Inserts @child into the list of children of @self, below another
10345  * child of @self or, if @sibling is %NULL, below all the children
10346  * of @self.
10347  *
10348  * This function will acquire a reference on @child that will only
10349  * be released when calling clutter_actor_remove_child().
10350  *
10351  * This function will not take into consideration the #ClutterActor:depth
10352  * of @child.
10353  *
10354  * This function will emit the #ClutterContainer::actor-added signal
10355  * on @self.
10356  *
10357  * Since: 1.10
10358  */
10359 void
10360 clutter_actor_insert_child_below (ClutterActor *self,
10361                                   ClutterActor *child,
10362                                   ClutterActor *sibling)
10363 {
10364   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10365   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10366   g_return_if_fail (self != child);
10367   g_return_if_fail (child != sibling);
10368   g_return_if_fail (child->priv->parent == NULL);
10369   g_return_if_fail (sibling == NULL ||
10370                     (CLUTTER_IS_ACTOR (sibling) &&
10371                      sibling->priv->parent == self));
10372
10373   clutter_actor_add_child_internal (self, child,
10374                                     ADD_CHILD_DEFAULT_FLAGS,
10375                                     insert_child_below,
10376                                     sibling);
10377 }
10378
10379 /**
10380  * clutter_actor_set_parent:
10381  * @self: A #ClutterActor
10382  * @parent: A new #ClutterActor parent
10383  *
10384  * Sets the parent of @self to @parent.
10385  *
10386  * This function will result in @parent acquiring a reference on @self,
10387  * eventually by sinking its floating reference first. The reference
10388  * will be released by clutter_actor_unparent().
10389  *
10390  * This function should only be called by legacy #ClutterActor<!-- -->s
10391  * implementing the #ClutterContainer interface.
10392  *
10393  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10394  */
10395 void
10396 clutter_actor_set_parent (ClutterActor *self,
10397                           ClutterActor *parent)
10398 {
10399   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10400   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10401   g_return_if_fail (self != parent);
10402   g_return_if_fail (self->priv->parent == NULL);
10403
10404   /* as this function will be called inside ClutterContainer::add
10405    * implementations or when building up a composite actor, we have
10406    * to preserve the old behaviour, and not create child meta or
10407    * emit the ::actor-added signal, to avoid recursion or double
10408    * emissions
10409    */
10410   clutter_actor_add_child_internal (parent, self,
10411                                     ADD_CHILD_LEGACY_FLAGS,
10412                                     insert_child_at_depth,
10413                                     NULL);
10414 }
10415
10416 /**
10417  * clutter_actor_get_parent:
10418  * @self: A #ClutterActor
10419  *
10420  * Retrieves the parent of @self.
10421  *
10422  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10423  *  if no parent is set
10424  */
10425 ClutterActor *
10426 clutter_actor_get_parent (ClutterActor *self)
10427 {
10428   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10429
10430   return self->priv->parent;
10431 }
10432
10433 /**
10434  * clutter_actor_get_paint_visibility:
10435  * @self: A #ClutterActor
10436  *
10437  * Retrieves the 'paint' visibility of an actor recursively checking for non
10438  * visible parents.
10439  *
10440  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10441  *
10442  * Return Value: %TRUE if the actor is visibile and will be painted.
10443  *
10444  * Since: 0.8.4
10445  */
10446 gboolean
10447 clutter_actor_get_paint_visibility (ClutterActor *actor)
10448 {
10449   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10450
10451   return CLUTTER_ACTOR_IS_MAPPED (actor);
10452 }
10453
10454 /**
10455  * clutter_actor_remove_child:
10456  * @self: a #ClutterActor
10457  * @child: a #ClutterActor
10458  *
10459  * Removes @child from the children of @self.
10460  *
10461  * This function will release the reference added by
10462  * clutter_actor_add_child(), so if you want to keep using @child
10463  * you will have to acquire a referenced on it before calling this
10464  * function.
10465  *
10466  * This function will emit the #ClutterContainer::actor-removed
10467  * signal on @self.
10468  *
10469  * Since: 1.10
10470  */
10471 void
10472 clutter_actor_remove_child (ClutterActor *self,
10473                             ClutterActor *child)
10474 {
10475   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10476   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10477   g_return_if_fail (self != child);
10478   g_return_if_fail (child->priv->parent != NULL);
10479   g_return_if_fail (child->priv->parent == self);
10480
10481   clutter_actor_remove_child_internal (self, child,
10482                                        REMOVE_CHILD_DEFAULT_FLAGS);
10483 }
10484
10485 /**
10486  * clutter_actor_remove_all_children:
10487  * @self: a #ClutterActor
10488  *
10489  * Removes all children of @self.
10490  *
10491  * This function releases the reference added by inserting a child actor
10492  * in the list of children of @self.
10493  *
10494  * If the reference count of a child drops to zero, the child will be
10495  * destroyed. If you want to ensure the destruction of all the children
10496  * of @self, use clutter_actor_destroy_all_children().
10497  *
10498  * Since: 1.10
10499  */
10500 void
10501 clutter_actor_remove_all_children (ClutterActor *self)
10502 {
10503   ClutterActorIter iter;
10504
10505   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10506
10507   if (self->priv->n_children == 0)
10508     return;
10509
10510   g_object_freeze_notify (G_OBJECT (self));
10511
10512   clutter_actor_iter_init (&iter, self);
10513   while (clutter_actor_iter_next (&iter, NULL))
10514     clutter_actor_iter_remove (&iter);
10515
10516   g_object_thaw_notify (G_OBJECT (self));
10517
10518   /* sanity check */
10519   g_assert (self->priv->first_child == NULL);
10520   g_assert (self->priv->last_child == NULL);
10521   g_assert (self->priv->n_children == 0);
10522 }
10523
10524 /**
10525  * clutter_actor_destroy_all_children:
10526  * @self: a #ClutterActor
10527  *
10528  * Destroys all children of @self.
10529  *
10530  * This function releases the reference added by inserting a child
10531  * actor in the list of children of @self, and ensures that the
10532  * #ClutterActor::destroy signal is emitted on each child of the
10533  * actor.
10534  *
10535  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10536  * when its reference count drops to 0; the default handler of the
10537  * #ClutterActor::destroy signal will destroy all the children of an
10538  * actor. This function ensures that all children are destroyed, instead
10539  * of just removed from @self, unlike clutter_actor_remove_all_children()
10540  * which will merely release the reference and remove each child.
10541  *
10542  * Unless you acquired an additional reference on each child of @self
10543  * prior to calling clutter_actor_remove_all_children() and want to reuse
10544  * the actors, you should use clutter_actor_destroy_all_children() in
10545  * order to make sure that children are destroyed and signal handlers
10546  * are disconnected even in cases where circular references prevent this
10547  * from automatically happening through reference counting alone.
10548  *
10549  * Since: 1.10
10550  */
10551 void
10552 clutter_actor_destroy_all_children (ClutterActor *self)
10553 {
10554   ClutterActorIter iter;
10555
10556   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10557
10558   if (self->priv->n_children == 0)
10559     return;
10560
10561   g_object_freeze_notify (G_OBJECT (self));
10562
10563   clutter_actor_iter_init (&iter, self);
10564   while (clutter_actor_iter_next (&iter, NULL))
10565     clutter_actor_iter_destroy (&iter);
10566
10567   g_object_thaw_notify (G_OBJECT (self));
10568
10569   /* sanity check */
10570   g_assert (self->priv->first_child == NULL);
10571   g_assert (self->priv->last_child == NULL);
10572   g_assert (self->priv->n_children == 0);
10573 }
10574
10575 typedef struct _InsertBetweenData {
10576   ClutterActor *prev_sibling;
10577   ClutterActor *next_sibling;
10578 } InsertBetweenData;
10579
10580 static void
10581 insert_child_between (ClutterActor *self,
10582                       ClutterActor *child,
10583                       gpointer      data_)
10584 {
10585   InsertBetweenData *data = data_;
10586   ClutterActor *prev_sibling = data->prev_sibling;
10587   ClutterActor *next_sibling = data->next_sibling;
10588
10589   child->priv->parent = self;
10590   child->priv->prev_sibling = prev_sibling;
10591   child->priv->next_sibling = next_sibling;
10592
10593   if (prev_sibling != NULL)
10594     prev_sibling->priv->next_sibling = child;
10595
10596   if (next_sibling != NULL)
10597     next_sibling->priv->prev_sibling = child;
10598
10599   if (child->priv->prev_sibling == NULL)
10600     self->priv->first_child = child;
10601
10602   if (child->priv->next_sibling == NULL)
10603     self->priv->last_child = child;
10604 }
10605
10606 /**
10607  * clutter_actor_replace_child:
10608  * @self: a #ClutterActor
10609  * @old_child: the child of @self to replace
10610  * @new_child: the #ClutterActor to replace @old_child
10611  *
10612  * Replaces @old_child with @new_child in the list of children of @self.
10613  *
10614  * Since: 1.10
10615  */
10616 void
10617 clutter_actor_replace_child (ClutterActor *self,
10618                              ClutterActor *old_child,
10619                              ClutterActor *new_child)
10620 {
10621   ClutterActor *prev_sibling, *next_sibling;
10622   InsertBetweenData clos;
10623
10624   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10625   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10626   g_return_if_fail (old_child->priv->parent == self);
10627   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10628   g_return_if_fail (old_child != new_child);
10629   g_return_if_fail (new_child != self);
10630   g_return_if_fail (new_child->priv->parent == NULL);
10631
10632   prev_sibling = old_child->priv->prev_sibling;
10633   next_sibling = old_child->priv->next_sibling;
10634   clutter_actor_remove_child_internal (self, old_child,
10635                                        REMOVE_CHILD_DEFAULT_FLAGS);
10636
10637   clos.prev_sibling = prev_sibling;
10638   clos.next_sibling = next_sibling;
10639   clutter_actor_add_child_internal (self, new_child,
10640                                     ADD_CHILD_DEFAULT_FLAGS,
10641                                     insert_child_between,
10642                                     &clos);
10643 }
10644
10645 /**
10646  * clutter_actor_unparent:
10647  * @self: a #ClutterActor
10648  *
10649  * Removes the parent of @self.
10650  *
10651  * This will cause the parent of @self to release the reference
10652  * acquired when calling clutter_actor_set_parent(), so if you
10653  * want to keep @self you will have to acquire a reference of
10654  * your own, through g_object_ref().
10655  *
10656  * This function should only be called by legacy #ClutterActor<!-- -->s
10657  * implementing the #ClutterContainer interface.
10658  *
10659  * Since: 0.1.1
10660  *
10661  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10662  */
10663 void
10664 clutter_actor_unparent (ClutterActor *self)
10665 {
10666   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10667
10668   if (self->priv->parent == NULL)
10669     return;
10670
10671   clutter_actor_remove_child_internal (self->priv->parent, self,
10672                                        REMOVE_CHILD_LEGACY_FLAGS);
10673 }
10674
10675 /**
10676  * clutter_actor_reparent:
10677  * @self: a #ClutterActor
10678  * @new_parent: the new #ClutterActor parent
10679  *
10680  * Resets the parent actor of @self.
10681  *
10682  * This function is logically equivalent to calling clutter_actor_unparent()
10683  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10684  * ensures the child is not finalized when unparented, and emits the
10685  * #ClutterActor::parent-set signal only once.
10686  *
10687  * In reality, calling this function is less useful than it sounds, as some
10688  * application code may rely on changes in the intermediate state between
10689  * removal and addition of the actor from its old parent to the @new_parent.
10690  * Thus, it is strongly encouraged to avoid using this function in application
10691  * code.
10692  *
10693  * Since: 0.2
10694  *
10695  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10696  *   clutter_actor_add_child() instead; remember to take a reference on
10697  *   the actor being removed before calling clutter_actor_remove_child()
10698  *   to avoid the reference count dropping to zero and the actor being
10699  *   destroyed.
10700  */
10701 void
10702 clutter_actor_reparent (ClutterActor *self,
10703                         ClutterActor *new_parent)
10704 {
10705   ClutterActorPrivate *priv;
10706
10707   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10708   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10709   g_return_if_fail (self != new_parent);
10710
10711   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10712     {
10713       g_warning ("Cannot set a parent on a toplevel actor");
10714       return;
10715     }
10716
10717   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10718     {
10719       g_warning ("Cannot set a parent currently being destroyed");
10720       return;
10721     }
10722
10723   priv = self->priv;
10724
10725   if (priv->parent != new_parent)
10726     {
10727       ClutterActor *old_parent;
10728
10729       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10730
10731       old_parent = priv->parent;
10732
10733       g_object_ref (self);
10734
10735       if (old_parent != NULL)
10736         {
10737          /* go through the Container implementation if this is a regular
10738           * child and not an internal one
10739           */
10740          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10741            {
10742              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10743
10744              /* this will have to call unparent() */
10745              clutter_container_remove_actor (parent, self);
10746            }
10747          else
10748            clutter_actor_remove_child_internal (old_parent, self,
10749                                                 REMOVE_CHILD_LEGACY_FLAGS);
10750         }
10751
10752       /* Note, will call set_parent() */
10753       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10754         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10755       else
10756         clutter_actor_add_child_internal (new_parent, self,
10757                                           ADD_CHILD_LEGACY_FLAGS,
10758                                           insert_child_at_depth,
10759                                           NULL);
10760
10761       /* we emit the ::parent-set signal once */
10762       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10763
10764       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10765
10766       /* the IN_REPARENT flag suspends state updates */
10767       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10768
10769       g_object_unref (self);
10770    }
10771 }
10772
10773 /**
10774  * clutter_actor_contains:
10775  * @self: A #ClutterActor
10776  * @descendant: A #ClutterActor, possibly contained in @self
10777  *
10778  * Determines if @descendant is contained inside @self (either as an
10779  * immediate child, or as a deeper descendant). If @self and
10780  * @descendant point to the same actor then it will also return %TRUE.
10781  *
10782  * Return value: whether @descendent is contained within @self
10783  *
10784  * Since: 1.4
10785  */
10786 gboolean
10787 clutter_actor_contains (ClutterActor *self,
10788                         ClutterActor *descendant)
10789 {
10790   ClutterActor *actor;
10791
10792   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10793   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10794
10795   for (actor = descendant; actor; actor = actor->priv->parent)
10796     if (actor == self)
10797       return TRUE;
10798
10799   return FALSE;
10800 }
10801
10802 /**
10803  * clutter_actor_set_child_above_sibling:
10804  * @self: a #ClutterActor
10805  * @child: a #ClutterActor child of @self
10806  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10807  *
10808  * Sets @child to be above @sibling in the list of children of @self.
10809  *
10810  * If @sibling is %NULL, @child will be the new last child of @self.
10811  *
10812  * This function is logically equivalent to removing @child and using
10813  * clutter_actor_insert_child_above(), but it will not emit signals
10814  * or change state on @child.
10815  *
10816  * Since: 1.10
10817  */
10818 void
10819 clutter_actor_set_child_above_sibling (ClutterActor *self,
10820                                        ClutterActor *child,
10821                                        ClutterActor *sibling)
10822 {
10823   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10824   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10825   g_return_if_fail (child->priv->parent == self);
10826   g_return_if_fail (child != sibling);
10827   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10828
10829   if (sibling != NULL)
10830     g_return_if_fail (sibling->priv->parent == self);
10831
10832   /* we don't want to change the state of child, or emit signals, or
10833    * regenerate ChildMeta instances here, but we still want to follow
10834    * the correct sequence of steps encoded in remove_child() and
10835    * add_child(), so that correctness is ensured, and we only go
10836    * through one known code path.
10837    */
10838   g_object_ref (child);
10839   clutter_actor_remove_child_internal (self, child, 0);
10840   clutter_actor_add_child_internal (self, child,
10841                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10842                                     insert_child_above,
10843                                     sibling);
10844
10845   clutter_actor_queue_relayout (self);
10846 }
10847
10848 /**
10849  * clutter_actor_set_child_below_sibling:
10850  * @self: a #ClutterActor
10851  * @child: a #ClutterActor child of @self
10852  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10853  *
10854  * Sets @child to be below @sibling in the list of children of @self.
10855  *
10856  * If @sibling is %NULL, @child will be the new first child of @self.
10857  *
10858  * This function is logically equivalent to removing @self and using
10859  * clutter_actor_insert_child_below(), but it will not emit signals
10860  * or change state on @child.
10861  *
10862  * Since: 1.10
10863  */
10864 void
10865 clutter_actor_set_child_below_sibling (ClutterActor *self,
10866                                        ClutterActor *child,
10867                                        ClutterActor *sibling)
10868 {
10869   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10870   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10871   g_return_if_fail (child->priv->parent == self);
10872   g_return_if_fail (child != sibling);
10873   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10874
10875   if (sibling != NULL)
10876     g_return_if_fail (sibling->priv->parent == self);
10877
10878   /* see the comment in set_child_above_sibling() */
10879   g_object_ref (child);
10880   clutter_actor_remove_child_internal (self, child, 0);
10881   clutter_actor_add_child_internal (self, child,
10882                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10883                                     insert_child_below,
10884                                     sibling);
10885
10886   clutter_actor_queue_relayout (self);
10887 }
10888
10889 /**
10890  * clutter_actor_set_child_at_index:
10891  * @self: a #ClutterActor
10892  * @child: a #ClutterActor child of @self
10893  * @index_: the new index for @child
10894  *
10895  * Changes the index of @child in the list of children of @self.
10896  *
10897  * This function is logically equivalent to removing @child and
10898  * calling clutter_actor_insert_child_at_index(), but it will not
10899  * emit signals or change state on @child.
10900  *
10901  * Since: 1.10
10902  */
10903 void
10904 clutter_actor_set_child_at_index (ClutterActor *self,
10905                                   ClutterActor *child,
10906                                   gint          index_)
10907 {
10908   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10909   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10910   g_return_if_fail (child->priv->parent == self);
10911   g_return_if_fail (index_ <= self->priv->n_children);
10912
10913   g_object_ref (child);
10914   clutter_actor_remove_child_internal (self, child, 0);
10915   clutter_actor_add_child_internal (self, child,
10916                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10917                                     insert_child_at_index,
10918                                     GINT_TO_POINTER (index_));
10919
10920   clutter_actor_queue_relayout (self);
10921 }
10922
10923 /**
10924  * clutter_actor_raise:
10925  * @self: A #ClutterActor
10926  * @below: (allow-none): A #ClutterActor to raise above.
10927  *
10928  * Puts @self above @below.
10929  *
10930  * Both actors must have the same parent, and the parent must implement
10931  * the #ClutterContainer interface
10932  *
10933  * This function calls clutter_container_raise_child() internally.
10934  *
10935  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
10936  */
10937 void
10938 clutter_actor_raise (ClutterActor *self,
10939                      ClutterActor *below)
10940 {
10941   ClutterActor *parent;
10942
10943   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10944
10945   parent = clutter_actor_get_parent (self);
10946   if (parent == NULL)
10947     {
10948       g_warning ("%s: Actor '%s' is not inside a container",
10949                  G_STRFUNC,
10950                  _clutter_actor_get_debug_name (self));
10951       return;
10952     }
10953
10954   if (below != NULL)
10955     {
10956       if (parent != clutter_actor_get_parent (below))
10957         {
10958           g_warning ("%s Actor '%s' is not in the same container as "
10959                      "actor '%s'",
10960                      G_STRFUNC,
10961                      _clutter_actor_get_debug_name (self),
10962                      _clutter_actor_get_debug_name (below));
10963           return;
10964         }
10965     }
10966
10967   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
10968 }
10969
10970 /**
10971  * clutter_actor_lower:
10972  * @self: A #ClutterActor
10973  * @above: (allow-none): A #ClutterActor to lower below
10974  *
10975  * Puts @self below @above.
10976  *
10977  * Both actors must have the same parent, and the parent must implement
10978  * the #ClutterContainer interface.
10979  *
10980  * This function calls clutter_container_lower_child() internally.
10981  *
10982  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
10983  */
10984 void
10985 clutter_actor_lower (ClutterActor *self,
10986                      ClutterActor *above)
10987 {
10988   ClutterActor *parent;
10989
10990   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10991
10992   parent = clutter_actor_get_parent (self);
10993   if (parent == NULL)
10994     {
10995       g_warning ("%s: Actor of type %s is not inside a container",
10996                  G_STRFUNC,
10997                  _clutter_actor_get_debug_name (self));
10998       return;
10999     }
11000
11001   if (above)
11002     {
11003       if (parent != clutter_actor_get_parent (above))
11004         {
11005           g_warning ("%s: Actor '%s' is not in the same container as "
11006                      "actor '%s'",
11007                      G_STRFUNC,
11008                      _clutter_actor_get_debug_name (self),
11009                      _clutter_actor_get_debug_name (above));
11010           return;
11011         }
11012     }
11013
11014   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11015 }
11016
11017 /**
11018  * clutter_actor_raise_top:
11019  * @self: A #ClutterActor
11020  *
11021  * Raises @self to the top.
11022  *
11023  * This function calls clutter_actor_raise() internally.
11024  *
11025  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11026  *   a %NULL sibling, instead.
11027  */
11028 void
11029 clutter_actor_raise_top (ClutterActor *self)
11030 {
11031   clutter_actor_raise (self, NULL);
11032 }
11033
11034 /**
11035  * clutter_actor_lower_bottom:
11036  * @self: A #ClutterActor
11037  *
11038  * Lowers @self to the bottom.
11039  *
11040  * This function calls clutter_actor_lower() internally.
11041  *
11042  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11043  *   a %NULL sibling, instead.
11044  */
11045 void
11046 clutter_actor_lower_bottom (ClutterActor *self)
11047 {
11048   clutter_actor_lower (self, NULL);
11049 }
11050
11051 /*
11052  * Event handling
11053  */
11054
11055 /**
11056  * clutter_actor_event:
11057  * @actor: a #ClutterActor
11058  * @event: a #ClutterEvent
11059  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11060  *
11061  * This function is used to emit an event on the main stage.
11062  * You should rarely need to use this function, except for
11063  * synthetising events.
11064  *
11065  * Return value: the return value from the signal emission: %TRUE
11066  *   if the actor handled the event, or %FALSE if the event was
11067  *   not handled
11068  *
11069  * Since: 0.6
11070  */
11071 gboolean
11072 clutter_actor_event (ClutterActor *actor,
11073                      ClutterEvent *event,
11074                      gboolean      capture)
11075 {
11076   gboolean retval = FALSE;
11077   gint signal_num = -1;
11078
11079   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11080   g_return_val_if_fail (event != NULL, FALSE);
11081
11082   g_object_ref (actor);
11083
11084   if (capture)
11085     {
11086       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11087                      event,
11088                      &retval);
11089       goto out;
11090     }
11091
11092   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11093
11094   if (!retval)
11095     {
11096       switch (event->type)
11097         {
11098         case CLUTTER_NOTHING:
11099           break;
11100         case CLUTTER_BUTTON_PRESS:
11101           signal_num = BUTTON_PRESS_EVENT;
11102           break;
11103         case CLUTTER_BUTTON_RELEASE:
11104           signal_num = BUTTON_RELEASE_EVENT;
11105           break;
11106         case CLUTTER_SCROLL:
11107           signal_num = SCROLL_EVENT;
11108           break;
11109         case CLUTTER_KEY_PRESS:
11110           signal_num = KEY_PRESS_EVENT;
11111           break;
11112         case CLUTTER_KEY_RELEASE:
11113           signal_num = KEY_RELEASE_EVENT;
11114           break;
11115         case CLUTTER_MOTION:
11116           signal_num = MOTION_EVENT;
11117           break;
11118         case CLUTTER_ENTER:
11119           signal_num = ENTER_EVENT;
11120           break;
11121         case CLUTTER_LEAVE:
11122           signal_num = LEAVE_EVENT;
11123           break;
11124         case CLUTTER_DELETE:
11125         case CLUTTER_DESTROY_NOTIFY:
11126         case CLUTTER_CLIENT_MESSAGE:
11127         default:
11128           signal_num = -1;
11129           break;
11130         }
11131
11132       if (signal_num != -1)
11133         g_signal_emit (actor, actor_signals[signal_num], 0,
11134                        event, &retval);
11135     }
11136
11137 out:
11138   g_object_unref (actor);
11139
11140   return retval;
11141 }
11142
11143 /**
11144  * clutter_actor_set_reactive:
11145  * @actor: a #ClutterActor
11146  * @reactive: whether the actor should be reactive to events
11147  *
11148  * Sets @actor as reactive. Reactive actors will receive events.
11149  *
11150  * Since: 0.6
11151  */
11152 void
11153 clutter_actor_set_reactive (ClutterActor *actor,
11154                             gboolean      reactive)
11155 {
11156   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11157
11158   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11159     return;
11160
11161   if (reactive)
11162     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11163   else
11164     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11165
11166   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11167 }
11168
11169 /**
11170  * clutter_actor_get_reactive:
11171  * @actor: a #ClutterActor
11172  *
11173  * Checks whether @actor is marked as reactive.
11174  *
11175  * Return value: %TRUE if the actor is reactive
11176  *
11177  * Since: 0.6
11178  */
11179 gboolean
11180 clutter_actor_get_reactive (ClutterActor *actor)
11181 {
11182   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11183
11184   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11185 }
11186
11187 /**
11188  * clutter_actor_get_anchor_point:
11189  * @self: a #ClutterActor
11190  * @anchor_x: (out): return location for the X coordinate of the anchor point
11191  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11192  *
11193  * Gets the current anchor point of the @actor in pixels.
11194  *
11195  * Since: 0.6
11196  */
11197 void
11198 clutter_actor_get_anchor_point (ClutterActor *self,
11199                                 gfloat       *anchor_x,
11200                                 gfloat       *anchor_y)
11201 {
11202   const ClutterTransformInfo *info;
11203
11204   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11205
11206   info = _clutter_actor_get_transform_info_or_defaults (self);
11207   clutter_anchor_coord_get_units (self, &info->anchor,
11208                                   anchor_x,
11209                                   anchor_y,
11210                                   NULL);
11211 }
11212
11213 /**
11214  * clutter_actor_set_anchor_point:
11215  * @self: a #ClutterActor
11216  * @anchor_x: X coordinate of the anchor point
11217  * @anchor_y: Y coordinate of the anchor point
11218  *
11219  * Sets an anchor point for @self. The anchor point is a point in the
11220  * coordinate space of an actor to which the actor position within its
11221  * parent is relative; the default is (0, 0), i.e. the top-left corner
11222  * of the actor.
11223  *
11224  * Since: 0.6
11225  */
11226 void
11227 clutter_actor_set_anchor_point (ClutterActor *self,
11228                                 gfloat        anchor_x,
11229                                 gfloat        anchor_y)
11230 {
11231   ClutterTransformInfo *info;
11232   ClutterActorPrivate *priv;
11233   gboolean changed = FALSE;
11234   gfloat old_anchor_x, old_anchor_y;
11235   GObject *obj;
11236
11237   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11238
11239   obj = G_OBJECT (self);
11240   priv = self->priv;
11241   info = _clutter_actor_get_transform_info (self);
11242
11243   g_object_freeze_notify (obj);
11244
11245   clutter_anchor_coord_get_units (self, &info->anchor,
11246                                   &old_anchor_x,
11247                                   &old_anchor_y,
11248                                   NULL);
11249
11250   if (info->anchor.is_fractional)
11251     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11252
11253   if (old_anchor_x != anchor_x)
11254     {
11255       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11256       changed = TRUE;
11257     }
11258
11259   if (old_anchor_y != anchor_y)
11260     {
11261       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11262       changed = TRUE;
11263     }
11264
11265   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11266
11267   if (changed)
11268     {
11269       priv->transform_valid = FALSE;
11270       clutter_actor_queue_redraw (self);
11271     }
11272
11273   g_object_thaw_notify (obj);
11274 }
11275
11276 /**
11277  * clutter_actor_get_anchor_point_gravity:
11278  * @self: a #ClutterActor
11279  *
11280  * Retrieves the anchor position expressed as a #ClutterGravity. If
11281  * the anchor point was specified using pixels or units this will
11282  * return %CLUTTER_GRAVITY_NONE.
11283  *
11284  * Return value: the #ClutterGravity used by the anchor point
11285  *
11286  * Since: 1.0
11287  */
11288 ClutterGravity
11289 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11290 {
11291   const ClutterTransformInfo *info;
11292
11293   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11294
11295   info = _clutter_actor_get_transform_info_or_defaults (self);
11296
11297   return clutter_anchor_coord_get_gravity (&info->anchor);
11298 }
11299
11300 /**
11301  * clutter_actor_move_anchor_point:
11302  * @self: a #ClutterActor
11303  * @anchor_x: X coordinate of the anchor point
11304  * @anchor_y: Y coordinate of the anchor point
11305  *
11306  * Sets an anchor point for the actor, and adjusts the actor postion so that
11307  * the relative position of the actor toward its parent remains the same.
11308  *
11309  * Since: 0.6
11310  */
11311 void
11312 clutter_actor_move_anchor_point (ClutterActor *self,
11313                                  gfloat        anchor_x,
11314                                  gfloat        anchor_y)
11315 {
11316   gfloat old_anchor_x, old_anchor_y;
11317   const ClutterTransformInfo *info;
11318
11319   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11320
11321   info = _clutter_actor_get_transform_info (self);
11322   clutter_anchor_coord_get_units (self, &info->anchor,
11323                                   &old_anchor_x,
11324                                   &old_anchor_y,
11325                                   NULL);
11326
11327   g_object_freeze_notify (G_OBJECT (self));
11328
11329   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11330
11331   if (self->priv->position_set)
11332     clutter_actor_move_by (self,
11333                            anchor_x - old_anchor_x,
11334                            anchor_y - old_anchor_y);
11335
11336   g_object_thaw_notify (G_OBJECT (self));
11337 }
11338
11339 /**
11340  * clutter_actor_move_anchor_point_from_gravity:
11341  * @self: a #ClutterActor
11342  * @gravity: #ClutterGravity.
11343  *
11344  * Sets an anchor point on the actor based on the given gravity, adjusting the
11345  * actor postion so that its relative position within its parent remains
11346  * unchanged.
11347  *
11348  * Since version 1.0 the anchor point will be stored as a gravity so
11349  * that if the actor changes size then the anchor point will move. For
11350  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11351  * and later double the size of the actor, the anchor point will move
11352  * to the bottom right.
11353  *
11354  * Since: 0.6
11355  */
11356 void
11357 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11358                                               ClutterGravity  gravity)
11359 {
11360   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11361   const ClutterTransformInfo *info;
11362   ClutterActorPrivate *priv;
11363
11364   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11365
11366   priv = self->priv;
11367   info = _clutter_actor_get_transform_info (self);
11368
11369   g_object_freeze_notify (G_OBJECT (self));
11370
11371   clutter_anchor_coord_get_units (self, &info->anchor,
11372                                   &old_anchor_x,
11373                                   &old_anchor_y,
11374                                   NULL);
11375   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11376   clutter_anchor_coord_get_units (self, &info->anchor,
11377                                   &new_anchor_x,
11378                                   &new_anchor_y,
11379                                   NULL);
11380
11381   if (priv->position_set)
11382     clutter_actor_move_by (self,
11383                            new_anchor_x - old_anchor_x,
11384                            new_anchor_y - old_anchor_y);
11385
11386   g_object_thaw_notify (G_OBJECT (self));
11387 }
11388
11389 /**
11390  * clutter_actor_set_anchor_point_from_gravity:
11391  * @self: a #ClutterActor
11392  * @gravity: #ClutterGravity.
11393  *
11394  * Sets an anchor point on the actor, based on the given gravity (this is a
11395  * convenience function wrapping clutter_actor_set_anchor_point()).
11396  *
11397  * Since version 1.0 the anchor point will be stored as a gravity so
11398  * that if the actor changes size then the anchor point will move. For
11399  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11400  * and later double the size of the actor, the anchor point will move
11401  * to the bottom right.
11402  *
11403  * Since: 0.6
11404  */
11405 void
11406 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11407                                              ClutterGravity  gravity)
11408 {
11409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11410
11411   if (gravity == CLUTTER_GRAVITY_NONE)
11412     clutter_actor_set_anchor_point (self, 0, 0);
11413   else
11414     {
11415       GObject *obj = G_OBJECT (self);
11416       ClutterTransformInfo *info;
11417
11418       g_object_freeze_notify (obj);
11419
11420       info = _clutter_actor_get_transform_info (self);
11421       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11422
11423       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11424       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11425       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11426
11427       self->priv->transform_valid = FALSE;
11428
11429       clutter_actor_queue_redraw (self);
11430
11431       g_object_thaw_notify (obj);
11432     }
11433 }
11434
11435 static void
11436 clutter_container_iface_init (ClutterContainerIface *iface)
11437 {
11438   /* we don't override anything, as ClutterContainer already has a default
11439    * implementation that we can use, and which calls into our own API.
11440    */
11441 }
11442
11443 typedef enum
11444 {
11445   PARSE_X,
11446   PARSE_Y,
11447   PARSE_WIDTH,
11448   PARSE_HEIGHT,
11449   PARSE_ANCHOR_X,
11450   PARSE_ANCHOR_Y
11451 } ParseDimension;
11452
11453 static gfloat
11454 parse_units (ClutterActor   *self,
11455              ParseDimension  dimension,
11456              JsonNode       *node)
11457 {
11458   GValue value = { 0, };
11459   gfloat retval = 0;
11460
11461   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11462     return 0;
11463
11464   json_node_get_value (node, &value);
11465
11466   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11467     {
11468       retval = (gfloat) g_value_get_int64 (&value);
11469     }
11470   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11471     {
11472       retval = g_value_get_double (&value);
11473     }
11474   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11475     {
11476       ClutterUnits units;
11477       gboolean res;
11478
11479       res = clutter_units_from_string (&units, g_value_get_string (&value));
11480       if (res)
11481         retval = clutter_units_to_pixels (&units);
11482       else
11483         {
11484           g_warning ("Invalid value '%s': integers, strings or floating point "
11485                      "values can be used for the x, y, width and height "
11486                      "properties. Valid modifiers for strings are 'px', 'mm', "
11487                      "'pt' and 'em'.",
11488                      g_value_get_string (&value));
11489           retval = 0;
11490         }
11491     }
11492   else
11493     {
11494       g_warning ("Invalid value of type '%s': integers, strings of floating "
11495                  "point values can be used for the x, y, width, height "
11496                  "anchor-x and anchor-y properties.",
11497                  g_type_name (G_VALUE_TYPE (&value)));
11498     }
11499
11500   g_value_unset (&value);
11501
11502   return retval;
11503 }
11504
11505 typedef struct {
11506   ClutterRotateAxis axis;
11507
11508   gdouble angle;
11509
11510   gfloat center_x;
11511   gfloat center_y;
11512   gfloat center_z;
11513 } RotationInfo;
11514
11515 static inline gboolean
11516 parse_rotation_array (ClutterActor *actor,
11517                       JsonArray    *array,
11518                       RotationInfo *info)
11519 {
11520   JsonNode *element;
11521
11522   if (json_array_get_length (array) != 2)
11523     return FALSE;
11524
11525   /* angle */
11526   element = json_array_get_element (array, 0);
11527   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11528     info->angle = json_node_get_double (element);
11529   else
11530     return FALSE;
11531
11532   /* center */
11533   element = json_array_get_element (array, 1);
11534   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11535     {
11536       JsonArray *center = json_node_get_array (element);
11537
11538       if (json_array_get_length (center) != 2)
11539         return FALSE;
11540
11541       switch (info->axis)
11542         {
11543         case CLUTTER_X_AXIS:
11544           info->center_y = parse_units (actor, PARSE_Y,
11545                                         json_array_get_element (center, 0));
11546           info->center_z = parse_units (actor, PARSE_Y,
11547                                         json_array_get_element (center, 1));
11548           return TRUE;
11549
11550         case CLUTTER_Y_AXIS:
11551           info->center_x = parse_units (actor, PARSE_X,
11552                                         json_array_get_element (center, 0));
11553           info->center_z = parse_units (actor, PARSE_X,
11554                                         json_array_get_element (center, 1));
11555           return TRUE;
11556
11557         case CLUTTER_Z_AXIS:
11558           info->center_x = parse_units (actor, PARSE_X,
11559                                         json_array_get_element (center, 0));
11560           info->center_y = parse_units (actor, PARSE_Y,
11561                                         json_array_get_element (center, 1));
11562           return TRUE;
11563         }
11564     }
11565
11566   return FALSE;
11567 }
11568
11569 static gboolean
11570 parse_rotation (ClutterActor *actor,
11571                 JsonNode     *node,
11572                 RotationInfo *info)
11573 {
11574   JsonArray *array;
11575   guint len, i;
11576   gboolean retval = FALSE;
11577
11578   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11579     {
11580       g_warning ("Invalid node of type '%s' found, expecting an array",
11581                  json_node_type_name (node));
11582       return FALSE;
11583     }
11584
11585   array = json_node_get_array (node);
11586   len = json_array_get_length (array);
11587
11588   for (i = 0; i < len; i++)
11589     {
11590       JsonNode *element = json_array_get_element (array, i);
11591       JsonObject *object;
11592       JsonNode *member;
11593
11594       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11595         {
11596           g_warning ("Invalid node of type '%s' found, expecting an object",
11597                      json_node_type_name (element));
11598           return FALSE;
11599         }
11600
11601       object = json_node_get_object (element);
11602
11603       if (json_object_has_member (object, "x-axis"))
11604         {
11605           member = json_object_get_member (object, "x-axis");
11606
11607           info->axis = CLUTTER_X_AXIS;
11608
11609           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11610             {
11611               info->angle = json_node_get_double (member);
11612               retval = TRUE;
11613             }
11614           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11615             retval = parse_rotation_array (actor,
11616                                            json_node_get_array (member),
11617                                            info);
11618           else
11619             retval = FALSE;
11620         }
11621       else if (json_object_has_member (object, "y-axis"))
11622         {
11623           member = json_object_get_member (object, "y-axis");
11624
11625           info->axis = CLUTTER_Y_AXIS;
11626
11627           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11628             {
11629               info->angle = json_node_get_double (member);
11630               retval = TRUE;
11631             }
11632           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11633             retval = parse_rotation_array (actor,
11634                                            json_node_get_array (member),
11635                                            info);
11636           else
11637             retval = FALSE;
11638         }
11639       else if (json_object_has_member (object, "z-axis"))
11640         {
11641           member = json_object_get_member (object, "z-axis");
11642
11643           info->axis = CLUTTER_Z_AXIS;
11644
11645           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11646             {
11647               info->angle = json_node_get_double (member);
11648               retval = TRUE;
11649             }
11650           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11651             retval = parse_rotation_array (actor,
11652                                            json_node_get_array (member),
11653                                            info);
11654           else
11655             retval = FALSE;
11656         }
11657     }
11658
11659   return retval;
11660 }
11661
11662 static GSList *
11663 parse_actor_metas (ClutterScript *script,
11664                    ClutterActor  *actor,
11665                    JsonNode      *node)
11666 {
11667   GList *elements, *l;
11668   GSList *retval = NULL;
11669
11670   if (!JSON_NODE_HOLDS_ARRAY (node))
11671     return NULL;
11672
11673   elements = json_array_get_elements (json_node_get_array (node));
11674
11675   for (l = elements; l != NULL; l = l->next)
11676     {
11677       JsonNode *element = l->data;
11678       const gchar *id_ = _clutter_script_get_id_from_node (element);
11679       GObject *meta;
11680
11681       if (id_ == NULL || *id_ == '\0')
11682         continue;
11683
11684       meta = clutter_script_get_object (script, id_);
11685       if (meta == NULL)
11686         continue;
11687
11688       retval = g_slist_prepend (retval, meta);
11689     }
11690
11691   g_list_free (elements);
11692
11693   return g_slist_reverse (retval);
11694 }
11695
11696 static GSList *
11697 parse_behaviours (ClutterScript *script,
11698                   ClutterActor  *actor,
11699                   JsonNode      *node)
11700 {
11701   GList *elements, *l;
11702   GSList *retval = NULL;
11703
11704   if (!JSON_NODE_HOLDS_ARRAY (node))
11705     return NULL;
11706
11707   elements = json_array_get_elements (json_node_get_array (node));
11708
11709   for (l = elements; l != NULL; l = l->next)
11710     {
11711       JsonNode *element = l->data;
11712       const gchar *id_ = _clutter_script_get_id_from_node (element);
11713       GObject *behaviour;
11714
11715       if (id_ == NULL || *id_ == '\0')
11716         continue;
11717
11718       behaviour = clutter_script_get_object (script, id_);
11719       if (behaviour == NULL)
11720         continue;
11721
11722       retval = g_slist_prepend (retval, behaviour);
11723     }
11724
11725   g_list_free (elements);
11726
11727   return g_slist_reverse (retval);
11728 }
11729
11730 static gboolean
11731 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11732                                  ClutterScript     *script,
11733                                  GValue            *value,
11734                                  const gchar       *name,
11735                                  JsonNode          *node)
11736 {
11737   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11738   gboolean retval = FALSE;
11739
11740   if ((name[0] == 'x' && name[1] == '\0') ||
11741       (name[0] == 'y' && name[1] == '\0') ||
11742       (strcmp (name, "width") == 0) ||
11743       (strcmp (name, "height") == 0) ||
11744       (strcmp (name, "anchor_x") == 0) ||
11745       (strcmp (name, "anchor_y") == 0))
11746     {
11747       ParseDimension dimension;
11748       gfloat units;
11749
11750       if (name[0] == 'x')
11751         dimension = PARSE_X;
11752       else if (name[0] == 'y')
11753         dimension = PARSE_Y;
11754       else if (name[0] == 'w')
11755         dimension = PARSE_WIDTH;
11756       else if (name[0] == 'h')
11757         dimension = PARSE_HEIGHT;
11758       else if (name[0] == 'a' && name[7] == 'x')
11759         dimension = PARSE_ANCHOR_X;
11760       else if (name[0] == 'a' && name[7] == 'y')
11761         dimension = PARSE_ANCHOR_Y;
11762       else
11763         return FALSE;
11764
11765       units = parse_units (actor, dimension, node);
11766
11767       /* convert back to pixels: all properties are pixel-based */
11768       g_value_init (value, G_TYPE_FLOAT);
11769       g_value_set_float (value, units);
11770
11771       retval = TRUE;
11772     }
11773   else if (strcmp (name, "rotation") == 0)
11774     {
11775       RotationInfo *info;
11776
11777       info = g_slice_new0 (RotationInfo);
11778       retval = parse_rotation (actor, node, info);
11779
11780       if (retval)
11781         {
11782           g_value_init (value, G_TYPE_POINTER);
11783           g_value_set_pointer (value, info);
11784         }
11785       else
11786         g_slice_free (RotationInfo, info);
11787     }
11788   else if (strcmp (name, "behaviours") == 0)
11789     {
11790       GSList *l;
11791
11792 #ifdef CLUTTER_ENABLE_DEBUG
11793       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11794         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11795                                      "and it should not be used in newly "
11796                                      "written ClutterScript definitions.");
11797 #endif
11798
11799       l = parse_behaviours (script, actor, node);
11800
11801       g_value_init (value, G_TYPE_POINTER);
11802       g_value_set_pointer (value, l);
11803
11804       retval = TRUE;
11805     }
11806   else if (strcmp (name, "actions") == 0 ||
11807            strcmp (name, "constraints") == 0 ||
11808            strcmp (name, "effects") == 0)
11809     {
11810       GSList *l;
11811
11812       l = parse_actor_metas (script, actor, node);
11813
11814       g_value_init (value, G_TYPE_POINTER);
11815       g_value_set_pointer (value, l);
11816
11817       retval = TRUE;
11818     }
11819
11820   return retval;
11821 }
11822
11823 static void
11824 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11825                                    ClutterScript     *script,
11826                                    const gchar       *name,
11827                                    const GValue      *value)
11828 {
11829   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11830
11831 #ifdef CLUTTER_ENABLE_DEBUG
11832   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11833     {
11834       gchar *tmp = g_strdup_value_contents (value);
11835
11836       CLUTTER_NOTE (SCRIPT,
11837                     "in ClutterActor::set_custom_property('%s') = %s",
11838                     name,
11839                     tmp);
11840
11841       g_free (tmp);
11842     }
11843 #endif /* CLUTTER_ENABLE_DEBUG */
11844
11845   if (strcmp (name, "rotation") == 0)
11846     {
11847       RotationInfo *info;
11848
11849       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11850         return;
11851
11852       info = g_value_get_pointer (value);
11853
11854       clutter_actor_set_rotation (actor,
11855                                   info->axis, info->angle,
11856                                   info->center_x,
11857                                   info->center_y,
11858                                   info->center_z);
11859
11860       g_slice_free (RotationInfo, info);
11861
11862       return;
11863     }
11864
11865   if (strcmp (name, "behaviours") == 0)
11866     {
11867       GSList *behaviours, *l;
11868
11869       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11870         return;
11871
11872       behaviours = g_value_get_pointer (value);
11873       for (l = behaviours; l != NULL; l = l->next)
11874         {
11875           ClutterBehaviour *behaviour = l->data;
11876
11877           clutter_behaviour_apply (behaviour, actor);
11878         }
11879
11880       g_slist_free (behaviours);
11881
11882       return;
11883     }
11884
11885   if (strcmp (name, "actions") == 0 ||
11886       strcmp (name, "constraints") == 0 ||
11887       strcmp (name, "effects") == 0)
11888     {
11889       GSList *metas, *l;
11890
11891       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11892         return;
11893
11894       metas = g_value_get_pointer (value);
11895       for (l = metas; l != NULL; l = l->next)
11896         {
11897           if (name[0] == 'a')
11898             clutter_actor_add_action (actor, l->data);
11899
11900           if (name[0] == 'c')
11901             clutter_actor_add_constraint (actor, l->data);
11902
11903           if (name[0] == 'e')
11904             clutter_actor_add_effect (actor, l->data);
11905         }
11906
11907       g_slist_free (metas);
11908
11909       return;
11910     }
11911
11912   g_object_set_property (G_OBJECT (scriptable), name, value);
11913 }
11914
11915 static void
11916 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
11917 {
11918   iface->parse_custom_node = clutter_actor_parse_custom_node;
11919   iface->set_custom_property = clutter_actor_set_custom_property;
11920 }
11921
11922 static ClutterActorMeta *
11923 get_meta_from_animation_property (ClutterActor  *actor,
11924                                   const gchar   *name,
11925                                   gchar        **name_p)
11926 {
11927   ClutterActorPrivate *priv = actor->priv;
11928   ClutterActorMeta *meta = NULL;
11929   gchar **tokens;
11930
11931   /* if this is not a special property, fall through */
11932   if (name[0] != '@')
11933     return NULL;
11934
11935   /* detect the properties named using the following spec:
11936    *
11937    *   @<section>.<meta-name>.<property-name>
11938    *
11939    * where <section> can be one of the following:
11940    *
11941    *   - actions
11942    *   - constraints
11943    *   - effects
11944    *
11945    * and <meta-name> is the name set on a specific ActorMeta
11946    */
11947
11948   tokens = g_strsplit (name + 1, ".", -1);
11949   if (tokens == NULL || g_strv_length (tokens) != 3)
11950     {
11951       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
11952                     name + 1);
11953       g_strfreev (tokens);
11954       return NULL;
11955     }
11956
11957   if (strcmp (tokens[0], "actions") == 0)
11958     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
11959
11960   if (strcmp (tokens[0], "constraints") == 0)
11961     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
11962
11963   if (strcmp (tokens[0], "effects") == 0)
11964     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
11965
11966   if (name_p != NULL)
11967     *name_p = g_strdup (tokens[2]);
11968
11969   CLUTTER_NOTE (ANIMATION,
11970                 "Looking for property '%s' of object '%s' in section '%s'",
11971                 tokens[2],
11972                 tokens[1],
11973                 tokens[0]);
11974
11975   g_strfreev (tokens);
11976
11977   return meta;
11978 }
11979
11980 static GParamSpec *
11981 clutter_actor_find_property (ClutterAnimatable *animatable,
11982                              const gchar       *property_name)
11983 {
11984   ClutterActorMeta *meta = NULL;
11985   GObjectClass *klass = NULL;
11986   GParamSpec *pspec = NULL;
11987   gchar *p_name = NULL;
11988
11989   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11990                                            property_name,
11991                                            &p_name);
11992
11993   if (meta != NULL)
11994     {
11995       klass = G_OBJECT_GET_CLASS (meta);
11996
11997       pspec = g_object_class_find_property (klass, p_name);
11998     }
11999   else
12000     {
12001       klass = G_OBJECT_GET_CLASS (animatable);
12002
12003       pspec = g_object_class_find_property (klass, property_name);
12004     }
12005
12006   g_free (p_name);
12007
12008   return pspec;
12009 }
12010
12011 static void
12012 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12013                                  const gchar       *property_name,
12014                                  GValue            *initial)
12015 {
12016   ClutterActorMeta *meta = NULL;
12017   gchar *p_name = NULL;
12018
12019   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12020                                            property_name,
12021                                            &p_name);
12022
12023   if (meta != NULL)
12024     g_object_get_property (G_OBJECT (meta), p_name, initial);
12025   else
12026     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12027
12028   g_free (p_name);
12029 }
12030
12031 static void
12032 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12033                                const gchar       *property_name,
12034                                const GValue      *final)
12035 {
12036   ClutterActorMeta *meta = NULL;
12037   gchar *p_name = NULL;
12038
12039   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12040                                            property_name,
12041                                            &p_name);
12042   if (meta != NULL)
12043     g_object_set_property (G_OBJECT (meta), p_name, final);
12044   else
12045     g_object_set_property (G_OBJECT (animatable), property_name, final);
12046
12047   g_free (p_name);
12048 }
12049
12050 static void
12051 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12052 {
12053   iface->find_property = clutter_actor_find_property;
12054   iface->get_initial_state = clutter_actor_get_initial_state;
12055   iface->set_final_state = clutter_actor_set_final_state;
12056 }
12057
12058 /**
12059  * clutter_actor_transform_stage_point:
12060  * @self: A #ClutterActor
12061  * @x: (in): x screen coordinate of the point to unproject
12062  * @y: (in): y screen coordinate of the point to unproject
12063  * @x_out: (out): return location for the unprojected x coordinance
12064  * @y_out: (out): return location for the unprojected y coordinance
12065  *
12066  * This function translates screen coordinates (@x, @y) to
12067  * coordinates relative to the actor. For example, it can be used to translate
12068  * screen events from global screen coordinates into actor-local coordinates.
12069  *
12070  * The conversion can fail, notably if the transform stack results in the
12071  * actor being projected on the screen as a mere line.
12072  *
12073  * The conversion should not be expected to be pixel-perfect due to the
12074  * nature of the operation. In general the error grows when the skewing
12075  * of the actor rectangle on screen increases.
12076  *
12077  * <note><para>This function can be computationally intensive.</para></note>
12078  *
12079  * <note><para>This function only works when the allocation is up-to-date,
12080  * i.e. inside of paint().</para></note>
12081  *
12082  * Return value: %TRUE if conversion was successful.
12083  *
12084  * Since: 0.6
12085  */
12086 gboolean
12087 clutter_actor_transform_stage_point (ClutterActor *self,
12088                                      gfloat        x,
12089                                      gfloat        y,
12090                                      gfloat       *x_out,
12091                                      gfloat       *y_out)
12092 {
12093   ClutterVertex v[4];
12094   float ST[3][3];
12095   float RQ[3][3];
12096   int du, dv, xi, yi;
12097   float px, py;
12098   float xf, yf, wf, det;
12099   ClutterActorPrivate *priv;
12100
12101   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12102
12103   priv = self->priv;
12104
12105   /* This implementation is based on the quad -> quad projection algorithm
12106    * described by Paul Heckbert in:
12107    *
12108    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12109    *
12110    * and the sample implementation at:
12111    *
12112    *   http://www.cs.cmu.edu/~ph/src/texfund/
12113    *
12114    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12115    * quad to rectangle only, which significantly simplifies things; the
12116    * function calls have been unrolled, and most of the math is done in fixed
12117    * point.
12118    */
12119
12120   clutter_actor_get_abs_allocation_vertices (self, v);
12121
12122   /* Keeping these as ints simplifies the multiplication (no significant
12123    * loss of precision here).
12124    */
12125   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12126   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12127
12128   if (!du || !dv)
12129     return FALSE;
12130
12131 #define UX2FP(x)        (x)
12132 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12133
12134   /* First, find mapping from unit uv square to xy quadrilateral; this
12135    * equivalent to the pmap_square_quad() functions in the sample
12136    * implementation, which we can simplify, since our target is always
12137    * a rectangle.
12138    */
12139   px = v[0].x - v[1].x + v[3].x - v[2].x;
12140   py = v[0].y - v[1].y + v[3].y - v[2].y;
12141
12142   if (!px && !py)
12143     {
12144       /* affine transform */
12145       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12146       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12147       RQ[2][0] = UX2FP (v[0].x);
12148       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12149       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12150       RQ[2][1] = UX2FP (v[0].y);
12151       RQ[0][2] = 0;
12152       RQ[1][2] = 0;
12153       RQ[2][2] = 1.0;
12154     }
12155   else
12156     {
12157       /* projective transform */
12158       double dx1, dx2, dy1, dy2, del;
12159
12160       dx1 = UX2FP (v[1].x - v[3].x);
12161       dx2 = UX2FP (v[2].x - v[3].x);
12162       dy1 = UX2FP (v[1].y - v[3].y);
12163       dy2 = UX2FP (v[2].y - v[3].y);
12164
12165       del = DET2FP (dx1, dx2, dy1, dy2);
12166       if (!del)
12167         return FALSE;
12168
12169       /*
12170        * The division here needs to be done in floating point for
12171        * precisions reasons.
12172        */
12173       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12174       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12175       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12176       RQ[2][2] = 1.0;
12177       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12178       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12179       RQ[2][0] = UX2FP (v[0].x);
12180       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12181       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12182       RQ[2][1] = UX2FP (v[0].y);
12183     }
12184
12185   /*
12186    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12187    * square. Since our rectangle is based at 0,0 we only need to scale.
12188    */
12189   RQ[0][0] /= du;
12190   RQ[1][0] /= dv;
12191   RQ[0][1] /= du;
12192   RQ[1][1] /= dv;
12193   RQ[0][2] /= du;
12194   RQ[1][2] /= dv;
12195
12196   /*
12197    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12198    * inverse of that.
12199    */
12200   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12201   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12202   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12203   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12204   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12205   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12206   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12207   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12208   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12209
12210   /*
12211    * Check the resulting matrix is OK.
12212    */
12213   det = (RQ[0][0] * ST[0][0])
12214       + (RQ[0][1] * ST[0][1])
12215       + (RQ[0][2] * ST[0][2]);
12216   if (!det)
12217     return FALSE;
12218
12219   /*
12220    * Now transform our point with the ST matrix; the notional w
12221    * coordinate is 1, hence the last part is simply added.
12222    */
12223   xi = (int) x;
12224   yi = (int) y;
12225
12226   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12227   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12228   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12229
12230   if (x_out)
12231     *x_out = xf / wf;
12232
12233   if (y_out)
12234     *y_out = yf / wf;
12235
12236 #undef UX2FP
12237 #undef DET2FP
12238
12239   return TRUE;
12240 }
12241
12242 /*
12243  * ClutterGeometry
12244  */
12245
12246 static ClutterGeometry*
12247 clutter_geometry_copy (const ClutterGeometry *geometry)
12248 {
12249   return g_slice_dup (ClutterGeometry, geometry);
12250 }
12251
12252 static void
12253 clutter_geometry_free (ClutterGeometry *geometry)
12254 {
12255   if (G_LIKELY (geometry != NULL))
12256     g_slice_free (ClutterGeometry, geometry);
12257 }
12258
12259 /**
12260  * clutter_geometry_union:
12261  * @geometry_a: a #ClutterGeometry
12262  * @geometry_b: another #ClutterGeometry
12263  * @result: (out): location to store the result
12264  *
12265  * Find the union of two rectangles represented as #ClutterGeometry.
12266  *
12267  * Since: 1.4
12268  */
12269 void
12270 clutter_geometry_union (const ClutterGeometry *geometry_a,
12271                         const ClutterGeometry *geometry_b,
12272                         ClutterGeometry       *result)
12273 {
12274   /* We don't try to handle rectangles that can't be represented
12275    * as a signed integer box */
12276   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12277   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12278   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12279                   geometry_b->x + (gint)geometry_b->width);
12280   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12281                   geometry_b->y + (gint)geometry_b->height);
12282   result->x = x_1;
12283   result->y = y_1;
12284   result->width = x_2 - x_1;
12285   result->height = y_2 - y_1;
12286 }
12287
12288 /**
12289  * clutter_geometry_intersects:
12290  * @geometry0: The first geometry to test
12291  * @geometry1: The second geometry to test
12292  *
12293  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12294  * they do else %FALSE.
12295  *
12296  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12297  * %FALSE.
12298  *
12299  * Since: 1.4
12300  */
12301 gboolean
12302 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12303                              const ClutterGeometry *geometry1)
12304 {
12305   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12306       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12307       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12308       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12309     return FALSE;
12310   else
12311     return TRUE;
12312 }
12313
12314 static gboolean
12315 clutter_geometry_progress (const GValue *a,
12316                            const GValue *b,
12317                            gdouble       progress,
12318                            GValue       *retval)
12319 {
12320   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12321   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12322   ClutterGeometry res = { 0, };
12323   gint a_width = a_geom->width;
12324   gint b_width = b_geom->width;
12325   gint a_height = a_geom->height;
12326   gint b_height = b_geom->height;
12327
12328   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12329   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12330
12331   res.width = a_width + (b_width - a_width) * progress;
12332   res.height = a_height + (b_height - a_height) * progress;
12333
12334   g_value_set_boxed (retval, &res);
12335
12336   return TRUE;
12337 }
12338
12339 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12340                                clutter_geometry_copy,
12341                                clutter_geometry_free,
12342                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12343
12344 /*
12345  * ClutterVertices
12346  */
12347
12348 /**
12349  * clutter_vertex_new:
12350  * @x: X coordinate
12351  * @y: Y coordinate
12352  * @z: Z coordinate
12353  *
12354  * Creates a new #ClutterVertex for the point in 3D space
12355  * identified by the 3 coordinates @x, @y, @z
12356  *
12357  * Return value: the newly allocate #ClutterVertex. Use
12358  *   clutter_vertex_free() to free the resources
12359  *
12360  * Since: 1.0
12361  */
12362 ClutterVertex *
12363 clutter_vertex_new (gfloat x,
12364                     gfloat y,
12365                     gfloat z)
12366 {
12367   ClutterVertex *vertex;
12368
12369   vertex = g_slice_new (ClutterVertex);
12370   vertex->x = x;
12371   vertex->y = y;
12372   vertex->z = z;
12373
12374   return vertex;
12375 }
12376
12377 /**
12378  * clutter_vertex_copy:
12379  * @vertex: a #ClutterVertex
12380  *
12381  * Copies @vertex
12382  *
12383  * Return value: a newly allocated copy of #ClutterVertex. Use
12384  *   clutter_vertex_free() to free the allocated resources
12385  *
12386  * Since: 1.0
12387  */
12388 ClutterVertex *
12389 clutter_vertex_copy (const ClutterVertex *vertex)
12390 {
12391   if (G_LIKELY (vertex != NULL))
12392     return g_slice_dup (ClutterVertex, vertex);
12393
12394   return NULL;
12395 }
12396
12397 /**
12398  * clutter_vertex_free:
12399  * @vertex: a #ClutterVertex
12400  *
12401  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12402  *
12403  * Since: 1.0
12404  */
12405 void
12406 clutter_vertex_free (ClutterVertex *vertex)
12407 {
12408   if (G_UNLIKELY (vertex != NULL))
12409     g_slice_free (ClutterVertex, vertex);
12410 }
12411
12412 /**
12413  * clutter_vertex_equal:
12414  * @vertex_a: a #ClutterVertex
12415  * @vertex_b: a #ClutterVertex
12416  *
12417  * Compares @vertex_a and @vertex_b for equality
12418  *
12419  * Return value: %TRUE if the passed #ClutterVertex are equal
12420  *
12421  * Since: 1.0
12422  */
12423 gboolean
12424 clutter_vertex_equal (const ClutterVertex *vertex_a,
12425                       const ClutterVertex *vertex_b)
12426 {
12427   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12428
12429   if (vertex_a == vertex_b)
12430     return TRUE;
12431
12432   return vertex_a->x == vertex_b->x &&
12433          vertex_a->y == vertex_b->y &&
12434          vertex_a->z == vertex_b->z;
12435 }
12436
12437 static gboolean
12438 clutter_vertex_progress (const GValue *a,
12439                          const GValue *b,
12440                          gdouble       progress,
12441                          GValue       *retval)
12442 {
12443   const ClutterVertex *av = g_value_get_boxed (a);
12444   const ClutterVertex *bv = g_value_get_boxed (b);
12445   ClutterVertex res = { 0, };
12446
12447   res.x = av->x + (bv->x - av->x) * progress;
12448   res.y = av->y + (bv->y - av->y) * progress;
12449   res.z = av->z + (bv->z - av->z) * progress;
12450
12451   g_value_set_boxed (retval, &res);
12452
12453   return TRUE;
12454 }
12455
12456 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12457                                clutter_vertex_copy,
12458                                clutter_vertex_free,
12459                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12460
12461 /**
12462  * clutter_actor_is_rotated:
12463  * @self: a #ClutterActor
12464  *
12465  * Checks whether any rotation is applied to the actor.
12466  *
12467  * Return value: %TRUE if the actor is rotated.
12468  *
12469  * Since: 0.6
12470  */
12471 gboolean
12472 clutter_actor_is_rotated (ClutterActor *self)
12473 {
12474   const ClutterTransformInfo *info;
12475
12476   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12477
12478   info = _clutter_actor_get_transform_info_or_defaults (self);
12479
12480   if (info->rx_angle || info->ry_angle || info->rz_angle)
12481     return TRUE;
12482
12483   return FALSE;
12484 }
12485
12486 /**
12487  * clutter_actor_is_scaled:
12488  * @self: a #ClutterActor
12489  *
12490  * Checks whether the actor is scaled in either dimension.
12491  *
12492  * Return value: %TRUE if the actor is scaled.
12493  *
12494  * Since: 0.6
12495  */
12496 gboolean
12497 clutter_actor_is_scaled (ClutterActor *self)
12498 {
12499   const ClutterTransformInfo *info;
12500
12501   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12502
12503   info = _clutter_actor_get_transform_info_or_defaults (self);
12504
12505   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12506     return TRUE;
12507
12508   return FALSE;
12509 }
12510
12511 ClutterActor *
12512 _clutter_actor_get_stage_internal (ClutterActor *actor)
12513 {
12514   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12515     actor = actor->priv->parent;
12516
12517   return actor;
12518 }
12519
12520 /**
12521  * clutter_actor_get_stage:
12522  * @actor: a #ClutterActor
12523  *
12524  * Retrieves the #ClutterStage where @actor is contained.
12525  *
12526  * Return value: (transfer none) (type Clutter.Stage): the stage
12527  *   containing the actor, or %NULL
12528  *
12529  * Since: 0.8
12530  */
12531 ClutterActor *
12532 clutter_actor_get_stage (ClutterActor *actor)
12533 {
12534   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12535
12536   return _clutter_actor_get_stage_internal (actor);
12537 }
12538
12539 /**
12540  * clutter_actor_allocate_available_size:
12541  * @self: a #ClutterActor
12542  * @x: the actor's X coordinate
12543  * @y: the actor's Y coordinate
12544  * @available_width: the maximum available width, or -1 to use the
12545  *   actor's natural width
12546  * @available_height: the maximum available height, or -1 to use the
12547  *   actor's natural height
12548  * @flags: flags controlling the allocation
12549  *
12550  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12551  * preferred size, but limiting it to the maximum available width
12552  * and height provided.
12553  *
12554  * This function will do the right thing when dealing with the
12555  * actor's request mode.
12556  *
12557  * The implementation of this function is equivalent to:
12558  *
12559  * |[
12560  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12561  *     {
12562  *       clutter_actor_get_preferred_width (self, available_height,
12563  *                                          &amp;min_width,
12564  *                                          &amp;natural_width);
12565  *       width = CLAMP (natural_width, min_width, available_width);
12566  *
12567  *       clutter_actor_get_preferred_height (self, width,
12568  *                                           &amp;min_height,
12569  *                                           &amp;natural_height);
12570  *       height = CLAMP (natural_height, min_height, available_height);
12571  *     }
12572  *   else
12573  *     {
12574  *       clutter_actor_get_preferred_height (self, available_width,
12575  *                                           &amp;min_height,
12576  *                                           &amp;natural_height);
12577  *       height = CLAMP (natural_height, min_height, available_height);
12578  *
12579  *       clutter_actor_get_preferred_width (self, height,
12580  *                                          &amp;min_width,
12581  *                                          &amp;natural_width);
12582  *       width = CLAMP (natural_width, min_width, available_width);
12583  *     }
12584  *
12585  *   box.x1 = x; box.y1 = y;
12586  *   box.x2 = box.x1 + available_width;
12587  *   box.y2 = box.y1 + available_height;
12588  *   clutter_actor_allocate (self, &amp;box, flags);
12589  * ]|
12590  *
12591  * This function can be used by fluid layout managers to allocate
12592  * an actor's preferred size without making it bigger than the area
12593  * available for the container.
12594  *
12595  * Since: 1.0
12596  */
12597 void
12598 clutter_actor_allocate_available_size (ClutterActor           *self,
12599                                        gfloat                  x,
12600                                        gfloat                  y,
12601                                        gfloat                  available_width,
12602                                        gfloat                  available_height,
12603                                        ClutterAllocationFlags  flags)
12604 {
12605   ClutterActorPrivate *priv;
12606   gfloat width, height;
12607   gfloat min_width, min_height;
12608   gfloat natural_width, natural_height;
12609   ClutterActorBox box;
12610
12611   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12612
12613   priv = self->priv;
12614
12615   width = height = 0.0;
12616
12617   switch (priv->request_mode)
12618     {
12619     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12620       clutter_actor_get_preferred_width (self, available_height,
12621                                          &min_width,
12622                                          &natural_width);
12623       width  = CLAMP (natural_width, min_width, available_width);
12624
12625       clutter_actor_get_preferred_height (self, width,
12626                                           &min_height,
12627                                           &natural_height);
12628       height = CLAMP (natural_height, min_height, available_height);
12629       break;
12630
12631     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12632       clutter_actor_get_preferred_height (self, available_width,
12633                                           &min_height,
12634                                           &natural_height);
12635       height = CLAMP (natural_height, min_height, available_height);
12636
12637       clutter_actor_get_preferred_width (self, height,
12638                                          &min_width,
12639                                          &natural_width);
12640       width  = CLAMP (natural_width, min_width, available_width);
12641       break;
12642     }
12643
12644
12645   box.x1 = x;
12646   box.y1 = y;
12647   box.x2 = box.x1 + width;
12648   box.y2 = box.y1 + height;
12649   clutter_actor_allocate (self, &box, flags);
12650 }
12651
12652 /**
12653  * clutter_actor_allocate_preferred_size:
12654  * @self: a #ClutterActor
12655  * @flags: flags controlling the allocation
12656  *
12657  * Allocates the natural size of @self.
12658  *
12659  * This function is a utility call for #ClutterActor implementations
12660  * that allocates the actor's preferred natural size. It can be used
12661  * by fixed layout managers (like #ClutterGroup or so called
12662  * 'composite actors') inside the ClutterActor::allocate
12663  * implementation to give each child exactly how much space it
12664  * requires.
12665  *
12666  * This function is not meant to be used by applications. It is also
12667  * not meant to be used outside the implementation of the
12668  * ClutterActor::allocate virtual function.
12669  *
12670  * Since: 0.8
12671  */
12672 void
12673 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12674                                        ClutterAllocationFlags  flags)
12675 {
12676   gfloat actor_x, actor_y;
12677   gfloat natural_width, natural_height;
12678   ClutterActorBox actor_box;
12679
12680   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12681
12682   actor_x = clutter_actor_get_x (self);
12683   actor_y = clutter_actor_get_y (self);
12684
12685   clutter_actor_get_preferred_size (self,
12686                                     NULL, NULL,
12687                                     &natural_width,
12688                                     &natural_height);
12689
12690   actor_box.x1 = actor_x;
12691   actor_box.y1 = actor_y;
12692   actor_box.x2 = actor_box.x1 + natural_width;
12693   actor_box.y2 = actor_box.y1 + natural_height;
12694
12695   clutter_actor_allocate (self, &actor_box, flags);
12696 }
12697
12698 /**
12699  * clutter_actor_allocate_align_fill:
12700  * @self: a #ClutterActor
12701  * @box: a #ClutterActorBox, containing the available width and height
12702  * @x_align: the horizontal alignment, between 0 and 1
12703  * @y_align: the vertical alignment, between 0 and 1
12704  * @x_fill: whether the actor should fill horizontally
12705  * @y_fill: whether the actor should fill vertically
12706  * @flags: allocation flags to be passed to clutter_actor_allocate()
12707  *
12708  * Allocates @self by taking into consideration the available allocation
12709  * area; an alignment factor on either axis; and whether the actor should
12710  * fill the allocation on either axis.
12711  *
12712  * The @box should contain the available allocation width and height;
12713  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12714  * allocation will be offset by their value.
12715  *
12716  * This function takes into consideration the geometry request specified by
12717  * the #ClutterActor:request-mode property, and the text direction.
12718  *
12719  * This function is useful for fluid layout managers, like #ClutterBinLayout
12720  * or #ClutterTableLayout
12721  *
12722  * Since: 1.4
12723  */
12724 void
12725 clutter_actor_allocate_align_fill (ClutterActor           *self,
12726                                    const ClutterActorBox  *box,
12727                                    gdouble                 x_align,
12728                                    gdouble                 y_align,
12729                                    gboolean                x_fill,
12730                                    gboolean                y_fill,
12731                                    ClutterAllocationFlags  flags)
12732 {
12733   ClutterActorPrivate *priv;
12734   ClutterActorBox allocation = { 0, };
12735   gfloat x_offset, y_offset;
12736   gfloat available_width, available_height;
12737   gfloat child_width, child_height;
12738
12739   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12740   g_return_if_fail (box != NULL);
12741   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12742   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12743
12744   priv = self->priv;
12745
12746   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12747   clutter_actor_box_get_size (box, &available_width, &available_height);
12748
12749   if (available_width < 0)
12750     available_width = 0;
12751
12752   if (available_height < 0)
12753     available_height = 0;
12754
12755   if (x_fill)
12756     {
12757       allocation.x1 = x_offset;
12758       allocation.x2 = allocation.x1 + available_width;
12759     }
12760
12761   if (y_fill)
12762     {
12763       allocation.y1 = y_offset;
12764       allocation.y2 = allocation.y1 + available_height;
12765     }
12766
12767   /* if we are filling horizontally and vertically then we're done */
12768   if (x_fill && y_fill)
12769     goto out;
12770
12771   child_width = child_height = 0.0f;
12772
12773   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12774     {
12775       gfloat min_width, natural_width;
12776       gfloat min_height, natural_height;
12777
12778       clutter_actor_get_preferred_width (self, available_height,
12779                                          &min_width,
12780                                          &natural_width);
12781
12782       child_width = CLAMP (natural_width, min_width, available_width);
12783
12784       if (!y_fill)
12785         {
12786           clutter_actor_get_preferred_height (self, child_width,
12787                                               &min_height,
12788                                               &natural_height);
12789
12790           child_height = CLAMP (natural_height, min_height, available_height);
12791         }
12792     }
12793   else
12794     {
12795       gfloat min_width, natural_width;
12796       gfloat min_height, natural_height;
12797
12798       clutter_actor_get_preferred_height (self, available_width,
12799                                           &min_height,
12800                                           &natural_height);
12801
12802       child_height = CLAMP (natural_height, min_height, available_height);
12803
12804       if (!x_fill)
12805         {
12806           clutter_actor_get_preferred_width (self, child_height,
12807                                              &min_width,
12808                                              &natural_width);
12809
12810           child_width = CLAMP (natural_width, min_width, available_width);
12811         }
12812     }
12813
12814   /* invert the horizontal alignment for RTL languages */
12815   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12816     x_align = 1.0 - x_align;
12817
12818   if (!x_fill)
12819     {
12820       allocation.x1 = x_offset
12821                     + ((available_width - child_width) * x_align);
12822       allocation.x2 = allocation.x1 + child_width;
12823     }
12824
12825   if (!y_fill)
12826     {
12827       allocation.y1 = y_offset
12828                     + ((available_height - child_height) * y_align);
12829       allocation.y2 = allocation.y1 + child_height;
12830     }
12831
12832 out:
12833   clutter_actor_box_clamp_to_pixel (&allocation);
12834   clutter_actor_allocate (self, &allocation, flags);
12835 }
12836
12837 /**
12838  * clutter_actor_grab_key_focus:
12839  * @self: a #ClutterActor
12840  *
12841  * Sets the key focus of the #ClutterStage including @self
12842  * to this #ClutterActor.
12843  *
12844  * Since: 1.0
12845  */
12846 void
12847 clutter_actor_grab_key_focus (ClutterActor *self)
12848 {
12849   ClutterActor *stage;
12850
12851   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12852
12853   stage = _clutter_actor_get_stage_internal (self);
12854   if (stage != NULL)
12855     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12856 }
12857
12858 /**
12859  * clutter_actor_get_pango_context:
12860  * @self: a #ClutterActor
12861  *
12862  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12863  * is already configured using the appropriate font map, resolution
12864  * and font options.
12865  *
12866  * Unlike clutter_actor_create_pango_context(), this context is owend
12867  * by the #ClutterActor and it will be updated each time the options
12868  * stored by the #ClutterBackend change.
12869  *
12870  * You can use the returned #PangoContext to create a #PangoLayout
12871  * and render text using cogl_pango_render_layout() to reuse the
12872  * glyphs cache also used by Clutter.
12873  *
12874  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12875  *   The returned #PangoContext is owned by the actor and should not be
12876  *   unreferenced by the application code
12877  *
12878  * Since: 1.0
12879  */
12880 PangoContext *
12881 clutter_actor_get_pango_context (ClutterActor *self)
12882 {
12883   ClutterActorPrivate *priv;
12884
12885   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12886
12887   priv = self->priv;
12888
12889   if (priv->pango_context != NULL)
12890     return priv->pango_context;
12891
12892   priv->pango_context = _clutter_context_get_pango_context ();
12893   g_object_ref (priv->pango_context);
12894
12895   return priv->pango_context;
12896 }
12897
12898 /**
12899  * clutter_actor_create_pango_context:
12900  * @self: a #ClutterActor
12901  *
12902  * Creates a #PangoContext for the given actor. The #PangoContext
12903  * is already configured using the appropriate font map, resolution
12904  * and font options.
12905  *
12906  * See also clutter_actor_get_pango_context().
12907  *
12908  * Return value: (transfer full): the newly created #PangoContext.
12909  *   Use g_object_unref() on the returned value to deallocate its
12910  *   resources
12911  *
12912  * Since: 1.0
12913  */
12914 PangoContext *
12915 clutter_actor_create_pango_context (ClutterActor *self)
12916 {
12917   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12918
12919   return _clutter_context_create_pango_context ();
12920 }
12921
12922 /**
12923  * clutter_actor_create_pango_layout:
12924  * @self: a #ClutterActor
12925  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
12926  *
12927  * Creates a new #PangoLayout from the same #PangoContext used
12928  * by the #ClutterActor. The #PangoLayout is already configured
12929  * with the font map, resolution and font options, and the
12930  * given @text.
12931  *
12932  * If you want to keep around a #PangoLayout created by this
12933  * function you will have to connect to the #ClutterBackend::font-changed
12934  * and #ClutterBackend::resolution-changed signals, and call
12935  * pango_layout_context_changed() in response to them.
12936  *
12937  * Return value: (transfer full): the newly created #PangoLayout.
12938  *   Use g_object_unref() when done
12939  *
12940  * Since: 1.0
12941  */
12942 PangoLayout *
12943 clutter_actor_create_pango_layout (ClutterActor *self,
12944                                    const gchar  *text)
12945 {
12946   PangoContext *context;
12947   PangoLayout *layout;
12948
12949   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12950
12951   context = clutter_actor_get_pango_context (self);
12952   layout = pango_layout_new (context);
12953
12954   if (text)
12955     pango_layout_set_text (layout, text, -1);
12956
12957   return layout;
12958 }
12959
12960 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
12961  * ClutterOffscreenEffect.
12962  */
12963 void
12964 _clutter_actor_set_opacity_override (ClutterActor *self,
12965                                      gint          opacity)
12966 {
12967   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12968
12969   self->priv->opacity_override = opacity;
12970 }
12971
12972 gint
12973 _clutter_actor_get_opacity_override (ClutterActor *self)
12974 {
12975   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
12976
12977   return self->priv->opacity_override;
12978 }
12979
12980 /* Allows you to disable applying the actors model view transform during
12981  * a paint. Used by ClutterClone. */
12982 void
12983 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
12984                                                 gboolean      enable)
12985 {
12986   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12987
12988   self->priv->enable_model_view_transform = enable;
12989 }
12990
12991 void
12992 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
12993                                           gboolean      enable)
12994 {
12995   ClutterActorPrivate *priv;
12996
12997   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12998
12999   priv = self->priv;
13000
13001   priv->enable_paint_unmapped = enable;
13002
13003   if (priv->enable_paint_unmapped)
13004     {
13005       /* Make sure that the parents of the widget are realized first;
13006        * otherwise checks in clutter_actor_update_map_state() will
13007        * fail.
13008        */
13009       clutter_actor_realize (self);
13010
13011       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13012     }
13013   else
13014     {
13015       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13016     }
13017 }
13018
13019 static void
13020 clutter_anchor_coord_get_units (ClutterActor      *self,
13021                                 const AnchorCoord *coord,
13022                                 gfloat            *x,
13023                                 gfloat            *y,
13024                                 gfloat            *z)
13025 {
13026   if (coord->is_fractional)
13027     {
13028       gfloat actor_width, actor_height;
13029
13030       clutter_actor_get_size (self, &actor_width, &actor_height);
13031
13032       if (x)
13033         *x = actor_width * coord->v.fraction.x;
13034
13035       if (y)
13036         *y = actor_height * coord->v.fraction.y;
13037
13038       if (z)
13039         *z = 0;
13040     }
13041   else
13042     {
13043       if (x)
13044         *x = coord->v.units.x;
13045
13046       if (y)
13047         *y = coord->v.units.y;
13048
13049       if (z)
13050         *z = coord->v.units.z;
13051     }
13052 }
13053
13054 static void
13055 clutter_anchor_coord_set_units (AnchorCoord *coord,
13056                                 gfloat       x,
13057                                 gfloat       y,
13058                                 gfloat       z)
13059 {
13060   coord->is_fractional = FALSE;
13061   coord->v.units.x = x;
13062   coord->v.units.y = y;
13063   coord->v.units.z = z;
13064 }
13065
13066 static ClutterGravity
13067 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13068 {
13069   if (coord->is_fractional)
13070     {
13071       if (coord->v.fraction.x == 0.0)
13072         {
13073           if (coord->v.fraction.y == 0.0)
13074             return CLUTTER_GRAVITY_NORTH_WEST;
13075           else if (coord->v.fraction.y == 0.5)
13076             return CLUTTER_GRAVITY_WEST;
13077           else if (coord->v.fraction.y == 1.0)
13078             return CLUTTER_GRAVITY_SOUTH_WEST;
13079           else
13080             return CLUTTER_GRAVITY_NONE;
13081         }
13082       else if (coord->v.fraction.x == 0.5)
13083         {
13084           if (coord->v.fraction.y == 0.0)
13085             return CLUTTER_GRAVITY_NORTH;
13086           else if (coord->v.fraction.y == 0.5)
13087             return CLUTTER_GRAVITY_CENTER;
13088           else if (coord->v.fraction.y == 1.0)
13089             return CLUTTER_GRAVITY_SOUTH;
13090           else
13091             return CLUTTER_GRAVITY_NONE;
13092         }
13093       else if (coord->v.fraction.x == 1.0)
13094         {
13095           if (coord->v.fraction.y == 0.0)
13096             return CLUTTER_GRAVITY_NORTH_EAST;
13097           else if (coord->v.fraction.y == 0.5)
13098             return CLUTTER_GRAVITY_EAST;
13099           else if (coord->v.fraction.y == 1.0)
13100             return CLUTTER_GRAVITY_SOUTH_EAST;
13101           else
13102             return CLUTTER_GRAVITY_NONE;
13103         }
13104       else
13105         return CLUTTER_GRAVITY_NONE;
13106     }
13107   else
13108     return CLUTTER_GRAVITY_NONE;
13109 }
13110
13111 static void
13112 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13113                                   ClutterGravity  gravity)
13114 {
13115   switch (gravity)
13116     {
13117     case CLUTTER_GRAVITY_NORTH:
13118       coord->v.fraction.x = 0.5;
13119       coord->v.fraction.y = 0.0;
13120       break;
13121
13122     case CLUTTER_GRAVITY_NORTH_EAST:
13123       coord->v.fraction.x = 1.0;
13124       coord->v.fraction.y = 0.0;
13125       break;
13126
13127     case CLUTTER_GRAVITY_EAST:
13128       coord->v.fraction.x = 1.0;
13129       coord->v.fraction.y = 0.5;
13130       break;
13131
13132     case CLUTTER_GRAVITY_SOUTH_EAST:
13133       coord->v.fraction.x = 1.0;
13134       coord->v.fraction.y = 1.0;
13135       break;
13136
13137     case CLUTTER_GRAVITY_SOUTH:
13138       coord->v.fraction.x = 0.5;
13139       coord->v.fraction.y = 1.0;
13140       break;
13141
13142     case CLUTTER_GRAVITY_SOUTH_WEST:
13143       coord->v.fraction.x = 0.0;
13144       coord->v.fraction.y = 1.0;
13145       break;
13146
13147     case CLUTTER_GRAVITY_WEST:
13148       coord->v.fraction.x = 0.0;
13149       coord->v.fraction.y = 0.5;
13150       break;
13151
13152     case CLUTTER_GRAVITY_NORTH_WEST:
13153       coord->v.fraction.x = 0.0;
13154       coord->v.fraction.y = 0.0;
13155       break;
13156
13157     case CLUTTER_GRAVITY_CENTER:
13158       coord->v.fraction.x = 0.5;
13159       coord->v.fraction.y = 0.5;
13160       break;
13161
13162     default:
13163       coord->v.fraction.x = 0.0;
13164       coord->v.fraction.y = 0.0;
13165       break;
13166     }
13167
13168   coord->is_fractional = TRUE;
13169 }
13170
13171 static gboolean
13172 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13173 {
13174   if (coord->is_fractional)
13175     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13176   else
13177     return (coord->v.units.x == 0.0
13178             && coord->v.units.y == 0.0
13179             && coord->v.units.z == 0.0);
13180 }
13181
13182 /**
13183  * clutter_actor_get_flags:
13184  * @self: a #ClutterActor
13185  *
13186  * Retrieves the flags set on @self
13187  *
13188  * Return value: a bitwise or of #ClutterActorFlags or 0
13189  *
13190  * Since: 1.0
13191  */
13192 ClutterActorFlags
13193 clutter_actor_get_flags (ClutterActor *self)
13194 {
13195   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13196
13197   return self->flags;
13198 }
13199
13200 /**
13201  * clutter_actor_set_flags:
13202  * @self: a #ClutterActor
13203  * @flags: the flags to set
13204  *
13205  * Sets @flags on @self
13206  *
13207  * This function will emit notifications for the changed properties
13208  *
13209  * Since: 1.0
13210  */
13211 void
13212 clutter_actor_set_flags (ClutterActor      *self,
13213                          ClutterActorFlags  flags)
13214 {
13215   ClutterActorFlags old_flags;
13216   GObject *obj;
13217   gboolean was_reactive_set, reactive_set;
13218   gboolean was_realized_set, realized_set;
13219   gboolean was_mapped_set, mapped_set;
13220   gboolean was_visible_set, visible_set;
13221
13222   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13223
13224   if (self->flags == flags)
13225     return;
13226
13227   obj = G_OBJECT (self);
13228   g_object_ref (obj);
13229   g_object_freeze_notify (obj);
13230
13231   old_flags = self->flags;
13232
13233   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13234   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13235   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13236   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13237
13238   self->flags |= flags;
13239
13240   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13241   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13242   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13243   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13244
13245   if (reactive_set != was_reactive_set)
13246     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13247
13248   if (realized_set != was_realized_set)
13249     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13250
13251   if (mapped_set != was_mapped_set)
13252     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13253
13254   if (visible_set != was_visible_set)
13255     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13256
13257   g_object_thaw_notify (obj);
13258   g_object_unref (obj);
13259 }
13260
13261 /**
13262  * clutter_actor_unset_flags:
13263  * @self: a #ClutterActor
13264  * @flags: the flags to unset
13265  *
13266  * Unsets @flags on @self
13267  *
13268  * This function will emit notifications for the changed properties
13269  *
13270  * Since: 1.0
13271  */
13272 void
13273 clutter_actor_unset_flags (ClutterActor      *self,
13274                            ClutterActorFlags  flags)
13275 {
13276   ClutterActorFlags old_flags;
13277   GObject *obj;
13278   gboolean was_reactive_set, reactive_set;
13279   gboolean was_realized_set, realized_set;
13280   gboolean was_mapped_set, mapped_set;
13281   gboolean was_visible_set, visible_set;
13282
13283   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13284
13285   obj = G_OBJECT (self);
13286   g_object_freeze_notify (obj);
13287
13288   old_flags = self->flags;
13289
13290   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13291   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13292   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13293   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13294
13295   self->flags &= ~flags;
13296
13297   if (self->flags == old_flags)
13298     return;
13299
13300   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13301   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13302   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13303   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13304
13305   if (reactive_set != was_reactive_set)
13306     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13307
13308   if (realized_set != was_realized_set)
13309     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13310
13311   if (mapped_set != was_mapped_set)
13312     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13313
13314   if (visible_set != was_visible_set)
13315     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13316
13317   g_object_thaw_notify (obj);
13318 }
13319
13320 /**
13321  * clutter_actor_get_transformation_matrix:
13322  * @self: a #ClutterActor
13323  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13324  *
13325  * Retrieves the transformations applied to @self relative to its
13326  * parent.
13327  *
13328  * Since: 1.0
13329  */
13330 void
13331 clutter_actor_get_transformation_matrix (ClutterActor *self,
13332                                          CoglMatrix   *matrix)
13333 {
13334   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13335
13336   cogl_matrix_init_identity (matrix);
13337
13338   _clutter_actor_apply_modelview_transform (self, matrix);
13339 }
13340
13341 void
13342 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13343                                    gboolean      is_in_clone_paint)
13344 {
13345   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13346   self->priv->in_clone_paint = is_in_clone_paint;
13347 }
13348
13349 /**
13350  * clutter_actor_is_in_clone_paint:
13351  * @self: a #ClutterActor
13352  *
13353  * Checks whether @self is being currently painted by a #ClutterClone
13354  *
13355  * This function is useful only inside the ::paint virtual function
13356  * implementations or within handlers for the #ClutterActor::paint
13357  * signal
13358  *
13359  * This function should not be used by applications
13360  *
13361  * Return value: %TRUE if the #ClutterActor is currently being painted
13362  *   by a #ClutterClone, and %FALSE otherwise
13363  *
13364  * Since: 1.0
13365  */
13366 gboolean
13367 clutter_actor_is_in_clone_paint (ClutterActor *self)
13368 {
13369   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13370
13371   return self->priv->in_clone_paint;
13372 }
13373
13374 static gboolean
13375 set_direction_recursive (ClutterActor *actor,
13376                          gpointer      user_data)
13377 {
13378   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13379
13380   clutter_actor_set_text_direction (actor, text_dir);
13381
13382   return TRUE;
13383 }
13384
13385 /**
13386  * clutter_actor_set_text_direction:
13387  * @self: a #ClutterActor
13388  * @text_dir: the text direction for @self
13389  *
13390  * Sets the #ClutterTextDirection for an actor
13391  *
13392  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13393  *
13394  * If @self implements #ClutterContainer then this function will recurse
13395  * inside all the children of @self (including the internal ones).
13396  *
13397  * Composite actors not implementing #ClutterContainer, or actors requiring
13398  * special handling when the text direction changes, should connect to
13399  * the #GObject::notify signal for the #ClutterActor:text-direction property
13400  *
13401  * Since: 1.2
13402  */
13403 void
13404 clutter_actor_set_text_direction (ClutterActor         *self,
13405                                   ClutterTextDirection  text_dir)
13406 {
13407   ClutterActorPrivate *priv;
13408
13409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13410   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13411
13412   priv = self->priv;
13413
13414   if (priv->text_direction != text_dir)
13415     {
13416       priv->text_direction = text_dir;
13417
13418       /* we need to emit the notify::text-direction first, so that
13419        * the sub-classes can catch that and do specific handling of
13420        * the text direction; see clutter_text_direction_changed_cb()
13421        * inside clutter-text.c
13422        */
13423       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13424
13425       _clutter_actor_foreach_child (self, set_direction_recursive,
13426                                     GINT_TO_POINTER (text_dir));
13427
13428       clutter_actor_queue_relayout (self);
13429     }
13430 }
13431
13432 void
13433 _clutter_actor_set_has_pointer (ClutterActor *self,
13434                                 gboolean      has_pointer)
13435 {
13436   ClutterActorPrivate *priv = self->priv;
13437
13438   if (priv->has_pointer != has_pointer)
13439     {
13440       priv->has_pointer = has_pointer;
13441
13442       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13443     }
13444 }
13445
13446 /**
13447  * clutter_actor_get_text_direction:
13448  * @self: a #ClutterActor
13449  *
13450  * Retrieves the value set using clutter_actor_set_text_direction()
13451  *
13452  * If no text direction has been previously set, the default text
13453  * direction, as returned by clutter_get_default_text_direction(), will
13454  * be returned instead
13455  *
13456  * Return value: the #ClutterTextDirection for the actor
13457  *
13458  * Since: 1.2
13459  */
13460 ClutterTextDirection
13461 clutter_actor_get_text_direction (ClutterActor *self)
13462 {
13463   ClutterActorPrivate *priv;
13464
13465   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13466                         CLUTTER_TEXT_DIRECTION_LTR);
13467
13468   priv = self->priv;
13469
13470   /* if no direction has been set yet use the default */
13471   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13472     priv->text_direction = clutter_get_default_text_direction ();
13473
13474   return priv->text_direction;
13475 }
13476
13477 /**
13478  * clutter_actor_push_internal:
13479  * @self: a #ClutterActor
13480  *
13481  * Should be used by actors implementing the #ClutterContainer and with
13482  * internal children added through clutter_actor_set_parent(), for instance:
13483  *
13484  * |[
13485  *   static void
13486  *   my_actor_init (MyActor *self)
13487  *   {
13488  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13489  *
13490  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13491  *
13492  *     /&ast; calling clutter_actor_set_parent() now will result in
13493  *      &ast; the internal flag being set on a child of MyActor
13494  *      &ast;/
13495  *
13496  *     /&ast; internal child - a background texture &ast;/
13497  *     self->priv->background_tex = clutter_texture_new ();
13498  *     clutter_actor_set_parent (self->priv->background_tex,
13499  *                               CLUTTER_ACTOR (self));
13500  *
13501  *     /&ast; internal child - a label &ast;/
13502  *     self->priv->label = clutter_text_new ();
13503  *     clutter_actor_set_parent (self->priv->label,
13504  *                               CLUTTER_ACTOR (self));
13505  *
13506  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13507  *
13508  *     /&ast; calling clutter_actor_set_parent() now will not result in
13509  *      &ast; the internal flag being set on a child of MyActor
13510  *      &ast;/
13511  *   }
13512  * ]|
13513  *
13514  * This function will be used by Clutter to toggle an "internal child"
13515  * flag whenever clutter_actor_set_parent() is called; internal children
13516  * are handled differently by Clutter, specifically when destroying their
13517  * parent.
13518  *
13519  * Call clutter_actor_pop_internal() when you finished adding internal
13520  * children.
13521  *
13522  * Nested calls to clutter_actor_push_internal() are allowed, but each
13523  * one must by followed by a clutter_actor_pop_internal() call.
13524  *
13525  * Since: 1.2
13526  *
13527  * Deprecated: 1.10: All children of an actor are accessible through
13528  *   the #ClutterActor API, and #ClutterActor implements the
13529  *   #ClutterContainer interface, so this function is only useful
13530  *   for legacy containers overriding the default implementation.
13531  */
13532 void
13533 clutter_actor_push_internal (ClutterActor *self)
13534 {
13535   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13536
13537   self->priv->internal_child += 1;
13538 }
13539
13540 /**
13541  * clutter_actor_pop_internal:
13542  * @self: a #ClutterActor
13543  *
13544  * Disables the effects of clutter_actor_push_internal().
13545  *
13546  * Since: 1.2
13547  *
13548  * Deprecated: 1.10: All children of an actor are accessible through
13549  *   the #ClutterActor API. This function is only useful for legacy
13550  *   containers overriding the default implementation of the
13551  *   #ClutterContainer interface.
13552  */
13553 void
13554 clutter_actor_pop_internal (ClutterActor *self)
13555 {
13556   ClutterActorPrivate *priv;
13557
13558   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13559
13560   priv = self->priv;
13561
13562   if (priv->internal_child == 0)
13563     {
13564       g_warning ("Mismatched %s: you need to call "
13565                  "clutter_actor_push_composite() at least once before "
13566                  "calling this function", G_STRFUNC);
13567       return;
13568     }
13569
13570   priv->internal_child -= 1;
13571 }
13572
13573 /**
13574  * clutter_actor_has_pointer:
13575  * @self: a #ClutterActor
13576  *
13577  * Checks whether an actor contains the pointer of a
13578  * #ClutterInputDevice
13579  *
13580  * Return value: %TRUE if the actor contains the pointer, and
13581  *   %FALSE otherwise
13582  *
13583  * Since: 1.2
13584  */
13585 gboolean
13586 clutter_actor_has_pointer (ClutterActor *self)
13587 {
13588   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13589
13590   return self->priv->has_pointer;
13591 }
13592
13593 /* XXX: This is a workaround for not being able to break the ABI of
13594  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13595  * clutter_actor_queue_clipped_redraw() for details.
13596  */
13597 ClutterPaintVolume *
13598 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13599 {
13600   return g_object_get_data (G_OBJECT (self),
13601                             "-clutter-actor-queue-redraw-clip");
13602 }
13603
13604 void
13605 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13606                                       ClutterPaintVolume *clip)
13607 {
13608   g_object_set_data (G_OBJECT (self),
13609                      "-clutter-actor-queue-redraw-clip",
13610                      clip);
13611 }
13612
13613 /**
13614  * clutter_actor_has_allocation:
13615  * @self: a #ClutterActor
13616  *
13617  * Checks if the actor has an up-to-date allocation assigned to
13618  * it. This means that the actor should have an allocation: it's
13619  * visible and has a parent. It also means that there is no
13620  * outstanding relayout request in progress for the actor or its
13621  * children (There might be other outstanding layout requests in
13622  * progress that will cause the actor to get a new allocation
13623  * when the stage is laid out, however).
13624  *
13625  * If this function returns %FALSE, then the actor will normally
13626  * be allocated before it is next drawn on the screen.
13627  *
13628  * Return value: %TRUE if the actor has an up-to-date allocation
13629  *
13630  * Since: 1.4
13631  */
13632 gboolean
13633 clutter_actor_has_allocation (ClutterActor *self)
13634 {
13635   ClutterActorPrivate *priv;
13636
13637   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13638
13639   priv = self->priv;
13640
13641   return priv->parent != NULL &&
13642          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13643          !priv->needs_allocation;
13644 }
13645
13646 /**
13647  * clutter_actor_add_action:
13648  * @self: a #ClutterActor
13649  * @action: a #ClutterAction
13650  *
13651  * Adds @action to the list of actions applied to @self
13652  *
13653  * A #ClutterAction can only belong to one actor at a time
13654  *
13655  * The #ClutterActor will hold a reference on @action until either
13656  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13657  * is called
13658  *
13659  * Since: 1.4
13660  */
13661 void
13662 clutter_actor_add_action (ClutterActor  *self,
13663                           ClutterAction *action)
13664 {
13665   ClutterActorPrivate *priv;
13666
13667   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13668   g_return_if_fail (CLUTTER_IS_ACTION (action));
13669
13670   priv = self->priv;
13671
13672   if (priv->actions == NULL)
13673     {
13674       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13675       priv->actions->actor = self;
13676     }
13677
13678   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13679
13680   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13681 }
13682
13683 /**
13684  * clutter_actor_add_action_with_name:
13685  * @self: a #ClutterActor
13686  * @name: the name to set on the action
13687  * @action: a #ClutterAction
13688  *
13689  * A convenience function for setting the name of a #ClutterAction
13690  * while adding it to the list of actions applied to @self
13691  *
13692  * This function is the logical equivalent of:
13693  *
13694  * |[
13695  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13696  *   clutter_actor_add_action (self, action);
13697  * ]|
13698  *
13699  * Since: 1.4
13700  */
13701 void
13702 clutter_actor_add_action_with_name (ClutterActor  *self,
13703                                     const gchar   *name,
13704                                     ClutterAction *action)
13705 {
13706   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13707   g_return_if_fail (name != NULL);
13708   g_return_if_fail (CLUTTER_IS_ACTION (action));
13709
13710   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13711   clutter_actor_add_action (self, action);
13712 }
13713
13714 /**
13715  * clutter_actor_remove_action:
13716  * @self: a #ClutterActor
13717  * @action: a #ClutterAction
13718  *
13719  * Removes @action from the list of actions applied to @self
13720  *
13721  * The reference held by @self on the #ClutterAction will be released
13722  *
13723  * Since: 1.4
13724  */
13725 void
13726 clutter_actor_remove_action (ClutterActor  *self,
13727                              ClutterAction *action)
13728 {
13729   ClutterActorPrivate *priv;
13730
13731   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13732   g_return_if_fail (CLUTTER_IS_ACTION (action));
13733
13734   priv = self->priv;
13735
13736   if (priv->actions == NULL)
13737     return;
13738
13739   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13740
13741   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13742 }
13743
13744 /**
13745  * clutter_actor_remove_action_by_name:
13746  * @self: a #ClutterActor
13747  * @name: the name of the action to remove
13748  *
13749  * Removes the #ClutterAction with the given name from the list
13750  * of actions applied to @self
13751  *
13752  * Since: 1.4
13753  */
13754 void
13755 clutter_actor_remove_action_by_name (ClutterActor *self,
13756                                      const gchar  *name)
13757 {
13758   ClutterActorPrivate *priv;
13759   ClutterActorMeta *meta;
13760
13761   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13762   g_return_if_fail (name != NULL);
13763
13764   priv = self->priv;
13765
13766   if (priv->actions == NULL)
13767     return;
13768
13769   meta = _clutter_meta_group_get_meta (priv->actions, name);
13770   if (meta == NULL)
13771     return;
13772
13773   _clutter_meta_group_remove_meta (priv->actions, meta);
13774
13775   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13776 }
13777
13778 /**
13779  * clutter_actor_get_actions:
13780  * @self: a #ClutterActor
13781  *
13782  * Retrieves the list of actions applied to @self
13783  *
13784  * Return value: (transfer container) (element-type Clutter.Action): a copy
13785  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13786  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13787  *   allocated by the returned #GList
13788  *
13789  * Since: 1.4
13790  */
13791 GList *
13792 clutter_actor_get_actions (ClutterActor *self)
13793 {
13794   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13795
13796   if (self->priv->actions == NULL)
13797     return NULL;
13798
13799   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13800 }
13801
13802 /**
13803  * clutter_actor_get_action:
13804  * @self: a #ClutterActor
13805  * @name: the name of the action to retrieve
13806  *
13807  * Retrieves the #ClutterAction with the given name in the list
13808  * of actions applied to @self
13809  *
13810  * Return value: (transfer none): a #ClutterAction for the given
13811  *   name, or %NULL. The returned #ClutterAction is owned by the
13812  *   actor and it should not be unreferenced directly
13813  *
13814  * Since: 1.4
13815  */
13816 ClutterAction *
13817 clutter_actor_get_action (ClutterActor *self,
13818                           const gchar  *name)
13819 {
13820   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13821   g_return_val_if_fail (name != NULL, NULL);
13822
13823   if (self->priv->actions == NULL)
13824     return NULL;
13825
13826   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13827 }
13828
13829 /**
13830  * clutter_actor_clear_actions:
13831  * @self: a #ClutterActor
13832  *
13833  * Clears the list of actions applied to @self
13834  *
13835  * Since: 1.4
13836  */
13837 void
13838 clutter_actor_clear_actions (ClutterActor *self)
13839 {
13840   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13841
13842   if (self->priv->actions == NULL)
13843     return;
13844
13845   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13846 }
13847
13848 /**
13849  * clutter_actor_add_constraint:
13850  * @self: a #ClutterActor
13851  * @constraint: a #ClutterConstraint
13852  *
13853  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13854  * to @self
13855  *
13856  * The #ClutterActor will hold a reference on the @constraint until
13857  * either clutter_actor_remove_constraint() or
13858  * clutter_actor_clear_constraints() is called.
13859  *
13860  * Since: 1.4
13861  */
13862 void
13863 clutter_actor_add_constraint (ClutterActor      *self,
13864                               ClutterConstraint *constraint)
13865 {
13866   ClutterActorPrivate *priv;
13867
13868   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13869   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13870
13871   priv = self->priv;
13872
13873   if (priv->constraints == NULL)
13874     {
13875       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13876       priv->constraints->actor = self;
13877     }
13878
13879   _clutter_meta_group_add_meta (priv->constraints,
13880                                 CLUTTER_ACTOR_META (constraint));
13881   clutter_actor_queue_relayout (self);
13882
13883   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13884 }
13885
13886 /**
13887  * clutter_actor_add_constraint_with_name:
13888  * @self: a #ClutterActor
13889  * @name: the name to set on the constraint
13890  * @constraint: a #ClutterConstraint
13891  *
13892  * A convenience function for setting the name of a #ClutterConstraint
13893  * while adding it to the list of constraints applied to @self
13894  *
13895  * This function is the logical equivalent of:
13896  *
13897  * |[
13898  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13899  *   clutter_actor_add_constraint (self, constraint);
13900  * ]|
13901  *
13902  * Since: 1.4
13903  */
13904 void
13905 clutter_actor_add_constraint_with_name (ClutterActor      *self,
13906                                         const gchar       *name,
13907                                         ClutterConstraint *constraint)
13908 {
13909   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13910   g_return_if_fail (name != NULL);
13911   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13912
13913   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13914   clutter_actor_add_constraint (self, constraint);
13915 }
13916
13917 /**
13918  * clutter_actor_remove_constraint:
13919  * @self: a #ClutterActor
13920  * @constraint: a #ClutterConstraint
13921  *
13922  * Removes @constraint from the list of constraints applied to @self
13923  *
13924  * The reference held by @self on the #ClutterConstraint will be released
13925  *
13926  * Since: 1.4
13927  */
13928 void
13929 clutter_actor_remove_constraint (ClutterActor      *self,
13930                                  ClutterConstraint *constraint)
13931 {
13932   ClutterActorPrivate *priv;
13933
13934   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13935   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13936
13937   priv = self->priv;
13938
13939   if (priv->constraints == NULL)
13940     return;
13941
13942   _clutter_meta_group_remove_meta (priv->constraints,
13943                                    CLUTTER_ACTOR_META (constraint));
13944   clutter_actor_queue_relayout (self);
13945
13946   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13947 }
13948
13949 /**
13950  * clutter_actor_remove_constraint_by_name:
13951  * @self: a #ClutterActor
13952  * @name: the name of the constraint to remove
13953  *
13954  * Removes the #ClutterConstraint with the given name from the list
13955  * of constraints applied to @self
13956  *
13957  * Since: 1.4
13958  */
13959 void
13960 clutter_actor_remove_constraint_by_name (ClutterActor *self,
13961                                          const gchar  *name)
13962 {
13963   ClutterActorPrivate *priv;
13964   ClutterActorMeta *meta;
13965
13966   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13967   g_return_if_fail (name != NULL);
13968
13969   priv = self->priv;
13970
13971   if (priv->constraints == NULL)
13972     return;
13973
13974   meta = _clutter_meta_group_get_meta (priv->constraints, name);
13975   if (meta == NULL)
13976     return;
13977
13978   _clutter_meta_group_remove_meta (priv->constraints, meta);
13979   clutter_actor_queue_relayout (self);
13980 }
13981
13982 /**
13983  * clutter_actor_get_constraints:
13984  * @self: a #ClutterActor
13985  *
13986  * Retrieves the list of constraints applied to @self
13987  *
13988  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
13989  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
13990  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13991  *   allocated by the returned #GList
13992  *
13993  * Since: 1.4
13994  */
13995 GList *
13996 clutter_actor_get_constraints (ClutterActor *self)
13997 {
13998   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13999
14000   if (self->priv->constraints == NULL)
14001     return NULL;
14002
14003   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14004 }
14005
14006 /**
14007  * clutter_actor_get_constraint:
14008  * @self: a #ClutterActor
14009  * @name: the name of the constraint to retrieve
14010  *
14011  * Retrieves the #ClutterConstraint with the given name in the list
14012  * of constraints applied to @self
14013  *
14014  * Return value: (transfer none): a #ClutterConstraint for the given
14015  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14016  *   actor and it should not be unreferenced directly
14017  *
14018  * Since: 1.4
14019  */
14020 ClutterConstraint *
14021 clutter_actor_get_constraint (ClutterActor *self,
14022                               const gchar  *name)
14023 {
14024   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14025   g_return_val_if_fail (name != NULL, NULL);
14026
14027   if (self->priv->constraints == NULL)
14028     return NULL;
14029
14030   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14031 }
14032
14033 /**
14034  * clutter_actor_clear_constraints:
14035  * @self: a #ClutterActor
14036  *
14037  * Clears the list of constraints applied to @self
14038  *
14039  * Since: 1.4
14040  */
14041 void
14042 clutter_actor_clear_constraints (ClutterActor *self)
14043 {
14044   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14045
14046   if (self->priv->constraints == NULL)
14047     return;
14048
14049   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14050
14051   clutter_actor_queue_relayout (self);
14052 }
14053
14054 /**
14055  * clutter_actor_set_clip_to_allocation:
14056  * @self: a #ClutterActor
14057  * @clip_set: %TRUE to apply a clip tracking the allocation
14058  *
14059  * Sets whether @self should be clipped to the same size as its
14060  * allocation
14061  *
14062  * Since: 1.4
14063  */
14064 void
14065 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14066                                       gboolean      clip_set)
14067 {
14068   ClutterActorPrivate *priv;
14069
14070   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14071
14072   clip_set = !!clip_set;
14073
14074   priv = self->priv;
14075
14076   if (priv->clip_to_allocation != clip_set)
14077     {
14078       priv->clip_to_allocation = clip_set;
14079
14080       clutter_actor_queue_redraw (self);
14081
14082       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14083     }
14084 }
14085
14086 /**
14087  * clutter_actor_get_clip_to_allocation:
14088  * @self: a #ClutterActor
14089  *
14090  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14091  *
14092  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14093  *
14094  * Since: 1.4
14095  */
14096 gboolean
14097 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14098 {
14099   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14100
14101   return self->priv->clip_to_allocation;
14102 }
14103
14104 /**
14105  * clutter_actor_add_effect:
14106  * @self: a #ClutterActor
14107  * @effect: a #ClutterEffect
14108  *
14109  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14110  *
14111  * The #ClutterActor will hold a reference on the @effect until either
14112  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14113  * called.
14114  *
14115  * Since: 1.4
14116  */
14117 void
14118 clutter_actor_add_effect (ClutterActor  *self,
14119                           ClutterEffect *effect)
14120 {
14121   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14122   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14123
14124   _clutter_actor_add_effect_internal (self, effect);
14125
14126   clutter_actor_queue_redraw (self);
14127
14128   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14129 }
14130
14131 /**
14132  * clutter_actor_add_effect_with_name:
14133  * @self: a #ClutterActor
14134  * @name: the name to set on the effect
14135  * @effect: a #ClutterEffect
14136  *
14137  * A convenience function for setting the name of a #ClutterEffect
14138  * while adding it to the list of effectss applied to @self
14139  *
14140  * This function is the logical equivalent of:
14141  *
14142  * |[
14143  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14144  *   clutter_actor_add_effect (self, effect);
14145  * ]|
14146  *
14147  * Since: 1.4
14148  */
14149 void
14150 clutter_actor_add_effect_with_name (ClutterActor  *self,
14151                                     const gchar   *name,
14152                                     ClutterEffect *effect)
14153 {
14154   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14155   g_return_if_fail (name != NULL);
14156   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14157
14158   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14159   clutter_actor_add_effect (self, effect);
14160 }
14161
14162 /**
14163  * clutter_actor_remove_effect:
14164  * @self: a #ClutterActor
14165  * @effect: a #ClutterEffect
14166  *
14167  * Removes @effect from the list of effects applied to @self
14168  *
14169  * The reference held by @self on the #ClutterEffect will be released
14170  *
14171  * Since: 1.4
14172  */
14173 void
14174 clutter_actor_remove_effect (ClutterActor  *self,
14175                              ClutterEffect *effect)
14176 {
14177   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14178   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14179
14180   _clutter_actor_remove_effect_internal (self, effect);
14181
14182   clutter_actor_queue_redraw (self);
14183
14184   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14185 }
14186
14187 /**
14188  * clutter_actor_remove_effect_by_name:
14189  * @self: a #ClutterActor
14190  * @name: the name of the effect to remove
14191  *
14192  * Removes the #ClutterEffect with the given name from the list
14193  * of effects applied to @self
14194  *
14195  * Since: 1.4
14196  */
14197 void
14198 clutter_actor_remove_effect_by_name (ClutterActor *self,
14199                                      const gchar  *name)
14200 {
14201   ClutterActorPrivate *priv;
14202   ClutterActorMeta *meta;
14203
14204   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14205   g_return_if_fail (name != NULL);
14206
14207   priv = self->priv;
14208
14209   if (priv->effects == NULL)
14210     return;
14211
14212   meta = _clutter_meta_group_get_meta (priv->effects, name);
14213   if (meta == NULL)
14214     return;
14215
14216   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14217 }
14218
14219 /**
14220  * clutter_actor_get_effects:
14221  * @self: a #ClutterActor
14222  *
14223  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14224  *
14225  * Return value: (transfer container) (element-type Clutter.Effect): a list
14226  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14227  *   list are owned by Clutter and they should not be freed. You should
14228  *   free the returned list using g_list_free() when done
14229  *
14230  * Since: 1.4
14231  */
14232 GList *
14233 clutter_actor_get_effects (ClutterActor *self)
14234 {
14235   ClutterActorPrivate *priv;
14236
14237   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14238
14239   priv = self->priv;
14240
14241   if (priv->effects == NULL)
14242     return NULL;
14243
14244   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14245 }
14246
14247 /**
14248  * clutter_actor_get_effect:
14249  * @self: a #ClutterActor
14250  * @name: the name of the effect to retrieve
14251  *
14252  * Retrieves the #ClutterEffect with the given name in the list
14253  * of effects applied to @self
14254  *
14255  * Return value: (transfer none): a #ClutterEffect for the given
14256  *   name, or %NULL. The returned #ClutterEffect is owned by the
14257  *   actor and it should not be unreferenced directly
14258  *
14259  * Since: 1.4
14260  */
14261 ClutterEffect *
14262 clutter_actor_get_effect (ClutterActor *self,
14263                           const gchar  *name)
14264 {
14265   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14266   g_return_val_if_fail (name != NULL, NULL);
14267
14268   if (self->priv->effects == NULL)
14269     return NULL;
14270
14271   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14272 }
14273
14274 /**
14275  * clutter_actor_clear_effects:
14276  * @self: a #ClutterActor
14277  *
14278  * Clears the list of effects applied to @self
14279  *
14280  * Since: 1.4
14281  */
14282 void
14283 clutter_actor_clear_effects (ClutterActor *self)
14284 {
14285   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14286
14287   if (self->priv->effects == NULL)
14288     return;
14289
14290   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14291
14292   clutter_actor_queue_redraw (self);
14293 }
14294
14295 /**
14296  * clutter_actor_has_key_focus:
14297  * @self: a #ClutterActor
14298  *
14299  * Checks whether @self is the #ClutterActor that has key focus
14300  *
14301  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14302  *
14303  * Since: 1.4
14304  */
14305 gboolean
14306 clutter_actor_has_key_focus (ClutterActor *self)
14307 {
14308   ClutterActor *stage;
14309
14310   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14311
14312   stage = _clutter_actor_get_stage_internal (self);
14313   if (stage == NULL)
14314     return FALSE;
14315
14316   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14317 }
14318
14319 static gboolean
14320 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14321                                       ClutterPaintVolume *pv)
14322 {
14323   ClutterActorPrivate *priv = self->priv;
14324
14325   /* Actors are only expected to report a valid paint volume
14326    * while they have a valid allocation. */
14327   if (G_UNLIKELY (priv->needs_allocation))
14328     {
14329       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14330                     "Actor needs allocation",
14331                     _clutter_actor_get_debug_name (self));
14332       return FALSE;
14333     }
14334
14335   /* Check if there are any handlers connected to the paint
14336    * signal. If there are then all bets are off for what the paint
14337    * volume for this actor might possibly be!
14338    *
14339    * XXX: It's expected that this is going to end up being quite a
14340    * costly check to have to do here, but we haven't come up with
14341    * another solution that can reliably catch paint signal handlers at
14342    * the right time to either avoid artefacts due to invalid stage
14343    * clipping or due to incorrect culling.
14344    *
14345    * Previously we checked in clutter_actor_paint(), but at that time
14346    * we may already be using a stage clip that could be derived from
14347    * an invalid paint-volume. We used to try and handle that by
14348    * queuing a follow up, unclipped, redraw but still the previous
14349    * checking wasn't enough to catch invalid volumes involved in
14350    * culling (considering that containers may derive their volume from
14351    * children that haven't yet been painted)
14352    *
14353    * Longer term, improved solutions could be:
14354    * - Disallow painting in the paint signal, only allow using it
14355    *   for tracking when paints happen. We can add another API that
14356    *   allows monkey patching the paint of arbitrary actors but in a
14357    *   more controlled way and that also supports modifying the
14358    *   paint-volume.
14359    * - If we could be notified somehow when signal handlers are
14360    *   connected we wouldn't have to poll for handlers like this.
14361    */
14362   if (g_signal_has_handler_pending (self,
14363                                     actor_signals[PAINT],
14364                                     0,
14365                                     TRUE))
14366     {
14367       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14368                     "Actor has \"paint\" signal handlers",
14369                     _clutter_actor_get_debug_name (self));
14370       return FALSE;
14371     }
14372
14373   _clutter_paint_volume_init_static (pv, self);
14374
14375   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14376     {
14377       clutter_paint_volume_free (pv);
14378       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14379                     "Actor failed to report a volume",
14380                     _clutter_actor_get_debug_name (self));
14381       return FALSE;
14382     }
14383
14384   /* since effects can modify the paint volume, we allow them to actually
14385    * do this by making get_paint_volume() "context sensitive"
14386    */
14387   if (priv->effects != NULL)
14388     {
14389       if (priv->current_effect != NULL)
14390         {
14391           const GList *effects, *l;
14392
14393           /* if we are being called from within the paint sequence of
14394            * an actor, get the paint volume up to the current effect
14395            */
14396           effects = _clutter_meta_group_peek_metas (priv->effects);
14397           for (l = effects;
14398                l != NULL || (l != NULL && l->data != priv->current_effect);
14399                l = l->next)
14400             {
14401               if (!_clutter_effect_get_paint_volume (l->data, pv))
14402                 {
14403                   clutter_paint_volume_free (pv);
14404                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14405                                 "Effect (%s) failed to report a volume",
14406                                 _clutter_actor_get_debug_name (self),
14407                                 _clutter_actor_meta_get_debug_name (l->data));
14408                   return FALSE;
14409                 }
14410             }
14411         }
14412       else
14413         {
14414           const GList *effects, *l;
14415
14416           /* otherwise, get the cumulative volume */
14417           effects = _clutter_meta_group_peek_metas (priv->effects);
14418           for (l = effects; l != NULL; l = l->next)
14419             if (!_clutter_effect_get_paint_volume (l->data, pv))
14420               {
14421                 clutter_paint_volume_free (pv);
14422                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14423                               "Effect (%s) failed to report a volume",
14424                               _clutter_actor_get_debug_name (self),
14425                               _clutter_actor_meta_get_debug_name (l->data));
14426                 return FALSE;
14427               }
14428         }
14429     }
14430
14431   return TRUE;
14432 }
14433
14434 /* The public clutter_actor_get_paint_volume API returns a const
14435  * pointer since we return a pointer directly to the cached
14436  * PaintVolume associated with the actor and don't want the user to
14437  * inadvertently modify it, but for internal uses we sometimes need
14438  * access to the same PaintVolume but need to apply some book-keeping
14439  * modifications to it so we don't want a const pointer.
14440  */
14441 static ClutterPaintVolume *
14442 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14443 {
14444   ClutterActorPrivate *priv;
14445
14446   priv = self->priv;
14447
14448   if (priv->paint_volume_valid)
14449     clutter_paint_volume_free (&priv->paint_volume);
14450
14451   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14452     {
14453       priv->paint_volume_valid = TRUE;
14454       return &priv->paint_volume;
14455     }
14456   else
14457     {
14458       priv->paint_volume_valid = FALSE;
14459       return NULL;
14460     }
14461 }
14462
14463 /**
14464  * clutter_actor_get_paint_volume:
14465  * @self: a #ClutterActor
14466  *
14467  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14468  * when a paint volume can't be determined.
14469  *
14470  * The paint volume is defined as the 3D space occupied by an actor
14471  * when being painted.
14472  *
14473  * This function will call the <function>get_paint_volume()</function>
14474  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14475  * should not usually care about overriding the default implementation,
14476  * unless they are, for instance: painting outside their allocation, or
14477  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14478  * 3D depth).
14479  *
14480  * <note>2D actors overriding <function>get_paint_volume()</function>
14481  * ensure their volume has a depth of 0. (This will be true so long as
14482  * you don't call clutter_paint_volume_set_depth().)</note>
14483  *
14484  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14485  *   or %NULL if no volume could be determined.
14486  *
14487  * Since: 1.6
14488  */
14489 const ClutterPaintVolume *
14490 clutter_actor_get_paint_volume (ClutterActor *self)
14491 {
14492   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14493
14494   return _clutter_actor_get_paint_volume_mutable (self);
14495 }
14496
14497 /**
14498  * clutter_actor_get_transformed_paint_volume:
14499  * @self: a #ClutterActor
14500  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14501  *    (or %NULL for the stage)
14502  *
14503  * Retrieves the 3D paint volume of an actor like
14504  * clutter_actor_get_paint_volume() does (Please refer to the
14505  * documentation of clutter_actor_get_paint_volume() for more
14506  * details.) and it additionally transforms the paint volume into the
14507  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14508  * is passed for @relative_to_ancestor)
14509  *
14510  * This can be used by containers that base their paint volume on
14511  * the volume of their children. Such containers can query the
14512  * transformed paint volume of all of its children and union them
14513  * together using clutter_paint_volume_union().
14514  *
14515  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14516  *   or %NULL if no volume could be determined.
14517  *
14518  * Since: 1.6
14519  */
14520 const ClutterPaintVolume *
14521 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14522                                             ClutterActor *relative_to_ancestor)
14523 {
14524   const ClutterPaintVolume *volume;
14525   ClutterActor *stage;
14526   ClutterPaintVolume *transformed_volume;
14527
14528   stage = _clutter_actor_get_stage_internal (self);
14529   if (G_UNLIKELY (stage == NULL))
14530     return NULL;
14531
14532   if (relative_to_ancestor == NULL)
14533     relative_to_ancestor = stage;
14534
14535   volume = clutter_actor_get_paint_volume (self);
14536   if (volume == NULL)
14537     return NULL;
14538
14539   transformed_volume =
14540     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14541
14542   _clutter_paint_volume_copy_static (volume, transformed_volume);
14543
14544   _clutter_paint_volume_transform_relative (transformed_volume,
14545                                             relative_to_ancestor);
14546
14547   return transformed_volume;
14548 }
14549
14550 /**
14551  * clutter_actor_get_paint_box:
14552  * @self: a #ClutterActor
14553  * @box: (out): return location for a #ClutterActorBox
14554  *
14555  * Retrieves the paint volume of the passed #ClutterActor, and
14556  * transforms it into a 2D bounding box in stage coordinates.
14557  *
14558  * This function is useful to determine the on screen area occupied by
14559  * the actor. The box is only an approximation and may often be
14560  * considerably larger due to the optimizations used to calculate the
14561  * box. The box is never smaller though, so it can reliably be used
14562  * for culling.
14563  *
14564  * There are times when a 2D paint box can't be determined, e.g.
14565  * because the actor isn't yet parented under a stage or because
14566  * the actor is unable to determine a paint volume.
14567  *
14568  * Return value: %TRUE if a 2D paint box could be determined, else
14569  * %FALSE.
14570  *
14571  * Since: 1.6
14572  */
14573 gboolean
14574 clutter_actor_get_paint_box (ClutterActor    *self,
14575                              ClutterActorBox *box)
14576 {
14577   ClutterActor *stage;
14578   ClutterPaintVolume *pv;
14579
14580   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14581   g_return_val_if_fail (box != NULL, FALSE);
14582
14583   stage = _clutter_actor_get_stage_internal (self);
14584   if (G_UNLIKELY (!stage))
14585     return FALSE;
14586
14587   pv = _clutter_actor_get_paint_volume_mutable (self);
14588   if (G_UNLIKELY (!pv))
14589     return FALSE;
14590
14591   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14592
14593   return TRUE;
14594 }
14595
14596 /**
14597  * clutter_actor_has_overlaps:
14598  * @self: A #ClutterActor
14599  *
14600  * Asks the actor's implementation whether it may contain overlapping
14601  * primitives.
14602  *
14603  * For example; Clutter may use this to determine whether the painting
14604  * should be redirected to an offscreen buffer to correctly implement
14605  * the opacity property.
14606  *
14607  * Custom actors can override the default response by implementing the
14608  * #ClutterActor <function>has_overlaps</function> virtual function. See
14609  * clutter_actor_set_offscreen_redirect() for more information.
14610  *
14611  * Return value: %TRUE if the actor may have overlapping primitives, and
14612  *   %FALSE otherwise
14613  *
14614  * Since: 1.8
14615  */
14616 gboolean
14617 clutter_actor_has_overlaps (ClutterActor *self)
14618 {
14619   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14620
14621   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14622 }
14623
14624 /**
14625  * clutter_actor_has_effects:
14626  * @self: A #ClutterActor
14627  *
14628  * Returns whether the actor has any effects applied.
14629  *
14630  * Return value: %TRUE if the actor has any effects,
14631  *   %FALSE otherwise
14632  *
14633  * Since: 1.10
14634  */
14635 gboolean
14636 clutter_actor_has_effects (ClutterActor *self)
14637 {
14638   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14639
14640   if (self->priv->effects == NULL)
14641     return FALSE;
14642
14643   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14644 }
14645
14646 /**
14647  * clutter_actor_has_constraints:
14648  * @self: A #ClutterActor
14649  *
14650  * Returns whether the actor has any constraints applied.
14651  *
14652  * Return value: %TRUE if the actor has any constraints,
14653  *   %FALSE otherwise
14654  *
14655  * Since: 1.10
14656  */
14657 gboolean
14658 clutter_actor_has_constraints (ClutterActor *self)
14659 {
14660   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14661
14662   return self->priv->constraints != NULL;
14663 }
14664
14665 /**
14666  * clutter_actor_has_actions:
14667  * @self: A #ClutterActor
14668  *
14669  * Returns whether the actor has any actions applied.
14670  *
14671  * Return value: %TRUE if the actor has any actions,
14672  *   %FALSE otherwise
14673  *
14674  * Since: 1.10
14675  */
14676 gboolean
14677 clutter_actor_has_actions (ClutterActor *self)
14678 {
14679   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14680
14681   return self->priv->actions != NULL;
14682 }
14683
14684 /**
14685  * clutter_actor_get_n_children:
14686  * @self: a #ClutterActor
14687  *
14688  * Retrieves the number of children of @self.
14689  *
14690  * Return value: the number of children of an actor
14691  *
14692  * Since: 1.10
14693  */
14694 gint
14695 clutter_actor_get_n_children (ClutterActor *self)
14696 {
14697   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14698
14699   return self->priv->n_children;
14700 }
14701
14702 /**
14703  * clutter_actor_get_child_at_index:
14704  * @self: a #ClutterActor
14705  * @index_: the position in the list of children
14706  *
14707  * Retrieves the actor at the given @index_ inside the list of
14708  * children of @self.
14709  *
14710  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14711  *
14712  * Since: 1.10
14713  */
14714 ClutterActor *
14715 clutter_actor_get_child_at_index (ClutterActor *self,
14716                                   gint          index_)
14717 {
14718   ClutterActor *iter;
14719   int i;
14720
14721   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14722   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14723
14724   for (iter = self->priv->first_child, i = 0;
14725        iter != NULL && i < index_;
14726        iter = iter->priv->next_sibling, i += 1)
14727     ;
14728
14729   return iter;
14730 }
14731
14732 /*< private >
14733  * _clutter_actor_foreach_child:
14734  * @actor: The actor whos children you want to iterate
14735  * @callback: The function to call for each child
14736  * @user_data: Private data to pass to @callback
14737  *
14738  * Calls a given @callback once for each child of the specified @actor and
14739  * passing the @user_data pointer each time.
14740  *
14741  * Return value: returns %TRUE if all children were iterated, else
14742  *    %FALSE if a callback broke out of iteration early.
14743  */
14744 gboolean
14745 _clutter_actor_foreach_child (ClutterActor           *self,
14746                               ClutterForeachCallback  callback,
14747                               gpointer                user_data)
14748 {
14749   ClutterActorPrivate *priv = self->priv;
14750   ClutterActor *iter;
14751   gboolean cont;
14752
14753   for (cont = TRUE, iter = priv->first_child;
14754        cont && iter != NULL;
14755        iter = iter->priv->next_sibling)
14756     {
14757       cont = callback (iter, user_data);
14758     }
14759
14760   return cont;
14761 }
14762
14763 /* For debugging purposes this gives us a simple way to print out
14764  * the scenegraph e.g in gdb using:
14765  * [|
14766  *   _clutter_actor_traverse (stage,
14767  *                            0,
14768  *                            _clutter_debug_print_actor_cb,
14769  *                            NULL,
14770  *                            NULL);
14771  * |]
14772  */
14773 ClutterActorTraverseVisitFlags
14774 _clutter_debug_print_actor_cb (ClutterActor *actor,
14775                                int depth,
14776                                void *user_data)
14777 {
14778   g_print ("%*s%s:%p\n",
14779            depth * 2, "",
14780            _clutter_actor_get_debug_name (actor),
14781            actor);
14782
14783   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14784 }
14785
14786 static void
14787 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14788                                  ClutterTraverseCallback callback,
14789                                  gpointer                user_data)
14790 {
14791   GQueue *queue = g_queue_new ();
14792   ClutterActor dummy;
14793   int current_depth = 0;
14794
14795   g_queue_push_tail (queue, actor);
14796   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14797
14798   while ((actor = g_queue_pop_head (queue)))
14799     {
14800       ClutterActorTraverseVisitFlags flags;
14801
14802       if (actor == &dummy)
14803         {
14804           current_depth++;
14805           g_queue_push_tail (queue, &dummy);
14806           continue;
14807         }
14808
14809       flags = callback (actor, current_depth, user_data);
14810       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14811         break;
14812       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14813         {
14814           ClutterActor *iter;
14815
14816           for (iter = actor->priv->first_child;
14817                iter != NULL;
14818                iter = iter->priv->next_sibling)
14819             {
14820               g_queue_push_tail (queue, iter);
14821             }
14822         }
14823     }
14824
14825   g_queue_free (queue);
14826 }
14827
14828 static ClutterActorTraverseVisitFlags
14829 _clutter_actor_traverse_depth (ClutterActor           *actor,
14830                                ClutterTraverseCallback before_children_callback,
14831                                ClutterTraverseCallback after_children_callback,
14832                                int                     current_depth,
14833                                gpointer                user_data)
14834 {
14835   ClutterActorTraverseVisitFlags flags;
14836
14837   flags = before_children_callback (actor, current_depth, user_data);
14838   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14839     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14840
14841   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14842     {
14843       ClutterActor *iter;
14844
14845       for (iter = actor->priv->first_child;
14846            iter != NULL;
14847            iter = iter->priv->next_sibling)
14848         {
14849           flags = _clutter_actor_traverse_depth (iter,
14850                                                  before_children_callback,
14851                                                  after_children_callback,
14852                                                  current_depth + 1,
14853                                                  user_data);
14854
14855           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14856             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14857         }
14858     }
14859
14860   if (after_children_callback)
14861     return after_children_callback (actor, current_depth, user_data);
14862   else
14863     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14864 }
14865
14866 /* _clutter_actor_traverse:
14867  * @actor: The actor to start traversing the graph from
14868  * @flags: These flags may affect how the traversal is done
14869  * @before_children_callback: A function to call before visiting the
14870  *   children of the current actor.
14871  * @after_children_callback: A function to call after visiting the
14872  *   children of the current actor. (Ignored if
14873  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14874  * @user_data: The private data to pass to the callbacks
14875  *
14876  * Traverses the scenegraph starting at the specified @actor and
14877  * descending through all its children and its children's children.
14878  * For each actor traversed @before_children_callback and
14879  * @after_children_callback are called with the specified
14880  * @user_data, before and after visiting that actor's children.
14881  *
14882  * The callbacks can return flags that affect the ongoing traversal
14883  * such as by skipping over an actors children or bailing out of
14884  * any further traversing.
14885  */
14886 void
14887 _clutter_actor_traverse (ClutterActor              *actor,
14888                          ClutterActorTraverseFlags  flags,
14889                          ClutterTraverseCallback    before_children_callback,
14890                          ClutterTraverseCallback    after_children_callback,
14891                          gpointer                   user_data)
14892 {
14893   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
14894     _clutter_actor_traverse_breadth (actor,
14895                                      before_children_callback,
14896                                      user_data);
14897   else /* DEPTH_FIRST */
14898     _clutter_actor_traverse_depth (actor,
14899                                    before_children_callback,
14900                                    after_children_callback,
14901                                    0, /* start depth */
14902                                    user_data);
14903 }
14904
14905 static void
14906 on_layout_manager_changed (ClutterLayoutManager *manager,
14907                            ClutterActor         *self)
14908 {
14909   clutter_actor_queue_relayout (self);
14910 }
14911
14912 /**
14913  * clutter_actor_set_layout_manager:
14914  * @self: a #ClutterActor
14915  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
14916  *
14917  * Sets the #ClutterLayoutManager delegate object that will be used to
14918  * lay out the children of @self.
14919  *
14920  * The #ClutterActor will take a reference on the passed @manager which
14921  * will be released either when the layout manager is removed, or when
14922  * the actor is destroyed.
14923  *
14924  * Since: 1.10
14925  */
14926 void
14927 clutter_actor_set_layout_manager (ClutterActor         *self,
14928                                   ClutterLayoutManager *manager)
14929 {
14930   ClutterActorPrivate *priv;
14931
14932   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14933   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
14934
14935   priv = self->priv;
14936
14937   if (priv->layout_manager != NULL)
14938     {
14939       g_signal_handlers_disconnect_by_func (priv->layout_manager,
14940                                             G_CALLBACK (on_layout_manager_changed),
14941                                             self);
14942       clutter_layout_manager_set_container (priv->layout_manager, NULL);
14943       g_object_unref (priv->layout_manager);
14944     }
14945
14946   priv->layout_manager = manager;
14947
14948   if (priv->layout_manager != NULL)
14949     {
14950       g_object_ref_sink (priv->layout_manager);
14951       clutter_layout_manager_set_container (priv->layout_manager,
14952                                             CLUTTER_CONTAINER (self));
14953       g_signal_connect (priv->layout_manager, "layout-changed",
14954                         G_CALLBACK (on_layout_manager_changed),
14955                         self);
14956     }
14957
14958   clutter_actor_queue_relayout (self);
14959
14960   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
14961 }
14962
14963 /**
14964  * clutter_actor_get_layout_manager:
14965  * @self: a #ClutterActor
14966  *
14967  * Retrieves the #ClutterLayoutManager used by @self.
14968  *
14969  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
14970  *   or %NULL
14971  *
14972  * Since: 1.10
14973  */
14974 ClutterLayoutManager *
14975 clutter_actor_get_layout_manager (ClutterActor *self)
14976 {
14977   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14978
14979   return self->priv->layout_manager;
14980 }
14981
14982 static const ClutterLayoutInfo default_layout_info = {
14983   0.f,                          /* fixed-x */
14984   0.f,                          /* fixed-y */
14985   { 0, 0, 0, 0 },               /* margin */
14986   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
14987   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
14988   0.f, 0.f,                     /* min_width, natural_width */
14989   0.f, 0.f,                     /* natual_width, natural_height */
14990 };
14991
14992 static void
14993 layout_info_free (gpointer data)
14994 {
14995   if (G_LIKELY (data != NULL))
14996     g_slice_free (ClutterLayoutInfo, data);
14997 }
14998
14999 /*< private >
15000  * _clutter_actor_get_layout_info:
15001  * @self: a #ClutterActor
15002  *
15003  * Retrieves a pointer to the ClutterLayoutInfo structure.
15004  *
15005  * If the actor does not have a ClutterLayoutInfo associated to it, one
15006  * will be created and initialized to the default values.
15007  *
15008  * This function should be used for setters.
15009  *
15010  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15011  * instead.
15012  *
15013  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15014  */
15015 ClutterLayoutInfo *
15016 _clutter_actor_get_layout_info (ClutterActor *self)
15017 {
15018   ClutterLayoutInfo *retval;
15019
15020   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15021   if (retval == NULL)
15022     {
15023       retval = g_slice_new (ClutterLayoutInfo);
15024
15025       *retval = default_layout_info;
15026
15027       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15028                                retval,
15029                                layout_info_free);
15030     }
15031
15032   return retval;
15033 }
15034
15035 /*< private >
15036  * _clutter_actor_get_layout_info_or_defaults:
15037  * @self: a #ClutterActor
15038  *
15039  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15040  *
15041  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15042  * then the default structure will be returned.
15043  *
15044  * This function should only be used for getters.
15045  *
15046  * Return value: a const pointer to the ClutterLayoutInfo structure
15047  */
15048 const ClutterLayoutInfo *
15049 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15050 {
15051   const ClutterLayoutInfo *info;
15052
15053   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15054   if (info == NULL)
15055     return &default_layout_info;
15056
15057   return info;
15058 }
15059
15060 /**
15061  * clutter_actor_set_x_align:
15062  * @self: a #ClutterActor
15063  * @x_align: the horizontal alignment policy
15064  *
15065  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15066  * actor received extra horizontal space.
15067  *
15068  * See also the #ClutterActor:x-align property.
15069  *
15070  * Since: 1.10
15071  */
15072 void
15073 clutter_actor_set_x_align (ClutterActor      *self,
15074                            ClutterActorAlign  x_align)
15075 {
15076   ClutterLayoutInfo *info;
15077
15078   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15079
15080   info = _clutter_actor_get_layout_info (self);
15081
15082   if (info->x_align != x_align)
15083     {
15084       info->x_align = x_align;
15085
15086       clutter_actor_queue_relayout (self);
15087
15088       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15089     }
15090 }
15091
15092 /**
15093  * clutter_actor_get_x_align:
15094  * @self: a #ClutterActor
15095  *
15096  * Retrieves the horizontal alignment policy set using
15097  * clutter_actor_set_x_align().
15098  *
15099  * Return value: the horizontal alignment policy.
15100  *
15101  * Since: 1.10
15102  */
15103 ClutterActorAlign
15104 clutter_actor_get_x_align (ClutterActor *self)
15105 {
15106   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15107
15108   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15109 }
15110
15111 /**
15112  * clutter_actor_set_y_align:
15113  * @self: a #ClutterActor
15114  * @y_align: the vertical alignment policy
15115  *
15116  * Sets the vertical alignment policy of a #ClutterActor, in case the
15117  * actor received extra vertical space.
15118  *
15119  * See also the #ClutterActor:y-align property.
15120  *
15121  * Since: 1.10
15122  */
15123 void
15124 clutter_actor_set_y_align (ClutterActor      *self,
15125                            ClutterActorAlign  y_align)
15126 {
15127   ClutterLayoutInfo *info;
15128
15129   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15130
15131   info = _clutter_actor_get_layout_info (self);
15132
15133   if (info->y_align != y_align)
15134     {
15135       info->y_align = y_align;
15136
15137       clutter_actor_queue_relayout (self);
15138
15139       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15140     }
15141 }
15142
15143 /**
15144  * clutter_actor_get_y_align:
15145  * @self: a #ClutterActor
15146  *
15147  * Retrieves the vertical alignment policy set using
15148  * clutter_actor_set_y_align().
15149  *
15150  * Return value: the vertical alignment policy.
15151  *
15152  * Since: 1.10
15153  */
15154 ClutterActorAlign
15155 clutter_actor_get_y_align (ClutterActor *self)
15156 {
15157   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15158
15159   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15160 }
15161
15162
15163 /**
15164  * clutter_margin_new:
15165  *
15166  * Creates a new #ClutterMargin.
15167  *
15168  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15169  *   clutter_margin_free() to free the resources associated with it when
15170  *   done.
15171  *
15172  * Since: 1.10
15173  */
15174 ClutterMargin *
15175 clutter_margin_new (void)
15176 {
15177   return g_slice_new0 (ClutterMargin);
15178 }
15179
15180 /**
15181  * clutter_margin_copy:
15182  * @margin_: a #ClutterMargin
15183  *
15184  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15185  * the newly created structure.
15186  *
15187  * Return value: (transfer full): a copy of the #ClutterMargin.
15188  *
15189  * Since: 1.10
15190  */
15191 ClutterMargin *
15192 clutter_margin_copy (const ClutterMargin *margin_)
15193 {
15194   if (G_LIKELY (margin_ != NULL))
15195     return g_slice_dup (ClutterMargin, margin_);
15196
15197   return NULL;
15198 }
15199
15200 /**
15201  * clutter_margin_free:
15202  * @margin_: a #ClutterMargin
15203  *
15204  * Frees the resources allocated by clutter_margin_new() and
15205  * clutter_margin_copy().
15206  *
15207  * Since: 1.10
15208  */
15209 void
15210 clutter_margin_free (ClutterMargin *margin_)
15211 {
15212   if (G_LIKELY (margin_ != NULL))
15213     g_slice_free (ClutterMargin, margin_);
15214 }
15215
15216 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15217                      clutter_margin_copy,
15218                      clutter_margin_free)
15219
15220 /**
15221  * clutter_actor_set_margin:
15222  * @self: a #ClutterActor
15223  * @margin: a #ClutterMargin
15224  *
15225  * Sets all the components of the margin of a #ClutterActor.
15226  *
15227  * Since: 1.10
15228  */
15229 void
15230 clutter_actor_set_margin (ClutterActor        *self,
15231                           const ClutterMargin *margin)
15232 {
15233   ClutterLayoutInfo *info;
15234   gboolean changed;
15235   GObject *obj;
15236
15237   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15238   g_return_if_fail (margin != NULL);
15239
15240   obj = G_OBJECT (self);
15241   changed = FALSE;
15242
15243   g_object_freeze_notify (obj);
15244
15245   info = _clutter_actor_get_layout_info (self);
15246
15247   if (info->margin.top != margin->top)
15248     {
15249       info->margin.top = margin->top;
15250       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15251       changed = TRUE;
15252     }
15253
15254   if (info->margin.right != margin->right)
15255     {
15256       info->margin.right = margin->right;
15257       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15258       changed = TRUE;
15259     }
15260
15261   if (info->margin.bottom != margin->bottom)
15262     {
15263       info->margin.bottom = margin->bottom;
15264       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15265       changed = TRUE;
15266     }
15267
15268   if (info->margin.left != margin->left)
15269     {
15270       info->margin.left = margin->left;
15271       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15272       changed = TRUE;
15273     }
15274
15275   if (changed)
15276     clutter_actor_queue_relayout (self);
15277
15278   g_object_thaw_notify (obj);
15279 }
15280
15281 /**
15282  * clutter_actor_get_margin:
15283  * @self: a #ClutterActor
15284  * @margin: (out caller-allocates): return location for a #ClutterMargin
15285  *
15286  * Retrieves all the components of the margin of a #ClutterActor.
15287  *
15288  * Since: 1.10
15289  */
15290 void
15291 clutter_actor_get_margin (ClutterActor  *self,
15292                           ClutterMargin *margin)
15293 {
15294   const ClutterLayoutInfo *info;
15295
15296   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15297   g_return_if_fail (margin != NULL);
15298
15299   info = _clutter_actor_get_layout_info_or_defaults (self);
15300
15301   *margin = info->margin;
15302 }
15303
15304 /**
15305  * clutter_actor_set_margin_top:
15306  * @self: a #ClutterActor
15307  * @margin: the top margin
15308  *
15309  * Sets the margin from the top of a #ClutterActor.
15310  *
15311  * Since: 1.10
15312  */
15313 void
15314 clutter_actor_set_margin_top (ClutterActor *self,
15315                               gfloat        margin)
15316 {
15317   ClutterLayoutInfo *info;
15318
15319   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15320   g_return_if_fail (margin >= 0.f);
15321
15322   info = _clutter_actor_get_layout_info (self);
15323
15324   if (info->margin.top == margin)
15325     return;
15326
15327   info->margin.top = margin;
15328
15329   clutter_actor_queue_relayout (self);
15330
15331   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15332 }
15333
15334 /**
15335  * clutter_actor_get_margin_top:
15336  * @self: a #ClutterActor
15337  *
15338  * Retrieves the top margin of a #ClutterActor.
15339  *
15340  * Return value: the top margin
15341  *
15342  * Since: 1.10
15343  */
15344 gfloat
15345 clutter_actor_get_margin_top (ClutterActor *self)
15346 {
15347   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15348
15349   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15350 }
15351
15352 /**
15353  * clutter_actor_set_margin_bottom:
15354  * @self: a #ClutterActor
15355  * @margin: the bottom margin
15356  *
15357  * Sets the margin from the bottom of a #ClutterActor.
15358  *
15359  * Since: 1.10
15360  */
15361 void
15362 clutter_actor_set_margin_bottom (ClutterActor *self,
15363                                  gfloat        margin)
15364 {
15365   ClutterLayoutInfo *info;
15366
15367   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15368   g_return_if_fail (margin >= 0.f);
15369
15370   info = _clutter_actor_get_layout_info (self);
15371
15372   if (info->margin.bottom == margin)
15373     return;
15374
15375   info->margin.bottom = margin;
15376
15377   clutter_actor_queue_relayout (self);
15378
15379   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15380 }
15381
15382 /**
15383  * clutter_actor_get_margin_bottom:
15384  * @self: a #ClutterActor
15385  *
15386  * Retrieves the bottom margin of a #ClutterActor.
15387  *
15388  * Return value: the bottom margin
15389  *
15390  * Since: 1.10
15391  */
15392 gfloat
15393 clutter_actor_get_margin_bottom (ClutterActor *self)
15394 {
15395   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15396
15397   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15398 }
15399
15400 /**
15401  * clutter_actor_set_margin_left:
15402  * @self: a #ClutterActor
15403  * @margin: the left margin
15404  *
15405  * Sets the margin from the left of a #ClutterActor.
15406  *
15407  * Since: 1.10
15408  */
15409 void
15410 clutter_actor_set_margin_left (ClutterActor *self,
15411                                gfloat        margin)
15412 {
15413   ClutterLayoutInfo *info;
15414
15415   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15416   g_return_if_fail (margin >= 0.f);
15417
15418   info = _clutter_actor_get_layout_info (self);
15419
15420   if (info->margin.left == margin)
15421     return;
15422
15423   info->margin.left = margin;
15424
15425   clutter_actor_queue_relayout (self);
15426
15427   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15428 }
15429
15430 /**
15431  * clutter_actor_get_margin_left:
15432  * @self: a #ClutterActor
15433  *
15434  * Retrieves the left margin of a #ClutterActor.
15435  *
15436  * Return value: the left margin
15437  *
15438  * Since: 1.10
15439  */
15440 gfloat
15441 clutter_actor_get_margin_left (ClutterActor *self)
15442 {
15443   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15444
15445   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15446 }
15447
15448 /**
15449  * clutter_actor_set_margin_right:
15450  * @self: a #ClutterActor
15451  * @margin: the right margin
15452  *
15453  * Sets the margin from the right of a #ClutterActor.
15454  *
15455  * Since: 1.10
15456  */
15457 void
15458 clutter_actor_set_margin_right (ClutterActor *self,
15459                                 gfloat        margin)
15460 {
15461   ClutterLayoutInfo *info;
15462
15463   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15464   g_return_if_fail (margin >= 0.f);
15465
15466   info = _clutter_actor_get_layout_info (self);
15467
15468   if (info->margin.right == margin)
15469     return;
15470
15471   info->margin.right = margin;
15472
15473   clutter_actor_queue_relayout (self);
15474
15475   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15476 }
15477
15478 /**
15479  * clutter_actor_get_margin_right:
15480  * @self: a #ClutterActor
15481  *
15482  * Retrieves the right margin of a #ClutterActor.
15483  *
15484  * Return value: the right margin
15485  *
15486  * Since: 1.10
15487  */
15488 gfloat
15489 clutter_actor_get_margin_right (ClutterActor *self)
15490 {
15491   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15492
15493   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15494 }
15495
15496 /**
15497  * clutter_actor_set_background_color:
15498  * @self: a #ClutterActor
15499  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15500  *  set color
15501  *
15502  * Sets the background color of a #ClutterActor.
15503  *
15504  * The background color will be used to cover the whole allocation of the
15505  * actor. The default background color of an actor is transparent.
15506  *
15507  * To check whether an actor has a background color, you can use the
15508  * #ClutterActor:background-color-set actor property.
15509  *
15510  * Since: 1.10
15511  */
15512 void
15513 clutter_actor_set_background_color (ClutterActor       *self,
15514                                     const ClutterColor *color)
15515 {
15516   ClutterActorPrivate *priv;
15517
15518   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15519
15520   priv = self->priv;
15521
15522   if (color == NULL)
15523     {
15524       priv->bg_color_set = FALSE;
15525       g_object_notify_by_pspec (G_OBJECT (self),
15526                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15527       return;
15528     }
15529
15530   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15531     return;
15532
15533   priv->bg_color = *color;
15534   priv->bg_color_set = TRUE;
15535
15536   clutter_actor_queue_redraw (self);
15537
15538   g_object_notify_by_pspec (G_OBJECT (self),
15539                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15540   g_object_notify_by_pspec (G_OBJECT (self),
15541                             obj_props[PROP_BACKGROUND_COLOR]);
15542 }
15543
15544 /**
15545  * clutter_actor_get_background_color:
15546  * @self: a #ClutterActor
15547  * @color: (out caller-allocates): return location for a #ClutterColor
15548  *
15549  * Retrieves the color set using clutter_actor_set_background_color().
15550  *
15551  * Since: 1.10
15552  */
15553 void
15554 clutter_actor_get_background_color (ClutterActor *self,
15555                                     ClutterColor *color)
15556 {
15557   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15558   g_return_if_fail (color != NULL);
15559
15560   *color = self->priv->bg_color;
15561 }
15562
15563 /**
15564  * clutter_actor_get_previous_sibling:
15565  * @self: a #ClutterActor
15566  *
15567  * Retrieves the sibling of @self that comes before it in the list
15568  * of children of @self's parent.
15569  *
15570  * The returned pointer is only valid until the scene graph changes; it
15571  * is not safe to modify the list of children of @self while iterating
15572  * it.
15573  *
15574  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15575  *
15576  * Since: 1.10
15577  */
15578 ClutterActor *
15579 clutter_actor_get_previous_sibling (ClutterActor *self)
15580 {
15581   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15582
15583   return self->priv->prev_sibling;
15584 }
15585
15586 /**
15587  * clutter_actor_get_next_sibling:
15588  * @self: a #ClutterActor
15589  *
15590  * Retrieves the sibling of @self that comes after it in the list
15591  * of children of @self's parent.
15592  *
15593  * The returned pointer is only valid until the scene graph changes; it
15594  * is not safe to modify the list of children of @self while iterating
15595  * it.
15596  *
15597  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15598  *
15599  * Since: 1.10
15600  */
15601 ClutterActor *
15602 clutter_actor_get_next_sibling (ClutterActor *self)
15603 {
15604   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15605
15606   return self->priv->next_sibling;
15607 }
15608
15609 /**
15610  * clutter_actor_get_first_child:
15611  * @self: a #ClutterActor
15612  *
15613  * Retrieves the first child of @self.
15614  *
15615  * The returned pointer is only valid until the scene graph changes; it
15616  * is not safe to modify the list of children of @self while iterating
15617  * it.
15618  *
15619  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15620  *
15621  * Since: 1.10
15622  */
15623 ClutterActor *
15624 clutter_actor_get_first_child (ClutterActor *self)
15625 {
15626   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15627
15628   return self->priv->first_child;
15629 }
15630
15631 /**
15632  * clutter_actor_get_last_child:
15633  * @self: a #ClutterActor
15634  *
15635  * Retrieves the last child of @self.
15636  *
15637  * The returned pointer is only valid until the scene graph changes; it
15638  * is not safe to modify the list of children of @self while iterating
15639  * it.
15640  *
15641  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15642  *
15643  * Since: 1.10
15644  */
15645 ClutterActor *
15646 clutter_actor_get_last_child (ClutterActor *self)
15647 {
15648   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15649
15650   return self->priv->last_child;
15651 }
15652
15653 /* easy way to have properly named fields instead of the dummy ones
15654  * we use in the public structure
15655  */
15656 typedef struct _RealActorIter
15657 {
15658   ClutterActor *root;           /* dummy1 */
15659   ClutterActor *current;        /* dummy2 */
15660   gpointer padding_1;           /* dummy3 */
15661   gint age;                     /* dummy4 */
15662   gpointer padding_2;           /* dummy5 */
15663 } RealActorIter;
15664
15665 /**
15666  * clutter_actor_iter_init:
15667  * @iter: a #ClutterActorIter
15668  * @root: a #ClutterActor
15669  *
15670  * Initializes a #ClutterActorIter, which can then be used to iterate
15671  * efficiently over a section of the scene graph, and associates it
15672  * with @root.
15673  *
15674  * Modifying the scene graph section that contains @root will invalidate
15675  * the iterator.
15676  *
15677  * |[
15678  *   ClutterActorIter iter;
15679  *   ClutterActor *child;
15680  *
15681  *   clutter_actor_iter_init (&iter, container);
15682  *   while (clutter_actor_iter_next (&iter, &child))
15683  *     {
15684  *       /&ast; do something with child &ast;/
15685  *     }
15686  * ]|
15687  *
15688  * Since: 1.10
15689  */
15690 void
15691 clutter_actor_iter_init (ClutterActorIter *iter,
15692                          ClutterActor     *root)
15693 {
15694   RealActorIter *ri = (RealActorIter *) iter;
15695
15696   g_return_if_fail (iter != NULL);
15697   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15698
15699   ri->root = root;
15700   ri->current = NULL;
15701   ri->age = root->priv->age;
15702 }
15703
15704 /**
15705  * clutter_actor_iter_next:
15706  * @iter: a #ClutterActorIter
15707  * @child: (out): return location for a #ClutterActor
15708  *
15709  * Advances the @iter and retrieves the next child of the root #ClutterActor
15710  * that was used to initialize the #ClutterActorIterator.
15711  *
15712  * If the iterator can advance, this function returns %TRUE and sets the
15713  * @child argument.
15714  *
15715  * If the iterator cannot advance, this function returns %FALSE, and
15716  * the contents of @child are undefined.
15717  *
15718  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15719  *
15720  * Since: 1.10
15721  */
15722 gboolean
15723 clutter_actor_iter_next (ClutterActorIter  *iter,
15724                          ClutterActor     **child)
15725 {
15726   RealActorIter *ri = (RealActorIter *) iter;
15727
15728   g_return_val_if_fail (iter != NULL, FALSE);
15729   g_return_val_if_fail (ri->root != NULL, FALSE);
15730 #ifndef G_DISABLE_ASSERT
15731   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15732 #endif
15733
15734   if (ri->current == NULL)
15735     ri->current = ri->root->priv->first_child;
15736   else
15737     ri->current = ri->current->priv->next_sibling;
15738
15739   if (child != NULL)
15740     *child = ri->current;
15741
15742   return ri->current != NULL;
15743 }
15744
15745 /**
15746  * clutter_actor_iter_next:
15747  * @iter: a #ClutterActorIter
15748  * @child: (out): return location for a #ClutterActor
15749  *
15750  * Advances the @iter and retrieves the previous child of the root
15751  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15752  *
15753  * If the iterator can advance, this function returns %TRUE and sets the
15754  * @child argument.
15755  *
15756  * If the iterator cannot advance, this function returns %FALSE, and
15757  * the contents of @child are undefined.
15758  *
15759  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15760  *
15761  * Since: 1.10
15762  */
15763 gboolean
15764 clutter_actor_iter_prev (ClutterActorIter  *iter,
15765                          ClutterActor     **child)
15766 {
15767   RealActorIter *ri = (RealActorIter *) iter;
15768
15769   g_return_val_if_fail (iter != NULL, FALSE);
15770   g_return_val_if_fail (ri->root != NULL, FALSE);
15771 #ifndef G_DISABLE_ASSERT
15772   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15773 #endif
15774
15775   if (ri->current == NULL)
15776     ri->current = ri->root->priv->last_child;
15777   else
15778     ri->current = ri->current->priv->prev_sibling;
15779
15780   if (child != NULL)
15781     *child = ri->current;
15782
15783   return ri->current != NULL;
15784 }
15785
15786 /**
15787  * clutter_actor_iter_remove:
15788  * @iter: a #ClutterActorIter
15789  *
15790  * Safely removes the #ClutterActor currently pointer to by the iterator
15791  * from its parent.
15792  *
15793  * This function can only be called after clutter_actor_iter_next() or
15794  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15795  * than once for the same actor.
15796  *
15797  * This function will call clutter_actor_remove_child() internally.
15798  *
15799  * Since: 1.10
15800  */
15801 void
15802 clutter_actor_iter_remove (ClutterActorIter *iter)
15803 {
15804   RealActorIter *ri = (RealActorIter *) iter;
15805   ClutterActor *cur;
15806
15807   g_return_if_fail (iter != NULL);
15808   g_return_if_fail (ri->root != NULL);
15809 #ifndef G_DISABLE_ASSERT
15810   g_return_if_fail (ri->age == ri->root->priv->age);
15811 #endif
15812   g_return_if_fail (ri->current != NULL);
15813
15814   cur = ri->current;
15815
15816   if (cur != NULL)
15817     {
15818       ri->current = cur->priv->prev_sibling;
15819
15820       clutter_actor_remove_child_internal (ri->root, cur,
15821                                            REMOVE_CHILD_DEFAULT_FLAGS);
15822
15823       ri->age += 1;
15824     }
15825 }
15826
15827 /**
15828  * clutter_actor_iter_destroy:
15829  * @iter: a #ClutterActorIter
15830  *
15831  * Safely destroys the #ClutterActor currently pointer to by the iterator
15832  * from its parent.
15833  *
15834  * This function can only be called after clutter_actor_iter_next() or
15835  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15836  * than once for the same actor.
15837  *
15838  * This function will call clutter_actor_destroy() internally.
15839  *
15840  * Since: 1.10
15841  */
15842 void
15843 clutter_actor_iter_destroy (ClutterActorIter *iter)
15844 {
15845   RealActorIter *ri = (RealActorIter *) iter;
15846   ClutterActor *cur;
15847
15848   g_return_if_fail (iter != NULL);
15849   g_return_if_fail (ri->root != NULL);
15850 #ifndef G_DISABLE_ASSERT
15851   g_return_if_fail (ri->age == ri->root->priv->age);
15852 #endif
15853   g_return_if_fail (ri->current != NULL);
15854
15855   cur = ri->current;
15856
15857   if (cur != NULL)
15858     {
15859       ri->current = cur->priv->prev_sibling;
15860
15861       clutter_actor_destroy (cur);
15862
15863       ri->age += 1;
15864     }
15865 }