actor: Correct get_paint_volume for an actor with no children and no clip
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="bin-layout">
113  *     <title>Actors</title>
114  *     <graphic fileref="test-actor.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  */
243
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
327
328 #include "clutter-actor-private.h"
329
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-main.h"
342 #include "clutter-marshal.h"
343 #include "clutter-flatten-effect.h"
344 #include "clutter-paint-volume-private.h"
345 #include "clutter-private.h"
346 #include "clutter-profile.h"
347 #include "clutter-scriptable.h"
348 #include "clutter-script-private.h"
349 #include "clutter-stage-private.h"
350 #include "clutter-units.h"
351
352 #include "deprecated/clutter-behaviour.h"
353 #include "deprecated/clutter-container.h"
354
355 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
356 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
357
358 /* Internal enum used to control mapped state update.  This is a hint
359  * which indicates when to do something other than just enforce
360  * invariants.
361  */
362 typedef enum {
363   MAP_STATE_CHECK,           /* just enforce invariants. */
364   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
365                               * used when about to unparent.
366                               */
367   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
368                               * used to set mapped on toplevels.
369                               */
370   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
371                               * used just before unmapping parent.
372                               */
373 } MapStateChange;
374
375 /* 3 entries should be a good compromise, few layout managers
376  * will ask for 3 different preferred size in each allocation cycle */
377 #define N_CACHED_SIZE_REQUESTS 3
378
379 struct _ClutterActorPrivate
380 {
381   /* request mode */
382   ClutterRequestMode request_mode;
383
384   /* our cached size requests for different width / height */
385   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
386   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
387
388   /* An age of 0 means the entry is not set */
389   guint cached_height_age;
390   guint cached_width_age;
391
392   /* the bounding box of the actor, relative to the parent's
393    * allocation
394    */
395   ClutterActorBox allocation;
396   ClutterAllocationFlags allocation_flags;
397
398   /* depth */
399   gfloat z;
400
401   /* clip, in actor coordinates */
402   cairo_rectangle_t clip;
403
404   /* the cached transformation matrix; see apply_transform() */
405   CoglMatrix transform;
406
407   guint8 opacity;
408   gint opacity_override;
409
410   ClutterOffscreenRedirect offscreen_redirect;
411
412   /* This is an internal effect used to implement the
413      offscreen-redirect property */
414   ClutterEffect *flatten_effect;
415
416   /* scene graph */
417   ClutterActor *parent;
418   ClutterActor *prev_sibling;
419   ClutterActor *next_sibling;
420   ClutterActor *first_child;
421   ClutterActor *last_child;
422
423   gint n_children;
424
425   /* tracks whenever the children of an actor are changed; the
426    * age is incremented by 1 whenever an actor is added or
427    * removed. the age is not incremented when the first or the
428    * last child pointers are changed, or when grandchildren of
429    * an actor are changed.
430    */
431   gint age;
432
433   gchar *name; /* a non-unique name, used for debugging */
434   guint32 id; /* unique id, used for backward compatibility */
435
436   gint32 pick_id; /* per-stage unique id, used for picking */
437
438   /* a back-pointer to the Pango context that we can use
439    * to create pre-configured PangoLayout
440    */
441   PangoContext *pango_context;
442
443   /* the text direction configured for this child - either by
444    * application code, or by the actor's parent
445    */
446   ClutterTextDirection text_direction;
447
448   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
449   gint internal_child;
450
451   /* meta classes */
452   ClutterMetaGroup *actions;
453   ClutterMetaGroup *constraints;
454   ClutterMetaGroup *effects;
455
456   /* delegate object used to allocate the children of this actor */
457   ClutterLayoutManager *layout_manager;
458
459   /* used when painting, to update the paint volume */
460   ClutterEffect *current_effect;
461
462   /* This is used to store an effect which needs to be redrawn. A
463      redraw can be queued to start from a particular effect. This is
464      used by parametrised effects that can cache an image of the
465      actor. If a parameter of the effect changes then it only needs to
466      redraw the cached image, not the actual actor. The pointer is
467      only valid if is_dirty == TRUE. If the pointer is NULL then the
468      whole actor is dirty. */
469   ClutterEffect *effect_to_redraw;
470
471   /* This is used when painting effects to implement the
472      clutter_actor_continue_paint() function. It points to the node in
473      the list of effects that is next in the chain */
474   const GList *next_effect_to_paint;
475
476   ClutterPaintVolume paint_volume;
477
478   /* NB: This volume isn't relative to this actor, it is in eye
479    * coordinates so that it can remain valid after the actor changes.
480    */
481   ClutterPaintVolume last_paint_volume;
482
483   ClutterStageQueueRedrawEntry *queue_redraw_entry;
484
485   ClutterColor bg_color;
486
487   /* bitfields */
488
489   /* fixed position and sizes */
490   guint position_set                : 1;
491   guint min_width_set               : 1;
492   guint min_height_set              : 1;
493   guint natural_width_set           : 1;
494   guint natural_height_set          : 1;
495   /* cached request is invalid (implies allocation is too) */
496   guint needs_width_request         : 1;
497   /* cached request is invalid (implies allocation is too) */
498   guint needs_height_request        : 1;
499   /* cached allocation is invalid (request has changed, probably) */
500   guint needs_allocation            : 1;
501   guint show_on_set_parent          : 1;
502   guint has_clip                    : 1;
503   guint clip_to_allocation          : 1;
504   guint enable_model_view_transform : 1;
505   guint enable_paint_unmapped       : 1;
506   guint has_pointer                 : 1;
507   guint propagated_one_redraw       : 1;
508   guint paint_volume_valid          : 1;
509   guint last_paint_volume_valid     : 1;
510   guint in_clone_paint              : 1;
511   guint transform_valid             : 1;
512   /* This is TRUE if anything has queued a redraw since we were last
513      painted. In this case effect_to_redraw will point to an effect
514      the redraw was queued from or it will be NULL if the redraw was
515      queued without an effect. */
516   guint is_dirty                    : 1;
517   guint bg_color_set                : 1;
518 };
519
520 enum
521 {
522   PROP_0,
523
524   PROP_NAME,
525
526   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
527    * when set they force a size request, when gotten they
528    * get the allocation if the allocation is valid, and the
529    * request otherwise
530    */
531   PROP_X,
532   PROP_Y,
533   PROP_WIDTH,
534   PROP_HEIGHT,
535
536   /* Then the rest of these size-related properties are the "actual"
537    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
538    */
539   PROP_FIXED_X,
540   PROP_FIXED_Y,
541
542   PROP_FIXED_POSITION_SET,
543
544   PROP_MIN_WIDTH,
545   PROP_MIN_WIDTH_SET,
546
547   PROP_MIN_HEIGHT,
548   PROP_MIN_HEIGHT_SET,
549
550   PROP_NATURAL_WIDTH,
551   PROP_NATURAL_WIDTH_SET,
552
553   PROP_NATURAL_HEIGHT,
554   PROP_NATURAL_HEIGHT_SET,
555
556   PROP_REQUEST_MODE,
557
558   /* Allocation properties are read-only */
559   PROP_ALLOCATION,
560
561   PROP_DEPTH,
562
563   PROP_CLIP,
564   PROP_HAS_CLIP,
565   PROP_CLIP_TO_ALLOCATION,
566
567   PROP_OPACITY,
568
569   PROP_OFFSCREEN_REDIRECT,
570
571   PROP_VISIBLE,
572   PROP_MAPPED,
573   PROP_REALIZED,
574   PROP_REACTIVE,
575
576   PROP_SCALE_X,
577   PROP_SCALE_Y,
578   PROP_SCALE_CENTER_X,
579   PROP_SCALE_CENTER_Y,
580   PROP_SCALE_GRAVITY,
581
582   PROP_ROTATION_ANGLE_X,
583   PROP_ROTATION_ANGLE_Y,
584   PROP_ROTATION_ANGLE_Z,
585   PROP_ROTATION_CENTER_X,
586   PROP_ROTATION_CENTER_Y,
587   PROP_ROTATION_CENTER_Z,
588   /* This property only makes sense for the z rotation because the
589      others would depend on the actor having a size along the
590      z-axis */
591   PROP_ROTATION_CENTER_Z_GRAVITY,
592
593   PROP_ANCHOR_X,
594   PROP_ANCHOR_Y,
595   PROP_ANCHOR_GRAVITY,
596
597   PROP_SHOW_ON_SET_PARENT,
598
599   PROP_TEXT_DIRECTION,
600   PROP_HAS_POINTER,
601
602   PROP_ACTIONS,
603   PROP_CONSTRAINTS,
604   PROP_EFFECT,
605
606   PROP_LAYOUT_MANAGER,
607
608   PROP_X_ALIGN,
609   PROP_Y_ALIGN,
610   PROP_MARGIN_TOP,
611   PROP_MARGIN_BOTTOM,
612   PROP_MARGIN_LEFT,
613   PROP_MARGIN_RIGHT,
614
615   PROP_BACKGROUND_COLOR,
616   PROP_BACKGROUND_COLOR_SET,
617
618   PROP_FIRST_CHILD,
619   PROP_LAST_CHILD,
620
621   PROP_LAST
622 };
623
624 static GParamSpec *obj_props[PROP_LAST];
625
626 enum
627 {
628   SHOW,
629   HIDE,
630   DESTROY,
631   PARENT_SET,
632   KEY_FOCUS_IN,
633   KEY_FOCUS_OUT,
634   PAINT,
635   PICK,
636   REALIZE,
637   UNREALIZE,
638   QUEUE_REDRAW,
639   QUEUE_RELAYOUT,
640   EVENT,
641   CAPTURED_EVENT,
642   BUTTON_PRESS_EVENT,
643   BUTTON_RELEASE_EVENT,
644   SCROLL_EVENT,
645   KEY_PRESS_EVENT,
646   KEY_RELEASE_EVENT,
647   MOTION_EVENT,
648   ENTER_EVENT,
649   LEAVE_EVENT,
650   ALLOCATION_CHANGED,
651
652   LAST_SIGNAL
653 };
654
655 static guint actor_signals[LAST_SIGNAL] = { 0, };
656
657 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
658 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
659 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
660 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
661
662 /* These setters are all static for now, maybe they should be in the
663  * public API, but they are perhaps obscure enough to leave only as
664  * properties
665  */
666 static void clutter_actor_set_min_width          (ClutterActor *self,
667                                                   gfloat        min_width);
668 static void clutter_actor_set_min_height         (ClutterActor *self,
669                                                   gfloat        min_height);
670 static void clutter_actor_set_natural_width      (ClutterActor *self,
671                                                   gfloat        natural_width);
672 static void clutter_actor_set_natural_height     (ClutterActor *self,
673                                                   gfloat        natural_height);
674 static void clutter_actor_set_min_width_set      (ClutterActor *self,
675                                                   gboolean      use_min_width);
676 static void clutter_actor_set_min_height_set     (ClutterActor *self,
677                                                   gboolean      use_min_height);
678 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
679                                                   gboolean  use_natural_width);
680 static void clutter_actor_set_natural_height_set (ClutterActor *self,
681                                                   gboolean  use_natural_height);
682 static void clutter_actor_update_map_state       (ClutterActor  *self,
683                                                   MapStateChange change);
684 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
685
686 /* Helper routines for managing anchor coords */
687 static void clutter_anchor_coord_get_units (ClutterActor      *self,
688                                             const AnchorCoord *coord,
689                                             gfloat            *x,
690                                             gfloat            *y,
691                                             gfloat            *z);
692 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
693                                             gfloat             x,
694                                             gfloat             y,
695                                             gfloat             z);
696
697 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
698 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
699                                                         ClutterGravity     gravity);
700
701 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
702
703 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
704
705 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
706                                                                ClutterActor *ancestor,
707                                                                CoglMatrix *matrix);
708
709 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
710
711 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
712
713 static void on_layout_manager_changed (ClutterLayoutManager *manager,
714                                        ClutterActor         *self);
715
716 /* Helper macro which translates by the anchor coord, applies the
717    given transformation and then translates back */
718 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
719   gfloat _tx, _ty, _tz;                                                \
720   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
721   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
722   { _transform; }                                                      \
723   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
724
725 static GQuark quark_shader_data = 0;
726 static GQuark quark_actor_layout_info = 0;
727 static GQuark quark_actor_transform_info = 0;
728
729 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
730                          clutter_actor,
731                          G_TYPE_INITIALLY_UNOWNED,
732                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
733                                                 clutter_container_iface_init)
734                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
735                                                 clutter_scriptable_iface_init)
736                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
737                                                 clutter_animatable_iface_init)
738                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
739                                                 atk_implementor_iface_init));
740
741 /*< private >
742  * clutter_actor_get_debug_name:
743  * @actor: a #ClutterActor
744  *
745  * Retrieves a printable name of @actor for debugging messages
746  *
747  * Return value: a string with a printable name
748  */
749 const gchar *
750 _clutter_actor_get_debug_name (ClutterActor *actor)
751 {
752   return actor->priv->name != NULL ? actor->priv->name
753                                    : G_OBJECT_TYPE_NAME (actor);
754 }
755
756 #ifdef CLUTTER_ENABLE_DEBUG
757 /* XXX - this is for debugging only, remove once working (or leave
758  * in only in some debug mode). Should leave it for a little while
759  * until we're confident in the new map/realize/visible handling.
760  */
761 static inline void
762 clutter_actor_verify_map_state (ClutterActor *self)
763 {
764   ClutterActorPrivate *priv = self->priv;
765
766   if (CLUTTER_ACTOR_IS_REALIZED (self))
767     {
768       /* all bets are off during reparent when we're potentially realized,
769        * but should not be according to invariants
770        */
771       if (!CLUTTER_ACTOR_IN_REPARENT (self))
772         {
773           if (priv->parent == NULL)
774             {
775               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
776                 {
777                 }
778               else
779                 g_warning ("Realized non-toplevel actor '%s' should "
780                            "have a parent",
781                            _clutter_actor_get_debug_name (self));
782             }
783           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
784             {
785               g_warning ("Realized actor %s has an unrealized parent %s",
786                          _clutter_actor_get_debug_name (self),
787                          _clutter_actor_get_debug_name (priv->parent));
788             }
789         }
790     }
791
792   if (CLUTTER_ACTOR_IS_MAPPED (self))
793     {
794       if (!CLUTTER_ACTOR_IS_REALIZED (self))
795         g_warning ("Actor '%s' is mapped but not realized",
796                    _clutter_actor_get_debug_name (self));
797
798       /* remaining bets are off during reparent when we're potentially
799        * mapped, but should not be according to invariants
800        */
801       if (!CLUTTER_ACTOR_IN_REPARENT (self))
802         {
803           if (priv->parent == NULL)
804             {
805               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
806                 {
807                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
808                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
809                     {
810                       g_warning ("Toplevel actor '%s' is mapped "
811                                  "but not visible",
812                                  _clutter_actor_get_debug_name (self));
813                     }
814                 }
815               else
816                 {
817                   g_warning ("Mapped actor '%s' should have a parent",
818                              _clutter_actor_get_debug_name (self));
819                 }
820             }
821           else
822             {
823               ClutterActor *iter = self;
824
825               /* check for the enable_paint_unmapped flag on the actor
826                * and parents; if the flag is enabled at any point of this
827                * branch of the scene graph then all the later checks
828                * become pointless
829                */
830               while (iter != NULL)
831                 {
832                   if (iter->priv->enable_paint_unmapped)
833                     return;
834
835                   iter = iter->priv->parent;
836                 }
837
838               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
839                 {
840                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
841                              "is not visible",
842                              _clutter_actor_get_debug_name (self),
843                              _clutter_actor_get_debug_name (priv->parent));
844                 }
845
846               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
847                 {
848                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
849                              "is not realized",
850                              _clutter_actor_get_debug_name (self),
851                              _clutter_actor_get_debug_name (priv->parent));
852                 }
853
854               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
855                 {
856                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
857                     g_warning ("Actor '%s' is mapped but its non-toplevel "
858                                "parent '%s' is not mapped",
859                                _clutter_actor_get_debug_name (self),
860                                _clutter_actor_get_debug_name (priv->parent));
861                 }
862             }
863         }
864     }
865 }
866
867 #endif /* CLUTTER_ENABLE_DEBUG */
868
869 static void
870 clutter_actor_set_mapped (ClutterActor *self,
871                           gboolean      mapped)
872 {
873   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
874     return;
875
876   if (mapped)
877     {
878       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
879       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
880     }
881   else
882     {
883       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
884       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
885     }
886 }
887
888 /* this function updates the mapped and realized states according to
889  * invariants, in the appropriate order.
890  */
891 static void
892 clutter_actor_update_map_state (ClutterActor  *self,
893                                 MapStateChange change)
894 {
895   gboolean was_mapped;
896
897   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
898
899   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
900     {
901       /* the mapped flag on top-level actors must be set by the
902        * per-backend implementation because it might be asynchronous.
903        *
904        * That is, the MAPPED flag on toplevels currently tracks the X
905        * server mapped-ness of the window, while the expected behavior
906        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
907        * This creates some weird complexity by breaking the invariant
908        * that if we're visible and all ancestors shown then we are
909        * also mapped - instead, we are mapped if all ancestors
910        * _possibly excepting_ the stage are mapped. The stage
911        * will map/unmap for example when it is minimized or
912        * moved to another workspace.
913        *
914        * So, the only invariant on the stage is that if visible it
915        * should be realized, and that it has to be visible to be
916        * mapped.
917        */
918       if (CLUTTER_ACTOR_IS_VISIBLE (self))
919         clutter_actor_realize (self);
920
921       switch (change)
922         {
923         case MAP_STATE_CHECK:
924           break;
925
926         case MAP_STATE_MAKE_MAPPED:
927           g_assert (!was_mapped);
928           clutter_actor_set_mapped (self, TRUE);
929           break;
930
931         case MAP_STATE_MAKE_UNMAPPED:
932           g_assert (was_mapped);
933           clutter_actor_set_mapped (self, FALSE);
934           break;
935
936         case MAP_STATE_MAKE_UNREALIZED:
937           /* we only use MAKE_UNREALIZED in unparent,
938            * and unparenting a stage isn't possible.
939            * If someone wants to just unrealize a stage
940            * then clutter_actor_unrealize() doesn't
941            * go through this codepath.
942            */
943           g_warning ("Trying to force unrealize stage is not allowed");
944           break;
945         }
946
947       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
948           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
949           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
950         {
951           g_warning ("Clutter toplevel of type '%s' is not visible, but "
952                      "it is somehow still mapped",
953                      _clutter_actor_get_debug_name (self));
954         }
955     }
956   else
957     {
958       ClutterActorPrivate *priv = self->priv;
959       ClutterActor *parent = priv->parent;
960       gboolean should_be_mapped;
961       gboolean may_be_realized;
962       gboolean must_be_realized;
963
964       should_be_mapped = FALSE;
965       may_be_realized = TRUE;
966       must_be_realized = FALSE;
967
968       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
969         {
970           may_be_realized = FALSE;
971         }
972       else
973         {
974           /* Maintain invariant that if parent is mapped, and we are
975            * visible, then we are mapped ...  unless parent is a
976            * stage, in which case we map regardless of parent's map
977            * state but do require stage to be visible and realized.
978            *
979            * If parent is realized, that does not force us to be
980            * realized; but if parent is unrealized, that does force
981            * us to be unrealized.
982            *
983            * The reason we don't force children to realize with
984            * parents is _clutter_actor_rerealize(); if we require that
985            * a realized parent means children are realized, then to
986            * unrealize an actor we would have to unrealize its
987            * parents, which would end up meaning unrealizing and
988            * hiding the entire stage. So we allow unrealizing a
989            * child (as long as that child is not mapped) while that
990            * child still has a realized parent.
991            *
992            * Also, if we unrealize from leaf nodes to root, and
993            * realize from root to leaf, the invariants are never
994            * violated if we allow children to be unrealized
995            * while parents are realized.
996            *
997            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
998            * to force us to unmap, even though parent is still
999            * mapped. This is because we're unmapping from leaf nodes
1000            * up to root nodes.
1001            */
1002           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1003               change != MAP_STATE_MAKE_UNMAPPED)
1004             {
1005               gboolean parent_is_visible_realized_toplevel;
1006
1007               parent_is_visible_realized_toplevel =
1008                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1009                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1010                  CLUTTER_ACTOR_IS_REALIZED (parent));
1011
1012               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1013                   parent_is_visible_realized_toplevel)
1014                 {
1015                   must_be_realized = TRUE;
1016                   should_be_mapped = TRUE;
1017                 }
1018             }
1019
1020           /* if the actor has been set to be painted even if unmapped
1021            * then we should map it and check for realization as well;
1022            * this is an override for the branch of the scene graph
1023            * which begins with this node
1024            */
1025           if (priv->enable_paint_unmapped)
1026             {
1027               if (priv->parent == NULL)
1028                 g_warning ("Attempting to map an unparented actor '%s'",
1029                            _clutter_actor_get_debug_name (self));
1030
1031               should_be_mapped = TRUE;
1032               must_be_realized = TRUE;
1033             }
1034
1035           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1036             may_be_realized = FALSE;
1037         }
1038
1039       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1040         {
1041           if (parent == NULL)
1042             g_warning ("Attempting to map a child that does not "
1043                        "meet the necessary invariants: the actor '%s' "
1044                        "has no parent",
1045                        _clutter_actor_get_debug_name (self));
1046           else
1047             g_warning ("Attempting to map a child that does not "
1048                        "meet the necessary invariants: the actor '%s' "
1049                        "is parented to an unmapped actor '%s'",
1050                        _clutter_actor_get_debug_name (self),
1051                        _clutter_actor_get_debug_name (priv->parent));
1052         }
1053
1054       /* If in reparent, we temporarily suspend unmap and unrealize.
1055        *
1056        * We want to go in the order "realize, map" and "unmap, unrealize"
1057        */
1058
1059       /* Unmap */
1060       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1061         clutter_actor_set_mapped (self, FALSE);
1062
1063       /* Realize */
1064       if (must_be_realized)
1065         clutter_actor_realize (self);
1066
1067       /* if we must be realized then we may be, presumably */
1068       g_assert (!(must_be_realized && !may_be_realized));
1069
1070       /* Unrealize */
1071       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1072         clutter_actor_unrealize_not_hiding (self);
1073
1074       /* Map */
1075       if (should_be_mapped)
1076         {
1077           if (!must_be_realized)
1078             g_warning ("Somehow we think actor '%s' should be mapped but "
1079                        "not realized, which isn't allowed",
1080                        _clutter_actor_get_debug_name (self));
1081
1082           /* realization is allowed to fail (though I don't know what
1083            * an app is supposed to do about that - shouldn't it just
1084            * be a g_error? anyway, we have to avoid mapping if this
1085            * happens)
1086            */
1087           if (CLUTTER_ACTOR_IS_REALIZED (self))
1088             clutter_actor_set_mapped (self, TRUE);
1089         }
1090     }
1091
1092 #ifdef CLUTTER_ENABLE_DEBUG
1093   /* check all invariants were kept */
1094   clutter_actor_verify_map_state (self);
1095 #endif
1096 }
1097
1098 static void
1099 clutter_actor_real_map (ClutterActor *self)
1100 {
1101   ClutterActorPrivate *priv = self->priv;
1102   ClutterActor *stage, *iter;
1103
1104   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1105
1106   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1107                 _clutter_actor_get_debug_name (self));
1108
1109   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1110
1111   stage = _clutter_actor_get_stage_internal (self);
1112   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1113
1114   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1115                 priv->pick_id,
1116                 _clutter_actor_get_debug_name (self));
1117
1118   /* notify on parent mapped before potentially mapping
1119    * children, so apps see a top-down notification.
1120    */
1121   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1122
1123   for (iter = self->priv->first_child;
1124        iter != NULL;
1125        iter = iter->priv->next_sibling)
1126     {
1127       clutter_actor_map (iter);
1128     }
1129 }
1130
1131 /**
1132  * clutter_actor_map:
1133  * @self: A #ClutterActor
1134  *
1135  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1136  * and realizes its children if they are visible. Does nothing if the
1137  * actor is not visible.
1138  *
1139  * Calling this function is strongly disencouraged: the default
1140  * implementation of #ClutterActorClass.map() will map all the children
1141  * of an actor when mapping its parent.
1142  *
1143  * When overriding map, it is mandatory to chain up to the parent
1144  * implementation.
1145  *
1146  * Since: 1.0
1147  */
1148 void
1149 clutter_actor_map (ClutterActor *self)
1150 {
1151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1152
1153   if (CLUTTER_ACTOR_IS_MAPPED (self))
1154     return;
1155
1156   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1157     return;
1158
1159   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1160 }
1161
1162 static void
1163 clutter_actor_real_unmap (ClutterActor *self)
1164 {
1165   ClutterActorPrivate *priv = self->priv;
1166   ClutterActor *iter;
1167
1168   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1169
1170   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1171                 _clutter_actor_get_debug_name (self));
1172
1173   for (iter = self->priv->first_child;
1174        iter != NULL;
1175        iter = iter->priv->next_sibling)
1176     {
1177       clutter_actor_unmap (iter);
1178     }
1179
1180   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1181
1182   /* clear the contents of the last paint volume, so that hiding + moving +
1183    * showing will not result in the wrong area being repainted
1184    */
1185   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1186   priv->last_paint_volume_valid = TRUE;
1187
1188   /* notify on parent mapped after potentially unmapping
1189    * children, so apps see a bottom-up notification.
1190    */
1191   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1192
1193   /* relinquish keyboard focus if we were unmapped while owning it */
1194   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1195     {
1196       ClutterStage *stage;
1197
1198       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1199
1200       if (stage != NULL)
1201         _clutter_stage_release_pick_id (stage, priv->pick_id);
1202
1203       priv->pick_id = -1;
1204
1205       if (stage != NULL &&
1206           clutter_stage_get_key_focus (stage) == self)
1207         {
1208           clutter_stage_set_key_focus (stage, NULL);
1209         }
1210     }
1211 }
1212
1213 /**
1214  * clutter_actor_unmap:
1215  * @self: A #ClutterActor
1216  *
1217  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1218  * unmaps its children if they were mapped.
1219  *
1220  * Calling this function is not encouraged: the default #ClutterActor
1221  * implementation of #ClutterActorClass.unmap() will also unmap any
1222  * eventual children by default when their parent is unmapped.
1223  *
1224  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1225  * chain up to the parent implementation.
1226  *
1227  * <note>It is important to note that the implementation of the
1228  * #ClutterActorClass.unmap() virtual function may be called after
1229  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1230  * implementation, but it is guaranteed to be called before the
1231  * #GObjectClass.finalize() implementation.</note>
1232  *
1233  * Since: 1.0
1234  */
1235 void
1236 clutter_actor_unmap (ClutterActor *self)
1237 {
1238   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1239
1240   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1241     return;
1242
1243   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1244 }
1245
1246 static void
1247 clutter_actor_real_show (ClutterActor *self)
1248 {
1249   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1250     {
1251       ClutterActorPrivate *priv = self->priv;
1252
1253       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1254
1255       /* we notify on the "visible" flag in the clutter_actor_show()
1256        * wrapper so the entire show signal emission completes first
1257        * (?)
1258        */
1259       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1260
1261       /* we queue a relayout unless the actor is inside a
1262        * container that explicitly told us not to
1263        */
1264       if (priv->parent != NULL &&
1265           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1266         {
1267           /* While an actor is hidden the parent may not have
1268            * allocated/requested so we need to start from scratch
1269            * and avoid the short-circuiting in
1270            * clutter_actor_queue_relayout().
1271            */
1272           priv->needs_width_request  = FALSE;
1273           priv->needs_height_request = FALSE;
1274           priv->needs_allocation     = FALSE;
1275           clutter_actor_queue_relayout (self);
1276         }
1277     }
1278 }
1279
1280 static inline void
1281 set_show_on_set_parent (ClutterActor *self,
1282                         gboolean      set_show)
1283 {
1284   ClutterActorPrivate *priv = self->priv;
1285
1286   set_show = !!set_show;
1287
1288   if (priv->show_on_set_parent == set_show)
1289     return;
1290
1291   if (priv->parent == NULL)
1292     {
1293       priv->show_on_set_parent = set_show;
1294       g_object_notify_by_pspec (G_OBJECT (self),
1295                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1296     }
1297 }
1298
1299 /**
1300  * clutter_actor_show:
1301  * @self: A #ClutterActor
1302  *
1303  * Flags an actor to be displayed. An actor that isn't shown will not
1304  * be rendered on the stage.
1305  *
1306  * Actors are visible by default.
1307  *
1308  * If this function is called on an actor without a parent, the
1309  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1310  * effect.
1311  */
1312 void
1313 clutter_actor_show (ClutterActor *self)
1314 {
1315   ClutterActorPrivate *priv;
1316
1317   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1318
1319   /* simple optimization */
1320   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1321     {
1322       /* we still need to set the :show-on-set-parent property, in
1323        * case show() is called on an unparented actor
1324        */
1325       set_show_on_set_parent (self, TRUE);
1326       return;
1327     }
1328
1329 #ifdef CLUTTER_ENABLE_DEBUG
1330   clutter_actor_verify_map_state (self);
1331 #endif
1332
1333   priv = self->priv;
1334
1335   g_object_freeze_notify (G_OBJECT (self));
1336
1337   set_show_on_set_parent (self, TRUE);
1338
1339   g_signal_emit (self, actor_signals[SHOW], 0);
1340   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1341
1342   if (priv->parent != NULL)
1343     clutter_actor_queue_redraw (priv->parent);
1344
1345   g_object_thaw_notify (G_OBJECT (self));
1346 }
1347
1348 /**
1349  * clutter_actor_show_all:
1350  * @self: a #ClutterActor
1351  *
1352  * Calls clutter_actor_show() on all children of an actor (if any).
1353  *
1354  * Since: 0.2
1355  *
1356  * Deprecated: 1.10: Actors are visible by default
1357  */
1358 void
1359 clutter_actor_show_all (ClutterActor *self)
1360 {
1361   ClutterActorClass *klass;
1362
1363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1364
1365   klass = CLUTTER_ACTOR_GET_CLASS (self);
1366   if (klass->show_all)
1367     klass->show_all (self);
1368 }
1369
1370 static void
1371 clutter_actor_real_hide (ClutterActor *self)
1372 {
1373   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1374     {
1375       ClutterActorPrivate *priv = self->priv;
1376
1377       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1378
1379       /* we notify on the "visible" flag in the clutter_actor_hide()
1380        * wrapper so the entire hide signal emission completes first
1381        * (?)
1382        */
1383       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1384
1385       /* we queue a relayout unless the actor is inside a
1386        * container that explicitly told us not to
1387        */
1388       if (priv->parent != NULL &&
1389           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1390         clutter_actor_queue_relayout (priv->parent);
1391     }
1392 }
1393
1394 /**
1395  * clutter_actor_hide:
1396  * @self: A #ClutterActor
1397  *
1398  * Flags an actor to be hidden. A hidden actor will not be
1399  * rendered on the stage.
1400  *
1401  * Actors are visible by default.
1402  *
1403  * If this function is called on an actor without a parent, the
1404  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1405  * as a side-effect.
1406  */
1407 void
1408 clutter_actor_hide (ClutterActor *self)
1409 {
1410   ClutterActorPrivate *priv;
1411
1412   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1413
1414   /* simple optimization */
1415   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1416     {
1417       /* we still need to set the :show-on-set-parent property, in
1418        * case hide() is called on an unparented actor
1419        */
1420       set_show_on_set_parent (self, FALSE);
1421       return;
1422     }
1423
1424 #ifdef CLUTTER_ENABLE_DEBUG
1425   clutter_actor_verify_map_state (self);
1426 #endif
1427
1428   priv = self->priv;
1429
1430   g_object_freeze_notify (G_OBJECT (self));
1431
1432   set_show_on_set_parent (self, FALSE);
1433
1434   g_signal_emit (self, actor_signals[HIDE], 0);
1435   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1436
1437   if (priv->parent != NULL)
1438     clutter_actor_queue_redraw (priv->parent);
1439
1440   g_object_thaw_notify (G_OBJECT (self));
1441 }
1442
1443 /**
1444  * clutter_actor_hide_all:
1445  * @self: a #ClutterActor
1446  *
1447  * Calls clutter_actor_hide() on all child actors (if any).
1448  *
1449  * Since: 0.2
1450  *
1451  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1452  *   prevent its children from being painted as well.
1453  */
1454 void
1455 clutter_actor_hide_all (ClutterActor *self)
1456 {
1457   ClutterActorClass *klass;
1458
1459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1460
1461   klass = CLUTTER_ACTOR_GET_CLASS (self);
1462   if (klass->hide_all)
1463     klass->hide_all (self);
1464 }
1465
1466 /**
1467  * clutter_actor_realize:
1468  * @self: A #ClutterActor
1469  *
1470  * Realization informs the actor that it is attached to a stage. It
1471  * can use this to allocate resources if it wanted to delay allocation
1472  * until it would be rendered. However it is perfectly acceptable for
1473  * an actor to create resources before being realized because Clutter
1474  * only ever has a single rendering context so that actor is free to
1475  * be moved from one stage to another.
1476  *
1477  * This function does nothing if the actor is already realized.
1478  *
1479  * Because a realized actor must have realized parent actors, calling
1480  * clutter_actor_realize() will also realize all parents of the actor.
1481  *
1482  * This function does not realize child actors, except in the special
1483  * case that realizing the stage, when the stage is visible, will
1484  * suddenly map (and thus realize) the children of the stage.
1485  **/
1486 void
1487 clutter_actor_realize (ClutterActor *self)
1488 {
1489   ClutterActorPrivate *priv;
1490
1491   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1492
1493   priv = self->priv;
1494
1495 #ifdef CLUTTER_ENABLE_DEBUG
1496   clutter_actor_verify_map_state (self);
1497 #endif
1498
1499   if (CLUTTER_ACTOR_IS_REALIZED (self))
1500     return;
1501
1502   /* To be realized, our parent actors must be realized first.
1503    * This will only succeed if we're inside a toplevel.
1504    */
1505   if (priv->parent != NULL)
1506     clutter_actor_realize (priv->parent);
1507
1508   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1509     {
1510       /* toplevels can be realized at any time */
1511     }
1512   else
1513     {
1514       /* "Fail" the realization if parent is missing or unrealized;
1515        * this should really be a g_warning() not some kind of runtime
1516        * failure; how can an app possibly recover? Instead it's a bug
1517        * in the app and the app should get an explanatory warning so
1518        * someone can fix it. But for now it's too hard to fix this
1519        * because e.g. ClutterTexture needs reworking.
1520        */
1521       if (priv->parent == NULL ||
1522           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1523         return;
1524     }
1525
1526   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1527
1528   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1529   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1530
1531   g_signal_emit (self, actor_signals[REALIZE], 0);
1532
1533   /* Stage actor is allowed to unset the realized flag again in its
1534    * default signal handler, though that is a pathological situation.
1535    */
1536
1537   /* If realization "failed" we'll have to update child state. */
1538   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1539 }
1540
1541 static void
1542 clutter_actor_real_unrealize (ClutterActor *self)
1543 {
1544   /* we must be unmapped (implying our children are also unmapped) */
1545   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1546 }
1547
1548 /**
1549  * clutter_actor_unrealize:
1550  * @self: A #ClutterActor
1551  *
1552  * Unrealization informs the actor that it may be being destroyed or
1553  * moved to another stage. The actor may want to destroy any
1554  * underlying graphics resources at this point. However it is
1555  * perfectly acceptable for it to retain the resources until the actor
1556  * is destroyed because Clutter only ever uses a single rendering
1557  * context and all of the graphics resources are valid on any stage.
1558  *
1559  * Because mapped actors must be realized, actors may not be
1560  * unrealized if they are mapped. This function hides the actor to be
1561  * sure it isn't mapped, an application-visible side effect that you
1562  * may not be expecting.
1563  *
1564  * This function should not be called by application code.
1565  */
1566 void
1567 clutter_actor_unrealize (ClutterActor *self)
1568 {
1569   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1570   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1571
1572 /* This function should not really be in the public API, because
1573  * there isn't a good reason to call it. ClutterActor will already
1574  * unrealize things for you when it's important to do so.
1575  *
1576  * If you were using clutter_actor_unrealize() in a dispose
1577  * implementation, then don't, just chain up to ClutterActor's
1578  * dispose.
1579  *
1580  * If you were using clutter_actor_unrealize() to implement
1581  * unrealizing children of your container, then don't, ClutterActor
1582  * will already take care of that.
1583  *
1584  * If you were using clutter_actor_unrealize() to re-realize to
1585  * create your resources in a different way, then use
1586  * _clutter_actor_rerealize() (inside Clutter) or just call your
1587  * code that recreates your resources directly (outside Clutter).
1588  */
1589
1590 #ifdef CLUTTER_ENABLE_DEBUG
1591   clutter_actor_verify_map_state (self);
1592 #endif
1593
1594   clutter_actor_hide (self);
1595
1596   clutter_actor_unrealize_not_hiding (self);
1597 }
1598
1599 static ClutterActorTraverseVisitFlags
1600 unrealize_actor_before_children_cb (ClutterActor *self,
1601                                     int depth,
1602                                     void *user_data)
1603 {
1604   /* If an actor is already unrealized we know its children have also
1605    * already been unrealized... */
1606   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1607     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1608
1609   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1610
1611   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1612 }
1613
1614 static ClutterActorTraverseVisitFlags
1615 unrealize_actor_after_children_cb (ClutterActor *self,
1616                                    int depth,
1617                                    void *user_data)
1618 {
1619   /* We want to unset the realized flag only _after_
1620    * child actors are unrealized, to maintain invariants.
1621    */
1622   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1623   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1624   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1625 }
1626
1627 /*
1628  * clutter_actor_unrealize_not_hiding:
1629  * @self: A #ClutterActor
1630  *
1631  * Unrealization informs the actor that it may be being destroyed or
1632  * moved to another stage. The actor may want to destroy any
1633  * underlying graphics resources at this point. However it is
1634  * perfectly acceptable for it to retain the resources until the actor
1635  * is destroyed because Clutter only ever uses a single rendering
1636  * context and all of the graphics resources are valid on any stage.
1637  *
1638  * Because mapped actors must be realized, actors may not be
1639  * unrealized if they are mapped. You must hide the actor or one of
1640  * its parents before attempting to unrealize.
1641  *
1642  * This function is separate from clutter_actor_unrealize() because it
1643  * does not automatically hide the actor.
1644  * Actors need not be hidden to be unrealized, they just need to
1645  * be unmapped. In fact we don't want to mess up the application's
1646  * setting of the "visible" flag, so hiding is very undesirable.
1647  *
1648  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1649  * backward compatibility.
1650  */
1651 static void
1652 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1653 {
1654   _clutter_actor_traverse (self,
1655                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1656                            unrealize_actor_before_children_cb,
1657                            unrealize_actor_after_children_cb,
1658                            NULL);
1659 }
1660
1661 /*
1662  * _clutter_actor_rerealize:
1663  * @self: A #ClutterActor
1664  * @callback: Function to call while unrealized
1665  * @data: data for callback
1666  *
1667  * If an actor is already unrealized, this just calls the callback.
1668  *
1669  * If it is realized, it unrealizes temporarily, calls the callback,
1670  * and then re-realizes the actor.
1671  *
1672  * As a side effect, leaves all children of the actor unrealized if
1673  * the actor was realized but not showing.  This is because when we
1674  * unrealize the actor temporarily we must unrealize its children
1675  * (e.g. children of a stage can't be realized if stage window is
1676  * gone). And we aren't clever enough to save the realization state of
1677  * all children. In most cases this should not matter, because
1678  * the children will automatically realize when they next become mapped.
1679  */
1680 void
1681 _clutter_actor_rerealize (ClutterActor    *self,
1682                           ClutterCallback  callback,
1683                           void            *data)
1684 {
1685   gboolean was_mapped;
1686   gboolean was_showing;
1687   gboolean was_realized;
1688
1689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1690
1691 #ifdef CLUTTER_ENABLE_DEBUG
1692   clutter_actor_verify_map_state (self);
1693 #endif
1694
1695   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1696   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1697   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1698
1699   /* Must be unmapped to unrealize. Note we only have to hide this
1700    * actor if it was mapped (if all parents were showing).  If actor
1701    * is merely visible (but not mapped), then that's fine, we can
1702    * leave it visible.
1703    */
1704   if (was_mapped)
1705     clutter_actor_hide (self);
1706
1707   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1708
1709   /* unrealize self and all children */
1710   clutter_actor_unrealize_not_hiding (self);
1711
1712   if (callback != NULL)
1713     {
1714       (* callback) (self, data);
1715     }
1716
1717   if (was_showing)
1718     clutter_actor_show (self); /* will realize only if mapping implies it */
1719   else if (was_realized)
1720     clutter_actor_realize (self); /* realize self and all parents */
1721 }
1722
1723 static void
1724 clutter_actor_real_pick (ClutterActor       *self,
1725                          const ClutterColor *color)
1726 {
1727   /* the default implementation is just to paint a rectangle
1728    * with the same size of the actor using the passed color
1729    */
1730   if (clutter_actor_should_pick_paint (self))
1731     {
1732       ClutterActorBox box = { 0, };
1733       float width, height;
1734
1735       clutter_actor_get_allocation_box (self, &box);
1736
1737       width = box.x2 - box.x1;
1738       height = box.y2 - box.y1;
1739
1740       cogl_set_source_color4ub (color->red,
1741                                 color->green,
1742                                 color->blue,
1743                                 color->alpha);
1744
1745       cogl_rectangle (0, 0, width, height);
1746     }
1747
1748   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1749    * with existing container classes that override the pick() virtual
1750    * and chain up to the default implementation - otherwise we'll end up
1751    * painting our children twice.
1752    *
1753    * this has to go away for 2.0; hopefully along the pick() itself.
1754    */
1755   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1756     {
1757       ClutterActor *iter;
1758
1759       for (iter = self->priv->first_child;
1760            iter != NULL;
1761            iter = iter->priv->next_sibling)
1762         clutter_actor_paint (iter);
1763     }
1764 }
1765
1766 /**
1767  * clutter_actor_should_pick_paint:
1768  * @self: A #ClutterActor
1769  *
1770  * Should be called inside the implementation of the
1771  * #ClutterActor::pick virtual function in order to check whether
1772  * the actor should paint itself in pick mode or not.
1773  *
1774  * This function should never be called directly by applications.
1775  *
1776  * Return value: %TRUE if the actor should paint its silhouette,
1777  *   %FALSE otherwise
1778  */
1779 gboolean
1780 clutter_actor_should_pick_paint (ClutterActor *self)
1781 {
1782   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1783
1784   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1785       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1786        CLUTTER_ACTOR_IS_REACTIVE (self)))
1787     return TRUE;
1788
1789   return FALSE;
1790 }
1791
1792 static void
1793 clutter_actor_real_get_preferred_width (ClutterActor *self,
1794                                         gfloat        for_height,
1795                                         gfloat       *min_width_p,
1796                                         gfloat       *natural_width_p)
1797 {
1798   ClutterActorPrivate *priv = self->priv;
1799
1800   if (priv->n_children != 0 &&
1801       priv->layout_manager != NULL)
1802     {
1803       ClutterContainer *container = CLUTTER_CONTAINER (self);
1804
1805       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1806                     "for the preferred width",
1807                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1808                     priv->layout_manager);
1809
1810       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1811                                                   container,
1812                                                   for_height,
1813                                                   min_width_p,
1814                                                   natural_width_p);
1815
1816       return;
1817     }
1818
1819   /* Default implementation is always 0x0, usually an actor
1820    * using this default is relying on someone to set the
1821    * request manually
1822    */
1823   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1824
1825   if (min_width_p)
1826     *min_width_p = 0;
1827
1828   if (natural_width_p)
1829     *natural_width_p = 0;
1830 }
1831
1832 static void
1833 clutter_actor_real_get_preferred_height (ClutterActor *self,
1834                                          gfloat        for_width,
1835                                          gfloat       *min_height_p,
1836                                          gfloat       *natural_height_p)
1837 {
1838   ClutterActorPrivate *priv = self->priv;
1839
1840   if (priv->n_children != 0 &&
1841       priv->layout_manager != NULL)
1842     {
1843       ClutterContainer *container = CLUTTER_CONTAINER (self);
1844
1845       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1846                     "for the preferred height",
1847                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1848                     priv->layout_manager);
1849
1850       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1851                                                    container,
1852                                                    for_width,
1853                                                    min_height_p,
1854                                                    natural_height_p);
1855
1856       return;
1857     }
1858   /* Default implementation is always 0x0, usually an actor
1859    * using this default is relying on someone to set the
1860    * request manually
1861    */
1862   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1863
1864   if (min_height_p)
1865     *min_height_p = 0;
1866
1867   if (natural_height_p)
1868     *natural_height_p = 0;
1869 }
1870
1871 static void
1872 clutter_actor_store_old_geometry (ClutterActor    *self,
1873                                   ClutterActorBox *box)
1874 {
1875   *box = self->priv->allocation;
1876 }
1877
1878 static inline void
1879 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1880                                           const ClutterActorBox *old)
1881 {
1882   ClutterActorPrivate *priv = self->priv;
1883   GObject *obj = G_OBJECT (self);
1884
1885   g_object_freeze_notify (obj);
1886
1887   /* to avoid excessive requisition or allocation cycles we
1888    * use the cached values.
1889    *
1890    * - if we don't have an allocation we assume that we need
1891    *   to notify anyway
1892    * - if we don't have a width or a height request we notify
1893    *   width and height
1894    * - if we have a valid allocation then we check the old
1895    *   bounding box with the current allocation and we notify
1896    *   the changes
1897    */
1898   if (priv->needs_allocation)
1899     {
1900       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1901       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1904     }
1905   else if (priv->needs_width_request || priv->needs_height_request)
1906     {
1907       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1908       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1909     }
1910   else
1911     {
1912       gfloat xu, yu;
1913       gfloat widthu, heightu;
1914
1915       xu = priv->allocation.x1;
1916       yu = priv->allocation.y1;
1917       widthu = priv->allocation.x2 - priv->allocation.x1;
1918       heightu = priv->allocation.y2 - priv->allocation.y1;
1919
1920       if (xu != old->x1)
1921         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1922
1923       if (yu != old->y1)
1924         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1925
1926       if (widthu != (old->x2 - old->x1))
1927         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1928
1929       if (heightu != (old->y2 - old->y1))
1930         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1931     }
1932
1933   g_object_thaw_notify (obj);
1934 }
1935
1936 /*< private >
1937  * clutter_actor_set_allocation_internal:
1938  * @self: a #ClutterActor
1939  * @box: a #ClutterActorBox
1940  * @flags: allocation flags
1941  *
1942  * Stores the allocation of @self.
1943  *
1944  * This function only performs basic storage and property notification.
1945  *
1946  * This function should be called by clutter_actor_set_allocation()
1947  * and by the default implementation of #ClutterActorClass.allocate().
1948  *
1949  * Return value: %TRUE if the allocation of the #ClutterActor has been
1950  *   changed, and %FALSE otherwise
1951  */
1952 static inline gboolean
1953 clutter_actor_set_allocation_internal (ClutterActor           *self,
1954                                        const ClutterActorBox  *box,
1955                                        ClutterAllocationFlags  flags)
1956 {
1957   ClutterActorPrivate *priv = self->priv;
1958   GObject *obj;
1959   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1960   gboolean flags_changed;
1961   gboolean retval;
1962   ClutterActorBox old_alloc = { 0, };
1963
1964   obj = G_OBJECT (self);
1965
1966   g_object_freeze_notify (obj);
1967
1968   clutter_actor_store_old_geometry (self, &old_alloc);
1969
1970   x1_changed = priv->allocation.x1 != box->x1;
1971   y1_changed = priv->allocation.y1 != box->y1;
1972   x2_changed = priv->allocation.x2 != box->x2;
1973   y2_changed = priv->allocation.y2 != box->y2;
1974
1975   flags_changed = priv->allocation_flags != flags;
1976
1977   priv->allocation = *box;
1978   priv->allocation_flags = flags;
1979
1980   /* allocation is authoritative */
1981   priv->needs_width_request = FALSE;
1982   priv->needs_height_request = FALSE;
1983   priv->needs_allocation = FALSE;
1984
1985   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1986     {
1987       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1988                     _clutter_actor_get_debug_name (self));
1989
1990       priv->transform_valid = FALSE;
1991
1992       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1993
1994       retval = TRUE;
1995     }
1996   else
1997     retval = FALSE;
1998
1999   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2000
2001   g_object_thaw_notify (obj);
2002
2003   return retval;
2004 }
2005
2006 static void clutter_actor_real_allocate (ClutterActor           *self,
2007                                          const ClutterActorBox  *box,
2008                                          ClutterAllocationFlags  flags);
2009
2010 static inline void
2011 clutter_actor_maybe_layout_children (ClutterActor           *self,
2012                                      const ClutterActorBox  *allocation,
2013                                      ClutterAllocationFlags  flags)
2014 {
2015   ClutterActorPrivate *priv = self->priv;
2016
2017   /* this is going to be a bit hard to follow, so let's put an explanation
2018    * here.
2019    *
2020    * we want ClutterActor to have a default layout manager if the actor was
2021    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2022    *
2023    * we also want any subclass of ClutterActor that does not override the
2024    * ::allocate() virtual function to delegate to a layout manager.
2025    *
2026    * finally, we want to allow people subclassing ClutterActor and overriding
2027    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2028    *
2029    * on the other hand, we want existing actor subclasses overriding the
2030    * ::allocate() virtual function and chaining up to the parent's
2031    * implementation to continue working without allocating their children
2032    * twice, or without entering an allocation loop.
2033    *
2034    * for the first two points, we check if the class of the actor is
2035    * overridding the ::allocate() virtual function; if it isn't, then we
2036    * follow through with checking whether we have children and a layout
2037    * manager, and eventually calling clutter_layout_manager_allocate().
2038    *
2039    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2040    * allocation flags that we got passed, and if it is present, we continue
2041    * with the check above.
2042    *
2043    * if neither of these two checks yields a positive result, we just
2044    * assume that the ::allocate() virtual function that resulted in this
2045    * function being called will also allocate the children of the actor.
2046    */
2047
2048   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2049     goto check_layout;
2050
2051   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2052     goto check_layout;
2053
2054   return;
2055
2056 check_layout:
2057   if (priv->n_children != 0 &&
2058       priv->layout_manager != NULL)
2059     {
2060       ClutterContainer *container = CLUTTER_CONTAINER (self);
2061       ClutterAllocationFlags children_flags;
2062       ClutterActorBox children_box;
2063
2064       /* normalize the box passed to the layout manager */
2065       children_box.x1 = children_box.y1 = 0.f;
2066       children_box.x2 = (allocation->x2 - allocation->x1);
2067       children_box.y2 = (allocation->y2 - allocation->y1);
2068
2069       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2070        * the actor's children, since it refers only to the current
2071        * actor's allocation.
2072        */
2073       children_flags = flags;
2074       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2075
2076       CLUTTER_NOTE (LAYOUT,
2077                     "Allocating %d children of %s "
2078                     "at { %.2f, %.2f - %.2f x %.2f } "
2079                     "using %s",
2080                     priv->n_children,
2081                     _clutter_actor_get_debug_name (self),
2082                     allocation->x1,
2083                     allocation->y1,
2084                     (allocation->x2 - allocation->x1),
2085                     (allocation->y2 - allocation->y1),
2086                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2087
2088       clutter_layout_manager_allocate (priv->layout_manager,
2089                                        container,
2090                                        &children_box,
2091                                        children_flags);
2092     }
2093 }
2094
2095 static void
2096 clutter_actor_real_allocate (ClutterActor           *self,
2097                              const ClutterActorBox  *box,
2098                              ClutterAllocationFlags  flags)
2099 {
2100   ClutterActorPrivate *priv = self->priv;
2101   gboolean changed;
2102
2103   g_object_freeze_notify (G_OBJECT (self));
2104
2105   changed = clutter_actor_set_allocation_internal (self, box, flags);
2106
2107   /* we allocate our children before we notify changes in our geometry,
2108    * so that people connecting to properties will be able to get valid
2109    * data out of the sub-tree of the scene graph that has this actor at
2110    * the root.
2111    */
2112   clutter_actor_maybe_layout_children (self, box, flags);
2113
2114   if (changed)
2115     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2116                    &priv->allocation,
2117                    priv->allocation_flags);
2118
2119   g_object_thaw_notify (G_OBJECT (self));
2120 }
2121
2122 static void
2123 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2124                                     ClutterActor *origin)
2125 {
2126   /* no point in queuing a redraw on a destroyed actor */
2127   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2128     return;
2129
2130   /* NB: We can't bail out early here if the actor is hidden in case
2131    * the actor bas been cloned. In this case the clone will need to
2132    * receive the signal so it can queue its own redraw.
2133    */
2134
2135   /* calls klass->queue_redraw in default handler */
2136   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2137 }
2138
2139 static void
2140 clutter_actor_real_queue_redraw (ClutterActor *self,
2141                                  ClutterActor *origin)
2142 {
2143   ClutterActor *parent;
2144
2145   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2146                 _clutter_actor_get_debug_name (self),
2147                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2148                                : "same actor");
2149
2150   /* no point in queuing a redraw on a destroyed actor */
2151   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2152     return;
2153
2154   /* If the queue redraw is coming from a child then the actor has
2155      become dirty and any queued effect is no longer valid */
2156   if (self != origin)
2157     {
2158       self->priv->is_dirty = TRUE;
2159       self->priv->effect_to_redraw = NULL;
2160     }
2161
2162   /* If the actor isn't visible, we still had to emit the signal
2163    * to allow for a ClutterClone, but the appearance of the parent
2164    * won't change so we don't have to propagate up the hierarchy.
2165    */
2166   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2167     return;
2168
2169   /* Although we could determine here that a full stage redraw
2170    * has already been queued and immediately bail out, we actually
2171    * guarantee that we will propagate a queue-redraw signal to our
2172    * parent at least once so that it's possible to implement a
2173    * container that tracks which of its children have queued a
2174    * redraw.
2175    */
2176   if (self->priv->propagated_one_redraw)
2177     {
2178       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2179       if (stage != NULL &&
2180           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2181         return;
2182     }
2183
2184   self->priv->propagated_one_redraw = TRUE;
2185
2186   /* notify parents, if they are all visible eventually we'll
2187    * queue redraw on the stage, which queues the redraw idle.
2188    */
2189   parent = clutter_actor_get_parent (self);
2190   if (parent != NULL)
2191     {
2192       /* this will go up recursively */
2193       _clutter_actor_signal_queue_redraw (parent, origin);
2194     }
2195 }
2196
2197 static void
2198 clutter_actor_real_queue_relayout (ClutterActor *self)
2199 {
2200   ClutterActorPrivate *priv = self->priv;
2201
2202   /* no point in queueing a redraw on a destroyed actor */
2203   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2204     return;
2205
2206   priv->needs_width_request  = TRUE;
2207   priv->needs_height_request = TRUE;
2208   priv->needs_allocation     = TRUE;
2209
2210   /* reset the cached size requests */
2211   memset (priv->width_requests, 0,
2212           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2213   memset (priv->height_requests, 0,
2214           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2215
2216   /* We need to go all the way up the hierarchy */
2217   if (priv->parent != NULL)
2218     _clutter_actor_queue_only_relayout (priv->parent);
2219 }
2220
2221 /**
2222  * clutter_actor_apply_relative_transform_to_point:
2223  * @self: A #ClutterActor
2224  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2225  *   default #ClutterStage
2226  * @point: A point as #ClutterVertex
2227  * @vertex: (out caller-allocates): The translated #ClutterVertex
2228  *
2229  * Transforms @point in coordinates relative to the actor into
2230  * ancestor-relative coordinates using the relevant transform
2231  * stack (i.e. scale, rotation, etc).
2232  *
2233  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2234  * this case, the coordinates returned will be the coordinates on
2235  * the stage before the projection is applied. This is different from
2236  * the behaviour of clutter_actor_apply_transform_to_point().
2237  *
2238  * Since: 0.6
2239  */
2240 void
2241 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2242                                                  ClutterActor        *ancestor,
2243                                                  const ClutterVertex *point,
2244                                                  ClutterVertex       *vertex)
2245 {
2246   gfloat w;
2247   CoglMatrix matrix;
2248
2249   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2250   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2251   g_return_if_fail (point != NULL);
2252   g_return_if_fail (vertex != NULL);
2253
2254   *vertex = *point;
2255   w = 1.0;
2256
2257   if (ancestor == NULL)
2258     ancestor = _clutter_actor_get_stage_internal (self);
2259
2260   if (ancestor == NULL)
2261     {
2262       *vertex = *point;
2263       return;
2264     }
2265
2266   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2267   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2268 }
2269
2270 static gboolean
2271 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2272                                          const ClutterVertex *vertices_in,
2273                                          ClutterVertex *vertices_out,
2274                                          int n_vertices)
2275 {
2276   ClutterActor *stage;
2277   CoglMatrix modelview;
2278   CoglMatrix projection;
2279   float viewport[4];
2280
2281   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2282
2283   stage = _clutter_actor_get_stage_internal (self);
2284
2285   /* We really can't do anything meaningful in this case so don't try
2286    * to do any transform */
2287   if (stage == NULL)
2288     return FALSE;
2289
2290   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2291    * that gets us to stage coordinates, we want to go all the way to eye
2292    * coordinates */
2293   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2294
2295   /* Fetch the projection and viewport */
2296   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2297   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2298                                &viewport[0],
2299                                &viewport[1],
2300                                &viewport[2],
2301                                &viewport[3]);
2302
2303   _clutter_util_fully_transform_vertices (&modelview,
2304                                           &projection,
2305                                           viewport,
2306                                           vertices_in,
2307                                           vertices_out,
2308                                           n_vertices);
2309
2310   return TRUE;
2311 }
2312
2313 /**
2314  * clutter_actor_apply_transform_to_point:
2315  * @self: A #ClutterActor
2316  * @point: A point as #ClutterVertex
2317  * @vertex: (out caller-allocates): The translated #ClutterVertex
2318  *
2319  * Transforms @point in coordinates relative to the actor
2320  * into screen-relative coordinates with the current actor
2321  * transformation (i.e. scale, rotation, etc)
2322  *
2323  * Since: 0.4
2324  **/
2325 void
2326 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2327                                         const ClutterVertex *point,
2328                                         ClutterVertex       *vertex)
2329 {
2330   g_return_if_fail (point != NULL);
2331   g_return_if_fail (vertex != NULL);
2332   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2333 }
2334
2335 /*
2336  * _clutter_actor_get_relative_transformation_matrix:
2337  * @self: The actor whose coordinate space you want to transform from.
2338  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2339  *            or %NULL if you want to transform all the way to eye coordinates.
2340  * @matrix: A #CoglMatrix to store the transformation
2341  *
2342  * This gets a transformation @matrix that will transform coordinates from the
2343  * coordinate space of @self into the coordinate space of @ancestor.
2344  *
2345  * For example if you need a matrix that can transform the local actor
2346  * coordinates of @self into stage coordinates you would pass the actor's stage
2347  * pointer as the @ancestor.
2348  *
2349  * If you pass %NULL then the transformation will take you all the way through
2350  * to eye coordinates. This can be useful if you want to extract the entire
2351  * modelview transform that Clutter applies before applying the projection
2352  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2353  * using cogl_set_modelview_matrix() for example then you would want a matrix
2354  * that transforms into eye coordinates.
2355  *
2356  * <note><para>This function explicitly initializes the given @matrix. If you just
2357  * want clutter to multiply a relative transformation with an existing matrix
2358  * you can use clutter_actor_apply_relative_transformation_matrix()
2359  * instead.</para></note>
2360  *
2361  */
2362 /* XXX: We should consider caching the stage relative modelview along with
2363  * the actor itself */
2364 static void
2365 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2366                                                    ClutterActor *ancestor,
2367                                                    CoglMatrix *matrix)
2368 {
2369   cogl_matrix_init_identity (matrix);
2370
2371   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2372 }
2373
2374 /* Project the given @box into stage window coordinates, writing the
2375  * transformed vertices to @verts[]. */
2376 static gboolean
2377 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2378                                           const ClutterActorBox *box,
2379                                           ClutterVertex          verts[])
2380 {
2381   ClutterVertex box_vertices[4];
2382
2383   box_vertices[0].x = box->x1;
2384   box_vertices[0].y = box->y1;
2385   box_vertices[0].z = 0;
2386   box_vertices[1].x = box->x2;
2387   box_vertices[1].y = box->y1;
2388   box_vertices[1].z = 0;
2389   box_vertices[2].x = box->x1;
2390   box_vertices[2].y = box->y2;
2391   box_vertices[2].z = 0;
2392   box_vertices[3].x = box->x2;
2393   box_vertices[3].y = box->y2;
2394   box_vertices[3].z = 0;
2395
2396   return
2397     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2398 }
2399
2400 /**
2401  * clutter_actor_get_allocation_vertices:
2402  * @self: A #ClutterActor
2403  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2404  *   against, or %NULL to use the #ClutterStage
2405  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2406  *   location for an array of 4 #ClutterVertex in which to store the result
2407  *
2408  * Calculates the transformed coordinates of the four corners of the
2409  * actor in the plane of @ancestor. The returned vertices relate to
2410  * the #ClutterActorBox coordinates as follows:
2411  * <itemizedlist>
2412  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2413  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2414  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2415  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2416  * </itemizedlist>
2417  *
2418  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2419  * this case, the coordinates returned will be the coordinates on
2420  * the stage before the projection is applied. This is different from
2421  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2422  *
2423  * Since: 0.6
2424  */
2425 void
2426 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2427                                        ClutterActor  *ancestor,
2428                                        ClutterVertex  verts[])
2429 {
2430   ClutterActorPrivate *priv;
2431   ClutterActorBox box;
2432   ClutterVertex vertices[4];
2433   CoglMatrix modelview;
2434
2435   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2436   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2437
2438   if (ancestor == NULL)
2439     ancestor = _clutter_actor_get_stage_internal (self);
2440
2441   /* Fallback to a NOP transform if the actor isn't parented under a
2442    * stage. */
2443   if (ancestor == NULL)
2444     ancestor = self;
2445
2446   priv = self->priv;
2447
2448   /* if the actor needs to be allocated we force a relayout, so that
2449    * we will have valid values to use in the transformations */
2450   if (priv->needs_allocation)
2451     {
2452       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2453       if (stage)
2454         _clutter_stage_maybe_relayout (stage);
2455       else
2456         {
2457           box.x1 = box.y1 = 0;
2458           /* The result isn't really meaningful in this case but at
2459            * least try to do something *vaguely* reasonable... */
2460           clutter_actor_get_size (self, &box.x2, &box.y2);
2461         }
2462     }
2463
2464   clutter_actor_get_allocation_box (self, &box);
2465
2466   vertices[0].x = box.x1;
2467   vertices[0].y = box.y1;
2468   vertices[0].z = 0;
2469   vertices[1].x = box.x2;
2470   vertices[1].y = box.y1;
2471   vertices[1].z = 0;
2472   vertices[2].x = box.x1;
2473   vertices[2].y = box.y2;
2474   vertices[2].z = 0;
2475   vertices[3].x = box.x2;
2476   vertices[3].y = box.y2;
2477   vertices[3].z = 0;
2478
2479   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2480                                                      &modelview);
2481
2482   cogl_matrix_transform_points (&modelview,
2483                                 3,
2484                                 sizeof (ClutterVertex),
2485                                 vertices,
2486                                 sizeof (ClutterVertex),
2487                                 vertices,
2488                                 4);
2489 }
2490
2491 /**
2492  * clutter_actor_get_abs_allocation_vertices:
2493  * @self: A #ClutterActor
2494  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2495  *   of 4 #ClutterVertex where to store the result.
2496  *
2497  * Calculates the transformed screen coordinates of the four corners of
2498  * the actor; the returned vertices relate to the #ClutterActorBox
2499  * coordinates  as follows:
2500  * <itemizedlist>
2501  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2502  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2503  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2504  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2505  * </itemizedlist>
2506  *
2507  * Since: 0.4
2508  */
2509 void
2510 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2511                                            ClutterVertex  verts[])
2512 {
2513   ClutterActorPrivate *priv;
2514   ClutterActorBox actor_space_allocation;
2515
2516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2517
2518   priv = self->priv;
2519
2520   /* if the actor needs to be allocated we force a relayout, so that
2521    * the actor allocation box will be valid for
2522    * _clutter_actor_transform_and_project_box()
2523    */
2524   if (priv->needs_allocation)
2525     {
2526       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2527       /* There's nothing meaningful we can do now */
2528       if (!stage)
2529         return;
2530
2531       _clutter_stage_maybe_relayout (stage);
2532     }
2533
2534   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2535    * own coordinate space... */
2536   actor_space_allocation.x1 = 0;
2537   actor_space_allocation.y1 = 0;
2538   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2539   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2540   _clutter_actor_transform_and_project_box (self,
2541                                             &actor_space_allocation,
2542                                             verts);
2543 }
2544
2545 static void
2546 clutter_actor_real_apply_transform (ClutterActor *self,
2547                                     CoglMatrix   *matrix)
2548 {
2549   ClutterActorPrivate *priv = self->priv;
2550
2551   if (!priv->transform_valid)
2552     {
2553       CoglMatrix *transform = &priv->transform;
2554       const ClutterTransformInfo *info;
2555
2556       info = _clutter_actor_get_transform_info_or_defaults (self);
2557
2558       cogl_matrix_init_identity (transform);
2559
2560       cogl_matrix_translate (transform,
2561                              priv->allocation.x1,
2562                              priv->allocation.y1,
2563                              0.0);
2564
2565       if (priv->z)
2566         cogl_matrix_translate (transform, 0, 0, priv->z);
2567
2568       /*
2569        * because the rotation involves translations, we must scale
2570        * before applying the rotations (if we apply the scale after
2571        * the rotations, the translations included in the rotation are
2572        * not scaled and so the entire object will move on the screen
2573        * as a result of rotating it).
2574        */
2575       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2576         {
2577           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2578                                         &info->scale_center,
2579                                         cogl_matrix_scale (transform,
2580                                                            info->scale_x,
2581                                                            info->scale_y,
2582                                                            1.0));
2583         }
2584
2585       if (info->rz_angle)
2586         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2587                                       &info->rz_center,
2588                                       cogl_matrix_rotate (transform,
2589                                                           info->rz_angle,
2590                                                           0, 0, 1.0));
2591
2592       if (info->ry_angle)
2593         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2594                                       &info->ry_center,
2595                                       cogl_matrix_rotate (transform,
2596                                                           info->ry_angle,
2597                                                           0, 1.0, 0));
2598
2599       if (info->rx_angle)
2600         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2601                                       &info->rx_center,
2602                                       cogl_matrix_rotate (transform,
2603                                                           info->rx_angle,
2604                                                           1.0, 0, 0));
2605
2606       if (!clutter_anchor_coord_is_zero (&info->anchor))
2607         {
2608           gfloat x, y, z;
2609
2610           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2611           cogl_matrix_translate (transform, -x, -y, -z);
2612         }
2613
2614       priv->transform_valid = TRUE;
2615     }
2616
2617   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2618 }
2619
2620 /* Applies the transforms associated with this actor to the given
2621  * matrix. */
2622 void
2623 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2624                                           CoglMatrix *matrix)
2625 {
2626   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2627 }
2628
2629 /*
2630  * clutter_actor_apply_relative_transformation_matrix:
2631  * @self: The actor whose coordinate space you want to transform from.
2632  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2633  *            or %NULL if you want to transform all the way to eye coordinates.
2634  * @matrix: A #CoglMatrix to apply the transformation too.
2635  *
2636  * This multiplies a transform with @matrix that will transform coordinates
2637  * from the coordinate space of @self into the coordinate space of @ancestor.
2638  *
2639  * For example if you need a matrix that can transform the local actor
2640  * coordinates of @self into stage coordinates you would pass the actor's stage
2641  * pointer as the @ancestor.
2642  *
2643  * If you pass %NULL then the transformation will take you all the way through
2644  * to eye coordinates. This can be useful if you want to extract the entire
2645  * modelview transform that Clutter applies before applying the projection
2646  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2647  * using cogl_set_modelview_matrix() for example then you would want a matrix
2648  * that transforms into eye coordinates.
2649  *
2650  * <note>This function doesn't initialize the given @matrix, it simply
2651  * multiplies the requested transformation matrix with the existing contents of
2652  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2653  * before calling this function, or you can use
2654  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2655  */
2656 void
2657 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2658                                                      ClutterActor *ancestor,
2659                                                      CoglMatrix *matrix)
2660 {
2661   ClutterActor *parent;
2662
2663   /* Note we terminate before ever calling stage->apply_transform()
2664    * since that would conceptually be relative to the underlying
2665    * window OpenGL coordinates so we'd need a special @ancestor
2666    * value to represent the fake parent of the stage. */
2667   if (self == ancestor)
2668     return;
2669
2670   parent = clutter_actor_get_parent (self);
2671
2672   if (parent != NULL)
2673     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2674                                                          matrix);
2675
2676   _clutter_actor_apply_modelview_transform (self, matrix);
2677 }
2678
2679 static void
2680 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2681                                        ClutterPaintVolume *pv,
2682                                        const char *label,
2683                                        const CoglColor *color)
2684 {
2685   static CoglPipeline *outline = NULL;
2686   CoglPrimitive *prim;
2687   ClutterVertex line_ends[12 * 2];
2688   int n_vertices;
2689   CoglContext *ctx =
2690     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2691   /* XXX: at some point we'll query this from the stage but we can't
2692    * do that until the osx backend uses Cogl natively. */
2693   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2694
2695   if (outline == NULL)
2696     outline = cogl_pipeline_new ();
2697
2698   _clutter_paint_volume_complete (pv);
2699
2700   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2701
2702   /* Front face */
2703   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2704   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2705   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2706   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2707
2708   if (!pv->is_2d)
2709     {
2710       /* Back face */
2711       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2712       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2713       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2714       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2715
2716       /* Lines connecting front face to back face */
2717       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2718       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2719       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2720       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2721     }
2722
2723   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES, n_vertices,
2724                                 (CoglVertexP3 *)line_ends);
2725
2726   cogl_pipeline_set_color (outline, color);
2727   cogl_framebuffer_draw_primitive (fb, outline, prim);
2728   cogl_object_unref (prim);
2729
2730   if (label)
2731     {
2732       PangoLayout *layout;
2733       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2734       pango_layout_set_text (layout, label, -1);
2735       cogl_pango_render_layout (layout,
2736                                 pv->vertices[0].x,
2737                                 pv->vertices[0].y,
2738                                 color,
2739                                 0);
2740       g_object_unref (layout);
2741     }
2742 }
2743
2744 static void
2745 _clutter_actor_draw_paint_volume (ClutterActor *self)
2746 {
2747   ClutterPaintVolume *pv;
2748   CoglColor color;
2749
2750   pv = _clutter_actor_get_paint_volume_mutable (self);
2751   if (!pv)
2752     {
2753       gfloat width, height;
2754       ClutterPaintVolume fake_pv;
2755
2756       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2757       _clutter_paint_volume_init_static (&fake_pv, stage);
2758
2759       clutter_actor_get_size (self, &width, &height);
2760       clutter_paint_volume_set_width (&fake_pv, width);
2761       clutter_paint_volume_set_height (&fake_pv, height);
2762
2763       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2764       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2765                                              _clutter_actor_get_debug_name (self),
2766                                              &color);
2767
2768       clutter_paint_volume_free (&fake_pv);
2769     }
2770   else
2771     {
2772       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2773       _clutter_actor_draw_paint_volume_full (self, pv,
2774                                              _clutter_actor_get_debug_name (self),
2775                                              &color);
2776     }
2777 }
2778
2779 static void
2780 _clutter_actor_paint_cull_result (ClutterActor *self,
2781                                   gboolean success,
2782                                   ClutterCullResult result)
2783 {
2784   ClutterPaintVolume *pv;
2785   CoglColor color;
2786
2787   if (success)
2788     {
2789       if (result == CLUTTER_CULL_RESULT_IN)
2790         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2791       else if (result == CLUTTER_CULL_RESULT_OUT)
2792         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2793       else
2794         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2795     }
2796   else
2797     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2798
2799   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2800     _clutter_actor_draw_paint_volume_full (self, pv,
2801                                            _clutter_actor_get_debug_name (self),
2802                                            &color);
2803   else
2804     {
2805       PangoLayout *layout;
2806       char *label =
2807         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2808       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2809       cogl_set_source_color (&color);
2810
2811       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2812       pango_layout_set_text (layout, label, -1);
2813       cogl_pango_render_layout (layout,
2814                                 0,
2815                                 0,
2816                                 &color,
2817                                 0);
2818       g_free (label);
2819       g_object_unref (layout);
2820     }
2821 }
2822
2823 static int clone_paint_level = 0;
2824
2825 void
2826 _clutter_actor_push_clone_paint (void)
2827 {
2828   clone_paint_level++;
2829 }
2830
2831 void
2832 _clutter_actor_pop_clone_paint (void)
2833 {
2834   clone_paint_level--;
2835 }
2836
2837 static gboolean
2838 in_clone_paint (void)
2839 {
2840   return clone_paint_level > 0;
2841 }
2842
2843 /* Returns TRUE if the actor can be ignored */
2844 /* FIXME: we should return a ClutterCullResult, and
2845  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2846  * means there's no point in trying to cull descendants of the current
2847  * node. */
2848 static gboolean
2849 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2850 {
2851   ClutterActorPrivate *priv = self->priv;
2852   ClutterActor *stage;
2853   const ClutterPlane *stage_clip;
2854
2855   if (!priv->last_paint_volume_valid)
2856     {
2857       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2858                     "->last_paint_volume_valid == FALSE",
2859                     _clutter_actor_get_debug_name (self));
2860       return FALSE;
2861     }
2862
2863   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2864     return FALSE;
2865
2866   stage = _clutter_actor_get_stage_internal (self);
2867   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2868   if (G_UNLIKELY (!stage_clip))
2869     {
2870       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2871                     "No stage clip set",
2872                     _clutter_actor_get_debug_name (self));
2873       return FALSE;
2874     }
2875
2876   if (cogl_get_draw_framebuffer () !=
2877       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2878     {
2879       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2880                     "Current framebuffer doesn't correspond to stage",
2881                     _clutter_actor_get_debug_name (self));
2882       return FALSE;
2883     }
2884
2885   *result_out =
2886     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2887   return TRUE;
2888 }
2889
2890 static void
2891 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2892 {
2893   ClutterActorPrivate *priv = self->priv;
2894   const ClutterPaintVolume *pv;
2895
2896   if (priv->last_paint_volume_valid)
2897     {
2898       clutter_paint_volume_free (&priv->last_paint_volume);
2899       priv->last_paint_volume_valid = FALSE;
2900     }
2901
2902   pv = clutter_actor_get_paint_volume (self);
2903   if (!pv)
2904     {
2905       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2906                     "Actor failed to report a paint volume",
2907                     _clutter_actor_get_debug_name (self));
2908       return;
2909     }
2910
2911   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2912
2913   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2914                                             NULL); /* eye coordinates */
2915
2916   priv->last_paint_volume_valid = TRUE;
2917 }
2918
2919 static inline gboolean
2920 actor_has_shader_data (ClutterActor *self)
2921 {
2922   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2923 }
2924
2925 guint32
2926 _clutter_actor_get_pick_id (ClutterActor *self)
2927 {
2928   if (self->priv->pick_id < 0)
2929     return 0;
2930
2931   return self->priv->pick_id;
2932 }
2933
2934 /* This is the same as clutter_actor_add_effect except that it doesn't
2935    queue a redraw and it doesn't notify on the effect property */
2936 static void
2937 _clutter_actor_add_effect_internal (ClutterActor  *self,
2938                                     ClutterEffect *effect)
2939 {
2940   ClutterActorPrivate *priv = self->priv;
2941
2942   if (priv->effects == NULL)
2943     {
2944       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2945       priv->effects->actor = self;
2946     }
2947
2948   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2949 }
2950
2951 /* This is the same as clutter_actor_remove_effect except that it doesn't
2952    queue a redraw and it doesn't notify on the effect property */
2953 static void
2954 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2955                                        ClutterEffect *effect)
2956 {
2957   ClutterActorPrivate *priv = self->priv;
2958
2959   if (priv->effects == NULL)
2960     return;
2961
2962   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2963 }
2964
2965 static gboolean
2966 needs_flatten_effect (ClutterActor *self)
2967 {
2968   ClutterActorPrivate *priv = self->priv;
2969
2970   if (G_UNLIKELY (clutter_paint_debug_flags &
2971                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2972     return FALSE;
2973
2974   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2975     return TRUE;
2976   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2977     {
2978       if (clutter_actor_get_paint_opacity (self) < 255 &&
2979           clutter_actor_has_overlaps (self))
2980         return TRUE;
2981     }
2982
2983   return FALSE;
2984 }
2985
2986 static void
2987 add_or_remove_flatten_effect (ClutterActor *self)
2988 {
2989   ClutterActorPrivate *priv = self->priv;
2990
2991   /* Add or remove the flatten effect depending on the
2992      offscreen-redirect property. */
2993   if (needs_flatten_effect (self))
2994     {
2995       if (priv->flatten_effect == NULL)
2996         {
2997           ClutterActorMeta *actor_meta;
2998           gint priority;
2999
3000           priv->flatten_effect = _clutter_flatten_effect_new ();
3001           /* Keep a reference to the effect so that we can queue
3002              redraws from it */
3003           g_object_ref_sink (priv->flatten_effect);
3004
3005           /* Set the priority of the effect to high so that it will
3006              always be applied to the actor first. It uses an internal
3007              priority so that it won't be visible to applications */
3008           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3009           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3010           _clutter_actor_meta_set_priority (actor_meta, priority);
3011
3012           /* This will add the effect without queueing a redraw */
3013           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3014         }
3015     }
3016   else
3017     {
3018       if (priv->flatten_effect != NULL)
3019         {
3020           /* Destroy the effect so that it will lose its fbo cache of
3021              the actor */
3022           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3023           g_object_unref (priv->flatten_effect);
3024           priv->flatten_effect = NULL;
3025         }
3026     }
3027 }
3028
3029 static void
3030 clutter_actor_real_paint (ClutterActor *actor)
3031 {
3032   ClutterActorPrivate *priv = actor->priv;
3033   ClutterActor *iter;
3034
3035   /* paint the background color, if set */
3036   if (priv->bg_color_set)
3037     {
3038       float width, height;
3039       guint8 real_alpha;
3040
3041       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3042
3043       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3044                  * priv->bg_color.alpha
3045                  / 255;
3046
3047       cogl_set_source_color4ub (priv->bg_color.red,
3048                                 priv->bg_color.green,
3049                                 priv->bg_color.blue,
3050                                 real_alpha);
3051
3052       cogl_rectangle (0, 0, width, height);
3053     }
3054
3055   for (iter = priv->first_child;
3056        iter != NULL;
3057        iter = iter->priv->next_sibling)
3058     {
3059       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3060                     _clutter_actor_get_debug_name (iter),
3061                     _clutter_actor_get_debug_name (actor),
3062                     iter->priv->allocation.x1,
3063                     iter->priv->allocation.y1,
3064                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3065                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3066
3067       clutter_actor_paint (iter);
3068     }
3069 }
3070
3071 /**
3072  * clutter_actor_paint:
3073  * @self: A #ClutterActor
3074  *
3075  * Renders the actor to display.
3076  *
3077  * This function should not be called directly by applications.
3078  * Call clutter_actor_queue_redraw() to queue paints, instead.
3079  *
3080  * This function is context-aware, and will either cause a
3081  * regular paint or a pick paint.
3082  *
3083  * This function will emit the #ClutterActor::paint signal or
3084  * the #ClutterActor::pick signal, depending on the context.
3085  *
3086  * This function does not paint the actor if the actor is set to 0,
3087  * unless it is performing a pick paint.
3088  */
3089 void
3090 clutter_actor_paint (ClutterActor *self)
3091 {
3092   ClutterActorPrivate *priv;
3093   ClutterPickMode pick_mode;
3094   gboolean clip_set = FALSE;
3095   gboolean shader_applied = FALSE;
3096
3097   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3098                           "Actor real-paint counter",
3099                           "Increments each time any actor is painted",
3100                           0 /* no application private data */);
3101   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3102                           "Actor pick-paint counter",
3103                           "Increments each time any actor is painted "
3104                           "for picking",
3105                           0 /* no application private data */);
3106
3107   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3108
3109   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3110     return;
3111
3112   priv = self->priv;
3113
3114   pick_mode = _clutter_context_get_pick_mode ();
3115
3116   if (pick_mode == CLUTTER_PICK_NONE)
3117     priv->propagated_one_redraw = FALSE;
3118
3119   /* It's an important optimization that we consider painting of
3120    * actors with 0 opacity to be a NOP... */
3121   if (pick_mode == CLUTTER_PICK_NONE &&
3122       /* ignore top-levels, since they might be transparent */
3123       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3124       /* Use the override opacity if its been set */
3125       ((priv->opacity_override >= 0) ?
3126        priv->opacity_override : priv->opacity) == 0)
3127     return;
3128
3129   /* if we aren't paintable (not in a toplevel with all
3130    * parents paintable) then do nothing.
3131    */
3132   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3133     return;
3134
3135   /* mark that we are in the paint process */
3136   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3137
3138   cogl_push_matrix();
3139
3140   if (priv->enable_model_view_transform)
3141     {
3142       CoglMatrix matrix;
3143
3144       /* XXX: It could be better to cache the modelview with the actor
3145        * instead of progressively building up the transformations on
3146        * the matrix stack every time we paint. */
3147       cogl_get_modelview_matrix (&matrix);
3148       _clutter_actor_apply_modelview_transform (self, &matrix);
3149
3150 #ifdef CLUTTER_ENABLE_DEBUG
3151       /* Catch when out-of-band transforms have been made by actors not as part
3152        * of an apply_transform vfunc... */
3153       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3154         {
3155           CoglMatrix expected_matrix;
3156
3157           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3158                                                              &expected_matrix);
3159
3160           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3161             {
3162               GString *buf = g_string_sized_new (1024);
3163               ClutterActor *parent;
3164
3165               parent = self;
3166               while (parent != NULL)
3167                 {
3168                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3169
3170                   if (parent->priv->parent != NULL)
3171                     g_string_append (buf, "->");
3172
3173                   parent = parent->priv->parent;
3174                 }
3175
3176               g_warning ("Unexpected transform found when painting actor "
3177                          "\"%s\". This will be caused by one of the actor's "
3178                          "ancestors (%s) using the Cogl API directly to transform "
3179                          "children instead of using ::apply_transform().",
3180                          _clutter_actor_get_debug_name (self),
3181                          buf->str);
3182
3183               g_string_free (buf, TRUE);
3184             }
3185         }
3186 #endif /* CLUTTER_ENABLE_DEBUG */
3187
3188       cogl_set_modelview_matrix (&matrix);
3189     }
3190
3191   if (priv->has_clip)
3192     {
3193       cogl_clip_push_rectangle (priv->clip.x,
3194                                 priv->clip.y,
3195                                 priv->clip.x + priv->clip.width,
3196                                 priv->clip.y + priv->clip.height);
3197       clip_set = TRUE;
3198     }
3199   else if (priv->clip_to_allocation)
3200     {
3201       gfloat width, height;
3202
3203       width  = priv->allocation.x2 - priv->allocation.x1;
3204       height = priv->allocation.y2 - priv->allocation.y1;
3205
3206       cogl_clip_push_rectangle (0, 0, width, height);
3207       clip_set = TRUE;
3208     }
3209
3210   if (pick_mode == CLUTTER_PICK_NONE)
3211     {
3212       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3213
3214       /* We check whether we need to add the flatten effect before
3215          each paint so that we can avoid having a mechanism for
3216          applications to notify when the value of the
3217          has_overlaps virtual changes. */
3218       add_or_remove_flatten_effect (self);
3219     }
3220   else
3221     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3222
3223   /* We save the current paint volume so that the next time the
3224    * actor queues a redraw we can constrain the redraw to just
3225    * cover the union of the new bounding box and the old.
3226    *
3227    * We also fetch the current paint volume to perform culling so
3228    * we can avoid painting actors outside the current clip region.
3229    *
3230    * If we are painting inside a clone, we should neither update
3231    * the paint volume or use it to cull painting, since the paint
3232    * box represents the location of the source actor on the
3233    * screen.
3234    *
3235    * XXX: We are starting to do a lot of vertex transforms on
3236    * the CPU in a typical paint, so at some point we should
3237    * audit these and consider caching some things.
3238    *
3239    * NB: We don't perform culling while picking at this point because
3240    * clutter-stage.c doesn't setup the clipping planes appropriately.
3241    *
3242    * NB: We don't want to update the last-paint-volume during picking
3243    * because the last-paint-volume is used to determine the old screen
3244    * space location of an actor that has moved so we can know the
3245    * minimal region to redraw to clear an old view of the actor. If we
3246    * update this during picking then by the time we come around to
3247    * paint then the last-paint-volume would likely represent the new
3248    * actor position not the old.
3249    */
3250   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3251     {
3252       gboolean success;
3253       /* annoyingly gcc warns if uninitialized even though
3254        * the initialization is redundant :-( */
3255       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3256
3257       if (G_LIKELY ((clutter_paint_debug_flags &
3258                      (CLUTTER_DEBUG_DISABLE_CULLING |
3259                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3260                     (CLUTTER_DEBUG_DISABLE_CULLING |
3261                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3262         _clutter_actor_update_last_paint_volume (self);
3263
3264       success = cull_actor (self, &result);
3265
3266       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3267         _clutter_actor_paint_cull_result (self, success, result);
3268       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3269         goto done;
3270     }
3271
3272   if (priv->effects == NULL)
3273     {
3274       if (pick_mode == CLUTTER_PICK_NONE &&
3275           actor_has_shader_data (self))
3276         {
3277           _clutter_actor_shader_pre_paint (self, FALSE);
3278           shader_applied = TRUE;
3279         }
3280
3281       priv->next_effect_to_paint = NULL;
3282     }
3283   else
3284     priv->next_effect_to_paint =
3285       _clutter_meta_group_peek_metas (priv->effects);
3286
3287   clutter_actor_continue_paint (self);
3288
3289   if (shader_applied)
3290     _clutter_actor_shader_post_paint (self);
3291
3292   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3293                   pick_mode == CLUTTER_PICK_NONE))
3294     _clutter_actor_draw_paint_volume (self);
3295
3296 done:
3297   /* If we make it here then the actor has run through a complete
3298      paint run including all the effects so it's no longer dirty */
3299   if (pick_mode == CLUTTER_PICK_NONE)
3300     priv->is_dirty = FALSE;
3301
3302   if (clip_set)
3303     cogl_clip_pop();
3304
3305   cogl_pop_matrix();
3306
3307   /* paint sequence complete */
3308   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3309 }
3310
3311 /**
3312  * clutter_actor_continue_paint:
3313  * @self: A #ClutterActor
3314  *
3315  * Run the next stage of the paint sequence. This function should only
3316  * be called within the implementation of the ‘run’ virtual of a
3317  * #ClutterEffect. It will cause the run method of the next effect to
3318  * be applied, or it will paint the actual actor if the current effect
3319  * is the last effect in the chain.
3320  *
3321  * Since: 1.8
3322  */
3323 void
3324 clutter_actor_continue_paint (ClutterActor *self)
3325 {
3326   ClutterActorPrivate *priv;
3327
3328   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3329   /* This should only be called from with in the ‘run’ implementation
3330      of a ClutterEffect */
3331   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3332
3333   priv = self->priv;
3334
3335   /* Skip any effects that are disabled */
3336   while (priv->next_effect_to_paint &&
3337          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3338     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3339
3340   /* If this has come from the last effect then we'll just paint the
3341      actual actor */
3342   if (priv->next_effect_to_paint == NULL)
3343     {
3344       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3345         {
3346           g_signal_emit (self, actor_signals[PAINT], 0);
3347         }
3348       else
3349         {
3350           ClutterColor col = { 0, };
3351
3352           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3353
3354           /* Actor will then paint silhouette of itself in supplied
3355            * color.  See clutter_stage_get_actor_at_pos() for where
3356            * picking is enabled.
3357            */
3358           g_signal_emit (self, actor_signals[PICK], 0, &col);
3359         }
3360     }
3361   else
3362     {
3363       ClutterEffect *old_current_effect;
3364       ClutterEffectPaintFlags run_flags = 0;
3365
3366       /* Cache the current effect so that we can put it back before
3367          returning */
3368       old_current_effect = priv->current_effect;
3369
3370       priv->current_effect = priv->next_effect_to_paint->data;
3371       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3372
3373       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3374         {
3375           if (priv->is_dirty)
3376             {
3377               /* If there's an effect queued with this redraw then all
3378                  effects up to that one will be considered dirty. It
3379                  is expected the queued effect will paint the cached
3380                  image and not call clutter_actor_continue_paint again
3381                  (although it should work ok if it does) */
3382               if (priv->effect_to_redraw == NULL ||
3383                   priv->current_effect != priv->effect_to_redraw)
3384                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3385             }
3386
3387           _clutter_effect_paint (priv->current_effect, run_flags);
3388         }
3389       else
3390         {
3391           /* We can't determine when an actor has been modified since
3392              its last pick so lets just assume it has always been
3393              modified */
3394           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3395
3396           _clutter_effect_pick (priv->current_effect, run_flags);
3397         }
3398
3399       priv->current_effect = old_current_effect;
3400     }
3401 }
3402
3403 static ClutterActorTraverseVisitFlags
3404 invalidate_queue_redraw_entry (ClutterActor *self,
3405                                int           depth,
3406                                gpointer      user_data)
3407 {
3408   ClutterActorPrivate *priv = self->priv;
3409
3410   if (priv->queue_redraw_entry != NULL)
3411     {
3412       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3413       priv->queue_redraw_entry = NULL;
3414     }
3415
3416   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3417 }
3418
3419 static inline void
3420 remove_child (ClutterActor *self,
3421               ClutterActor *child)
3422 {
3423   ClutterActor *prev_sibling, *next_sibling;
3424
3425   prev_sibling = child->priv->prev_sibling;
3426   next_sibling = child->priv->next_sibling;
3427
3428   if (prev_sibling != NULL)
3429     prev_sibling->priv->next_sibling = next_sibling;
3430
3431   if (next_sibling != NULL)
3432     next_sibling->priv->prev_sibling = prev_sibling;
3433
3434   if (self->priv->first_child == child)
3435     self->priv->first_child = next_sibling;
3436
3437   if (self->priv->last_child == child)
3438     self->priv->last_child = prev_sibling;
3439
3440   child->priv->parent = NULL;
3441   child->priv->prev_sibling = NULL;
3442   child->priv->next_sibling = NULL;
3443 }
3444
3445 typedef enum {
3446   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3447   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3448   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3449   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3450   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3451   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3452
3453   /* default flags for public API */
3454   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3455                                     REMOVE_CHILD_EMIT_PARENT_SET |
3456                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3457                                     REMOVE_CHILD_CHECK_STATE |
3458                                     REMOVE_CHILD_FLUSH_QUEUE |
3459                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3460
3461   /* flags for legacy/deprecated API */
3462   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3463                                     REMOVE_CHILD_FLUSH_QUEUE |
3464                                     REMOVE_CHILD_EMIT_PARENT_SET |
3465                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3466 } ClutterActorRemoveChildFlags;
3467
3468 /*< private >
3469  * clutter_actor_remove_child_internal:
3470  * @self: a #ClutterActor
3471  * @child: the child of @self that has to be removed
3472  * @flags: control the removal operations
3473  *
3474  * Removes @child from the list of children of @self.
3475  */
3476 static void
3477 clutter_actor_remove_child_internal (ClutterActor                 *self,
3478                                      ClutterActor                 *child,
3479                                      ClutterActorRemoveChildFlags  flags)
3480 {
3481   ClutterActor *old_first, *old_last;
3482   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3483   gboolean flush_queue;
3484   gboolean notify_first_last;
3485   gboolean was_mapped;
3486
3487   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3488   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3489   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3490   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3491   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3492   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3493
3494   g_object_freeze_notify (G_OBJECT (self));
3495
3496   if (destroy_meta)
3497     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3498
3499   if (check_state)
3500     {
3501       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3502
3503       /* we need to unrealize *before* we set parent_actor to NULL,
3504        * because in an unrealize method actors are dissociating from the
3505        * stage, which means they need to be able to
3506        * clutter_actor_get_stage().
3507        *
3508        * yhis should unmap and unrealize, unless we're reparenting.
3509        */
3510       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3511     }
3512   else
3513     was_mapped = FALSE;
3514
3515   if (flush_queue)
3516     {
3517       /* We take this opportunity to invalidate any queue redraw entry
3518        * associated with the actor and descendants since we won't be able to
3519        * determine the appropriate stage after this.
3520        *
3521        * we do this after we updated the mapped state because actors might
3522        * end up queueing redraws inside their mapped/unmapped virtual
3523        * functions, and if we invalidate the redraw entry we could end up
3524        * with an inconsistent state and weird memory corruption. see
3525        * bugs:
3526        *
3527        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3528        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3529        */
3530       _clutter_actor_traverse (child,
3531                                0,
3532                                invalidate_queue_redraw_entry,
3533                                NULL,
3534                                NULL);
3535     }
3536
3537   old_first = self->priv->first_child;
3538   old_last = self->priv->last_child;
3539
3540   remove_child (self, child);
3541
3542   self->priv->n_children -= 1;
3543
3544   self->priv->age += 1;
3545
3546   /* clutter_actor_reparent() will emit ::parent-set for us */
3547   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3548     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3549
3550   /* if the child was mapped then we need to relayout ourselves to account
3551    * for the removed child
3552    */
3553   if (was_mapped)
3554     clutter_actor_queue_relayout (self);
3555
3556   /* we need to emit the signal before dropping the reference */
3557   if (emit_actor_removed)
3558     g_signal_emit_by_name (self, "actor-removed", child);
3559
3560   if (notify_first_last)
3561     {
3562       if (old_first != self->priv->first_child)
3563         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3564
3565       if (old_last != self->priv->last_child)
3566         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3567     }
3568
3569   g_object_thaw_notify (G_OBJECT (self));
3570
3571   /* remove the reference we acquired in clutter_actor_add_child() */
3572   g_object_unref (child);
3573 }
3574
3575 static const ClutterTransformInfo default_transform_info = {
3576   0.0, { 0, },          /* rotation-x */
3577   0.0, { 0, },          /* rotation-y */
3578   0.0, { 0, },          /* rotation-z */
3579
3580   1.0, 1.0, { 0, },     /* scale */
3581
3582   { 0, },               /* anchor */
3583 };
3584
3585 /*< private >
3586  * _clutter_actor_get_transform_info_or_defaults:
3587  * @self: a #ClutterActor
3588  *
3589  * Retrieves the ClutterTransformInfo structure associated to an actor.
3590  *
3591  * If the actor does not have a ClutterTransformInfo structure associated
3592  * to it, then the default structure will be returned.
3593  *
3594  * This function should only be used for getters.
3595  *
3596  * Return value: a const pointer to the ClutterTransformInfo structure
3597  */
3598 const ClutterTransformInfo *
3599 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3600 {
3601   ClutterTransformInfo *info;
3602
3603   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3604   if (info != NULL)
3605     return info;
3606
3607   return &default_transform_info;
3608 }
3609
3610 static void
3611 clutter_transform_info_free (gpointer data)
3612 {
3613   if (data != NULL)
3614     g_slice_free (ClutterTransformInfo, data);
3615 }
3616
3617 /*< private >
3618  * _clutter_actor_get_transform_info:
3619  * @self: a #ClutterActor
3620  *
3621  * Retrieves a pointer to the ClutterTransformInfo structure.
3622  *
3623  * If the actor does not have a ClutterTransformInfo associated to it, one
3624  * will be created and initialized to the default values.
3625  *
3626  * This function should be used for setters.
3627  *
3628  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3629  * instead.
3630  *
3631  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3632  *   structure
3633  */
3634 ClutterTransformInfo *
3635 _clutter_actor_get_transform_info (ClutterActor *self)
3636 {
3637   ClutterTransformInfo *info;
3638
3639   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3640   if (info == NULL)
3641     {
3642       info = g_slice_new (ClutterTransformInfo);
3643
3644       *info = default_transform_info;
3645
3646       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3647                                info,
3648                                clutter_transform_info_free);
3649     }
3650
3651   return info;
3652 }
3653
3654 /*< private >
3655  * clutter_actor_set_rotation_angle_internal:
3656  * @self: a #ClutterActor
3657  * @axis: the axis of the angle to change
3658  * @angle: the angle of rotation
3659  *
3660  * Sets the rotation angle on the given axis without affecting the
3661  * rotation center point.
3662  */
3663 static inline void
3664 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3665                                            ClutterRotateAxis  axis,
3666                                            gdouble            angle)
3667 {
3668   GObject *obj = G_OBJECT (self);
3669   ClutterTransformInfo *info;
3670
3671   info = _clutter_actor_get_transform_info (self);
3672
3673   g_object_freeze_notify (obj);
3674
3675   switch (axis)
3676     {
3677     case CLUTTER_X_AXIS:
3678       info->rx_angle = angle;
3679       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3680       break;
3681
3682     case CLUTTER_Y_AXIS:
3683       info->ry_angle = angle;
3684       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3685       break;
3686
3687     case CLUTTER_Z_AXIS:
3688       info->rz_angle = angle;
3689       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3690       break;
3691     }
3692
3693   self->priv->transform_valid = FALSE;
3694
3695   g_object_thaw_notify (obj);
3696
3697   clutter_actor_queue_redraw (self);
3698 }
3699
3700 /*< private >
3701  * clutter_actor_set_rotation_center_internal:
3702  * @self: a #ClutterActor
3703  * @axis: the axis of the center to change
3704  * @center: the coordinates of the rotation center
3705  *
3706  * Sets the rotation center on the given axis without affecting the
3707  * rotation angle.
3708  */
3709 static inline void
3710 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3711                                             ClutterRotateAxis    axis,
3712                                             const ClutterVertex *center)
3713 {
3714   GObject *obj = G_OBJECT (self);
3715   ClutterTransformInfo *info;
3716   ClutterVertex v = { 0, 0, 0 };
3717
3718   info = _clutter_actor_get_transform_info (self);
3719
3720   if (center != NULL)
3721     v = *center;
3722
3723   g_object_freeze_notify (obj);
3724
3725   switch (axis)
3726     {
3727     case CLUTTER_X_AXIS:
3728       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3729       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3730       break;
3731
3732     case CLUTTER_Y_AXIS:
3733       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3734       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3735       break;
3736
3737     case CLUTTER_Z_AXIS:
3738       /* if the previously set rotation center was fractional, then
3739        * setting explicit coordinates will have to notify the
3740        * :rotation-center-z-gravity property as well
3741        */
3742       if (info->rz_center.is_fractional)
3743         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3744
3745       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3746       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3747       break;
3748     }
3749
3750   self->priv->transform_valid = FALSE;
3751
3752   g_object_thaw_notify (obj);
3753
3754   clutter_actor_queue_redraw (self);
3755 }
3756
3757 static inline void
3758 clutter_actor_set_scale_factor (ClutterActor      *self,
3759                                 ClutterRotateAxis  axis,
3760                                 gdouble            factor)
3761 {
3762   GObject *obj = G_OBJECT (self);
3763   ClutterTransformInfo *info;
3764
3765   info = _clutter_actor_get_transform_info (self);
3766
3767   g_object_freeze_notify (obj);
3768
3769   switch (axis)
3770     {
3771     case CLUTTER_X_AXIS:
3772       info->scale_x = factor;
3773       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3774       break;
3775
3776     case CLUTTER_Y_AXIS:
3777       info->scale_y = factor;
3778       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3779       break;
3780
3781     default:
3782       g_assert_not_reached ();
3783     }
3784
3785   self->priv->transform_valid = FALSE;
3786
3787   clutter_actor_queue_redraw (self);
3788
3789   g_object_thaw_notify (obj);
3790 }
3791
3792 static inline void
3793 clutter_actor_set_scale_center (ClutterActor      *self,
3794                                 ClutterRotateAxis  axis,
3795                                 gfloat             coord)
3796 {
3797   GObject *obj = G_OBJECT (self);
3798   ClutterTransformInfo *info;
3799   gfloat center_x, center_y;
3800
3801   info = _clutter_actor_get_transform_info (self);
3802
3803   g_object_freeze_notify (obj);
3804
3805   /* get the current scale center coordinates */
3806   clutter_anchor_coord_get_units (self, &info->scale_center,
3807                                   &center_x,
3808                                   &center_y,
3809                                   NULL);
3810
3811   /* we need to notify this too, because setting explicit coordinates will
3812    * change the gravity as a side effect
3813    */
3814   if (info->scale_center.is_fractional)
3815     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3816
3817   switch (axis)
3818     {
3819     case CLUTTER_X_AXIS:
3820       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3821       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3822       break;
3823
3824     case CLUTTER_Y_AXIS:
3825       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3826       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3827       break;
3828
3829     default:
3830       g_assert_not_reached ();
3831     }
3832
3833   self->priv->transform_valid = FALSE;
3834
3835   clutter_actor_queue_redraw (self);
3836
3837   g_object_thaw_notify (obj);
3838 }
3839
3840 static inline void
3841 clutter_actor_set_anchor_coord (ClutterActor      *self,
3842                                 ClutterRotateAxis  axis,
3843                                 gfloat             coord)
3844 {
3845   GObject *obj = G_OBJECT (self);
3846   ClutterTransformInfo *info;
3847   gfloat anchor_x, anchor_y;
3848
3849   info = _clutter_actor_get_transform_info (self);
3850
3851   g_object_freeze_notify (obj);
3852
3853   clutter_anchor_coord_get_units (self, &info->anchor,
3854                                   &anchor_x,
3855                                   &anchor_y,
3856                                   NULL);
3857
3858   if (info->anchor.is_fractional)
3859     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3860
3861   switch (axis)
3862     {
3863     case CLUTTER_X_AXIS:
3864       clutter_anchor_coord_set_units (&info->anchor,
3865                                       coord,
3866                                       anchor_y,
3867                                       0.0);
3868       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3869       break;
3870
3871     case CLUTTER_Y_AXIS:
3872       clutter_anchor_coord_set_units (&info->anchor,
3873                                       anchor_x,
3874                                       coord,
3875                                       0.0);
3876       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3877       break;
3878
3879     default:
3880       g_assert_not_reached ();
3881     }
3882
3883   self->priv->transform_valid = FALSE;
3884
3885   clutter_actor_queue_redraw (self);
3886
3887   g_object_thaw_notify (obj);
3888 }
3889
3890 static void
3891 clutter_actor_set_property (GObject      *object,
3892                             guint         prop_id,
3893                             const GValue *value,
3894                             GParamSpec   *pspec)
3895 {
3896   ClutterActor *actor = CLUTTER_ACTOR (object);
3897   ClutterActorPrivate *priv = actor->priv;
3898
3899   switch (prop_id)
3900     {
3901     case PROP_X:
3902       clutter_actor_set_x (actor, g_value_get_float (value));
3903       break;
3904
3905     case PROP_Y:
3906       clutter_actor_set_y (actor, g_value_get_float (value));
3907       break;
3908
3909     case PROP_WIDTH:
3910       clutter_actor_set_width (actor, g_value_get_float (value));
3911       break;
3912
3913     case PROP_HEIGHT:
3914       clutter_actor_set_height (actor, g_value_get_float (value));
3915       break;
3916
3917     case PROP_FIXED_X:
3918       clutter_actor_set_x (actor, g_value_get_float (value));
3919       break;
3920
3921     case PROP_FIXED_Y:
3922       clutter_actor_set_y (actor, g_value_get_float (value));
3923       break;
3924
3925     case PROP_FIXED_POSITION_SET:
3926       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3927       break;
3928
3929     case PROP_MIN_WIDTH:
3930       clutter_actor_set_min_width (actor, g_value_get_float (value));
3931       break;
3932
3933     case PROP_MIN_HEIGHT:
3934       clutter_actor_set_min_height (actor, g_value_get_float (value));
3935       break;
3936
3937     case PROP_NATURAL_WIDTH:
3938       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3939       break;
3940
3941     case PROP_NATURAL_HEIGHT:
3942       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3943       break;
3944
3945     case PROP_MIN_WIDTH_SET:
3946       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3947       break;
3948
3949     case PROP_MIN_HEIGHT_SET:
3950       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3951       break;
3952
3953     case PROP_NATURAL_WIDTH_SET:
3954       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3955       break;
3956
3957     case PROP_NATURAL_HEIGHT_SET:
3958       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3959       break;
3960
3961     case PROP_REQUEST_MODE:
3962       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3963       break;
3964
3965     case PROP_DEPTH:
3966       clutter_actor_set_depth (actor, g_value_get_float (value));
3967       break;
3968
3969     case PROP_OPACITY:
3970       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3971       break;
3972
3973     case PROP_OFFSCREEN_REDIRECT:
3974       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3975       break;
3976
3977     case PROP_NAME:
3978       clutter_actor_set_name (actor, g_value_get_string (value));
3979       break;
3980
3981     case PROP_VISIBLE:
3982       if (g_value_get_boolean (value) == TRUE)
3983         clutter_actor_show (actor);
3984       else
3985         clutter_actor_hide (actor);
3986       break;
3987
3988     case PROP_SCALE_X:
3989       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3990                                       g_value_get_double (value));
3991       break;
3992
3993     case PROP_SCALE_Y:
3994       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3995                                       g_value_get_double (value));
3996       break;
3997
3998     case PROP_SCALE_CENTER_X:
3999       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4000                                       g_value_get_float (value));
4001       break;
4002
4003     case PROP_SCALE_CENTER_Y:
4004       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4005                                       g_value_get_float (value));
4006       break;
4007
4008     case PROP_SCALE_GRAVITY:
4009       {
4010         const ClutterTransformInfo *info;
4011         ClutterGravity gravity;
4012
4013         info = _clutter_actor_get_transform_info_or_defaults (actor);
4014         gravity = g_value_get_enum (value);
4015
4016         clutter_actor_set_scale_with_gravity (actor,
4017                                               info->scale_x,
4018                                               info->scale_y,
4019                                               gravity);
4020       }
4021       break;
4022
4023     case PROP_CLIP:
4024       {
4025         const ClutterGeometry *geom = g_value_get_boxed (value);
4026
4027         clutter_actor_set_clip (actor,
4028                                 geom->x, geom->y,
4029                                 geom->width, geom->height);
4030       }
4031       break;
4032
4033     case PROP_CLIP_TO_ALLOCATION:
4034       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4035       break;
4036
4037     case PROP_REACTIVE:
4038       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4039       break;
4040
4041     case PROP_ROTATION_ANGLE_X:
4042       clutter_actor_set_rotation_angle_internal (actor,
4043                                                  CLUTTER_X_AXIS,
4044                                                  g_value_get_double (value));
4045       break;
4046
4047     case PROP_ROTATION_ANGLE_Y:
4048       clutter_actor_set_rotation_angle_internal (actor,
4049                                                  CLUTTER_Y_AXIS,
4050                                                  g_value_get_double (value));
4051       break;
4052
4053     case PROP_ROTATION_ANGLE_Z:
4054       clutter_actor_set_rotation_angle_internal (actor,
4055                                                  CLUTTER_Z_AXIS,
4056                                                  g_value_get_double (value));
4057       break;
4058
4059     case PROP_ROTATION_CENTER_X:
4060       clutter_actor_set_rotation_center_internal (actor,
4061                                                   CLUTTER_X_AXIS,
4062                                                   g_value_get_boxed (value));
4063       break;
4064
4065     case PROP_ROTATION_CENTER_Y:
4066       clutter_actor_set_rotation_center_internal (actor,
4067                                                   CLUTTER_Y_AXIS,
4068                                                   g_value_get_boxed (value));
4069       break;
4070
4071     case PROP_ROTATION_CENTER_Z:
4072       clutter_actor_set_rotation_center_internal (actor,
4073                                                   CLUTTER_Z_AXIS,
4074                                                   g_value_get_boxed (value));
4075       break;
4076
4077     case PROP_ROTATION_CENTER_Z_GRAVITY:
4078       {
4079         const ClutterTransformInfo *info;
4080
4081         info = _clutter_actor_get_transform_info_or_defaults (actor);
4082         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4083                                                    g_value_get_enum (value));
4084       }
4085       break;
4086
4087     case PROP_ANCHOR_X:
4088       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4089                                       g_value_get_float (value));
4090       break;
4091
4092     case PROP_ANCHOR_Y:
4093       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4094                                       g_value_get_float (value));
4095       break;
4096
4097     case PROP_ANCHOR_GRAVITY:
4098       clutter_actor_set_anchor_point_from_gravity (actor,
4099                                                    g_value_get_enum (value));
4100       break;
4101
4102     case PROP_SHOW_ON_SET_PARENT:
4103       priv->show_on_set_parent = g_value_get_boolean (value);
4104       break;
4105
4106     case PROP_TEXT_DIRECTION:
4107       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4108       break;
4109
4110     case PROP_ACTIONS:
4111       clutter_actor_add_action (actor, g_value_get_object (value));
4112       break;
4113
4114     case PROP_CONSTRAINTS:
4115       clutter_actor_add_constraint (actor, g_value_get_object (value));
4116       break;
4117
4118     case PROP_EFFECT:
4119       clutter_actor_add_effect (actor, g_value_get_object (value));
4120       break;
4121
4122     case PROP_LAYOUT_MANAGER:
4123       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4124       break;
4125
4126     case PROP_X_ALIGN:
4127       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4128       break;
4129
4130     case PROP_Y_ALIGN:
4131       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4132       break;
4133
4134     case PROP_MARGIN_TOP:
4135       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4136       break;
4137
4138     case PROP_MARGIN_BOTTOM:
4139       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4140       break;
4141
4142     case PROP_MARGIN_LEFT:
4143       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4144       break;
4145
4146     case PROP_MARGIN_RIGHT:
4147       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4148       break;
4149
4150     case PROP_BACKGROUND_COLOR:
4151       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4152       break;
4153
4154     default:
4155       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4156       break;
4157     }
4158 }
4159
4160 static void
4161 clutter_actor_get_property (GObject    *object,
4162                             guint       prop_id,
4163                             GValue     *value,
4164                             GParamSpec *pspec)
4165 {
4166   ClutterActor *actor = CLUTTER_ACTOR (object);
4167   ClutterActorPrivate *priv = actor->priv;
4168
4169   switch (prop_id)
4170     {
4171     case PROP_X:
4172       g_value_set_float (value, clutter_actor_get_x (actor));
4173       break;
4174
4175     case PROP_Y:
4176       g_value_set_float (value, clutter_actor_get_y (actor));
4177       break;
4178
4179     case PROP_WIDTH:
4180       g_value_set_float (value, clutter_actor_get_width (actor));
4181       break;
4182
4183     case PROP_HEIGHT:
4184       g_value_set_float (value, clutter_actor_get_height (actor));
4185       break;
4186
4187     case PROP_FIXED_X:
4188       {
4189         const ClutterLayoutInfo *info;
4190
4191         info = _clutter_actor_get_layout_info_or_defaults (actor);
4192         g_value_set_float (value, info->fixed_x);
4193       }
4194       break;
4195
4196     case PROP_FIXED_Y:
4197       {
4198         const ClutterLayoutInfo *info;
4199
4200         info = _clutter_actor_get_layout_info_or_defaults (actor);
4201         g_value_set_float (value, info->fixed_y);
4202       }
4203       break;
4204
4205     case PROP_FIXED_POSITION_SET:
4206       g_value_set_boolean (value, priv->position_set);
4207       break;
4208
4209     case PROP_MIN_WIDTH:
4210       {
4211         const ClutterLayoutInfo *info;
4212
4213         info = _clutter_actor_get_layout_info_or_defaults (actor);
4214         g_value_set_float (value, info->min_width);
4215       }
4216       break;
4217
4218     case PROP_MIN_HEIGHT:
4219       {
4220         const ClutterLayoutInfo *info;
4221
4222         info = _clutter_actor_get_layout_info_or_defaults (actor);
4223         g_value_set_float (value, info->min_height);
4224       }
4225       break;
4226
4227     case PROP_NATURAL_WIDTH:
4228       {
4229         const ClutterLayoutInfo *info;
4230
4231         info = _clutter_actor_get_layout_info_or_defaults (actor);
4232         g_value_set_float (value, info->natural_width);
4233       }
4234       break;
4235
4236     case PROP_NATURAL_HEIGHT:
4237       {
4238         const ClutterLayoutInfo *info;
4239
4240         info = _clutter_actor_get_layout_info_or_defaults (actor);
4241         g_value_set_float (value, info->natural_height);
4242       }
4243       break;
4244
4245     case PROP_MIN_WIDTH_SET:
4246       g_value_set_boolean (value, priv->min_width_set);
4247       break;
4248
4249     case PROP_MIN_HEIGHT_SET:
4250       g_value_set_boolean (value, priv->min_height_set);
4251       break;
4252
4253     case PROP_NATURAL_WIDTH_SET:
4254       g_value_set_boolean (value, priv->natural_width_set);
4255       break;
4256
4257     case PROP_NATURAL_HEIGHT_SET:
4258       g_value_set_boolean (value, priv->natural_height_set);
4259       break;
4260
4261     case PROP_REQUEST_MODE:
4262       g_value_set_enum (value, priv->request_mode);
4263       break;
4264
4265     case PROP_ALLOCATION:
4266       g_value_set_boxed (value, &priv->allocation);
4267       break;
4268
4269     case PROP_DEPTH:
4270       g_value_set_float (value, clutter_actor_get_depth (actor));
4271       break;
4272
4273     case PROP_OPACITY:
4274       g_value_set_uint (value, priv->opacity);
4275       break;
4276
4277     case PROP_OFFSCREEN_REDIRECT:
4278       g_value_set_enum (value, priv->offscreen_redirect);
4279       break;
4280
4281     case PROP_NAME:
4282       g_value_set_string (value, priv->name);
4283       break;
4284
4285     case PROP_VISIBLE:
4286       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4287       break;
4288
4289     case PROP_MAPPED:
4290       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4291       break;
4292
4293     case PROP_REALIZED:
4294       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4295       break;
4296
4297     case PROP_HAS_CLIP:
4298       g_value_set_boolean (value, priv->has_clip);
4299       break;
4300
4301     case PROP_CLIP:
4302       {
4303         ClutterGeometry clip;
4304
4305         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4306         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4307         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4308         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4309
4310         g_value_set_boxed (value, &clip);
4311       }
4312       break;
4313
4314     case PROP_CLIP_TO_ALLOCATION:
4315       g_value_set_boolean (value, priv->clip_to_allocation);
4316       break;
4317
4318     case PROP_SCALE_X:
4319       {
4320         const ClutterTransformInfo *info;
4321
4322         info = _clutter_actor_get_transform_info_or_defaults (actor);
4323         g_value_set_double (value, info->scale_x);
4324       }
4325       break;
4326
4327     case PROP_SCALE_Y:
4328       {
4329         const ClutterTransformInfo *info;
4330
4331         info = _clutter_actor_get_transform_info_or_defaults (actor);
4332         g_value_set_double (value, info->scale_y);
4333       }
4334       break;
4335
4336     case PROP_SCALE_CENTER_X:
4337       {
4338         gfloat center;
4339
4340         clutter_actor_get_scale_center (actor, &center, NULL);
4341
4342         g_value_set_float (value, center);
4343       }
4344       break;
4345
4346     case PROP_SCALE_CENTER_Y:
4347       {
4348         gfloat center;
4349
4350         clutter_actor_get_scale_center (actor, NULL, &center);
4351
4352         g_value_set_float (value, center);
4353       }
4354       break;
4355
4356     case PROP_SCALE_GRAVITY:
4357       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4358       break;
4359
4360     case PROP_REACTIVE:
4361       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4362       break;
4363
4364     case PROP_ROTATION_ANGLE_X:
4365       {
4366         const ClutterTransformInfo *info;
4367
4368         info = _clutter_actor_get_transform_info_or_defaults (actor);
4369         g_value_set_double (value, info->rx_angle);
4370       }
4371       break;
4372
4373     case PROP_ROTATION_ANGLE_Y:
4374       {
4375         const ClutterTransformInfo *info;
4376
4377         info = _clutter_actor_get_transform_info_or_defaults (actor);
4378         g_value_set_double (value, info->ry_angle);
4379       }
4380       break;
4381
4382     case PROP_ROTATION_ANGLE_Z:
4383       {
4384         const ClutterTransformInfo *info;
4385
4386         info = _clutter_actor_get_transform_info_or_defaults (actor);
4387         g_value_set_double (value, info->rz_angle);
4388       }
4389       break;
4390
4391     case PROP_ROTATION_CENTER_X:
4392       {
4393         ClutterVertex center;
4394
4395         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4396                                     &center.x,
4397                                     &center.y,
4398                                     &center.z);
4399
4400         g_value_set_boxed (value, &center);
4401       }
4402       break;
4403
4404     case PROP_ROTATION_CENTER_Y:
4405       {
4406         ClutterVertex center;
4407
4408         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4409                                     &center.x,
4410                                     &center.y,
4411                                     &center.z);
4412
4413         g_value_set_boxed (value, &center);
4414       }
4415       break;
4416
4417     case PROP_ROTATION_CENTER_Z:
4418       {
4419         ClutterVertex center;
4420
4421         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4422                                     &center.x,
4423                                     &center.y,
4424                                     &center.z);
4425
4426         g_value_set_boxed (value, &center);
4427       }
4428       break;
4429
4430     case PROP_ROTATION_CENTER_Z_GRAVITY:
4431       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4432       break;
4433
4434     case PROP_ANCHOR_X:
4435       {
4436         const ClutterTransformInfo *info;
4437         gfloat anchor_x;
4438
4439         info = _clutter_actor_get_transform_info_or_defaults (actor);
4440         clutter_anchor_coord_get_units (actor, &info->anchor,
4441                                         &anchor_x,
4442                                         NULL,
4443                                         NULL);
4444         g_value_set_float (value, anchor_x);
4445       }
4446       break;
4447
4448     case PROP_ANCHOR_Y:
4449       {
4450         const ClutterTransformInfo *info;
4451         gfloat anchor_y;
4452
4453         info = _clutter_actor_get_transform_info_or_defaults (actor);
4454         clutter_anchor_coord_get_units (actor, &info->anchor,
4455                                         NULL,
4456                                         &anchor_y,
4457                                         NULL);
4458         g_value_set_float (value, anchor_y);
4459       }
4460       break;
4461
4462     case PROP_ANCHOR_GRAVITY:
4463       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4464       break;
4465
4466     case PROP_SHOW_ON_SET_PARENT:
4467       g_value_set_boolean (value, priv->show_on_set_parent);
4468       break;
4469
4470     case PROP_TEXT_DIRECTION:
4471       g_value_set_enum (value, priv->text_direction);
4472       break;
4473
4474     case PROP_HAS_POINTER:
4475       g_value_set_boolean (value, priv->has_pointer);
4476       break;
4477
4478     case PROP_LAYOUT_MANAGER:
4479       g_value_set_object (value, priv->layout_manager);
4480       break;
4481
4482     case PROP_X_ALIGN:
4483       {
4484         const ClutterLayoutInfo *info;
4485
4486         info = _clutter_actor_get_layout_info_or_defaults (actor);
4487         g_value_set_enum (value, info->x_align);
4488       }
4489       break;
4490
4491     case PROP_Y_ALIGN:
4492       {
4493         const ClutterLayoutInfo *info;
4494
4495         info = _clutter_actor_get_layout_info_or_defaults (actor);
4496         g_value_set_enum (value, info->y_align);
4497       }
4498       break;
4499
4500     case PROP_MARGIN_TOP:
4501       {
4502         const ClutterLayoutInfo *info;
4503
4504         info = _clutter_actor_get_layout_info_or_defaults (actor);
4505         g_value_set_float (value, info->margin.top);
4506       }
4507       break;
4508
4509     case PROP_MARGIN_BOTTOM:
4510       {
4511         const ClutterLayoutInfo *info;
4512
4513         info = _clutter_actor_get_layout_info_or_defaults (actor);
4514         g_value_set_float (value, info->margin.bottom);
4515       }
4516       break;
4517
4518     case PROP_MARGIN_LEFT:
4519       {
4520         const ClutterLayoutInfo *info;
4521
4522         info = _clutter_actor_get_layout_info_or_defaults (actor);
4523         g_value_set_float (value, info->margin.left);
4524       }
4525       break;
4526
4527     case PROP_MARGIN_RIGHT:
4528       {
4529         const ClutterLayoutInfo *info;
4530
4531         info = _clutter_actor_get_layout_info_or_defaults (actor);
4532         g_value_set_float (value, info->margin.right);
4533       }
4534       break;
4535
4536     case PROP_BACKGROUND_COLOR_SET:
4537       g_value_set_boolean (value, priv->bg_color_set);
4538       break;
4539
4540     case PROP_BACKGROUND_COLOR:
4541       g_value_set_boxed (value, &priv->bg_color);
4542       break;
4543
4544     case PROP_FIRST_CHILD:
4545       g_value_set_object (value, priv->first_child);
4546       break;
4547
4548     case PROP_LAST_CHILD:
4549       g_value_set_object (value, priv->last_child);
4550       break;
4551
4552     default:
4553       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4554       break;
4555     }
4556 }
4557
4558 static void
4559 clutter_actor_dispose (GObject *object)
4560 {
4561   ClutterActor *self = CLUTTER_ACTOR (object);
4562   ClutterActorPrivate *priv = self->priv;
4563
4564   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4565                 priv->id,
4566                 g_type_name (G_OBJECT_TYPE (self)),
4567                 object->ref_count);
4568
4569   g_signal_emit (self, actor_signals[DESTROY], 0);
4570
4571   /* avoid recursing when called from clutter_actor_destroy() */
4572   if (priv->parent != NULL)
4573     {
4574       ClutterActor *parent = priv->parent;
4575
4576       /* go through the Container implementation unless this
4577        * is an internal child and has been marked as such.
4578        *
4579        * removing the actor from its parent will reset the
4580        * realized and mapped states.
4581        */
4582       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4583         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4584       else
4585         clutter_actor_remove_child_internal (parent, self,
4586                                              REMOVE_CHILD_LEGACY_FLAGS);
4587     }
4588
4589   /* parent must be gone at this point */
4590   g_assert (priv->parent == NULL);
4591
4592   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4593     {
4594       /* can't be mapped or realized with no parent */
4595       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4596       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4597     }
4598
4599   g_clear_object (&priv->pango_context);
4600   g_clear_object (&priv->actions);
4601   g_clear_object (&priv->constraints);
4602   g_clear_object (&priv->effects);
4603   g_clear_object (&priv->flatten_effect);
4604
4605   if (priv->layout_manager != NULL)
4606     {
4607       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4608       g_object_unref (priv->layout_manager);
4609       priv->layout_manager = NULL;
4610     }
4611
4612   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4613 }
4614
4615 static void
4616 clutter_actor_finalize (GObject *object)
4617 {
4618   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4619
4620   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4621                 priv->name != NULL ? priv->name : "<none>",
4622                 priv->id,
4623                 g_type_name (G_OBJECT_TYPE (object)));
4624
4625   _clutter_context_release_id (priv->id);
4626
4627   g_free (priv->name);
4628
4629   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4630 }
4631
4632
4633 /**
4634  * clutter_actor_get_accessible:
4635  * @self: a #ClutterActor
4636  *
4637  * Returns the accessible object that describes the actor to an
4638  * assistive technology.
4639  *
4640  * If no class-specific #AtkObject implementation is available for the
4641  * actor instance in question, it will inherit an #AtkObject
4642  * implementation from the first ancestor class for which such an
4643  * implementation is defined.
4644  *
4645  * The documentation of the <ulink
4646  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4647  * library contains more information about accessible objects and
4648  * their uses.
4649  *
4650  * Returns: (transfer none): the #AtkObject associated with @actor
4651  */
4652 AtkObject *
4653 clutter_actor_get_accessible (ClutterActor *self)
4654 {
4655   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4656
4657   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4658 }
4659
4660 static AtkObject *
4661 clutter_actor_real_get_accessible (ClutterActor *actor)
4662 {
4663   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4664 }
4665
4666 static AtkObject *
4667 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4668 {
4669   AtkObject *accessible;
4670
4671   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4672   if (accessible != NULL)
4673     g_object_ref (accessible);
4674
4675   return accessible;
4676 }
4677
4678 static void
4679 atk_implementor_iface_init (AtkImplementorIface *iface)
4680 {
4681   iface->ref_accessible = _clutter_actor_ref_accessible;
4682 }
4683
4684 static gboolean
4685 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4686                                      ClutterPaintVolume *volume)
4687 {
4688   ClutterActorPrivate *priv = self->priv;
4689   ClutterActor *child;
4690   ClutterActorClass *klass;
4691   gboolean res;
4692
4693   klass = CLUTTER_ACTOR_GET_CLASS (self);
4694
4695   /* XXX - this thoroughly sucks, but we don't want to penalize users
4696    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4697    * redraw. This should go away in 2.0.
4698    */
4699   if (klass->paint == clutter_actor_real_paint &&
4700       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4701     {
4702       res = TRUE;
4703     }
4704   else
4705     {
4706       /* this is the default return value: we cannot know if a class
4707        * is going to paint outside its allocation, so we take the
4708        * conservative approach.
4709        */
4710       res = FALSE;
4711     }
4712
4713   /* we start from the allocation */
4714   clutter_paint_volume_set_width (volume,
4715                                   priv->allocation.x2 - priv->allocation.x1);
4716   clutter_paint_volume_set_height (volume,
4717                                    priv->allocation.y2 - priv->allocation.y1);
4718
4719   /* if the actor has a clip set then we have a pretty definite
4720    * size for the paint volume: the actor cannot possibly paint
4721    * outside the clip region.
4722    */
4723   if (priv->clip_to_allocation)
4724     {
4725       /* the allocation has already been set, so we just flip the
4726        * return value
4727        */
4728       res = TRUE;
4729     }
4730   else
4731     {
4732       if (priv->has_clip &&
4733           priv->clip.width >= 0 &&
4734           priv->clip.height >= 0)
4735         {
4736           ClutterVertex origin;
4737
4738           origin.x = priv->clip.x;
4739           origin.y = priv->clip.y;
4740           origin.z = 0;
4741
4742           clutter_paint_volume_set_origin (volume, &origin);
4743           clutter_paint_volume_set_width (volume, priv->clip.width);
4744           clutter_paint_volume_set_height (volume, priv->clip.height);
4745
4746           res = TRUE;
4747         }
4748
4749       /* if we don't have children we just bail out here... */
4750       if (priv->n_children == 0)
4751         return res;
4752
4753       /* ...but if we have children then we ask for their paint volume in
4754        * our coordinates. if any of our children replies that it doesn't
4755        * have a paint volume, we bail out
4756        */
4757       for (child = priv->first_child;
4758            child != NULL;
4759            child = child->priv->next_sibling)
4760         {
4761           const ClutterPaintVolume *child_volume;
4762
4763           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4764           if (child_volume == NULL)
4765             {
4766               res = FALSE;
4767               break;
4768             }
4769
4770           clutter_paint_volume_union (volume, child_volume);
4771           res = TRUE;
4772         }
4773     }
4774
4775   return res;
4776 }
4777
4778 static gboolean
4779 clutter_actor_real_has_overlaps (ClutterActor *self)
4780 {
4781   /* By default we'll assume that all actors need an offscreen redirect to get
4782    * the correct opacity. Actors such as ClutterTexture that would never need
4783    * an offscreen redirect can override this to return FALSE. */
4784   return TRUE;
4785 }
4786
4787 static void
4788 clutter_actor_real_destroy (ClutterActor *actor)
4789 {
4790   ClutterActorIter iter;
4791
4792   clutter_actor_iter_init (&iter, actor);
4793   while (clutter_actor_iter_next (&iter, NULL))
4794     clutter_actor_iter_destroy (&iter);
4795 }
4796
4797 static GObject *
4798 clutter_actor_constructor (GType gtype,
4799                            guint n_props,
4800                            GObjectConstructParam *props)
4801 {
4802   GObjectClass *gobject_class;
4803   ClutterActor *self;
4804   GObject *retval;
4805
4806   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4807   retval = gobject_class->constructor (gtype, n_props, props);
4808   self = CLUTTER_ACTOR (retval);
4809
4810   if (self->priv->layout_manager == NULL)
4811     {
4812       ClutterLayoutManager *default_layout;
4813
4814       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4815
4816       default_layout = clutter_fixed_layout_new ();
4817       clutter_actor_set_layout_manager (self, default_layout);
4818     }
4819
4820   return retval;
4821 }
4822
4823 static void
4824 clutter_actor_class_init (ClutterActorClass *klass)
4825 {
4826   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4827
4828   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4829   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4830   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4831
4832   object_class->constructor = clutter_actor_constructor;
4833   object_class->set_property = clutter_actor_set_property;
4834   object_class->get_property = clutter_actor_get_property;
4835   object_class->dispose = clutter_actor_dispose;
4836   object_class->finalize = clutter_actor_finalize;
4837
4838   klass->show = clutter_actor_real_show;
4839   klass->show_all = clutter_actor_show;
4840   klass->hide = clutter_actor_real_hide;
4841   klass->hide_all = clutter_actor_hide;
4842   klass->map = clutter_actor_real_map;
4843   klass->unmap = clutter_actor_real_unmap;
4844   klass->unrealize = clutter_actor_real_unrealize;
4845   klass->pick = clutter_actor_real_pick;
4846   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4847   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4848   klass->allocate = clutter_actor_real_allocate;
4849   klass->queue_redraw = clutter_actor_real_queue_redraw;
4850   klass->queue_relayout = clutter_actor_real_queue_relayout;
4851   klass->apply_transform = clutter_actor_real_apply_transform;
4852   klass->get_accessible = clutter_actor_real_get_accessible;
4853   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4854   klass->has_overlaps = clutter_actor_real_has_overlaps;
4855   klass->paint = clutter_actor_real_paint;
4856   klass->destroy = clutter_actor_real_destroy;
4857
4858   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4859
4860   /**
4861    * ClutterActor:x:
4862    *
4863    * X coordinate of the actor in pixels. If written, forces a fixed
4864    * position for the actor. If read, returns the fixed position if any,
4865    * otherwise the allocation if available, otherwise 0.
4866    */
4867   obj_props[PROP_X] =
4868     g_param_spec_float ("x",
4869                         P_("X coordinate"),
4870                         P_("X coordinate of the actor"),
4871                         -G_MAXFLOAT, G_MAXFLOAT,
4872                         0.0,
4873                         CLUTTER_PARAM_READWRITE);
4874
4875   /**
4876    * ClutterActor:y:
4877    *
4878    * Y coordinate of the actor in pixels. If written, forces a fixed
4879    * position for the actor.  If read, returns the fixed position if
4880    * any, otherwise the allocation if available, otherwise 0.
4881    */
4882   obj_props[PROP_Y] =
4883     g_param_spec_float ("y",
4884                         P_("Y coordinate"),
4885                         P_("Y coordinate of the actor"),
4886                         -G_MAXFLOAT, G_MAXFLOAT,
4887                         0.0,
4888                         CLUTTER_PARAM_READWRITE);
4889
4890   /**
4891    * ClutterActor:width:
4892    *
4893    * Width of the actor (in pixels). If written, forces the minimum and
4894    * natural size request of the actor to the given width. If read, returns
4895    * the allocated width if available, otherwise the width request.
4896    */
4897   obj_props[PROP_WIDTH] =
4898     g_param_spec_float ("width",
4899                         P_("Width"),
4900                         P_("Width of the actor"),
4901                         0.0, G_MAXFLOAT,
4902                         0.0,
4903                         CLUTTER_PARAM_READWRITE);
4904
4905   /**
4906    * ClutterActor:height:
4907    *
4908    * Height of the actor (in pixels).  If written, forces the minimum and
4909    * natural size request of the actor to the given height. If read, returns
4910    * the allocated height if available, otherwise the height request.
4911    */
4912   obj_props[PROP_HEIGHT] =
4913     g_param_spec_float ("height",
4914                         P_("Height"),
4915                         P_("Height of the actor"),
4916                         0.0, G_MAXFLOAT,
4917                         0.0,
4918                         CLUTTER_PARAM_READWRITE);
4919
4920   /**
4921    * ClutterActor:fixed-x:
4922    *
4923    * The fixed X position of the actor in pixels.
4924    *
4925    * Writing this property sets #ClutterActor:fixed-position-set
4926    * property as well, as a side effect
4927    *
4928    * Since: 0.8
4929    */
4930   obj_props[PROP_FIXED_X] =
4931     g_param_spec_float ("fixed-x",
4932                         P_("Fixed X"),
4933                         P_("Forced X position of the actor"),
4934                         -G_MAXFLOAT, G_MAXFLOAT,
4935                         0.0,
4936                         CLUTTER_PARAM_READWRITE);
4937
4938   /**
4939    * ClutterActor:fixed-y:
4940    *
4941    * The fixed Y position of the actor in pixels.
4942    *
4943    * Writing this property sets the #ClutterActor:fixed-position-set
4944    * property as well, as a side effect
4945    *
4946    * Since: 0.8
4947    */
4948   obj_props[PROP_FIXED_Y] =
4949     g_param_spec_float ("fixed-y",
4950                         P_("Fixed Y"),
4951                         P_("Forced Y position of the actor"),
4952                         -G_MAXFLOAT, G_MAXFLOAT,
4953                         0,
4954                         CLUTTER_PARAM_READWRITE);
4955
4956   /**
4957    * ClutterActor:fixed-position-set:
4958    *
4959    * This flag controls whether the #ClutterActor:fixed-x and
4960    * #ClutterActor:fixed-y properties are used
4961    *
4962    * Since: 0.8
4963    */
4964   obj_props[PROP_FIXED_POSITION_SET] =
4965     g_param_spec_boolean ("fixed-position-set",
4966                           P_("Fixed position set"),
4967                           P_("Whether to use fixed positioning for the actor"),
4968                           FALSE,
4969                           CLUTTER_PARAM_READWRITE);
4970
4971   /**
4972    * ClutterActor:min-width:
4973    *
4974    * A forced minimum width request for the actor, in pixels
4975    *
4976    * Writing this property sets the #ClutterActor:min-width-set property
4977    * as well, as a side effect.
4978    *
4979    *This property overrides the usual width request of the actor.
4980    *
4981    * Since: 0.8
4982    */
4983   obj_props[PROP_MIN_WIDTH] =
4984     g_param_spec_float ("min-width",
4985                         P_("Min Width"),
4986                         P_("Forced minimum width request for the actor"),
4987                         0.0, G_MAXFLOAT,
4988                         0.0,
4989                         CLUTTER_PARAM_READWRITE);
4990
4991   /**
4992    * ClutterActor:min-height:
4993    *
4994    * A forced minimum height request for the actor, in pixels
4995    *
4996    * Writing this property sets the #ClutterActor:min-height-set property
4997    * as well, as a side effect. This property overrides the usual height
4998    * request of the actor.
4999    *
5000    * Since: 0.8
5001    */
5002   obj_props[PROP_MIN_HEIGHT] =
5003     g_param_spec_float ("min-height",
5004                         P_("Min Height"),
5005                         P_("Forced minimum height request for the actor"),
5006                         0.0, G_MAXFLOAT,
5007                         0.0,
5008                         CLUTTER_PARAM_READWRITE);
5009
5010   /**
5011    * ClutterActor:natural-width:
5012    *
5013    * A forced natural width request for the actor, in pixels
5014    *
5015    * Writing this property sets the #ClutterActor:natural-width-set
5016    * property as well, as a side effect. This property overrides the
5017    * usual width request of the actor
5018    *
5019    * Since: 0.8
5020    */
5021   obj_props[PROP_NATURAL_WIDTH] =
5022     g_param_spec_float ("natural-width",
5023                         P_("Natural Width"),
5024                         P_("Forced natural width request for the actor"),
5025                         0.0, G_MAXFLOAT,
5026                         0.0,
5027                         CLUTTER_PARAM_READWRITE);
5028
5029   /**
5030    * ClutterActor:natural-height:
5031    *
5032    * A forced natural height request for the actor, in pixels
5033    *
5034    * Writing this property sets the #ClutterActor:natural-height-set
5035    * property as well, as a side effect. This property overrides the
5036    * usual height request of the actor
5037    *
5038    * Since: 0.8
5039    */
5040   obj_props[PROP_NATURAL_HEIGHT] =
5041     g_param_spec_float ("natural-height",
5042                         P_("Natural Height"),
5043                         P_("Forced natural height request for the actor"),
5044                         0.0, G_MAXFLOAT,
5045                         0.0,
5046                         CLUTTER_PARAM_READWRITE);
5047
5048   /**
5049    * ClutterActor:min-width-set:
5050    *
5051    * This flag controls whether the #ClutterActor:min-width property
5052    * is used
5053    *
5054    * Since: 0.8
5055    */
5056   obj_props[PROP_MIN_WIDTH_SET] =
5057     g_param_spec_boolean ("min-width-set",
5058                           P_("Minimum width set"),
5059                           P_("Whether to use the min-width property"),
5060                           FALSE,
5061                           CLUTTER_PARAM_READWRITE);
5062
5063   /**
5064    * ClutterActor:min-height-set:
5065    *
5066    * This flag controls whether the #ClutterActor:min-height property
5067    * is used
5068    *
5069    * Since: 0.8
5070    */
5071   obj_props[PROP_MIN_HEIGHT_SET] =
5072     g_param_spec_boolean ("min-height-set",
5073                           P_("Minimum height set"),
5074                           P_("Whether to use the min-height property"),
5075                           FALSE,
5076                           CLUTTER_PARAM_READWRITE);
5077
5078   /**
5079    * ClutterActor:natural-width-set:
5080    *
5081    * This flag controls whether the #ClutterActor:natural-width property
5082    * is used
5083    *
5084    * Since: 0.8
5085    */
5086   obj_props[PROP_NATURAL_WIDTH_SET] =
5087     g_param_spec_boolean ("natural-width-set",
5088                           P_("Natural width set"),
5089                           P_("Whether to use the natural-width property"),
5090                           FALSE,
5091                           CLUTTER_PARAM_READWRITE);
5092
5093   /**
5094    * ClutterActor:natural-height-set:
5095    *
5096    * This flag controls whether the #ClutterActor:natural-height property
5097    * is used
5098    *
5099    * Since: 0.8
5100    */
5101   obj_props[PROP_NATURAL_HEIGHT_SET] =
5102     g_param_spec_boolean ("natural-height-set",
5103                           P_("Natural height set"),
5104                           P_("Whether to use the natural-height property"),
5105                           FALSE,
5106                           CLUTTER_PARAM_READWRITE);
5107
5108   /**
5109    * ClutterActor:allocation:
5110    *
5111    * The allocation for the actor, in pixels
5112    *
5113    * This is property is read-only, but you might monitor it to know when an
5114    * actor moves or resizes
5115    *
5116    * Since: 0.8
5117    */
5118   obj_props[PROP_ALLOCATION] =
5119     g_param_spec_boxed ("allocation",
5120                         P_("Allocation"),
5121                         P_("The actor's allocation"),
5122                         CLUTTER_TYPE_ACTOR_BOX,
5123                         CLUTTER_PARAM_READABLE);
5124
5125   /**
5126    * ClutterActor:request-mode:
5127    *
5128    * Request mode for the #ClutterActor. The request mode determines the
5129    * type of geometry management used by the actor, either height for width
5130    * (the default) or width for height.
5131    *
5132    * For actors implementing height for width, the parent container should get
5133    * the preferred width first, and then the preferred height for that width.
5134    *
5135    * For actors implementing width for height, the parent container should get
5136    * the preferred height first, and then the preferred width for that height.
5137    *
5138    * For instance:
5139    *
5140    * |[
5141    *   ClutterRequestMode mode;
5142    *   gfloat natural_width, min_width;
5143    *   gfloat natural_height, min_height;
5144    *
5145    *   mode = clutter_actor_get_request_mode (child);
5146    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5147    *     {
5148    *       clutter_actor_get_preferred_width (child, -1,
5149    *                                          &amp;min_width,
5150    *                                          &amp;natural_width);
5151    *       clutter_actor_get_preferred_height (child, natural_width,
5152    *                                           &amp;min_height,
5153    *                                           &amp;natural_height);
5154    *     }
5155    *   else
5156    *     {
5157    *       clutter_actor_get_preferred_height (child, -1,
5158    *                                           &amp;min_height,
5159    *                                           &amp;natural_height);
5160    *       clutter_actor_get_preferred_width (child, natural_height,
5161    *                                          &amp;min_width,
5162    *                                          &amp;natural_width);
5163    *     }
5164    * ]|
5165    *
5166    * will retrieve the minimum and natural width and height depending on the
5167    * preferred request mode of the #ClutterActor "child".
5168    *
5169    * The clutter_actor_get_preferred_size() function will implement this
5170    * check for you.
5171    *
5172    * Since: 0.8
5173    */
5174   obj_props[PROP_REQUEST_MODE] =
5175     g_param_spec_enum ("request-mode",
5176                        P_("Request Mode"),
5177                        P_("The actor's request mode"),
5178                        CLUTTER_TYPE_REQUEST_MODE,
5179                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5180                        CLUTTER_PARAM_READWRITE);
5181
5182   /**
5183    * ClutterActor:depth:
5184    *
5185    * The position of the actor on the Z axis
5186    *
5187    * Since: 0.6
5188    */
5189   obj_props[PROP_DEPTH] =
5190     g_param_spec_float ("depth",
5191                         P_("Depth"),
5192                         P_("Position on the Z axis"),
5193                         -G_MAXFLOAT, G_MAXFLOAT,
5194                         0.0,
5195                         CLUTTER_PARAM_READWRITE);
5196
5197   /**
5198    * ClutterActor:opacity:
5199    *
5200    * Opacity of an actor, between 0 (fully transparent) and
5201    * 255 (fully opaque)
5202    */
5203   obj_props[PROP_OPACITY] =
5204     g_param_spec_uint ("opacity",
5205                        P_("Opacity"),
5206                        P_("Opacity of an actor"),
5207                        0, 255,
5208                        255,
5209                        CLUTTER_PARAM_READWRITE);
5210
5211   /**
5212    * ClutterActor:offscreen-redirect:
5213    *
5214    * Determines the conditions in which the actor will be redirected
5215    * to an offscreen framebuffer while being painted. For example this
5216    * can be used to cache an actor in a framebuffer or for improved
5217    * handling of transparent actors. See
5218    * clutter_actor_set_offscreen_redirect() for details.
5219    *
5220    * Since: 1.8
5221    */
5222   obj_props[PROP_OFFSCREEN_REDIRECT] =
5223     g_param_spec_flags ("offscreen-redirect",
5224                         P_("Offscreen redirect"),
5225                         P_("Flags controlling when to flatten the actor into a single image"),
5226                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5227                         0,
5228                         CLUTTER_PARAM_READWRITE);
5229
5230   /**
5231    * ClutterActor:visible:
5232    *
5233    * Whether the actor is set to be visible or not
5234    *
5235    * See also #ClutterActor:mapped
5236    */
5237   obj_props[PROP_VISIBLE] =
5238     g_param_spec_boolean ("visible",
5239                           P_("Visible"),
5240                           P_("Whether the actor is visible or not"),
5241                           FALSE,
5242                           CLUTTER_PARAM_READWRITE);
5243
5244   /**
5245    * ClutterActor:mapped:
5246    *
5247    * Whether the actor is mapped (will be painted when the stage
5248    * to which it belongs is mapped)
5249    *
5250    * Since: 1.0
5251    */
5252   obj_props[PROP_MAPPED] =
5253     g_param_spec_boolean ("mapped",
5254                           P_("Mapped"),
5255                           P_("Whether the actor will be painted"),
5256                           FALSE,
5257                           CLUTTER_PARAM_READABLE);
5258
5259   /**
5260    * ClutterActor:realized:
5261    *
5262    * Whether the actor has been realized
5263    *
5264    * Since: 1.0
5265    */
5266   obj_props[PROP_REALIZED] =
5267     g_param_spec_boolean ("realized",
5268                           P_("Realized"),
5269                           P_("Whether the actor has been realized"),
5270                           FALSE,
5271                           CLUTTER_PARAM_READABLE);
5272
5273   /**
5274    * ClutterActor:reactive:
5275    *
5276    * Whether the actor is reactive to events or not
5277    *
5278    * Only reactive actors will emit event-related signals
5279    *
5280    * Since: 0.6
5281    */
5282   obj_props[PROP_REACTIVE] =
5283     g_param_spec_boolean ("reactive",
5284                           P_("Reactive"),
5285                           P_("Whether the actor is reactive to events"),
5286                           FALSE,
5287                           CLUTTER_PARAM_READWRITE);
5288
5289   /**
5290    * ClutterActor:has-clip:
5291    *
5292    * Whether the actor has the #ClutterActor:clip property set or not
5293    */
5294   obj_props[PROP_HAS_CLIP] =
5295     g_param_spec_boolean ("has-clip",
5296                           P_("Has Clip"),
5297                           P_("Whether the actor has a clip set"),
5298                           FALSE,
5299                           CLUTTER_PARAM_READABLE);
5300
5301   /**
5302    * ClutterActor:clip:
5303    *
5304    * The clip region for the actor, in actor-relative coordinates
5305    *
5306    * Every part of the actor outside the clip region will not be
5307    * painted
5308    */
5309   obj_props[PROP_CLIP] =
5310     g_param_spec_boxed ("clip",
5311                         P_("Clip"),
5312                         P_("The clip region for the actor"),
5313                         CLUTTER_TYPE_GEOMETRY,
5314                         CLUTTER_PARAM_READWRITE);
5315
5316   /**
5317    * ClutterActor:name:
5318    *
5319    * The name of the actor
5320    *
5321    * Since: 0.2
5322    */
5323   obj_props[PROP_NAME] =
5324     g_param_spec_string ("name",
5325                          P_("Name"),
5326                          P_("Name of the actor"),
5327                          NULL,
5328                          CLUTTER_PARAM_READWRITE);
5329
5330   /**
5331    * ClutterActor:scale-x:
5332    *
5333    * The horizontal scale of the actor
5334    *
5335    * Since: 0.6
5336    */
5337   obj_props[PROP_SCALE_X] =
5338     g_param_spec_double ("scale-x",
5339                          P_("Scale X"),
5340                          P_("Scale factor on the X axis"),
5341                          0.0, G_MAXDOUBLE,
5342                          1.0,
5343                          CLUTTER_PARAM_READWRITE);
5344
5345   /**
5346    * ClutterActor:scale-y:
5347    *
5348    * The vertical scale of the actor
5349    *
5350    * Since: 0.6
5351    */
5352   obj_props[PROP_SCALE_Y] =
5353     g_param_spec_double ("scale-y",
5354                          P_("Scale Y"),
5355                          P_("Scale factor on the Y axis"),
5356                          0.0, G_MAXDOUBLE,
5357                          1.0,
5358                          CLUTTER_PARAM_READWRITE);
5359
5360   /**
5361    * ClutterActor:scale-center-x:
5362    *
5363    * The horizontal center point for scaling
5364    *
5365    * Since: 1.0
5366    */
5367   obj_props[PROP_SCALE_CENTER_X] =
5368     g_param_spec_float ("scale-center-x",
5369                         P_("Scale Center X"),
5370                         P_("Horizontal scale center"),
5371                         -G_MAXFLOAT, G_MAXFLOAT,
5372                         0.0,
5373                         CLUTTER_PARAM_READWRITE);
5374
5375   /**
5376    * ClutterActor:scale-center-y:
5377    *
5378    * The vertical center point for scaling
5379    *
5380    * Since: 1.0
5381    */
5382   obj_props[PROP_SCALE_CENTER_Y] =
5383     g_param_spec_float ("scale-center-y",
5384                         P_("Scale Center Y"),
5385                         P_("Vertical scale center"),
5386                         -G_MAXFLOAT, G_MAXFLOAT,
5387                         0.0,
5388                         CLUTTER_PARAM_READWRITE);
5389
5390   /**
5391    * ClutterActor:scale-gravity:
5392    *
5393    * The center point for scaling expressed as a #ClutterGravity
5394    *
5395    * Since: 1.0
5396    */
5397   obj_props[PROP_SCALE_GRAVITY] =
5398     g_param_spec_enum ("scale-gravity",
5399                        P_("Scale Gravity"),
5400                        P_("The center of scaling"),
5401                        CLUTTER_TYPE_GRAVITY,
5402                        CLUTTER_GRAVITY_NONE,
5403                        CLUTTER_PARAM_READWRITE);
5404
5405   /**
5406    * ClutterActor:rotation-angle-x:
5407    *
5408    * The rotation angle on the X axis
5409    *
5410    * Since: 0.6
5411    */
5412   obj_props[PROP_ROTATION_ANGLE_X] =
5413     g_param_spec_double ("rotation-angle-x",
5414                          P_("Rotation Angle X"),
5415                          P_("The rotation angle on the X axis"),
5416                          -G_MAXDOUBLE, G_MAXDOUBLE,
5417                          0.0,
5418                          CLUTTER_PARAM_READWRITE);
5419
5420   /**
5421    * ClutterActor:rotation-angle-y:
5422    *
5423    * The rotation angle on the Y axis
5424    *
5425    * Since: 0.6
5426    */
5427   obj_props[PROP_ROTATION_ANGLE_Y] =
5428     g_param_spec_double ("rotation-angle-y",
5429                          P_("Rotation Angle Y"),
5430                          P_("The rotation angle on the Y axis"),
5431                          -G_MAXDOUBLE, G_MAXDOUBLE,
5432                          0.0,
5433                          CLUTTER_PARAM_READWRITE);
5434
5435   /**
5436    * ClutterActor:rotation-angle-z:
5437    *
5438    * The rotation angle on the Z axis
5439    *
5440    * Since: 0.6
5441    */
5442   obj_props[PROP_ROTATION_ANGLE_Z] =
5443     g_param_spec_double ("rotation-angle-z",
5444                          P_("Rotation Angle Z"),
5445                          P_("The rotation angle on the Z axis"),
5446                          -G_MAXDOUBLE, G_MAXDOUBLE,
5447                          0.0,
5448                          CLUTTER_PARAM_READWRITE);
5449
5450   /**
5451    * ClutterActor:rotation-center-x:
5452    *
5453    * The rotation center on the X axis.
5454    *
5455    * Since: 0.6
5456    */
5457   obj_props[PROP_ROTATION_CENTER_X] =
5458     g_param_spec_boxed ("rotation-center-x",
5459                         P_("Rotation Center X"),
5460                         P_("The rotation center on the X axis"),
5461                         CLUTTER_TYPE_VERTEX,
5462                         CLUTTER_PARAM_READWRITE);
5463
5464   /**
5465    * ClutterActor:rotation-center-y:
5466    *
5467    * The rotation center on the Y axis.
5468    *
5469    * Since: 0.6
5470    */
5471   obj_props[PROP_ROTATION_CENTER_Y] =
5472     g_param_spec_boxed ("rotation-center-y",
5473                         P_("Rotation Center Y"),
5474                         P_("The rotation center on the Y axis"),
5475                         CLUTTER_TYPE_VERTEX,
5476                         CLUTTER_PARAM_READWRITE);
5477
5478   /**
5479    * ClutterActor:rotation-center-z:
5480    *
5481    * The rotation center on the Z axis.
5482    *
5483    * Since: 0.6
5484    */
5485   obj_props[PROP_ROTATION_CENTER_Z] =
5486     g_param_spec_boxed ("rotation-center-z",
5487                         P_("Rotation Center Z"),
5488                         P_("The rotation center on the Z axis"),
5489                         CLUTTER_TYPE_VERTEX,
5490                         CLUTTER_PARAM_READWRITE);
5491
5492   /**
5493    * ClutterActor:rotation-center-z-gravity:
5494    *
5495    * The rotation center on the Z axis expressed as a #ClutterGravity.
5496    *
5497    * Since: 1.0
5498    */
5499   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5500     g_param_spec_enum ("rotation-center-z-gravity",
5501                        P_("Rotation Center Z Gravity"),
5502                        P_("Center point for rotation around the Z axis"),
5503                        CLUTTER_TYPE_GRAVITY,
5504                        CLUTTER_GRAVITY_NONE,
5505                        CLUTTER_PARAM_READWRITE);
5506
5507   /**
5508    * ClutterActor:anchor-x:
5509    *
5510    * The X coordinate of an actor's anchor point, relative to
5511    * the actor coordinate space, in pixels
5512    *
5513    * Since: 0.8
5514    */
5515   obj_props[PROP_ANCHOR_X] =
5516     g_param_spec_float ("anchor-x",
5517                         P_("Anchor X"),
5518                         P_("X coordinate of the anchor point"),
5519                         -G_MAXFLOAT, G_MAXFLOAT,
5520                         0,
5521                         CLUTTER_PARAM_READWRITE);
5522
5523   /**
5524    * ClutterActor:anchor-y:
5525    *
5526    * The Y coordinate of an actor's anchor point, relative to
5527    * the actor coordinate space, in pixels
5528    *
5529    * Since: 0.8
5530    */
5531   obj_props[PROP_ANCHOR_Y] =
5532     g_param_spec_float ("anchor-y",
5533                         P_("Anchor Y"),
5534                         P_("Y coordinate of the anchor point"),
5535                         -G_MAXFLOAT, G_MAXFLOAT,
5536                         0,
5537                         CLUTTER_PARAM_READWRITE);
5538
5539   /**
5540    * ClutterActor:anchor-gravity:
5541    *
5542    * The anchor point expressed as a #ClutterGravity
5543    *
5544    * Since: 1.0
5545    */
5546   obj_props[PROP_ANCHOR_GRAVITY] =
5547     g_param_spec_enum ("anchor-gravity",
5548                        P_("Anchor Gravity"),
5549                        P_("The anchor point as a ClutterGravity"),
5550                        CLUTTER_TYPE_GRAVITY,
5551                        CLUTTER_GRAVITY_NONE,
5552                        CLUTTER_PARAM_READWRITE);
5553
5554   /**
5555    * ClutterActor:show-on-set-parent:
5556    *
5557    * If %TRUE, the actor is automatically shown when parented.
5558    *
5559    * Calling clutter_actor_hide() on an actor which has not been
5560    * parented will set this property to %FALSE as a side effect.
5561    *
5562    * Since: 0.8
5563    */
5564   obj_props[PROP_SHOW_ON_SET_PARENT] =
5565     g_param_spec_boolean ("show-on-set-parent",
5566                           P_("Show on set parent"),
5567                           P_("Whether the actor is shown when parented"),
5568                           TRUE,
5569                           CLUTTER_PARAM_READWRITE);
5570
5571   /**
5572    * ClutterActor:clip-to-allocation:
5573    *
5574    * Whether the clip region should track the allocated area
5575    * of the actor.
5576    *
5577    * This property is ignored if a clip area has been explicitly
5578    * set using clutter_actor_set_clip().
5579    *
5580    * Since: 1.0
5581    */
5582   obj_props[PROP_CLIP_TO_ALLOCATION] =
5583     g_param_spec_boolean ("clip-to-allocation",
5584                           P_("Clip to Allocation"),
5585                           P_("Sets the clip region to track the actor's allocation"),
5586                           FALSE,
5587                           CLUTTER_PARAM_READWRITE);
5588
5589   /**
5590    * ClutterActor:text-direction:
5591    *
5592    * The direction of the text inside a #ClutterActor.
5593    *
5594    * Since: 1.0
5595    */
5596   obj_props[PROP_TEXT_DIRECTION] =
5597     g_param_spec_enum ("text-direction",
5598                        P_("Text Direction"),
5599                        P_("Direction of the text"),
5600                        CLUTTER_TYPE_TEXT_DIRECTION,
5601                        CLUTTER_TEXT_DIRECTION_LTR,
5602                        CLUTTER_PARAM_READWRITE);
5603
5604   /**
5605    * ClutterActor:has-pointer:
5606    *
5607    * Whether the actor contains the pointer of a #ClutterInputDevice
5608    * or not.
5609    *
5610    * Since: 1.2
5611    */
5612   obj_props[PROP_HAS_POINTER] =
5613     g_param_spec_boolean ("has-pointer",
5614                           P_("Has Pointer"),
5615                           P_("Whether the actor contains the pointer of an input device"),
5616                           FALSE,
5617                           CLUTTER_PARAM_READABLE);
5618
5619   /**
5620    * ClutterActor:actions:
5621    *
5622    * Adds a #ClutterAction to the actor
5623    *
5624    * Since: 1.4
5625    */
5626   obj_props[PROP_ACTIONS] =
5627     g_param_spec_object ("actions",
5628                          P_("Actions"),
5629                          P_("Adds an action to the actor"),
5630                          CLUTTER_TYPE_ACTION,
5631                          CLUTTER_PARAM_WRITABLE);
5632
5633   /**
5634    * ClutterActor:constraints:
5635    *
5636    * Adds a #ClutterConstraint to the actor
5637    *
5638    * Since: 1.4
5639    */
5640   obj_props[PROP_CONSTRAINTS] =
5641     g_param_spec_object ("constraints",
5642                          P_("Constraints"),
5643                          P_("Adds a constraint to the actor"),
5644                          CLUTTER_TYPE_CONSTRAINT,
5645                          CLUTTER_PARAM_WRITABLE);
5646
5647   /**
5648    * ClutterActor:effect:
5649    *
5650    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5651    *
5652    * Since: 1.4
5653    */
5654   obj_props[PROP_EFFECT] =
5655     g_param_spec_object ("effect",
5656                          P_("Effect"),
5657                          P_("Add an effect to be applied on the actor"),
5658                          CLUTTER_TYPE_EFFECT,
5659                          CLUTTER_PARAM_WRITABLE);
5660
5661   /**
5662    * ClutterActor:layout-manager:
5663    *
5664    * A delegate object for controlling the layout of the children of
5665    * an actor.
5666    *
5667    * Since: 1.10
5668    */
5669   obj_props[PROP_LAYOUT_MANAGER] =
5670     g_param_spec_object ("layout-manager",
5671                          P_("Layout Manager"),
5672                          P_("The object controlling the layout of an actor's children"),
5673                          CLUTTER_TYPE_LAYOUT_MANAGER,
5674                          CLUTTER_PARAM_READWRITE);
5675
5676
5677   /**
5678    * ClutterActor:x-align:
5679    *
5680    * The alignment of an actor on the X axis, if the actor has been given
5681    * extra space for its allocation.
5682    *
5683    * Since: 1.10
5684    */
5685   obj_props[PROP_X_ALIGN] =
5686     g_param_spec_enum ("x-align",
5687                        P_("X Alignment"),
5688                        P_("The alignment of the actor on the X axis within its allocation"),
5689                        CLUTTER_TYPE_ACTOR_ALIGN,
5690                        CLUTTER_ACTOR_ALIGN_FILL,
5691                        CLUTTER_PARAM_READWRITE);
5692
5693   /**
5694    * ClutterActor:y-align:
5695    *
5696    * The alignment of an actor on the Y axis, if the actor has been given
5697    * extra space for its allocation.
5698    *
5699    * Since: 1.10
5700    */
5701   obj_props[PROP_Y_ALIGN] =
5702     g_param_spec_enum ("y-align",
5703                        P_("Y Alignment"),
5704                        P_("The alignment of the actor on the Y axis within its allocation"),
5705                        CLUTTER_TYPE_ACTOR_ALIGN,
5706                        CLUTTER_ACTOR_ALIGN_FILL,
5707                        CLUTTER_PARAM_READWRITE);
5708
5709   /**
5710    * ClutterActor:margin-top:
5711    *
5712    * The margin (in pixels) from the top of the actor.
5713    *
5714    * This property adds a margin to the actor's preferred size; the margin
5715    * will be automatically taken into account when allocating the actor.
5716    *
5717    * Since: 1.10
5718    */
5719   obj_props[PROP_MARGIN_TOP] =
5720     g_param_spec_float ("margin-top",
5721                         P_("Margin Top"),
5722                         P_("Extra space at the top"),
5723                         0.0, G_MAXFLOAT,
5724                         0.0,
5725                         CLUTTER_PARAM_READWRITE);
5726
5727   /**
5728    * ClutterActor:margin-bottom:
5729    *
5730    * The margin (in pixels) from the bottom of the actor.
5731    *
5732    * This property adds a margin to the actor's preferred size; the margin
5733    * will be automatically taken into account when allocating the actor.
5734    *
5735    * Since: 1.10
5736    */
5737   obj_props[PROP_MARGIN_BOTTOM] =
5738     g_param_spec_float ("margin-bottom",
5739                         P_("Margin Bottom"),
5740                         P_("Extra space at the bottom"),
5741                         0.0, G_MAXFLOAT,
5742                         0.0,
5743                         CLUTTER_PARAM_READWRITE);
5744
5745   /**
5746    * ClutterActor:margin-left:
5747    *
5748    * The margin (in pixels) from the left of the actor.
5749    *
5750    * This property adds a margin to the actor's preferred size; the margin
5751    * will be automatically taken into account when allocating the actor.
5752    *
5753    * Since: 1.10
5754    */
5755   obj_props[PROP_MARGIN_LEFT] =
5756     g_param_spec_float ("margin-left",
5757                         P_("Margin Left"),
5758                         P_("Extra space at the left"),
5759                         0.0, G_MAXFLOAT,
5760                         0.0,
5761                         CLUTTER_PARAM_READWRITE);
5762
5763   /**
5764    * ClutterActor:margin-right:
5765    *
5766    * The margin (in pixels) from the right of the actor.
5767    *
5768    * This property adds a margin to the actor's preferred size; the margin
5769    * will be automatically taken into account when allocating the actor.
5770    *
5771    * Since: 1.10
5772    */
5773   obj_props[PROP_MARGIN_RIGHT] =
5774     g_param_spec_float ("margin-right",
5775                         P_("Margin Right"),
5776                         P_("Extra space at the right"),
5777                         0.0, G_MAXFLOAT,
5778                         0.0,
5779                         CLUTTER_PARAM_READWRITE);
5780
5781   /**
5782    * ClutterActor:background-color-set:
5783    *
5784    * Whether the #ClutterActor:background-color property has been set.
5785    *
5786    * Since: 1.10
5787    */
5788   obj_props[PROP_BACKGROUND_COLOR_SET] =
5789     g_param_spec_boolean ("background-color-set",
5790                           P_("Background Color Set"),
5791                           P_("Whether the background color is set"),
5792                           FALSE,
5793                           CLUTTER_PARAM_READABLE);
5794
5795   /**
5796    * ClutterActor:background-color:
5797    *
5798    * Paints a solid fill of the actor's allocation using the specified
5799    * color.
5800    *
5801    * Since: 1.10
5802    */
5803   obj_props[PROP_BACKGROUND_COLOR] =
5804     clutter_param_spec_color ("background-color",
5805                               P_("Background color"),
5806                               P_("The actor's background color"),
5807                               CLUTTER_COLOR_Transparent,
5808                               CLUTTER_PARAM_READWRITE);
5809
5810   /**
5811    * ClutterActor:first-child:
5812    *
5813    * The actor's first child.
5814    *
5815    * Since: 1.10
5816    */
5817   obj_props[PROP_FIRST_CHILD] =
5818     g_param_spec_object ("first-child",
5819                          P_("First Child"),
5820                          P_("The actor's first child"),
5821                          CLUTTER_TYPE_ACTOR,
5822                          CLUTTER_PARAM_READABLE);
5823
5824   /**
5825    * ClutterActor:last-child:
5826    *
5827    * The actor's last child.
5828    *
5829    * Since: 1.10
5830    */
5831   obj_props[PROP_LAST_CHILD] =
5832     g_param_spec_object ("last-child",
5833                          P_("Last Child"),
5834                          P_("The actor's last child"),
5835                          CLUTTER_TYPE_ACTOR,
5836                          CLUTTER_PARAM_READABLE);
5837
5838   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5839
5840   /**
5841    * ClutterActor::destroy:
5842    * @actor: the #ClutterActor which emitted the signal
5843    *
5844    * The ::destroy signal notifies that all references held on the
5845    * actor which emitted it should be released.
5846    *
5847    * The ::destroy signal should be used by all holders of a reference
5848    * on @actor.
5849    *
5850    * This signal might result in the finalization of the #ClutterActor
5851    * if all references are released.
5852    *
5853    * Composite actors and actors implementing the #ClutterContainer
5854    * interface should override the default implementation of the
5855    * class handler of this signal and call clutter_actor_destroy() on
5856    * their children. When overriding the default class handler, it is
5857    * required to chain up to the parent's implementation.
5858    *
5859    * Since: 0.2
5860    */
5861   actor_signals[DESTROY] =
5862     g_signal_new (I_("destroy"),
5863                   G_TYPE_FROM_CLASS (object_class),
5864                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5865                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5866                   NULL, NULL,
5867                   _clutter_marshal_VOID__VOID,
5868                   G_TYPE_NONE, 0);
5869   /**
5870    * ClutterActor::show:
5871    * @actor: the object which received the signal
5872    *
5873    * The ::show signal is emitted when an actor is visible and
5874    * rendered on the stage.
5875    *
5876    * Since: 0.2
5877    */
5878   actor_signals[SHOW] =
5879     g_signal_new (I_("show"),
5880                   G_TYPE_FROM_CLASS (object_class),
5881                   G_SIGNAL_RUN_FIRST,
5882                   G_STRUCT_OFFSET (ClutterActorClass, show),
5883                   NULL, NULL,
5884                   _clutter_marshal_VOID__VOID,
5885                   G_TYPE_NONE, 0);
5886   /**
5887    * ClutterActor::hide:
5888    * @actor: the object which received the signal
5889    *
5890    * The ::hide signal is emitted when an actor is no longer rendered
5891    * on the stage.
5892    *
5893    * Since: 0.2
5894    */
5895   actor_signals[HIDE] =
5896     g_signal_new (I_("hide"),
5897                   G_TYPE_FROM_CLASS (object_class),
5898                   G_SIGNAL_RUN_FIRST,
5899                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5900                   NULL, NULL,
5901                   _clutter_marshal_VOID__VOID,
5902                   G_TYPE_NONE, 0);
5903   /**
5904    * ClutterActor::parent-set:
5905    * @actor: the object which received the signal
5906    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5907    *
5908    * This signal is emitted when the parent of the actor changes.
5909    *
5910    * Since: 0.2
5911    */
5912   actor_signals[PARENT_SET] =
5913     g_signal_new (I_("parent-set"),
5914                   G_TYPE_FROM_CLASS (object_class),
5915                   G_SIGNAL_RUN_LAST,
5916                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5917                   NULL, NULL,
5918                   _clutter_marshal_VOID__OBJECT,
5919                   G_TYPE_NONE, 1,
5920                   CLUTTER_TYPE_ACTOR);
5921
5922   /**
5923    * ClutterActor::queue-redraw:
5924    * @actor: the actor we're bubbling the redraw request through
5925    * @origin: the actor which initiated the redraw request
5926    *
5927    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5928    * is called on @origin.
5929    *
5930    * The default implementation for #ClutterActor chains up to the
5931    * parent actor and queues a redraw on the parent, thus "bubbling"
5932    * the redraw queue up through the actor graph. The default
5933    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5934    * in a main loop idle handler.
5935    *
5936    * Note that the @origin actor may be the stage, or a container; it
5937    * does not have to be a leaf node in the actor graph.
5938    *
5939    * Toolkits embedding a #ClutterStage which require a redraw and
5940    * relayout cycle can stop the emission of this signal using the
5941    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
5942    * themselves, like:
5943    *
5944    * |[
5945    *   static void
5946    *   on_redraw_complete (gpointer data)
5947    *   {
5948    *     ClutterStage *stage = data;
5949    *
5950    *     /&ast; execute the Clutter drawing pipeline &ast;/
5951    *     clutter_stage_ensure_redraw (stage);
5952    *   }
5953    *
5954    *   static void
5955    *   on_stage_queue_redraw (ClutterStage *stage)
5956    *   {
5957    *     /&ast; this prevents the default handler to run &ast;/
5958    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
5959    *
5960    *     /&ast; queue a redraw with the host toolkit and call
5961    *      &ast; a function when the redraw has been completed
5962    *      &ast;/
5963    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
5964    *   }
5965    * ]|
5966    *
5967    * <note><para>This signal is emitted before the Clutter paint
5968    * pipeline is executed. If you want to know when the pipeline has
5969    * been completed you should connect to the ::paint signal on the
5970    * Stage with g_signal_connect_after().</para></note>
5971    *
5972    * Since: 1.0
5973    */
5974   actor_signals[QUEUE_REDRAW] =
5975     g_signal_new (I_("queue-redraw"),
5976                   G_TYPE_FROM_CLASS (object_class),
5977                   G_SIGNAL_RUN_LAST,
5978                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
5979                   NULL, NULL,
5980                   _clutter_marshal_VOID__OBJECT,
5981                   G_TYPE_NONE, 1,
5982                   CLUTTER_TYPE_ACTOR);
5983
5984   /**
5985    * ClutterActor::queue-relayout
5986    * @actor: the actor being queued for relayout
5987    *
5988    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
5989    * is called on an actor.
5990    *
5991    * The default implementation for #ClutterActor chains up to the
5992    * parent actor and queues a relayout on the parent, thus "bubbling"
5993    * the relayout queue up through the actor graph.
5994    *
5995    * The main purpose of this signal is to allow relayout to be propagated
5996    * properly in the procense of #ClutterClone actors. Applications will
5997    * not normally need to connect to this signal.
5998    *
5999    * Since: 1.2
6000    */
6001   actor_signals[QUEUE_RELAYOUT] =
6002     g_signal_new (I_("queue-relayout"),
6003                   G_TYPE_FROM_CLASS (object_class),
6004                   G_SIGNAL_RUN_LAST,
6005                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6006                   NULL, NULL,
6007                   _clutter_marshal_VOID__VOID,
6008                   G_TYPE_NONE, 0);
6009
6010   /**
6011    * ClutterActor::event:
6012    * @actor: the actor which received the event
6013    * @event: a #ClutterEvent
6014    *
6015    * The ::event signal is emitted each time an event is received
6016    * by the @actor. This signal will be emitted on every actor,
6017    * following the hierarchy chain, until it reaches the top-level
6018    * container (the #ClutterStage).
6019    *
6020    * Return value: %TRUE if the event has been handled by the actor,
6021    *   or %FALSE to continue the emission.
6022    *
6023    * Since: 0.6
6024    */
6025   actor_signals[EVENT] =
6026     g_signal_new (I_("event"),
6027                   G_TYPE_FROM_CLASS (object_class),
6028                   G_SIGNAL_RUN_LAST,
6029                   G_STRUCT_OFFSET (ClutterActorClass, event),
6030                   _clutter_boolean_handled_accumulator, NULL,
6031                   _clutter_marshal_BOOLEAN__BOXED,
6032                   G_TYPE_BOOLEAN, 1,
6033                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6034   /**
6035    * ClutterActor::button-press-event:
6036    * @actor: the actor which received the event
6037    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6038    *
6039    * The ::button-press-event signal is emitted each time a mouse button
6040    * is pressed on @actor.
6041    *
6042    * Return value: %TRUE if the event has been handled by the actor,
6043    *   or %FALSE to continue the emission.
6044    *
6045    * Since: 0.6
6046    */
6047   actor_signals[BUTTON_PRESS_EVENT] =
6048     g_signal_new (I_("button-press-event"),
6049                   G_TYPE_FROM_CLASS (object_class),
6050                   G_SIGNAL_RUN_LAST,
6051                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6052                   _clutter_boolean_handled_accumulator, NULL,
6053                   _clutter_marshal_BOOLEAN__BOXED,
6054                   G_TYPE_BOOLEAN, 1,
6055                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6056   /**
6057    * ClutterActor::button-release-event:
6058    * @actor: the actor which received the event
6059    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6060    *
6061    * The ::button-release-event signal is emitted each time a mouse button
6062    * is released on @actor.
6063    *
6064    * Return value: %TRUE if the event has been handled by the actor,
6065    *   or %FALSE to continue the emission.
6066    *
6067    * Since: 0.6
6068    */
6069   actor_signals[BUTTON_RELEASE_EVENT] =
6070     g_signal_new (I_("button-release-event"),
6071                   G_TYPE_FROM_CLASS (object_class),
6072                   G_SIGNAL_RUN_LAST,
6073                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6074                   _clutter_boolean_handled_accumulator, NULL,
6075                   _clutter_marshal_BOOLEAN__BOXED,
6076                   G_TYPE_BOOLEAN, 1,
6077                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6078   /**
6079    * ClutterActor::scroll-event:
6080    * @actor: the actor which received the event
6081    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6082    *
6083    * The ::scroll-event signal is emitted each time the mouse is
6084    * scrolled on @actor
6085    *
6086    * Return value: %TRUE if the event has been handled by the actor,
6087    *   or %FALSE to continue the emission.
6088    *
6089    * Since: 0.6
6090    */
6091   actor_signals[SCROLL_EVENT] =
6092     g_signal_new (I_("scroll-event"),
6093                   G_TYPE_FROM_CLASS (object_class),
6094                   G_SIGNAL_RUN_LAST,
6095                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6096                   _clutter_boolean_handled_accumulator, NULL,
6097                   _clutter_marshal_BOOLEAN__BOXED,
6098                   G_TYPE_BOOLEAN, 1,
6099                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6100   /**
6101    * ClutterActor::key-press-event:
6102    * @actor: the actor which received the event
6103    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6104    *
6105    * The ::key-press-event signal is emitted each time a keyboard button
6106    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6107    *
6108    * Return value: %TRUE if the event has been handled by the actor,
6109    *   or %FALSE to continue the emission.
6110    *
6111    * Since: 0.6
6112    */
6113   actor_signals[KEY_PRESS_EVENT] =
6114     g_signal_new (I_("key-press-event"),
6115                   G_TYPE_FROM_CLASS (object_class),
6116                   G_SIGNAL_RUN_LAST,
6117                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6118                   _clutter_boolean_handled_accumulator, NULL,
6119                   _clutter_marshal_BOOLEAN__BOXED,
6120                   G_TYPE_BOOLEAN, 1,
6121                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6122   /**
6123    * ClutterActor::key-release-event:
6124    * @actor: the actor which received the event
6125    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6126    *
6127    * The ::key-release-event signal is emitted each time a keyboard button
6128    * is released while @actor has key focus (see
6129    * clutter_stage_set_key_focus()).
6130    *
6131    * Return value: %TRUE if the event has been handled by the actor,
6132    *   or %FALSE to continue the emission.
6133    *
6134    * Since: 0.6
6135    */
6136   actor_signals[KEY_RELEASE_EVENT] =
6137     g_signal_new (I_("key-release-event"),
6138                   G_TYPE_FROM_CLASS (object_class),
6139                   G_SIGNAL_RUN_LAST,
6140                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6141                   _clutter_boolean_handled_accumulator, NULL,
6142                   _clutter_marshal_BOOLEAN__BOXED,
6143                   G_TYPE_BOOLEAN, 1,
6144                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6145   /**
6146    * ClutterActor::motion-event:
6147    * @actor: the actor which received the event
6148    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6149    *
6150    * The ::motion-event signal is emitted each time the mouse pointer is
6151    * moved over @actor.
6152    *
6153    * Return value: %TRUE if the event has been handled by the actor,
6154    *   or %FALSE to continue the emission.
6155    *
6156    * Since: 0.6
6157    */
6158   actor_signals[MOTION_EVENT] =
6159     g_signal_new (I_("motion-event"),
6160                   G_TYPE_FROM_CLASS (object_class),
6161                   G_SIGNAL_RUN_LAST,
6162                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6163                   _clutter_boolean_handled_accumulator, NULL,
6164                   _clutter_marshal_BOOLEAN__BOXED,
6165                   G_TYPE_BOOLEAN, 1,
6166                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6167
6168   /**
6169    * ClutterActor::key-focus-in:
6170    * @actor: the actor which now has key focus
6171    *
6172    * The ::key-focus-in signal is emitted when @actor receives key focus.
6173    *
6174    * Since: 0.6
6175    */
6176   actor_signals[KEY_FOCUS_IN] =
6177     g_signal_new (I_("key-focus-in"),
6178                   G_TYPE_FROM_CLASS (object_class),
6179                   G_SIGNAL_RUN_LAST,
6180                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6181                   NULL, NULL,
6182                   _clutter_marshal_VOID__VOID,
6183                   G_TYPE_NONE, 0);
6184
6185   /**
6186    * ClutterActor::key-focus-out:
6187    * @actor: the actor which now has key focus
6188    *
6189    * The ::key-focus-out signal is emitted when @actor loses key focus.
6190    *
6191    * Since: 0.6
6192    */
6193   actor_signals[KEY_FOCUS_OUT] =
6194     g_signal_new (I_("key-focus-out"),
6195                   G_TYPE_FROM_CLASS (object_class),
6196                   G_SIGNAL_RUN_LAST,
6197                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6198                   NULL, NULL,
6199                   _clutter_marshal_VOID__VOID,
6200                   G_TYPE_NONE, 0);
6201
6202   /**
6203    * ClutterActor::enter-event:
6204    * @actor: the actor which the pointer has entered.
6205    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6206    *
6207    * The ::enter-event signal is emitted when the pointer enters the @actor
6208    *
6209    * Return value: %TRUE if the event has been handled by the actor,
6210    *   or %FALSE to continue the emission.
6211    *
6212    * Since: 0.6
6213    */
6214   actor_signals[ENTER_EVENT] =
6215     g_signal_new (I_("enter-event"),
6216                   G_TYPE_FROM_CLASS (object_class),
6217                   G_SIGNAL_RUN_LAST,
6218                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6219                   _clutter_boolean_handled_accumulator, NULL,
6220                   _clutter_marshal_BOOLEAN__BOXED,
6221                   G_TYPE_BOOLEAN, 1,
6222                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6223
6224   /**
6225    * ClutterActor::leave-event:
6226    * @actor: the actor which the pointer has left
6227    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6228    *
6229    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6230    *
6231    * Return value: %TRUE if the event has been handled by the actor,
6232    *   or %FALSE to continue the emission.
6233    *
6234    * Since: 0.6
6235    */
6236   actor_signals[LEAVE_EVENT] =
6237     g_signal_new (I_("leave-event"),
6238                   G_TYPE_FROM_CLASS (object_class),
6239                   G_SIGNAL_RUN_LAST,
6240                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6241                   _clutter_boolean_handled_accumulator, NULL,
6242                   _clutter_marshal_BOOLEAN__BOXED,
6243                   G_TYPE_BOOLEAN, 1,
6244                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6245
6246   /**
6247    * ClutterActor::captured-event:
6248    * @actor: the actor which received the signal
6249    * @event: a #ClutterEvent
6250    *
6251    * The ::captured-event signal is emitted when an event is captured
6252    * by Clutter. This signal will be emitted starting from the top-level
6253    * container (the #ClutterStage) to the actor which received the event
6254    * going down the hierarchy. This signal can be used to intercept every
6255    * event before the specialized events (like
6256    * ClutterActor::button-press-event or ::key-released-event) are
6257    * emitted.
6258    *
6259    * Return value: %TRUE if the event has been handled by the actor,
6260    *   or %FALSE to continue the emission.
6261    *
6262    * Since: 0.6
6263    */
6264   actor_signals[CAPTURED_EVENT] =
6265     g_signal_new (I_("captured-event"),
6266                   G_TYPE_FROM_CLASS (object_class),
6267                   G_SIGNAL_RUN_LAST,
6268                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6269                   _clutter_boolean_handled_accumulator, NULL,
6270                   _clutter_marshal_BOOLEAN__BOXED,
6271                   G_TYPE_BOOLEAN, 1,
6272                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6273
6274   /**
6275    * ClutterActor::paint:
6276    * @actor: the #ClutterActor that received the signal
6277    *
6278    * The ::paint signal is emitted each time an actor is being painted.
6279    *
6280    * Subclasses of #ClutterActor should override the class signal handler
6281    * and paint themselves in that function.
6282    *
6283    * It is possible to connect a handler to the ::paint signal in order
6284    * to set up some custom aspect of a paint.
6285    *
6286    * Since: 0.8
6287    */
6288   actor_signals[PAINT] =
6289     g_signal_new (I_("paint"),
6290                   G_TYPE_FROM_CLASS (object_class),
6291                   G_SIGNAL_RUN_LAST,
6292                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6293                   NULL, NULL,
6294                   _clutter_marshal_VOID__VOID,
6295                   G_TYPE_NONE, 0);
6296   /**
6297    * ClutterActor::realize:
6298    * @actor: the #ClutterActor that received the signal
6299    *
6300    * The ::realize signal is emitted each time an actor is being
6301    * realized.
6302    *
6303    * Since: 0.8
6304    */
6305   actor_signals[REALIZE] =
6306     g_signal_new (I_("realize"),
6307                   G_TYPE_FROM_CLASS (object_class),
6308                   G_SIGNAL_RUN_LAST,
6309                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6310                   NULL, NULL,
6311                   _clutter_marshal_VOID__VOID,
6312                   G_TYPE_NONE, 0);
6313   /**
6314    * ClutterActor::unrealize:
6315    * @actor: the #ClutterActor that received the signal
6316    *
6317    * The ::unrealize signal is emitted each time an actor is being
6318    * unrealized.
6319    *
6320    * Since: 0.8
6321    */
6322   actor_signals[UNREALIZE] =
6323     g_signal_new (I_("unrealize"),
6324                   G_TYPE_FROM_CLASS (object_class),
6325                   G_SIGNAL_RUN_LAST,
6326                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6327                   NULL, NULL,
6328                   _clutter_marshal_VOID__VOID,
6329                   G_TYPE_NONE, 0);
6330
6331   /**
6332    * ClutterActor::pick:
6333    * @actor: the #ClutterActor that received the signal
6334    * @color: the #ClutterColor to be used when picking
6335    *
6336    * The ::pick signal is emitted each time an actor is being painted
6337    * in "pick mode". The pick mode is used to identify the actor during
6338    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6339    * The actor should paint its shape using the passed @pick_color.
6340    *
6341    * Subclasses of #ClutterActor should override the class signal handler
6342    * and paint themselves in that function.
6343    *
6344    * It is possible to connect a handler to the ::pick signal in order
6345    * to set up some custom aspect of a paint in pick mode.
6346    *
6347    * Since: 1.0
6348    */
6349   actor_signals[PICK] =
6350     g_signal_new (I_("pick"),
6351                   G_TYPE_FROM_CLASS (object_class),
6352                   G_SIGNAL_RUN_LAST,
6353                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6354                   NULL, NULL,
6355                   _clutter_marshal_VOID__BOXED,
6356                   G_TYPE_NONE, 1,
6357                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6358
6359   /**
6360    * ClutterActor::allocation-changed:
6361    * @actor: the #ClutterActor that emitted the signal
6362    * @box: a #ClutterActorBox with the new allocation
6363    * @flags: #ClutterAllocationFlags for the allocation
6364    *
6365    * The ::allocation-changed signal is emitted when the
6366    * #ClutterActor:allocation property changes. Usually, application
6367    * code should just use the notifications for the :allocation property
6368    * but if you want to track the allocation flags as well, for instance
6369    * to know whether the absolute origin of @actor changed, then you might
6370    * want use this signal instead.
6371    *
6372    * Since: 1.0
6373    */
6374   actor_signals[ALLOCATION_CHANGED] =
6375     g_signal_new (I_("allocation-changed"),
6376                   G_TYPE_FROM_CLASS (object_class),
6377                   G_SIGNAL_RUN_LAST,
6378                   0,
6379                   NULL, NULL,
6380                   _clutter_marshal_VOID__BOXED_FLAGS,
6381                   G_TYPE_NONE, 2,
6382                   CLUTTER_TYPE_ACTOR_BOX,
6383                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6384 }
6385
6386 static void
6387 clutter_actor_init (ClutterActor *self)
6388 {
6389   ClutterActorPrivate *priv;
6390
6391   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6392
6393   priv->id = _clutter_context_acquire_id (self);
6394   priv->pick_id = -1;
6395
6396   priv->opacity = 0xff;
6397   priv->show_on_set_parent = TRUE;
6398
6399   priv->needs_width_request = TRUE;
6400   priv->needs_height_request = TRUE;
6401   priv->needs_allocation = TRUE;
6402
6403   priv->cached_width_age = 1;
6404   priv->cached_height_age = 1;
6405
6406   priv->opacity_override = -1;
6407   priv->enable_model_view_transform = TRUE;
6408
6409   /* Initialize an empty paint volume to start with */
6410   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6411   priv->last_paint_volume_valid = TRUE;
6412
6413   priv->transform_valid = FALSE;
6414 }
6415
6416 /**
6417  * clutter_actor_new:
6418  *
6419  * Creates a new #ClutterActor.
6420  *
6421  * A newly created actor has a floating reference, which will be sunk
6422  * when it is added to another actor.
6423  *
6424  * Return value: (transfer full): the newly created #ClutterActor
6425  *
6426  * Since: 1.10
6427  */
6428 ClutterActor *
6429 clutter_actor_new (void)
6430 {
6431   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6432 }
6433
6434 /**
6435  * clutter_actor_destroy:
6436  * @self: a #ClutterActor
6437  *
6438  * Destroys an actor.  When an actor is destroyed, it will break any
6439  * references it holds to other objects.  If the actor is inside a
6440  * container, the actor will be removed.
6441  *
6442  * When you destroy a container, its children will be destroyed as well.
6443  *
6444  * Note: you cannot destroy the #ClutterStage returned by
6445  * clutter_stage_get_default().
6446  */
6447 void
6448 clutter_actor_destroy (ClutterActor *self)
6449 {
6450   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6451
6452   g_object_ref (self);
6453
6454   /* avoid recursion while destroying */
6455   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6456     {
6457       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6458
6459       g_object_run_dispose (G_OBJECT (self));
6460
6461       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6462     }
6463
6464   g_object_unref (self);
6465 }
6466
6467 void
6468 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6469                                     ClutterPaintVolume *clip)
6470 {
6471   ClutterActorPrivate *priv = self->priv;
6472   ClutterPaintVolume *pv;
6473   gboolean clipped;
6474
6475   /* If we've been explicitly passed a clip volume then there's
6476    * nothing more to calculate, but otherwise the only thing we know
6477    * is that the change is constrained to the given actor.
6478    *
6479    * The idea is that if we know the paint volume for where the actor
6480    * was last drawn (in eye coordinates) and we also have the paint
6481    * volume for where it will be drawn next (in actor coordinates)
6482    * then if we queue a redraw for both these volumes that will cover
6483    * everything that needs to be redrawn to clear the old view and
6484    * show the latest view of the actor.
6485    *
6486    * Don't clip this redraw if we don't know what position we had for
6487    * the previous redraw since we don't know where to set the clip so
6488    * it will clear the actor as it is currently.
6489    */
6490   if (clip)
6491     {
6492       _clutter_actor_set_queue_redraw_clip (self, clip);
6493       clipped = TRUE;
6494     }
6495   else if (G_LIKELY (priv->last_paint_volume_valid))
6496     {
6497       pv = _clutter_actor_get_paint_volume_mutable (self);
6498       if (pv)
6499         {
6500           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6501
6502           /* make sure we redraw the actors old position... */
6503           _clutter_actor_set_queue_redraw_clip (stage,
6504                                                 &priv->last_paint_volume);
6505           _clutter_actor_signal_queue_redraw (stage, stage);
6506           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6507
6508           /* XXX: Ideally the redraw signal would take a clip volume
6509            * argument, but that would be an ABI break. Until we can
6510            * break the ABI we pass the argument out-of-band
6511            */
6512
6513           /* setup the clip for the actors new position... */
6514           _clutter_actor_set_queue_redraw_clip (self, pv);
6515           clipped = TRUE;
6516         }
6517       else
6518         clipped = FALSE;
6519     }
6520   else
6521     clipped = FALSE;
6522
6523   _clutter_actor_signal_queue_redraw (self, self);
6524
6525   /* Just in case anyone is manually firing redraw signals without
6526    * using the public queue_redraw() API we are careful to ensure that
6527    * our out-of-band clip member is cleared before returning...
6528    *
6529    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6530    */
6531   if (G_LIKELY (clipped))
6532     _clutter_actor_set_queue_redraw_clip (self, NULL);
6533
6534   priv->queue_redraw_entry = NULL;
6535 }
6536
6537 static void
6538 _clutter_actor_get_allocation_clip (ClutterActor *self,
6539                                     ClutterActorBox *clip)
6540 {
6541   ClutterActorBox allocation;
6542
6543   /* XXX: we don't care if we get an out of date allocation here
6544    * because clutter_actor_queue_redraw_with_clip knows to ignore
6545    * the clip if the actor's allocation is invalid.
6546    *
6547    * This is noted because clutter_actor_get_allocation_box does some
6548    * unnecessary work to support buggy code with a comment suggesting
6549    * that it could be changed later which would be good for this use
6550    * case!
6551    */
6552   clutter_actor_get_allocation_box (self, &allocation);
6553
6554   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6555    * actor's own coordinate space but the allocation is in parent
6556    * coordinates */
6557   clip->x1 = 0;
6558   clip->y1 = 0;
6559   clip->x2 = allocation.x2 - allocation.x1;
6560   clip->y2 = allocation.y2 - allocation.y1;
6561 }
6562
6563 void
6564 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6565                                   ClutterRedrawFlags  flags,
6566                                   ClutterPaintVolume *volume,
6567                                   ClutterEffect      *effect)
6568 {
6569   ClutterActorPrivate *priv = self->priv;
6570   ClutterPaintVolume allocation_pv;
6571   ClutterPaintVolume *pv;
6572   gboolean should_free_pv;
6573   ClutterActor *stage;
6574
6575   /* Here's an outline of the actor queue redraw mechanism:
6576    *
6577    * The process starts in one of the following two functions which
6578    * are wrappers for this function:
6579    * clutter_actor_queue_redraw
6580    * _clutter_actor_queue_redraw_with_clip
6581    *
6582    * additionally, an effect can queue a redraw by wrapping this
6583    * function in clutter_effect_queue_rerun
6584    *
6585    * This functions queues an entry in a list associated with the
6586    * stage which is a list of actors that queued a redraw while
6587    * updating the timelines, performing layouting and processing other
6588    * mainloop sources before the next paint starts.
6589    *
6590    * We aim to minimize the processing done at this point because
6591    * there is a good chance other events will happen while updating
6592    * the scenegraph that would invalidate any expensive work we might
6593    * otherwise try to do here. For example we don't try and resolve
6594    * the screen space bounding box of an actor at this stage so as to
6595    * minimize how much of the screen redraw because it's possible
6596    * something else will happen which will force a full redraw anyway.
6597    *
6598    * When all updates are complete and we come to paint the stage then
6599    * we iterate this list and actually emit the "queue-redraw" signals
6600    * for each of the listed actors which will bubble up to the stage
6601    * for each actor and at that point we will transform the actors
6602    * paint volume into screen coordinates to determine the clip region
6603    * for what needs to be redrawn in the next paint.
6604    *
6605    * Besides minimizing redundant work another reason for this
6606    * deferred design is that it's more likely we will be able to
6607    * determine the paint volume of an actor once we've finished
6608    * updating the scenegraph because its allocation should be up to
6609    * date. NB: If we can't determine an actors paint volume then we
6610    * can't automatically queue a clipped redraw which can make a big
6611    * difference to performance.
6612    *
6613    * So the control flow goes like this:
6614    * One of clutter_actor_queue_redraw,
6615    *        _clutter_actor_queue_redraw_with_clip
6616    *     or clutter_effect_queue_rerun
6617    *
6618    * then control moves to:
6619    *   _clutter_stage_queue_actor_redraw
6620    *
6621    * later during _clutter_stage_do_update, once relayouting is done
6622    * and the scenegraph has been updated we will call:
6623    * _clutter_stage_finish_queue_redraws
6624    *
6625    * _clutter_stage_finish_queue_redraws will call
6626    * _clutter_actor_finish_queue_redraw for each listed actor.
6627    * Note: actors *are* allowed to queue further redraws during this
6628    * process (considering clone actors or texture_new_from_actor which
6629    * respond to their source queueing a redraw by queuing a redraw
6630    * themselves). We repeat the process until the list is empty.
6631    *
6632    * This will result in the "queue-redraw" signal being fired for
6633    * each actor which will pass control to the default signal handler:
6634    * clutter_actor_real_queue_redraw
6635    *
6636    * This will bubble up to the stages handler:
6637    * clutter_stage_real_queue_redraw
6638    *
6639    * clutter_stage_real_queue_redraw will transform the actors paint
6640    * volume into screen space and add it as a clip region for the next
6641    * paint.
6642    */
6643
6644   /* ignore queueing a redraw for actors being destroyed */
6645   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6646     return;
6647
6648   stage = _clutter_actor_get_stage_internal (self);
6649
6650   /* Ignore queueing a redraw for actors not descended from a stage */
6651   if (stage == NULL)
6652     return;
6653
6654   /* ignore queueing a redraw on stages that are being destroyed */
6655   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6656     return;
6657
6658   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6659     {
6660       ClutterActorBox allocation_clip;
6661       ClutterVertex origin;
6662
6663       /* If the actor doesn't have a valid allocation then we will
6664        * queue a full stage redraw. */
6665       if (priv->needs_allocation)
6666         {
6667           /* NB: NULL denotes an undefined clip which will result in a
6668            * full redraw... */
6669           _clutter_actor_set_queue_redraw_clip (self, NULL);
6670           _clutter_actor_signal_queue_redraw (self, self);
6671           return;
6672         }
6673
6674       _clutter_paint_volume_init_static (&allocation_pv, self);
6675       pv = &allocation_pv;
6676
6677       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6678
6679       origin.x = allocation_clip.x1;
6680       origin.y = allocation_clip.y1;
6681       origin.z = 0;
6682       clutter_paint_volume_set_origin (pv, &origin);
6683       clutter_paint_volume_set_width (pv,
6684                                       allocation_clip.x2 - allocation_clip.x1);
6685       clutter_paint_volume_set_height (pv,
6686                                        allocation_clip.y2 -
6687                                        allocation_clip.y1);
6688       should_free_pv = TRUE;
6689     }
6690   else
6691     {
6692       pv = volume;
6693       should_free_pv = FALSE;
6694     }
6695
6696   self->priv->queue_redraw_entry =
6697     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6698                                        priv->queue_redraw_entry,
6699                                        self,
6700                                        pv);
6701
6702   if (should_free_pv)
6703     clutter_paint_volume_free (pv);
6704
6705   /* If this is the first redraw queued then we can directly use the
6706      effect parameter */
6707   if (!priv->is_dirty)
6708     priv->effect_to_redraw = effect;
6709   /* Otherwise we need to merge it with the existing effect parameter */
6710   else if (effect != NULL)
6711     {
6712       /* If there's already an effect then we need to use whichever is
6713          later in the chain of actors. Otherwise a full redraw has
6714          already been queued on the actor so we need to ignore the
6715          effect parameter */
6716       if (priv->effect_to_redraw != NULL)
6717         {
6718           if (priv->effects == NULL)
6719             g_warning ("Redraw queued with an effect that is "
6720                        "not applied to the actor");
6721           else
6722             {
6723               const GList *l;
6724
6725               for (l = _clutter_meta_group_peek_metas (priv->effects);
6726                    l != NULL;
6727                    l = l->next)
6728                 {
6729                   if (l->data == priv->effect_to_redraw ||
6730                       l->data == effect)
6731                     priv->effect_to_redraw = l->data;
6732                 }
6733             }
6734         }
6735     }
6736   else
6737     {
6738       /* If no effect is specified then we need to redraw the whole
6739          actor */
6740       priv->effect_to_redraw = NULL;
6741     }
6742
6743   priv->is_dirty = TRUE;
6744 }
6745
6746 /**
6747  * clutter_actor_queue_redraw:
6748  * @self: A #ClutterActor
6749  *
6750  * Queues up a redraw of an actor and any children. The redraw occurs
6751  * once the main loop becomes idle (after the current batch of events
6752  * has been processed, roughly).
6753  *
6754  * Applications rarely need to call this, as redraws are handled
6755  * automatically by modification functions.
6756  *
6757  * This function will not do anything if @self is not visible, or
6758  * if the actor is inside an invisible part of the scenegraph.
6759  *
6760  * Also be aware that painting is a NOP for actors with an opacity of
6761  * 0
6762  *
6763  * When you are implementing a custom actor you must queue a redraw
6764  * whenever some private state changes that will affect painting or
6765  * picking of your actor.
6766  */
6767 void
6768 clutter_actor_queue_redraw (ClutterActor *self)
6769 {
6770   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6771
6772   _clutter_actor_queue_redraw_full (self,
6773                                     0, /* flags */
6774                                     NULL, /* clip volume */
6775                                     NULL /* effect */);
6776 }
6777
6778 /*< private >
6779  * _clutter_actor_queue_redraw_with_clip:
6780  * @self: A #ClutterActor
6781  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6782  *   this queue redraw.
6783  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6784  *   redrawn or %NULL if you are just using a @flag to state your
6785  *   desired clipping.
6786  *
6787  * Queues up a clipped redraw of an actor and any children. The redraw
6788  * occurs once the main loop becomes idle (after the current batch of
6789  * events has been processed, roughly).
6790  *
6791  * If no flags are given the clip volume is defined by @volume
6792  * specified in actor coordinates and tells Clutter that only content
6793  * within this volume has been changed so Clutter can optionally
6794  * optimize the redraw.
6795  *
6796  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6797  * should be %NULL and this tells Clutter to use the actor's current
6798  * allocation as a clip box. This flag can only be used for 2D actors,
6799  * because any actor with depth may be projected outside its
6800  * allocation.
6801  *
6802  * Applications rarely need to call this, as redraws are handled
6803  * automatically by modification functions.
6804  *
6805  * This function will not do anything if @self is not visible, or if
6806  * the actor is inside an invisible part of the scenegraph.
6807  *
6808  * Also be aware that painting is a NOP for actors with an opacity of
6809  * 0
6810  *
6811  * When you are implementing a custom actor you must queue a redraw
6812  * whenever some private state changes that will affect painting or
6813  * picking of your actor.
6814  */
6815 void
6816 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6817                                        ClutterRedrawFlags  flags,
6818                                        ClutterPaintVolume *volume)
6819 {
6820   _clutter_actor_queue_redraw_full (self,
6821                                     flags, /* flags */
6822                                     volume, /* clip volume */
6823                                     NULL /* effect */);
6824 }
6825
6826 static void
6827 _clutter_actor_queue_only_relayout (ClutterActor *self)
6828 {
6829   ClutterActorPrivate *priv = self->priv;
6830
6831   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6832     return;
6833
6834   if (priv->needs_width_request &&
6835       priv->needs_height_request &&
6836       priv->needs_allocation)
6837     return; /* save some cpu cycles */
6838
6839 #if CLUTTER_ENABLE_DEBUG
6840   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6841     {
6842       g_warning ("The actor '%s' is currently inside an allocation "
6843                  "cycle; calling clutter_actor_queue_relayout() is "
6844                  "not recommended",
6845                  _clutter_actor_get_debug_name (self));
6846     }
6847 #endif /* CLUTTER_ENABLE_DEBUG */
6848
6849   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6850 }
6851
6852 /**
6853  * clutter_actor_queue_redraw_with_clip:
6854  * @self: a #ClutterActor
6855  * @clip: (allow-none): a rectangular clip region, or %NULL
6856  *
6857  * Queues a redraw on @self limited to a specific, actor-relative
6858  * rectangular area.
6859  *
6860  * If @clip is %NULL this function is equivalent to
6861  * clutter_actor_queue_redraw().
6862  *
6863  * Since: 1.10
6864  */
6865 void
6866 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6867                                       const cairo_rectangle_int_t *clip)
6868 {
6869   ClutterPaintVolume volume;
6870   ClutterVertex origin;
6871
6872   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6873
6874   if (clip == NULL)
6875     {
6876       clutter_actor_queue_redraw (self);
6877       return;
6878     }
6879
6880   _clutter_paint_volume_init_static (&volume, self);
6881
6882   origin.x = clip->x;
6883   origin.y = clip->y;
6884   origin.z = 0.0f;
6885
6886   clutter_paint_volume_set_origin (&volume, &origin);
6887   clutter_paint_volume_set_width (&volume, clip->width);
6888   clutter_paint_volume_set_height (&volume, clip->height);
6889
6890   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6891
6892   clutter_paint_volume_free (&volume);
6893 }
6894
6895 /**
6896  * clutter_actor_queue_relayout:
6897  * @self: A #ClutterActor
6898  *
6899  * Indicates that the actor's size request or other layout-affecting
6900  * properties may have changed. This function is used inside #ClutterActor
6901  * subclass implementations, not by applications directly.
6902  *
6903  * Queueing a new layout automatically queues a redraw as well.
6904  *
6905  * Since: 0.8
6906  */
6907 void
6908 clutter_actor_queue_relayout (ClutterActor *self)
6909 {
6910   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6911
6912   _clutter_actor_queue_only_relayout (self);
6913   clutter_actor_queue_redraw (self);
6914 }
6915
6916 /**
6917  * clutter_actor_get_preferred_size:
6918  * @self: a #ClutterActor
6919  * @min_width_p: (out) (allow-none): return location for the minimum
6920  *   width, or %NULL
6921  * @min_height_p: (out) (allow-none): return location for the minimum
6922  *   height, or %NULL
6923  * @natural_width_p: (out) (allow-none): return location for the natural
6924  *   width, or %NULL
6925  * @natural_height_p: (out) (allow-none): return location for the natural
6926  *   height, or %NULL
6927  *
6928  * Computes the preferred minimum and natural size of an actor, taking into
6929  * account the actor's geometry management (either height-for-width
6930  * or width-for-height).
6931  *
6932  * The width and height used to compute the preferred height and preferred
6933  * width are the actor's natural ones.
6934  *
6935  * If you need to control the height for the preferred width, or the width for
6936  * the preferred height, you should use clutter_actor_get_preferred_width()
6937  * and clutter_actor_get_preferred_height(), and check the actor's preferred
6938  * geometry management using the #ClutterActor:request-mode property.
6939  *
6940  * Since: 0.8
6941  */
6942 void
6943 clutter_actor_get_preferred_size (ClutterActor *self,
6944                                   gfloat       *min_width_p,
6945                                   gfloat       *min_height_p,
6946                                   gfloat       *natural_width_p,
6947                                   gfloat       *natural_height_p)
6948 {
6949   ClutterActorPrivate *priv;
6950   gfloat min_width, min_height;
6951   gfloat natural_width, natural_height;
6952
6953   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6954
6955   priv = self->priv;
6956
6957   min_width = min_height = 0;
6958   natural_width = natural_height = 0;
6959
6960   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
6961     {
6962       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
6963       clutter_actor_get_preferred_width (self, -1,
6964                                          &min_width,
6965                                          &natural_width);
6966       clutter_actor_get_preferred_height (self, natural_width,
6967                                           &min_height,
6968                                           &natural_height);
6969     }
6970   else
6971     {
6972       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
6973       clutter_actor_get_preferred_height (self, -1,
6974                                           &min_height,
6975                                           &natural_height);
6976       clutter_actor_get_preferred_width (self, natural_height,
6977                                          &min_width,
6978                                          &natural_width);
6979     }
6980
6981   if (min_width_p)
6982     *min_width_p = min_width;
6983
6984   if (min_height_p)
6985     *min_height_p = min_height;
6986
6987   if (natural_width_p)
6988     *natural_width_p = natural_width;
6989
6990   if (natural_height_p)
6991     *natural_height_p = natural_height;
6992 }
6993
6994 /*< private >
6995  * effective_align:
6996  * @align: a #ClutterActorAlign
6997  * @direction: a #ClutterTextDirection
6998  *
6999  * Retrieves the correct alignment depending on the text direction
7000  *
7001  * Return value: the effective alignment
7002  */
7003 static ClutterActorAlign
7004 effective_align (ClutterActorAlign    align,
7005                  ClutterTextDirection direction)
7006 {
7007   ClutterActorAlign res;
7008
7009   switch (align)
7010     {
7011     case CLUTTER_ACTOR_ALIGN_START:
7012       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7013           ? CLUTTER_ACTOR_ALIGN_END
7014           : CLUTTER_ACTOR_ALIGN_START;
7015       break;
7016
7017     case CLUTTER_ACTOR_ALIGN_END:
7018       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7019           ? CLUTTER_ACTOR_ALIGN_START
7020           : CLUTTER_ACTOR_ALIGN_END;
7021       break;
7022
7023     default:
7024       res = align;
7025       break;
7026     }
7027
7028   return res;
7029 }
7030
7031 static inline void
7032 adjust_for_margin (float  margin_start,
7033                    float  margin_end,
7034                    float *minimum_size,
7035                    float *natural_size,
7036                    float *allocated_start,
7037                    float *allocated_end)
7038 {
7039   *minimum_size -= (margin_start + margin_end);
7040   *natural_size -= (margin_start + margin_end);
7041   *allocated_start += margin_start;
7042   *allocated_end -= margin_end;
7043 }
7044
7045 static inline void
7046 adjust_for_alignment (ClutterActorAlign  alignment,
7047                       float              natural_size,
7048                       float             *allocated_start,
7049                       float             *allocated_end)
7050 {
7051   float allocated_size = *allocated_end - *allocated_start;
7052
7053   switch (alignment)
7054     {
7055     case CLUTTER_ACTOR_ALIGN_FILL:
7056       /* do nothing */
7057       break;
7058
7059     case CLUTTER_ACTOR_ALIGN_START:
7060       /* keep start */
7061       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7062       break;
7063
7064     case CLUTTER_ACTOR_ALIGN_END:
7065       if (allocated_size > natural_size)
7066         {
7067           *allocated_start += (allocated_size - natural_size);
7068           *allocated_end = *allocated_start + natural_size;
7069         }
7070       break;
7071
7072     case CLUTTER_ACTOR_ALIGN_CENTER:
7073       if (allocated_size > natural_size)
7074         {
7075           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7076           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7077         }
7078       break;
7079     }
7080 }
7081
7082 /*< private >
7083  * clutter_actor_adjust_width:
7084  * @self: a #ClutterActor
7085  * @minimum_width: (inout): the actor's preferred minimum width, which
7086  *   will be adjusted depending on the margin
7087  * @natural_width: (inout): the actor's preferred natural width, which
7088  *   will be adjusted depending on the margin
7089  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7090  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7091  *
7092  * Adjusts the preferred and allocated position and size of an actor,
7093  * depending on the margin and alignment properties.
7094  */
7095 static void
7096 clutter_actor_adjust_width (ClutterActor *self,
7097                             gfloat       *minimum_width,
7098                             gfloat       *natural_width,
7099                             gfloat       *adjusted_x1,
7100                             gfloat       *adjusted_x2)
7101 {
7102   ClutterTextDirection text_dir;
7103   const ClutterLayoutInfo *info;
7104
7105   info = _clutter_actor_get_layout_info_or_defaults (self);
7106   text_dir = clutter_actor_get_text_direction (self);
7107
7108   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7109
7110   /* this will tweak natural_width to remove the margin, so that
7111    * adjust_for_alignment() will use the correct size
7112    */
7113   adjust_for_margin (info->margin.left, info->margin.right,
7114                      minimum_width, natural_width,
7115                      adjusted_x1, adjusted_x2);
7116
7117   adjust_for_alignment (effective_align (info->x_align, text_dir),
7118                         *natural_width,
7119                         adjusted_x1, adjusted_x2);
7120 }
7121
7122 /*< private >
7123  * clutter_actor_adjust_height:
7124  * @self: a #ClutterActor
7125  * @minimum_height: (inout): the actor's preferred minimum height, which
7126  *   will be adjusted depending on the margin
7127  * @natural_height: (inout): the actor's preferred natural height, which
7128  *   will be adjusted depending on the margin
7129  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7130  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7131  *
7132  * Adjusts the preferred and allocated position and size of an actor,
7133  * depending on the margin and alignment properties.
7134  */
7135 static void
7136 clutter_actor_adjust_height (ClutterActor *self,
7137                              gfloat       *minimum_height,
7138                              gfloat       *natural_height,
7139                              gfloat       *adjusted_y1,
7140                              gfloat       *adjusted_y2)
7141 {
7142   const ClutterLayoutInfo *info;
7143
7144   info = _clutter_actor_get_layout_info_or_defaults (self);
7145
7146   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7147
7148   /* this will tweak natural_height to remove the margin, so that
7149    * adjust_for_alignment() will use the correct size
7150    */
7151   adjust_for_margin (info->margin.top, info->margin.bottom,
7152                      minimum_height, natural_height,
7153                      adjusted_y1,
7154                      adjusted_y2);
7155
7156   /* we don't use effective_align() here, because text direction
7157    * only affects the horizontal axis
7158    */
7159   adjust_for_alignment (info->y_align,
7160                         *natural_height,
7161                         adjusted_y1,
7162                         adjusted_y2);
7163
7164 }
7165
7166 /* looks for a cached size request for this for_size. If not
7167  * found, returns the oldest entry so it can be overwritten */
7168 static gboolean
7169 _clutter_actor_get_cached_size_request (gfloat         for_size,
7170                                         SizeRequest   *cached_size_requests,
7171                                         SizeRequest  **result)
7172 {
7173   guint i;
7174
7175   *result = &cached_size_requests[0];
7176
7177   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7178     {
7179       SizeRequest *sr;
7180
7181       sr = &cached_size_requests[i];
7182
7183       if (sr->age > 0 &&
7184           sr->for_size == for_size)
7185         {
7186           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7187           *result = sr;
7188           return TRUE;
7189         }
7190       else if (sr->age < (*result)->age)
7191         {
7192           *result = sr;
7193         }
7194     }
7195
7196   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7197
7198   return FALSE;
7199 }
7200
7201 /**
7202  * clutter_actor_get_preferred_width:
7203  * @self: A #ClutterActor
7204  * @for_height: available height when computing the preferred width,
7205  *   or a negative value to indicate that no height is defined
7206  * @min_width_p: (out) (allow-none): return location for minimum width,
7207  *   or %NULL
7208  * @natural_width_p: (out) (allow-none): return location for the natural
7209  *   width, or %NULL
7210  *
7211  * Computes the requested minimum and natural widths for an actor,
7212  * optionally depending on the specified height, or if they are
7213  * already computed, returns the cached values.
7214  *
7215  * An actor may not get its request - depending on the layout
7216  * manager that's in effect.
7217  *
7218  * A request should not incorporate the actor's scale or anchor point;
7219  * those transformations do not affect layout, only rendering.
7220  *
7221  * Since: 0.8
7222  */
7223 void
7224 clutter_actor_get_preferred_width (ClutterActor *self,
7225                                    gfloat        for_height,
7226                                    gfloat       *min_width_p,
7227                                    gfloat       *natural_width_p)
7228 {
7229   float request_min_width, request_natural_width;
7230   SizeRequest *cached_size_request;
7231   const ClutterLayoutInfo *info;
7232   ClutterActorPrivate *priv;
7233   gboolean found_in_cache;
7234
7235   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7236
7237   priv = self->priv;
7238
7239   info = _clutter_actor_get_layout_info_or_defaults (self);
7240
7241   /* we shortcircuit the case of a fixed size set using set_width() */
7242   if (priv->min_width_set && priv->natural_width_set)
7243     {
7244       if (min_width_p != NULL)
7245         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7246
7247       if (natural_width_p != NULL)
7248         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7249
7250       return;
7251     }
7252
7253   /* the remaining cases are:
7254    *
7255    *   - either min_width or natural_width have been set
7256    *   - neither min_width or natural_width have been set
7257    *
7258    * in both cases, we go through the cache (and through the actor in case
7259    * of cache misses) and determine the authoritative value depending on
7260    * the *_set flags.
7261    */
7262
7263   if (!priv->needs_width_request)
7264     {
7265       found_in_cache =
7266         _clutter_actor_get_cached_size_request (for_height,
7267                                                 priv->width_requests,
7268                                                 &cached_size_request);
7269     }
7270   else
7271     {
7272       /* if the actor needs a width request we use the first slot */
7273       found_in_cache = FALSE;
7274       cached_size_request = &priv->width_requests[0];
7275     }
7276
7277   if (!found_in_cache)
7278     {
7279       gfloat minimum_width, natural_width;
7280       ClutterActorClass *klass;
7281
7282       minimum_width = natural_width = 0;
7283
7284       /* adjust for the margin */
7285       if (for_height >= 0)
7286         {
7287           for_height -= (info->margin.top + info->margin.bottom);
7288           if (for_height < 0)
7289             for_height = 0;
7290         }
7291
7292       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7293
7294       klass = CLUTTER_ACTOR_GET_CLASS (self);
7295       klass->get_preferred_width (self, for_height,
7296                                   &minimum_width,
7297                                   &natural_width);
7298
7299       /* adjust for the margin */
7300       minimum_width += (info->margin.left + info->margin.right);
7301       natural_width += (info->margin.left + info->margin.right);
7302
7303       /* Due to accumulated float errors, it's better not to warn
7304        * on this, but just fix it.
7305        */
7306       if (natural_width < minimum_width)
7307         natural_width = minimum_width;
7308
7309       cached_size_request->min_size = minimum_width;
7310       cached_size_request->natural_size = natural_width;
7311       cached_size_request->for_size = for_height;
7312       cached_size_request->age = priv->cached_width_age;
7313
7314       priv->cached_width_age += 1;
7315       priv->needs_width_request = FALSE;
7316     }
7317
7318   if (!priv->min_width_set)
7319     request_min_width = cached_size_request->min_size;
7320   else
7321     request_min_width = info->min_width;
7322
7323   if (!priv->natural_width_set)
7324     request_natural_width = cached_size_request->natural_size;
7325   else
7326     request_natural_width = info->natural_width;
7327
7328   if (min_width_p)
7329     *min_width_p = request_min_width;
7330
7331   if (natural_width_p)
7332     *natural_width_p = request_natural_width;
7333 }
7334
7335 /**
7336  * clutter_actor_get_preferred_height:
7337  * @self: A #ClutterActor
7338  * @for_width: available width to assume in computing desired height,
7339  *   or a negative value to indicate that no width is defined
7340  * @min_height_p: (out) (allow-none): return location for minimum height,
7341  *   or %NULL
7342  * @natural_height_p: (out) (allow-none): return location for natural
7343  *   height, or %NULL
7344  *
7345  * Computes the requested minimum and natural heights for an actor,
7346  * or if they are already computed, returns the cached values.
7347  *
7348  * An actor may not get its request - depending on the layout
7349  * manager that's in effect.
7350  *
7351  * A request should not incorporate the actor's scale or anchor point;
7352  * those transformations do not affect layout, only rendering.
7353  *
7354  * Since: 0.8
7355  */
7356 void
7357 clutter_actor_get_preferred_height (ClutterActor *self,
7358                                     gfloat        for_width,
7359                                     gfloat       *min_height_p,
7360                                     gfloat       *natural_height_p)
7361 {
7362   float request_min_height, request_natural_height;
7363   SizeRequest *cached_size_request;
7364   const ClutterLayoutInfo *info;
7365   ClutterActorPrivate *priv;
7366   gboolean found_in_cache;
7367
7368   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7369
7370   priv = self->priv;
7371
7372   info = _clutter_actor_get_layout_info_or_defaults (self);
7373
7374   /* we shortcircuit the case of a fixed size set using set_height() */
7375   if (priv->min_height_set && priv->natural_height_set)
7376     {
7377       if (min_height_p != NULL)
7378         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7379
7380       if (natural_height_p != NULL)
7381         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7382
7383       return;
7384     }
7385
7386   /* the remaining cases are:
7387    *
7388    *   - either min_height or natural_height have been set
7389    *   - neither min_height or natural_height have been set
7390    *
7391    * in both cases, we go through the cache (and through the actor in case
7392    * of cache misses) and determine the authoritative value depending on
7393    * the *_set flags.
7394    */
7395
7396   if (!priv->needs_height_request)
7397     {
7398       found_in_cache =
7399         _clutter_actor_get_cached_size_request (for_width,
7400                                                 priv->height_requests,
7401                                                 &cached_size_request);
7402     }
7403   else
7404     {
7405       found_in_cache = FALSE;
7406       cached_size_request = &priv->height_requests[0];
7407     }
7408
7409   if (!found_in_cache)
7410     {
7411       gfloat minimum_height, natural_height;
7412       ClutterActorClass *klass;
7413
7414       minimum_height = natural_height = 0;
7415
7416       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7417
7418       /* adjust for margin */
7419       if (for_width >= 0)
7420         {
7421           for_width -= (info->margin.left + info->margin.right);
7422           if (for_width < 0)
7423             for_width = 0;
7424         }
7425
7426       klass = CLUTTER_ACTOR_GET_CLASS (self);
7427       klass->get_preferred_height (self, for_width,
7428                                    &minimum_height,
7429                                    &natural_height);
7430
7431       /* adjust for margin */
7432       minimum_height += (info->margin.top + info->margin.bottom);
7433       natural_height += (info->margin.top + info->margin.bottom);
7434
7435       /* Due to accumulated float errors, it's better not to warn
7436        * on this, but just fix it.
7437        */
7438       if (natural_height < minimum_height)
7439         natural_height = minimum_height;
7440
7441       cached_size_request->min_size = minimum_height;
7442       cached_size_request->natural_size = natural_height;
7443       cached_size_request->for_size = for_width;
7444       cached_size_request->age = priv->cached_height_age;
7445
7446       priv->cached_height_age += 1;
7447       priv->needs_height_request = FALSE;
7448     }
7449
7450   if (!priv->min_height_set)
7451     request_min_height = cached_size_request->min_size;
7452   else
7453     request_min_height = info->min_height;
7454
7455   if (!priv->natural_height_set)
7456     request_natural_height = cached_size_request->natural_size;
7457   else
7458     request_natural_height = info->natural_height;
7459
7460   if (min_height_p)
7461     *min_height_p = request_min_height;
7462
7463   if (natural_height_p)
7464     *natural_height_p = request_natural_height;
7465 }
7466
7467 /**
7468  * clutter_actor_get_allocation_box:
7469  * @self: A #ClutterActor
7470  * @box: (out): the function fills this in with the actor's allocation
7471  *
7472  * Gets the layout box an actor has been assigned. The allocation can
7473  * only be assumed valid inside a paint() method; anywhere else, it
7474  * may be out-of-date.
7475  *
7476  * An allocation does not incorporate the actor's scale or anchor point;
7477  * those transformations do not affect layout, only rendering.
7478  *
7479  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7480  * of functions inside the implementation of the get_preferred_width()
7481  * or get_preferred_height() virtual functions.</note>
7482  *
7483  * Since: 0.8
7484  */
7485 void
7486 clutter_actor_get_allocation_box (ClutterActor    *self,
7487                                   ClutterActorBox *box)
7488 {
7489   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7490
7491   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7492    * which limits calling get_allocation to inside paint() basically; or
7493    * we can 2) force a layout, which could be expensive if someone calls
7494    * get_allocation somewhere silly; or we can 3) just return the latest
7495    * value, allowing it to be out-of-date, and assume people know what
7496    * they are doing.
7497    *
7498    * The least-surprises approach that keeps existing code working is
7499    * likely to be 2). People can end up doing some inefficient things,
7500    * though, and in general code that requires 2) is probably broken.
7501    */
7502
7503   /* this implements 2) */
7504   if (G_UNLIKELY (self->priv->needs_allocation))
7505     {
7506       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7507
7508       /* do not queue a relayout on an unparented actor */
7509       if (stage)
7510         _clutter_stage_maybe_relayout (stage);
7511     }
7512
7513   /* commenting out the code above and just keeping this assigment
7514    * implements 3)
7515    */
7516   *box = self->priv->allocation;
7517 }
7518
7519 /**
7520  * clutter_actor_get_allocation_geometry:
7521  * @self: A #ClutterActor
7522  * @geom: (out): allocation geometry in pixels
7523  *
7524  * Gets the layout box an actor has been assigned.  The allocation can
7525  * only be assumed valid inside a paint() method; anywhere else, it
7526  * may be out-of-date.
7527  *
7528  * An allocation does not incorporate the actor's scale or anchor point;
7529  * those transformations do not affect layout, only rendering.
7530  *
7531  * The returned rectangle is in pixels.
7532  *
7533  * Since: 0.8
7534  */
7535 void
7536 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7537                                        ClutterGeometry *geom)
7538 {
7539   ClutterActorBox box;
7540
7541   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7542   g_return_if_fail (geom != NULL);
7543
7544   clutter_actor_get_allocation_box (self, &box);
7545
7546   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7547   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7548   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7549   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7550 }
7551
7552 static void
7553 clutter_actor_update_constraints (ClutterActor    *self,
7554                                   ClutterActorBox *allocation)
7555 {
7556   ClutterActorPrivate *priv = self->priv;
7557   const GList *constraints, *l;
7558
7559   if (priv->constraints == NULL)
7560     return;
7561
7562   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7563   for (l = constraints; l != NULL; l = l->next)
7564     {
7565       ClutterConstraint *constraint = l->data;
7566       ClutterActorMeta *meta = l->data;
7567
7568       if (clutter_actor_meta_get_enabled (meta))
7569         {
7570           _clutter_constraint_update_allocation (constraint,
7571                                                  self,
7572                                                  allocation);
7573         }
7574     }
7575 }
7576
7577 /*< private >
7578  * clutter_actor_adjust_allocation:
7579  * @self: a #ClutterActor
7580  * @allocation: (inout): the allocation to adjust
7581  *
7582  * Adjusts the passed allocation box taking into account the actor's
7583  * layout information, like alignment, expansion, and margin.
7584  */
7585 static void
7586 clutter_actor_adjust_allocation (ClutterActor    *self,
7587                                  ClutterActorBox *allocation)
7588 {
7589   ClutterActorBox adj_allocation;
7590   float alloc_width, alloc_height;
7591   float min_width, min_height;
7592   float nat_width, nat_height;
7593   ClutterRequestMode req_mode;
7594
7595   adj_allocation = *allocation;
7596
7597   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7598
7599   /* we want to hit the cache, so we use the public API */
7600   req_mode = clutter_actor_get_request_mode (self);
7601
7602   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7603     {
7604       clutter_actor_get_preferred_width (self, -1,
7605                                          &min_width,
7606                                          &nat_width);
7607       clutter_actor_get_preferred_height (self, alloc_width,
7608                                           &min_height,
7609                                           &nat_height);
7610     }
7611   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7612     {
7613       clutter_actor_get_preferred_height (self, -1,
7614                                           &min_height,
7615                                           &nat_height);
7616       clutter_actor_get_preferred_height (self, alloc_height,
7617                                           &min_width,
7618                                           &nat_width);
7619     }
7620
7621 #ifdef CLUTTER_ENABLE_DEBUG
7622   /* warn about underallocations */
7623   if (_clutter_diagnostic_enabled () &&
7624       (floorf (min_width - alloc_width) > 0 ||
7625        floorf (min_height - alloc_height) > 0))
7626     {
7627       ClutterActor *parent = clutter_actor_get_parent (self);
7628
7629       /* the only actors that are allowed to be underallocated are the Stage,
7630        * as it doesn't have an implicit size, and Actors that specifically
7631        * told us that they want to opt-out from layout control mechanisms
7632        * through the NO_LAYOUT escape hatch.
7633        */
7634       if (parent != NULL &&
7635           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7636         {
7637           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7638                      "of %.2f x %.2f from its parent actor '%s', but its "
7639                      "requested minimum size is of %.2f x %.2f",
7640                      _clutter_actor_get_debug_name (self),
7641                      alloc_width, alloc_height,
7642                      _clutter_actor_get_debug_name (parent),
7643                      min_width, min_height);
7644         }
7645     }
7646 #endif
7647
7648   clutter_actor_adjust_width (self,
7649                               &min_width,
7650                               &nat_width,
7651                               &adj_allocation.x1,
7652                               &adj_allocation.x2);
7653
7654   clutter_actor_adjust_height (self,
7655                                &min_height,
7656                                &nat_height,
7657                                &adj_allocation.y1,
7658                                &adj_allocation.y2);
7659
7660   /* we maintain the invariant that an allocation cannot be adjusted
7661    * to be outside the parent-given box
7662    */
7663   if (adj_allocation.x1 < allocation->x1 ||
7664       adj_allocation.y1 < allocation->y1 ||
7665       adj_allocation.x2 > allocation->x2 ||
7666       adj_allocation.y2 > allocation->y2)
7667     {
7668       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7669                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7670                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7671                  _clutter_actor_get_debug_name (self),
7672                  adj_allocation.x1, adj_allocation.y1,
7673                  adj_allocation.x2 - adj_allocation.x1,
7674                  adj_allocation.y2 - adj_allocation.y1,
7675                  allocation->x1, allocation->y1,
7676                  allocation->x2 - allocation->x1,
7677                  allocation->y2 - allocation->y1);
7678       return;
7679     }
7680
7681   *allocation = adj_allocation;
7682 }
7683
7684 /**
7685  * clutter_actor_allocate:
7686  * @self: A #ClutterActor
7687  * @box: new allocation of the actor, in parent-relative coordinates
7688  * @flags: flags that control the allocation
7689  *
7690  * Called by the parent of an actor to assign the actor its size.
7691  * Should never be called by applications (except when implementing
7692  * a container or layout manager).
7693  *
7694  * Actors can know from their allocation box whether they have moved
7695  * with respect to their parent actor. The @flags parameter describes
7696  * additional information about the allocation, for instance whether
7697  * the parent has moved with respect to the stage, for example because
7698  * a grandparent's origin has moved.
7699  *
7700  * Since: 0.8
7701  */
7702 void
7703 clutter_actor_allocate (ClutterActor           *self,
7704                         const ClutterActorBox  *box,
7705                         ClutterAllocationFlags  flags)
7706 {
7707   ClutterActorPrivate *priv;
7708   ClutterActorClass *klass;
7709   ClutterActorBox old_allocation, real_allocation;
7710   gboolean origin_changed, child_moved, size_changed;
7711   gboolean stage_allocation_changed;
7712
7713   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7714   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7715     {
7716       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7717                  "which isn't a descendent of the stage!\n",
7718                  self, _clutter_actor_get_debug_name (self));
7719       return;
7720     }
7721
7722   priv = self->priv;
7723
7724   old_allocation = priv->allocation;
7725   real_allocation = *box;
7726
7727   /* constraints are allowed to modify the allocation only here; we do
7728    * this prior to all the other checks so that we can bail out if the
7729    * allocation did not change
7730    */
7731   clutter_actor_update_constraints (self, &real_allocation);
7732
7733   /* adjust the allocation depending on the align/margin properties */
7734   clutter_actor_adjust_allocation (self, &real_allocation);
7735
7736   if (real_allocation.x2 < real_allocation.x1 ||
7737       real_allocation.y2 < real_allocation.y1)
7738     {
7739       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7740                  _clutter_actor_get_debug_name (self),
7741                  real_allocation.x2 - real_allocation.x1,
7742                  real_allocation.y2 - real_allocation.y1);
7743     }
7744
7745   /* we allow 0-sized actors, but not negative-sized ones */
7746   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7747   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7748
7749   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7750
7751   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7752                  real_allocation.y1 != old_allocation.y1);
7753
7754   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7755                   real_allocation.y2 != old_allocation.y2);
7756
7757   if (origin_changed || child_moved || size_changed)
7758     stage_allocation_changed = TRUE;
7759   else
7760     stage_allocation_changed = FALSE;
7761
7762   /* If we get an allocation "out of the blue"
7763    * (we did not queue relayout), then we want to
7764    * ignore it. But if we have needs_allocation set,
7765    * we want to guarantee that allocate() virtual
7766    * method is always called, i.e. that queue_relayout()
7767    * always results in an allocate() invocation on
7768    * an actor.
7769    *
7770    * The optimization here is to avoid re-allocating
7771    * actors that did not queue relayout and were
7772    * not moved.
7773    */
7774   if (!priv->needs_allocation && !stage_allocation_changed)
7775     {
7776       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7777       return;
7778     }
7779
7780   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7781    * clutter_actor_allocate(), it indicates whether the parent has its
7782    * absolute origin moved; when passed in to ClutterActor::allocate()
7783    * virtual method though, it indicates whether the child has its
7784    * absolute origin moved.  So we set it when child_moved is TRUE
7785    */
7786   if (child_moved)
7787     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7788
7789   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7790
7791   klass = CLUTTER_ACTOR_GET_CLASS (self);
7792   klass->allocate (self, &real_allocation, flags);
7793
7794   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7795
7796   if (stage_allocation_changed)
7797     clutter_actor_queue_redraw (self);
7798 }
7799
7800 /**
7801  * clutter_actor_set_allocation:
7802  * @self: a #ClutterActor
7803  * @box: a #ClutterActorBox
7804  * @flags: allocation flags
7805  *
7806  * Stores the allocation of @self as defined by @box.
7807  *
7808  * This function can only be called from within the implementation of
7809  * the #ClutterActorClass.allocate() virtual function.
7810  *
7811  * The allocation should have been adjusted to take into account constraints,
7812  * alignment, and margin properties. If you are implementing a #ClutterActor
7813  * subclass that provides its own layout management policy for its children
7814  * instead of using a #ClutterLayoutManager delegate, you should not call
7815  * this function on the children of @self; instead, you should call
7816  * clutter_actor_allocate(), which will adjust the allocation box for
7817  * you.
7818  *
7819  * This function should only be used by subclasses of #ClutterActor
7820  * that wish to store their allocation but cannot chain up to the
7821  * parent's implementation; the default implementation of the
7822  * #ClutterActorClass.allocate() virtual function will call this
7823  * function.
7824  *
7825  * It is important to note that, while chaining up was the recommended
7826  * behaviour for #ClutterActor subclasses prior to the introduction of
7827  * this function, it is recommended to call clutter_actor_set_allocation()
7828  * instead.
7829  *
7830  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7831  * to handle the allocation of its children, this function will call
7832  * the clutter_layout_manager_allocate() function only if the
7833  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7834  * expected that the subclass will call clutter_layout_manager_allocate()
7835  * by itself. For instance, the following code:
7836  *
7837  * |[
7838  * static void
7839  * my_actor_allocate (ClutterActor *actor,
7840  *                    const ClutterActorBox *allocation,
7841  *                    ClutterAllocationFlags flags)
7842  * {
7843  *   ClutterActorBox new_alloc;
7844  *   ClutterAllocationFlags new_flags;
7845  *
7846  *   adjust_allocation (allocation, &amp;new_alloc);
7847  *
7848  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7849  *
7850  *   /&ast; this will use the layout manager set on the actor &ast;/
7851  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7852  * }
7853  * ]|
7854  *
7855  * is equivalent to this:
7856  *
7857  * |[
7858  * static void
7859  * my_actor_allocate (ClutterActor *actor,
7860  *                    const ClutterActorBox *allocation,
7861  *                    ClutterAllocationFlags flags)
7862  * {
7863  *   ClutterLayoutManager *layout;
7864  *   ClutterActorBox new_alloc;
7865  *
7866  *   adjust_allocation (allocation, &amp;new_alloc);
7867  *
7868  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7869  *
7870  *   layout = clutter_actor_get_layout_manager (actor);
7871  *   clutter_layout_manager_allocate (layout,
7872  *                                    CLUTTER_CONTAINER (actor),
7873  *                                    &amp;new_alloc,
7874  *                                    flags);
7875  * }
7876  * ]|
7877  *
7878  * Since: 1.10
7879  */
7880 void
7881 clutter_actor_set_allocation (ClutterActor           *self,
7882                               const ClutterActorBox  *box,
7883                               ClutterAllocationFlags  flags)
7884 {
7885   ClutterActorPrivate *priv;
7886   gboolean changed;
7887
7888   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7889   g_return_if_fail (box != NULL);
7890
7891   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7892     {
7893       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7894                   "can only be called from within the implementation of "
7895                   "the ClutterActor::allocate() virtual function.");
7896       return;
7897     }
7898
7899   priv = self->priv;
7900
7901   g_object_freeze_notify (G_OBJECT (self));
7902
7903   changed = clutter_actor_set_allocation_internal (self, box, flags);
7904
7905   /* we allocate our children before we notify changes in our geometry,
7906    * so that people connecting to properties will be able to get valid
7907    * data out of the sub-tree of the scene graph that has this actor at
7908    * the root.
7909    */
7910   clutter_actor_maybe_layout_children (self, box, flags);
7911
7912   if (changed)
7913     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7914                    &priv->allocation,
7915                    priv->allocation_flags);
7916
7917   g_object_thaw_notify (G_OBJECT (self));
7918 }
7919
7920 /**
7921  * clutter_actor_set_geometry:
7922  * @self: A #ClutterActor
7923  * @geometry: A #ClutterGeometry
7924  *
7925  * Sets the actor's fixed position and forces its minimum and natural
7926  * size, in pixels. This means the untransformed actor will have the
7927  * given geometry. This is the same as calling clutter_actor_set_position()
7928  * and clutter_actor_set_size().
7929  *
7930  * Deprecated: 1.10: Use clutter_actor_set_position() and
7931  *   clutter_actor_set_size() instead.
7932  */
7933 void
7934 clutter_actor_set_geometry (ClutterActor          *self,
7935                             const ClutterGeometry *geometry)
7936 {
7937   g_object_freeze_notify (G_OBJECT (self));
7938
7939   clutter_actor_set_position (self, geometry->x, geometry->y);
7940   clutter_actor_set_size (self, geometry->width, geometry->height);
7941
7942   g_object_thaw_notify (G_OBJECT (self));
7943 }
7944
7945 /**
7946  * clutter_actor_get_geometry:
7947  * @self: A #ClutterActor
7948  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
7949  *
7950  * Gets the size and position of an actor relative to its parent
7951  * actor. This is the same as calling clutter_actor_get_position() and
7952  * clutter_actor_get_size(). It tries to "do what you mean" and get the
7953  * requested size and position if the actor's allocation is invalid.
7954  *
7955  * Deprecated: 1.10: Use clutter_actor_get_position() and
7956  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
7957  *   instead.
7958  */
7959 void
7960 clutter_actor_get_geometry (ClutterActor    *self,
7961                             ClutterGeometry *geometry)
7962 {
7963   gfloat x, y, width, height;
7964
7965   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7966   g_return_if_fail (geometry != NULL);
7967
7968   clutter_actor_get_position (self, &x, &y);
7969   clutter_actor_get_size (self, &width, &height);
7970
7971   geometry->x = (int) x;
7972   geometry->y = (int) y;
7973   geometry->width = (int) width;
7974   geometry->height = (int) height;
7975 }
7976
7977 /**
7978  * clutter_actor_set_position:
7979  * @self: A #ClutterActor
7980  * @x: New left position of actor in pixels.
7981  * @y: New top position of actor in pixels.
7982  *
7983  * Sets the actor's fixed position in pixels relative to any parent
7984  * actor.
7985  *
7986  * If a layout manager is in use, this position will override the
7987  * layout manager and force a fixed position.
7988  */
7989 void
7990 clutter_actor_set_position (ClutterActor *self,
7991                             gfloat        x,
7992                             gfloat        y)
7993 {
7994   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7995
7996   g_object_freeze_notify (G_OBJECT (self));
7997
7998   clutter_actor_set_x (self, x);
7999   clutter_actor_set_y (self, y);
8000
8001   g_object_thaw_notify (G_OBJECT (self));
8002 }
8003
8004 /**
8005  * clutter_actor_get_fixed_position_set:
8006  * @self: A #ClutterActor
8007  *
8008  * Checks whether an actor has a fixed position set (and will thus be
8009  * unaffected by any layout manager).
8010  *
8011  * Return value: %TRUE if the fixed position is set on the actor
8012  *
8013  * Since: 0.8
8014  */
8015 gboolean
8016 clutter_actor_get_fixed_position_set (ClutterActor *self)
8017 {
8018   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8019
8020   return self->priv->position_set;
8021 }
8022
8023 /**
8024  * clutter_actor_set_fixed_position_set:
8025  * @self: A #ClutterActor
8026  * @is_set: whether to use fixed position
8027  *
8028  * Sets whether an actor has a fixed position set (and will thus be
8029  * unaffected by any layout manager).
8030  *
8031  * Since: 0.8
8032  */
8033 void
8034 clutter_actor_set_fixed_position_set (ClutterActor *self,
8035                                       gboolean      is_set)
8036 {
8037   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8038
8039   if (self->priv->position_set == (is_set != FALSE))
8040     return;
8041
8042   self->priv->position_set = is_set != FALSE;
8043   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8044
8045   clutter_actor_queue_relayout (self);
8046 }
8047
8048 /**
8049  * clutter_actor_move_by:
8050  * @self: A #ClutterActor
8051  * @dx: Distance to move Actor on X axis.
8052  * @dy: Distance to move Actor on Y axis.
8053  *
8054  * Moves an actor by the specified distance relative to its current
8055  * position in pixels.
8056  *
8057  * This function modifies the fixed position of an actor and thus removes
8058  * it from any layout management. Another way to move an actor is with an
8059  * anchor point, see clutter_actor_set_anchor_point().
8060  *
8061  * Since: 0.2
8062  */
8063 void
8064 clutter_actor_move_by (ClutterActor *self,
8065                        gfloat        dx,
8066                        gfloat        dy)
8067 {
8068   const ClutterLayoutInfo *info;
8069   gfloat x, y;
8070
8071   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8072
8073   info = _clutter_actor_get_layout_info_or_defaults (self);
8074   x = info->fixed_x;
8075   y = info->fixed_y;
8076
8077   clutter_actor_set_position (self, x + dx, y + dy);
8078 }
8079
8080 static void
8081 clutter_actor_set_min_width (ClutterActor *self,
8082                              gfloat        min_width)
8083 {
8084   ClutterActorPrivate *priv = self->priv;
8085   ClutterActorBox old = { 0, };
8086   ClutterLayoutInfo *info;
8087
8088   /* if we are setting the size on a top-level actor and the
8089    * backend only supports static top-levels (e.g. framebuffers)
8090    * then we ignore the passed value and we override it with
8091    * the stage implementation's preferred size.
8092    */
8093   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8094       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8095     return;
8096
8097   info = _clutter_actor_get_layout_info (self);
8098
8099   if (priv->min_width_set && min_width == info->min_width)
8100     return;
8101
8102   g_object_freeze_notify (G_OBJECT (self));
8103
8104   clutter_actor_store_old_geometry (self, &old);
8105
8106   info->min_width = min_width;
8107   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8108   clutter_actor_set_min_width_set (self, TRUE);
8109
8110   clutter_actor_notify_if_geometry_changed (self, &old);
8111
8112   g_object_thaw_notify (G_OBJECT (self));
8113
8114   clutter_actor_queue_relayout (self);
8115 }
8116
8117 static void
8118 clutter_actor_set_min_height (ClutterActor *self,
8119                               gfloat        min_height)
8120
8121 {
8122   ClutterActorPrivate *priv = self->priv;
8123   ClutterActorBox old = { 0, };
8124   ClutterLayoutInfo *info;
8125
8126   /* if we are setting the size on a top-level actor and the
8127    * backend only supports static top-levels (e.g. framebuffers)
8128    * then we ignore the passed value and we override it with
8129    * the stage implementation's preferred size.
8130    */
8131   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8132       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8133     return;
8134
8135   info = _clutter_actor_get_layout_info (self);
8136
8137   if (priv->min_height_set && min_height == info->min_height)
8138     return;
8139
8140   g_object_freeze_notify (G_OBJECT (self));
8141
8142   clutter_actor_store_old_geometry (self, &old);
8143
8144   info->min_height = min_height;
8145   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8146   clutter_actor_set_min_height_set (self, TRUE);
8147
8148   clutter_actor_notify_if_geometry_changed (self, &old);
8149
8150   g_object_thaw_notify (G_OBJECT (self));
8151
8152   clutter_actor_queue_relayout (self);
8153 }
8154
8155 static void
8156 clutter_actor_set_natural_width (ClutterActor *self,
8157                                  gfloat        natural_width)
8158 {
8159   ClutterActorPrivate *priv = self->priv;
8160   ClutterActorBox old = { 0, };
8161   ClutterLayoutInfo *info;
8162
8163   /* if we are setting the size on a top-level actor and the
8164    * backend only supports static top-levels (e.g. framebuffers)
8165    * then we ignore the passed value and we override it with
8166    * the stage implementation's preferred size.
8167    */
8168   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8169       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8170     return;
8171
8172   info = _clutter_actor_get_layout_info (self);
8173
8174   if (priv->natural_width_set && natural_width == info->natural_width)
8175     return;
8176
8177   g_object_freeze_notify (G_OBJECT (self));
8178
8179   clutter_actor_store_old_geometry (self, &old);
8180
8181   info->natural_width = natural_width;
8182   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8183   clutter_actor_set_natural_width_set (self, TRUE);
8184
8185   clutter_actor_notify_if_geometry_changed (self, &old);
8186
8187   g_object_thaw_notify (G_OBJECT (self));
8188
8189   clutter_actor_queue_relayout (self);
8190 }
8191
8192 static void
8193 clutter_actor_set_natural_height (ClutterActor *self,
8194                                   gfloat        natural_height)
8195 {
8196   ClutterActorPrivate *priv = self->priv;
8197   ClutterActorBox old = { 0, };
8198   ClutterLayoutInfo *info;
8199
8200   /* if we are setting the size on a top-level actor and the
8201    * backend only supports static top-levels (e.g. framebuffers)
8202    * then we ignore the passed value and we override it with
8203    * the stage implementation's preferred size.
8204    */
8205   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8206       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8207     return;
8208
8209   info = _clutter_actor_get_layout_info (self);
8210
8211   if (priv->natural_height_set && natural_height == info->natural_height)
8212     return;
8213
8214   g_object_freeze_notify (G_OBJECT (self));
8215
8216   clutter_actor_store_old_geometry (self, &old);
8217
8218   info->natural_height = natural_height;
8219   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8220   clutter_actor_set_natural_height_set (self, TRUE);
8221
8222   clutter_actor_notify_if_geometry_changed (self, &old);
8223
8224   g_object_thaw_notify (G_OBJECT (self));
8225
8226   clutter_actor_queue_relayout (self);
8227 }
8228
8229 static void
8230 clutter_actor_set_min_width_set (ClutterActor *self,
8231                                  gboolean      use_min_width)
8232 {
8233   ClutterActorPrivate *priv = self->priv;
8234   ClutterActorBox old = { 0, };
8235
8236   if (priv->min_width_set == (use_min_width != FALSE))
8237     return;
8238
8239   clutter_actor_store_old_geometry (self, &old);
8240
8241   priv->min_width_set = use_min_width != FALSE;
8242   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8243
8244   clutter_actor_notify_if_geometry_changed (self, &old);
8245
8246   clutter_actor_queue_relayout (self);
8247 }
8248
8249 static void
8250 clutter_actor_set_min_height_set (ClutterActor *self,
8251                                   gboolean      use_min_height)
8252 {
8253   ClutterActorPrivate *priv = self->priv;
8254   ClutterActorBox old = { 0, };
8255
8256   if (priv->min_height_set == (use_min_height != FALSE))
8257     return;
8258
8259   clutter_actor_store_old_geometry (self, &old);
8260
8261   priv->min_height_set = use_min_height != FALSE;
8262   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8263
8264   clutter_actor_notify_if_geometry_changed (self, &old);
8265
8266   clutter_actor_queue_relayout (self);
8267 }
8268
8269 static void
8270 clutter_actor_set_natural_width_set (ClutterActor *self,
8271                                      gboolean      use_natural_width)
8272 {
8273   ClutterActorPrivate *priv = self->priv;
8274   ClutterActorBox old = { 0, };
8275
8276   if (priv->natural_width_set == (use_natural_width != FALSE))
8277     return;
8278
8279   clutter_actor_store_old_geometry (self, &old);
8280
8281   priv->natural_width_set = use_natural_width != FALSE;
8282   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8283
8284   clutter_actor_notify_if_geometry_changed (self, &old);
8285
8286   clutter_actor_queue_relayout (self);
8287 }
8288
8289 static void
8290 clutter_actor_set_natural_height_set (ClutterActor *self,
8291                                       gboolean      use_natural_height)
8292 {
8293   ClutterActorPrivate *priv = self->priv;
8294   ClutterActorBox old = { 0, };
8295
8296   if (priv->natural_height_set == (use_natural_height != FALSE))
8297     return;
8298
8299   clutter_actor_store_old_geometry (self, &old);
8300
8301   priv->natural_height_set = use_natural_height != FALSE;
8302   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8303
8304   clutter_actor_notify_if_geometry_changed (self, &old);
8305
8306   clutter_actor_queue_relayout (self);
8307 }
8308
8309 /**
8310  * clutter_actor_set_request_mode:
8311  * @self: a #ClutterActor
8312  * @mode: the request mode
8313  *
8314  * Sets the geometry request mode of @self.
8315  *
8316  * The @mode determines the order for invoking
8317  * clutter_actor_get_preferred_width() and
8318  * clutter_actor_get_preferred_height()
8319  *
8320  * Since: 1.2
8321  */
8322 void
8323 clutter_actor_set_request_mode (ClutterActor       *self,
8324                                 ClutterRequestMode  mode)
8325 {
8326   ClutterActorPrivate *priv;
8327
8328   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8329
8330   priv = self->priv;
8331
8332   if (priv->request_mode == mode)
8333     return;
8334
8335   priv->request_mode = mode;
8336
8337   priv->needs_width_request = TRUE;
8338   priv->needs_height_request = TRUE;
8339
8340   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8341
8342   clutter_actor_queue_relayout (self);
8343 }
8344
8345 /**
8346  * clutter_actor_get_request_mode:
8347  * @self: a #ClutterActor
8348  *
8349  * Retrieves the geometry request mode of @self
8350  *
8351  * Return value: the request mode for the actor
8352  *
8353  * Since: 1.2
8354  */
8355 ClutterRequestMode
8356 clutter_actor_get_request_mode (ClutterActor *self)
8357 {
8358   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8359                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8360
8361   return self->priv->request_mode;
8362 }
8363
8364 /* variant of set_width() without checks and without notification
8365  * freeze+thaw, for internal usage only
8366  */
8367 static inline void
8368 clutter_actor_set_width_internal (ClutterActor *self,
8369                                   gfloat        width)
8370 {
8371   if (width >= 0)
8372     {
8373       /* the Stage will use the :min-width to control the minimum
8374        * width to be resized to, so we should not be setting it
8375        * along with the :natural-width
8376        */
8377       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8378         clutter_actor_set_min_width (self, width);
8379
8380       clutter_actor_set_natural_width (self, width);
8381     }
8382   else
8383     {
8384       /* we only unset the :natural-width for the Stage */
8385       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8386         clutter_actor_set_min_width_set (self, FALSE);
8387
8388       clutter_actor_set_natural_width_set (self, FALSE);
8389     }
8390 }
8391
8392 /* variant of set_height() without checks and without notification
8393  * freeze+thaw, for internal usage only
8394  */
8395 static inline void
8396 clutter_actor_set_height_internal (ClutterActor *self,
8397                                    gfloat        height)
8398 {
8399   if (height >= 0)
8400     {
8401       /* see the comment above in set_width_internal() */
8402       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8403         clutter_actor_set_min_height (self, height);
8404
8405       clutter_actor_set_natural_height (self, height);
8406     }
8407   else
8408     {
8409       /* see the comment above in set_width_internal() */
8410       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8411         clutter_actor_set_min_height_set (self, FALSE);
8412
8413       clutter_actor_set_natural_height_set (self, FALSE);
8414     }
8415 }
8416
8417 /**
8418  * clutter_actor_set_size:
8419  * @self: A #ClutterActor
8420  * @width: New width of actor in pixels, or -1
8421  * @height: New height of actor in pixels, or -1
8422  *
8423  * Sets the actor's size request in pixels. This overrides any
8424  * "normal" size request the actor would have. For example
8425  * a text actor might normally request the size of the text;
8426  * this function would force a specific size instead.
8427  *
8428  * If @width and/or @height are -1 the actor will use its
8429  * "normal" size request instead of overriding it, i.e.
8430  * you can "unset" the size with -1.
8431  *
8432  * This function sets or unsets both the minimum and natural size.
8433  */
8434 void
8435 clutter_actor_set_size (ClutterActor *self,
8436                         gfloat        width,
8437                         gfloat        height)
8438 {
8439   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8440
8441   g_object_freeze_notify (G_OBJECT (self));
8442
8443   clutter_actor_set_width_internal (self, width);
8444   clutter_actor_set_height_internal (self, height);
8445
8446   g_object_thaw_notify (G_OBJECT (self));
8447 }
8448
8449 /**
8450  * clutter_actor_get_size:
8451  * @self: A #ClutterActor
8452  * @width: (out) (allow-none): return location for the width, or %NULL.
8453  * @height: (out) (allow-none): return location for the height, or %NULL.
8454  *
8455  * This function tries to "do what you mean" and return
8456  * the size an actor will have. If the actor has a valid
8457  * allocation, the allocation will be returned; otherwise,
8458  * the actors natural size request will be returned.
8459  *
8460  * If you care whether you get the request vs. the allocation, you
8461  * should probably call a different function like
8462  * clutter_actor_get_allocation_box() or
8463  * clutter_actor_get_preferred_width().
8464  *
8465  * Since: 0.2
8466  */
8467 void
8468 clutter_actor_get_size (ClutterActor *self,
8469                         gfloat       *width,
8470                         gfloat       *height)
8471 {
8472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8473
8474   if (width)
8475     *width = clutter_actor_get_width (self);
8476
8477   if (height)
8478     *height = clutter_actor_get_height (self);
8479 }
8480
8481 /**
8482  * clutter_actor_get_position:
8483  * @self: a #ClutterActor
8484  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8485  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8486  *
8487  * This function tries to "do what you mean" and tell you where the
8488  * actor is, prior to any transformations. Retrieves the fixed
8489  * position of an actor in pixels, if one has been set; otherwise, if
8490  * the allocation is valid, returns the actor's allocated position;
8491  * otherwise, returns 0,0.
8492  *
8493  * The returned position is in pixels.
8494  *
8495  * Since: 0.6
8496  */
8497 void
8498 clutter_actor_get_position (ClutterActor *self,
8499                             gfloat       *x,
8500                             gfloat       *y)
8501 {
8502   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8503
8504   if (x)
8505     *x = clutter_actor_get_x (self);
8506
8507   if (y)
8508     *y = clutter_actor_get_y (self);
8509 }
8510
8511 /**
8512  * clutter_actor_get_transformed_position:
8513  * @self: A #ClutterActor
8514  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8515  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8516  *
8517  * Gets the absolute position of an actor, in pixels relative to the stage.
8518  *
8519  * Since: 0.8
8520  */
8521 void
8522 clutter_actor_get_transformed_position (ClutterActor *self,
8523                                         gfloat       *x,
8524                                         gfloat       *y)
8525 {
8526   ClutterVertex v1;
8527   ClutterVertex v2;
8528
8529   v1.x = v1.y = v1.z = 0;
8530   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8531
8532   if (x)
8533     *x = v2.x;
8534
8535   if (y)
8536     *y = v2.y;
8537 }
8538
8539 /**
8540  * clutter_actor_get_transformed_size:
8541  * @self: A #ClutterActor
8542  * @width: (out) (allow-none): return location for the width, or %NULL
8543  * @height: (out) (allow-none): return location for the height, or %NULL
8544  *
8545  * Gets the absolute size of an actor in pixels, taking into account the
8546  * scaling factors.
8547  *
8548  * If the actor has a valid allocation, the allocated size will be used.
8549  * If the actor has not a valid allocation then the preferred size will
8550  * be transformed and returned.
8551  *
8552  * If you want the transformed allocation, see
8553  * clutter_actor_get_abs_allocation_vertices() instead.
8554  *
8555  * <note>When the actor (or one of its ancestors) is rotated around the
8556  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8557  * as a generic quadrangle; in that case this function returns the size
8558  * of the smallest rectangle that encapsulates the entire quad. Please
8559  * note that in this case no assumptions can be made about the relative
8560  * position of this envelope to the absolute position of the actor, as
8561  * returned by clutter_actor_get_transformed_position(); if you need this
8562  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8563  * to get the coords of the actual quadrangle.</note>
8564  *
8565  * Since: 0.8
8566  */
8567 void
8568 clutter_actor_get_transformed_size (ClutterActor *self,
8569                                     gfloat       *width,
8570                                     gfloat       *height)
8571 {
8572   ClutterActorPrivate *priv;
8573   ClutterVertex v[4];
8574   gfloat x_min, x_max, y_min, y_max;
8575   gint i;
8576
8577   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8578
8579   priv = self->priv;
8580
8581   /* if the actor hasn't been allocated yet, get the preferred
8582    * size and transform that
8583    */
8584   if (priv->needs_allocation)
8585     {
8586       gfloat natural_width, natural_height;
8587       ClutterActorBox box;
8588
8589       /* Make a fake allocation to transform.
8590        *
8591        * NB: _clutter_actor_transform_and_project_box expects a box in
8592        * the actor's coordinate space... */
8593
8594       box.x1 = 0;
8595       box.y1 = 0;
8596
8597       natural_width = natural_height = 0;
8598       clutter_actor_get_preferred_size (self, NULL, NULL,
8599                                         &natural_width,
8600                                         &natural_height);
8601
8602       box.x2 = natural_width;
8603       box.y2 = natural_height;
8604
8605       _clutter_actor_transform_and_project_box (self, &box, v);
8606     }
8607   else
8608     clutter_actor_get_abs_allocation_vertices (self, v);
8609
8610   x_min = x_max = v[0].x;
8611   y_min = y_max = v[0].y;
8612
8613   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8614     {
8615       if (v[i].x < x_min)
8616         x_min = v[i].x;
8617
8618       if (v[i].x > x_max)
8619         x_max = v[i].x;
8620
8621       if (v[i].y < y_min)
8622         y_min = v[i].y;
8623
8624       if (v[i].y > y_max)
8625         y_max = v[i].y;
8626     }
8627
8628   if (width)
8629     *width  = x_max - x_min;
8630
8631   if (height)
8632     *height = y_max - y_min;
8633 }
8634
8635 /**
8636  * clutter_actor_get_width:
8637  * @self: A #ClutterActor
8638  *
8639  * Retrieves the width of a #ClutterActor.
8640  *
8641  * If the actor has a valid allocation, this function will return the
8642  * width of the allocated area given to the actor.
8643  *
8644  * If the actor does not have a valid allocation, this function will
8645  * return the actor's natural width, that is the preferred width of
8646  * the actor.
8647  *
8648  * If you care whether you get the preferred width or the width that
8649  * has been assigned to the actor, you should probably call a different
8650  * function like clutter_actor_get_allocation_box() to retrieve the
8651  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8652  * preferred width.
8653  *
8654  * If an actor has a fixed width, for instance a width that has been
8655  * assigned using clutter_actor_set_width(), the width returned will
8656  * be the same value.
8657  *
8658  * Return value: the width of the actor, in pixels
8659  */
8660 gfloat
8661 clutter_actor_get_width (ClutterActor *self)
8662 {
8663   ClutterActorPrivate *priv;
8664
8665   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8666
8667   priv = self->priv;
8668
8669   if (priv->needs_allocation)
8670     {
8671       gfloat natural_width = 0;
8672
8673       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8674         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8675       else
8676         {
8677           gfloat natural_height = 0;
8678
8679           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8680           clutter_actor_get_preferred_width (self, natural_height,
8681                                              NULL,
8682                                              &natural_width);
8683         }
8684
8685       return natural_width;
8686     }
8687   else
8688     return priv->allocation.x2 - priv->allocation.x1;
8689 }
8690
8691 /**
8692  * clutter_actor_get_height:
8693  * @self: A #ClutterActor
8694  *
8695  * Retrieves the height of a #ClutterActor.
8696  *
8697  * If the actor has a valid allocation, this function will return the
8698  * height of the allocated area given to the actor.
8699  *
8700  * If the actor does not have a valid allocation, this function will
8701  * return the actor's natural height, that is the preferred height of
8702  * the actor.
8703  *
8704  * If you care whether you get the preferred height or the height that
8705  * has been assigned to the actor, you should probably call a different
8706  * function like clutter_actor_get_allocation_box() to retrieve the
8707  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8708  * preferred height.
8709  *
8710  * If an actor has a fixed height, for instance a height that has been
8711  * assigned using clutter_actor_set_height(), the height returned will
8712  * be the same value.
8713  *
8714  * Return value: the height of the actor, in pixels
8715  */
8716 gfloat
8717 clutter_actor_get_height (ClutterActor *self)
8718 {
8719   ClutterActorPrivate *priv;
8720
8721   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8722
8723   priv = self->priv;
8724
8725   if (priv->needs_allocation)
8726     {
8727       gfloat natural_height = 0;
8728
8729       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8730         {
8731           gfloat natural_width = 0;
8732
8733           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8734           clutter_actor_get_preferred_height (self, natural_width,
8735                                               NULL, &natural_height);
8736         }
8737       else
8738         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8739
8740       return natural_height;
8741     }
8742   else
8743     return priv->allocation.y2 - priv->allocation.y1;
8744 }
8745
8746 /**
8747  * clutter_actor_set_width:
8748  * @self: A #ClutterActor
8749  * @width: Requested new width for the actor, in pixels, or -1
8750  *
8751  * Forces a width on an actor, causing the actor's preferred width
8752  * and height (if any) to be ignored.
8753  *
8754  * If @width is -1 the actor will use its preferred width request
8755  * instead of overriding it, i.e. you can "unset" the width with -1.
8756  *
8757  * This function sets both the minimum and natural size of the actor.
8758  *
8759  * since: 0.2
8760  */
8761 void
8762 clutter_actor_set_width (ClutterActor *self,
8763                          gfloat        width)
8764 {
8765   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8766
8767   g_object_freeze_notify (G_OBJECT (self));
8768
8769   clutter_actor_set_width_internal (self, width);
8770
8771   g_object_thaw_notify (G_OBJECT (self));
8772 }
8773
8774 /**
8775  * clutter_actor_set_height:
8776  * @self: A #ClutterActor
8777  * @height: Requested new height for the actor, in pixels, or -1
8778  *
8779  * Forces a height on an actor, causing the actor's preferred width
8780  * and height (if any) to be ignored.
8781  *
8782  * If @height is -1 the actor will use its preferred height instead of
8783  * overriding it, i.e. you can "unset" the height with -1.
8784  *
8785  * This function sets both the minimum and natural size of the actor.
8786  *
8787  * since: 0.2
8788  */
8789 void
8790 clutter_actor_set_height (ClutterActor *self,
8791                           gfloat        height)
8792 {
8793   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8794
8795   g_object_freeze_notify (G_OBJECT (self));
8796
8797   clutter_actor_set_height_internal (self, height);
8798
8799   g_object_thaw_notify (G_OBJECT (self));
8800 }
8801
8802 /**
8803  * clutter_actor_set_x:
8804  * @self: a #ClutterActor
8805  * @x: the actor's position on the X axis
8806  *
8807  * Sets the actor's X coordinate, relative to its parent, in pixels.
8808  *
8809  * Overrides any layout manager and forces a fixed position for
8810  * the actor.
8811  *
8812  * Since: 0.6
8813  */
8814 void
8815 clutter_actor_set_x (ClutterActor *self,
8816                      gfloat        x)
8817 {
8818   ClutterActorBox old = { 0, };
8819   ClutterActorPrivate *priv;
8820   ClutterLayoutInfo *info;
8821
8822   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8823
8824   priv = self->priv;
8825
8826   info = _clutter_actor_get_layout_info (self);
8827
8828   if (priv->position_set && info->fixed_x == x)
8829     return;
8830
8831   clutter_actor_store_old_geometry (self, &old);
8832
8833   info->fixed_x = x;
8834   clutter_actor_set_fixed_position_set (self, TRUE);
8835
8836   clutter_actor_notify_if_geometry_changed (self, &old);
8837
8838   clutter_actor_queue_relayout (self);
8839 }
8840
8841 /**
8842  * clutter_actor_set_y:
8843  * @self: a #ClutterActor
8844  * @y: the actor's position on the Y axis
8845  *
8846  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8847  *
8848  * Overrides any layout manager and forces a fixed position for
8849  * the actor.
8850  *
8851  * Since: 0.6
8852  */
8853 void
8854 clutter_actor_set_y (ClutterActor *self,
8855                      gfloat        y)
8856 {
8857   ClutterActorBox old = { 0, };
8858   ClutterActorPrivate *priv;
8859   ClutterLayoutInfo *info;
8860
8861   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8862
8863   priv = self->priv;
8864
8865   info = _clutter_actor_get_layout_info (self);
8866
8867   if (priv->position_set && info->fixed_y == y)
8868     return;
8869
8870   clutter_actor_store_old_geometry (self, &old);
8871
8872   info->fixed_y = y;
8873   clutter_actor_set_fixed_position_set (self, TRUE);
8874
8875   clutter_actor_notify_if_geometry_changed (self, &old);
8876
8877   clutter_actor_queue_relayout (self);
8878 }
8879
8880 /**
8881  * clutter_actor_get_x:
8882  * @self: A #ClutterActor
8883  *
8884  * Retrieves the X coordinate of a #ClutterActor.
8885  *
8886  * This function tries to "do what you mean", by returning the
8887  * correct value depending on the actor's state.
8888  *
8889  * If the actor has a valid allocation, this function will return
8890  * the X coordinate of the origin of the allocation box.
8891  *
8892  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8893  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8894  * function will return that coordinate.
8895  *
8896  * If both the allocation and a fixed position are missing, this function
8897  * will return 0.
8898  *
8899  * Return value: the X coordinate, in pixels, ignoring any
8900  *   transformation (i.e. scaling, rotation)
8901  */
8902 gfloat
8903 clutter_actor_get_x (ClutterActor *self)
8904 {
8905   ClutterActorPrivate *priv;
8906
8907   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8908
8909   priv = self->priv;
8910
8911   if (priv->needs_allocation)
8912     {
8913       if (priv->position_set)
8914         {
8915           const ClutterLayoutInfo *info;
8916
8917           info = _clutter_actor_get_layout_info_or_defaults (self);
8918
8919           return info->fixed_x;
8920         }
8921       else
8922         return 0;
8923     }
8924   else
8925     return priv->allocation.x1;
8926 }
8927
8928 /**
8929  * clutter_actor_get_y:
8930  * @self: A #ClutterActor
8931  *
8932  * Retrieves the Y coordinate of a #ClutterActor.
8933  *
8934  * This function tries to "do what you mean", by returning the
8935  * correct value depending on the actor's state.
8936  *
8937  * If the actor has a valid allocation, this function will return
8938  * the Y coordinate of the origin of the allocation box.
8939  *
8940  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
8941  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8942  * function will return that coordinate.
8943  *
8944  * If both the allocation and a fixed position are missing, this function
8945  * will return 0.
8946  *
8947  * Return value: the Y coordinate, in pixels, ignoring any
8948  *   transformation (i.e. scaling, rotation)
8949  */
8950 gfloat
8951 clutter_actor_get_y (ClutterActor *self)
8952 {
8953   ClutterActorPrivate *priv;
8954
8955   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8956
8957   priv = self->priv;
8958
8959   if (priv->needs_allocation)
8960     {
8961       if (priv->position_set)
8962         {
8963           const ClutterLayoutInfo *info;
8964
8965           info = _clutter_actor_get_layout_info_or_defaults (self);
8966
8967           return info->fixed_y;
8968         }
8969       else
8970         return 0;
8971     }
8972   else
8973     return priv->allocation.y1;
8974 }
8975
8976 /**
8977  * clutter_actor_set_scale:
8978  * @self: A #ClutterActor
8979  * @scale_x: double factor to scale actor by horizontally.
8980  * @scale_y: double factor to scale actor by vertically.
8981  *
8982  * Scales an actor with the given factors. The scaling is relative to
8983  * the scale center and the anchor point. The scale center is
8984  * unchanged by this function and defaults to 0,0.
8985  *
8986  * Since: 0.2
8987  */
8988 void
8989 clutter_actor_set_scale (ClutterActor *self,
8990                          gdouble       scale_x,
8991                          gdouble       scale_y)
8992 {
8993   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8994
8995   g_object_freeze_notify (G_OBJECT (self));
8996
8997   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
8998   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
8999
9000   g_object_thaw_notify (G_OBJECT (self));
9001 }
9002
9003 /**
9004  * clutter_actor_set_scale_full:
9005  * @self: A #ClutterActor
9006  * @scale_x: double factor to scale actor by horizontally.
9007  * @scale_y: double factor to scale actor by vertically.
9008  * @center_x: X coordinate of the center of the scale.
9009  * @center_y: Y coordinate of the center of the scale
9010  *
9011  * Scales an actor with the given factors around the given center
9012  * point. The center point is specified in pixels relative to the
9013  * anchor point (usually the top left corner of the actor).
9014  *
9015  * Since: 1.0
9016  */
9017 void
9018 clutter_actor_set_scale_full (ClutterActor *self,
9019                               gdouble       scale_x,
9020                               gdouble       scale_y,
9021                               gfloat        center_x,
9022                               gfloat        center_y)
9023 {
9024   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9025
9026   g_object_freeze_notify (G_OBJECT (self));
9027
9028   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9029   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9030   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9031   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9032
9033   g_object_thaw_notify (G_OBJECT (self));
9034 }
9035
9036 /**
9037  * clutter_actor_set_scale_with_gravity:
9038  * @self: A #ClutterActor
9039  * @scale_x: double factor to scale actor by horizontally.
9040  * @scale_y: double factor to scale actor by vertically.
9041  * @gravity: the location of the scale center expressed as a compass
9042  * direction.
9043  *
9044  * Scales an actor with the given factors around the given
9045  * center point. The center point is specified as one of the compass
9046  * directions in #ClutterGravity. For example, setting it to north
9047  * will cause the top of the actor to remain unchanged and the rest of
9048  * the actor to expand left, right and downwards.
9049  *
9050  * Since: 1.0
9051  */
9052 void
9053 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9054                                       gdouble         scale_x,
9055                                       gdouble         scale_y,
9056                                       ClutterGravity  gravity)
9057 {
9058   ClutterTransformInfo *info;
9059   GObject *obj;
9060
9061   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9062
9063   obj = G_OBJECT (self);
9064
9065   g_object_freeze_notify (obj);
9066
9067   info = _clutter_actor_get_transform_info (self);
9068   info->scale_x = scale_x;
9069   info->scale_y = scale_y;
9070
9071   if (gravity == CLUTTER_GRAVITY_NONE)
9072     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9073   else
9074     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9075
9076   self->priv->transform_valid = FALSE;
9077
9078   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9079   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9080   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9081   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9082   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9083
9084   clutter_actor_queue_redraw (self);
9085
9086   g_object_thaw_notify (obj);
9087 }
9088
9089 /**
9090  * clutter_actor_get_scale:
9091  * @self: A #ClutterActor
9092  * @scale_x: (out) (allow-none): Location to store horizonal
9093  *   scale factor, or %NULL.
9094  * @scale_y: (out) (allow-none): Location to store vertical
9095  *   scale factor, or %NULL.
9096  *
9097  * Retrieves an actors scale factors.
9098  *
9099  * Since: 0.2
9100  */
9101 void
9102 clutter_actor_get_scale (ClutterActor *self,
9103                          gdouble      *scale_x,
9104                          gdouble      *scale_y)
9105 {
9106   const ClutterTransformInfo *info;
9107
9108   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9109
9110   info = _clutter_actor_get_transform_info_or_defaults (self);
9111
9112   if (scale_x)
9113     *scale_x = info->scale_x;
9114
9115   if (scale_y)
9116     *scale_y = info->scale_y;
9117 }
9118
9119 /**
9120  * clutter_actor_get_scale_center:
9121  * @self: A #ClutterActor
9122  * @center_x: (out) (allow-none): Location to store the X position
9123  *   of the scale center, or %NULL.
9124  * @center_y: (out) (allow-none): Location to store the Y position
9125  *   of the scale center, or %NULL.
9126  *
9127  * Retrieves the scale center coordinate in pixels relative to the top
9128  * left corner of the actor. If the scale center was specified using a
9129  * #ClutterGravity this will calculate the pixel offset using the
9130  * current size of the actor.
9131  *
9132  * Since: 1.0
9133  */
9134 void
9135 clutter_actor_get_scale_center (ClutterActor *self,
9136                                 gfloat       *center_x,
9137                                 gfloat       *center_y)
9138 {
9139   const ClutterTransformInfo *info;
9140
9141   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9142
9143   info = _clutter_actor_get_transform_info_or_defaults (self);
9144
9145   clutter_anchor_coord_get_units (self, &info->scale_center,
9146                                   center_x,
9147                                   center_y,
9148                                   NULL);
9149 }
9150
9151 /**
9152  * clutter_actor_get_scale_gravity:
9153  * @self: A #ClutterActor
9154  *
9155  * Retrieves the scale center as a compass direction. If the scale
9156  * center was specified in pixels or units this will return
9157  * %CLUTTER_GRAVITY_NONE.
9158  *
9159  * Return value: the scale gravity
9160  *
9161  * Since: 1.0
9162  */
9163 ClutterGravity
9164 clutter_actor_get_scale_gravity (ClutterActor *self)
9165 {
9166   const ClutterTransformInfo *info;
9167
9168   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9169
9170   info = _clutter_actor_get_transform_info_or_defaults (self);
9171
9172   return clutter_anchor_coord_get_gravity (&info->scale_center);
9173 }
9174
9175 /**
9176  * clutter_actor_set_opacity:
9177  * @self: A #ClutterActor
9178  * @opacity: New opacity value for the actor.
9179  *
9180  * Sets the actor's opacity, with zero being completely transparent and
9181  * 255 (0xff) being fully opaque.
9182  */
9183 void
9184 clutter_actor_set_opacity (ClutterActor *self,
9185                            guint8        opacity)
9186 {
9187   ClutterActorPrivate *priv;
9188
9189   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9190
9191   priv = self->priv;
9192
9193   if (priv->opacity != opacity)
9194     {
9195       priv->opacity = opacity;
9196
9197       /* Queue a redraw from the flatten effect so that it can use
9198          its cached image if available instead of having to redraw the
9199          actual actor. If it doesn't end up using the FBO then the
9200          effect is still able to continue the paint anyway. If there
9201          is no flatten effect yet then this is equivalent to queueing
9202          a full redraw */
9203       _clutter_actor_queue_redraw_full (self,
9204                                         0, /* flags */
9205                                         NULL, /* clip */
9206                                         priv->flatten_effect);
9207
9208       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9209     }
9210 }
9211
9212 /*
9213  * clutter_actor_get_paint_opacity_internal:
9214  * @self: a #ClutterActor
9215  *
9216  * Retrieves the absolute opacity of the actor, as it appears on the stage
9217  *
9218  * This function does not do type checks
9219  *
9220  * Return value: the absolute opacity of the actor
9221  */
9222 static guint8
9223 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9224 {
9225   ClutterActorPrivate *priv = self->priv;
9226   ClutterActor *parent;
9227
9228   /* override the top-level opacity to always be 255; even in
9229    * case of ClutterStage:use-alpha being TRUE we want the rest
9230    * of the scene to be painted
9231    */
9232   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9233     return 255;
9234
9235   if (priv->opacity_override >= 0)
9236     return priv->opacity_override;
9237
9238   parent = priv->parent;
9239
9240   /* Factor in the actual actors opacity with parents */
9241   if (parent != NULL)
9242     {
9243       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9244
9245       if (opacity != 0xff)
9246         return (opacity * priv->opacity) / 0xff;
9247     }
9248
9249   return priv->opacity;
9250
9251 }
9252
9253 /**
9254  * clutter_actor_get_paint_opacity:
9255  * @self: A #ClutterActor
9256  *
9257  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9258  *
9259  * This function traverses the hierarchy chain and composites the opacity of
9260  * the actor with that of its parents.
9261  *
9262  * This function is intended for subclasses to use in the paint virtual
9263  * function, to paint themselves with the correct opacity.
9264  *
9265  * Return value: The actor opacity value.
9266  *
9267  * Since: 0.8
9268  */
9269 guint8
9270 clutter_actor_get_paint_opacity (ClutterActor *self)
9271 {
9272   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9273
9274   return clutter_actor_get_paint_opacity_internal (self);
9275 }
9276
9277 /**
9278  * clutter_actor_get_opacity:
9279  * @self: a #ClutterActor
9280  *
9281  * Retrieves the opacity value of an actor, as set by
9282  * clutter_actor_set_opacity().
9283  *
9284  * For retrieving the absolute opacity of the actor inside a paint
9285  * virtual function, see clutter_actor_get_paint_opacity().
9286  *
9287  * Return value: the opacity of the actor
9288  */
9289 guint8
9290 clutter_actor_get_opacity (ClutterActor *self)
9291 {
9292   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9293
9294   return self->priv->opacity;
9295 }
9296
9297 /**
9298  * clutter_actor_set_offscreen_redirect:
9299  * @self: A #ClutterActor
9300  * @redirect: New offscreen redirect flags for the actor.
9301  *
9302  * Defines the circumstances where the actor should be redirected into
9303  * an offscreen image. The offscreen image is used to flatten the
9304  * actor into a single image while painting for two main reasons.
9305  * Firstly, when the actor is painted a second time without any of its
9306  * contents changing it can simply repaint the cached image without
9307  * descending further down the actor hierarchy. Secondly, it will make
9308  * the opacity look correct even if there are overlapping primitives
9309  * in the actor.
9310  *
9311  * Caching the actor could in some cases be a performance win and in
9312  * some cases be a performance lose so it is important to determine
9313  * which value is right for an actor before modifying this value. For
9314  * example, there is never any reason to flatten an actor that is just
9315  * a single texture (such as a #ClutterTexture) because it is
9316  * effectively already cached in an image so the offscreen would be
9317  * redundant. Also if the actor contains primitives that are far apart
9318  * with a large transparent area in the middle (such as a large
9319  * CluterGroup with a small actor in the top left and a small actor in
9320  * the bottom right) then the cached image will contain the entire
9321  * image of the large area and the paint will waste time blending all
9322  * of the transparent pixels in the middle.
9323  *
9324  * The default method of implementing opacity on a container simply
9325  * forwards on the opacity to all of the children. If the children are
9326  * overlapping then it will appear as if they are two separate glassy
9327  * objects and there will be a break in the color where they
9328  * overlap. By redirecting to an offscreen buffer it will be as if the
9329  * two opaque objects are combined into one and then made transparent
9330  * which is usually what is expected.
9331  *
9332  * The image below demonstrates the difference between redirecting and
9333  * not. The image shows two Clutter groups, each containing a red and
9334  * a green rectangle which overlap. The opacity on the group is set to
9335  * 128 (which is 50%). When the offscreen redirect is not used, the
9336  * red rectangle can be seen through the blue rectangle as if the two
9337  * rectangles were separately transparent. When the redirect is used
9338  * the group as a whole is transparent instead so the red rectangle is
9339  * not visible where they overlap.
9340  *
9341  * <figure id="offscreen-redirect">
9342  *   <title>Sample of using an offscreen redirect for transparency</title>
9343  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9344  * </figure>
9345  *
9346  * The default value for this property is 0, so we effectively will
9347  * never redirect an actor offscreen by default. This means that there
9348  * are times that transparent actors may look glassy as described
9349  * above. The reason this is the default is because there is a
9350  * performance trade off between quality and performance here. In many
9351  * cases the default form of glassy opacity looks good enough, but if
9352  * it's not you will need to set the
9353  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9354  * redirection for opacity.
9355  *
9356  * Custom actors that don't contain any overlapping primitives are
9357  * recommended to override the has_overlaps() virtual to return %FALSE
9358  * for maximum efficiency.
9359  *
9360  * Since: 1.8
9361  */
9362 void
9363 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9364                                       ClutterOffscreenRedirect redirect)
9365 {
9366   ClutterActorPrivate *priv;
9367
9368   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9369
9370   priv = self->priv;
9371
9372   if (priv->offscreen_redirect != redirect)
9373     {
9374       priv->offscreen_redirect = redirect;
9375
9376       /* Queue a redraw from the effect so that it can use its cached
9377          image if available instead of having to redraw the actual
9378          actor. If it doesn't end up using the FBO then the effect is
9379          still able to continue the paint anyway. If there is no
9380          effect then this is equivalent to queuing a full redraw */
9381       _clutter_actor_queue_redraw_full (self,
9382                                         0, /* flags */
9383                                         NULL, /* clip */
9384                                         priv->flatten_effect);
9385
9386       g_object_notify_by_pspec (G_OBJECT (self),
9387                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9388     }
9389 }
9390
9391 /**
9392  * clutter_actor_get_offscreen_redirect:
9393  * @self: a #ClutterActor
9394  *
9395  * Retrieves whether to redirect the actor to an offscreen buffer, as
9396  * set by clutter_actor_set_offscreen_redirect().
9397  *
9398  * Return value: the value of the offscreen-redirect property of the actor
9399  *
9400  * Since: 1.8
9401  */
9402 ClutterOffscreenRedirect
9403 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9404 {
9405   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9406
9407   return self->priv->offscreen_redirect;
9408 }
9409
9410 /**
9411  * clutter_actor_set_name:
9412  * @self: A #ClutterActor
9413  * @name: Textual tag to apply to actor
9414  *
9415  * Sets the given name to @self. The name can be used to identify
9416  * a #ClutterActor.
9417  */
9418 void
9419 clutter_actor_set_name (ClutterActor *self,
9420                         const gchar  *name)
9421 {
9422   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9423
9424   g_free (self->priv->name);
9425   self->priv->name = g_strdup (name);
9426
9427   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9428 }
9429
9430 /**
9431  * clutter_actor_get_name:
9432  * @self: A #ClutterActor
9433  *
9434  * Retrieves the name of @self.
9435  *
9436  * Return value: the name of the actor, or %NULL. The returned string is
9437  *   owned by the actor and should not be modified or freed.
9438  */
9439 const gchar *
9440 clutter_actor_get_name (ClutterActor *self)
9441 {
9442   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9443
9444   return self->priv->name;
9445 }
9446
9447 /**
9448  * clutter_actor_get_gid:
9449  * @self: A #ClutterActor
9450  *
9451  * Retrieves the unique id for @self.
9452  *
9453  * Return value: Globally unique value for this object instance.
9454  *
9455  * Since: 0.6
9456  *
9457  * Deprecated: 1.8: The id is not used any longer.
9458  */
9459 guint32
9460 clutter_actor_get_gid (ClutterActor *self)
9461 {
9462   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9463
9464   return self->priv->id;
9465 }
9466
9467 /**
9468  * clutter_actor_set_depth:
9469  * @self: a #ClutterActor
9470  * @depth: Z co-ord
9471  *
9472  * Sets the Z coordinate of @self to @depth.
9473  *
9474  * The unit used by @depth is dependant on the perspective setup. See
9475  * also clutter_stage_set_perspective().
9476  */
9477 void
9478 clutter_actor_set_depth (ClutterActor *self,
9479                          gfloat        depth)
9480 {
9481   ClutterActorPrivate *priv;
9482
9483   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9484
9485   priv = self->priv;
9486
9487   if (priv->z != depth)
9488     {
9489       /* Sets Z value - XXX 2.0: should we invert? */
9490       priv->z = depth;
9491
9492       priv->transform_valid = FALSE;
9493
9494       /* FIXME - remove this crap; sadly, there are still containers
9495        * in Clutter that depend on this utter brain damage
9496        */
9497       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9498
9499       clutter_actor_queue_redraw (self);
9500
9501       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9502     }
9503 }
9504
9505 /**
9506  * clutter_actor_get_depth:
9507  * @self: a #ClutterActor
9508  *
9509  * Retrieves the depth of @self.
9510  *
9511  * Return value: the depth of the actor
9512  */
9513 gfloat
9514 clutter_actor_get_depth (ClutterActor *self)
9515 {
9516   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9517
9518   return self->priv->z;
9519 }
9520
9521 /**
9522  * clutter_actor_set_rotation:
9523  * @self: a #ClutterActor
9524  * @axis: the axis of rotation
9525  * @angle: the angle of rotation
9526  * @x: X coordinate of the rotation center
9527  * @y: Y coordinate of the rotation center
9528  * @z: Z coordinate of the rotation center
9529  *
9530  * Sets the rotation angle of @self around the given axis.
9531  *
9532  * The rotation center coordinates used depend on the value of @axis:
9533  * <itemizedlist>
9534  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9535  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9536  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9537  * </itemizedlist>
9538  *
9539  * The rotation coordinates are relative to the anchor point of the
9540  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9541  * point is set, the upper left corner is assumed as the origin.
9542  *
9543  * Since: 0.8
9544  */
9545 void
9546 clutter_actor_set_rotation (ClutterActor      *self,
9547                             ClutterRotateAxis  axis,
9548                             gdouble            angle,
9549                             gfloat             x,
9550                             gfloat             y,
9551                             gfloat             z)
9552 {
9553   ClutterVertex v;
9554
9555   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9556
9557   v.x = x;
9558   v.y = y;
9559   v.z = z;
9560
9561   g_object_freeze_notify (G_OBJECT (self));
9562
9563   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9564   clutter_actor_set_rotation_center_internal (self, axis, &v);
9565
9566   g_object_thaw_notify (G_OBJECT (self));
9567 }
9568
9569 /**
9570  * clutter_actor_set_z_rotation_from_gravity:
9571  * @self: a #ClutterActor
9572  * @angle: the angle of rotation
9573  * @gravity: the center point of the rotation
9574  *
9575  * Sets the rotation angle of @self around the Z axis using the center
9576  * point specified as a compass point. For example to rotate such that
9577  * the center of the actor remains static you can use
9578  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9579  * will move accordingly.
9580  *
9581  * Since: 1.0
9582  */
9583 void
9584 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9585                                            gdouble         angle,
9586                                            ClutterGravity  gravity)
9587 {
9588   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9589
9590   if (gravity == CLUTTER_GRAVITY_NONE)
9591     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9592   else
9593     {
9594       GObject *obj = G_OBJECT (self);
9595       ClutterTransformInfo *info;
9596
9597       info = _clutter_actor_get_transform_info (self);
9598
9599       g_object_freeze_notify (obj);
9600
9601       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9602
9603       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9604       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9605       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9606
9607       g_object_thaw_notify (obj);
9608     }
9609 }
9610
9611 /**
9612  * clutter_actor_get_rotation:
9613  * @self: a #ClutterActor
9614  * @axis: the axis of rotation
9615  * @x: (out): return value for the X coordinate of the center of rotation
9616  * @y: (out): return value for the Y coordinate of the center of rotation
9617  * @z: (out): return value for the Z coordinate of the center of rotation
9618  *
9619  * Retrieves the angle and center of rotation on the given axis,
9620  * set using clutter_actor_set_rotation().
9621  *
9622  * Return value: the angle of rotation
9623  *
9624  * Since: 0.8
9625  */
9626 gdouble
9627 clutter_actor_get_rotation (ClutterActor      *self,
9628                             ClutterRotateAxis  axis,
9629                             gfloat            *x,
9630                             gfloat            *y,
9631                             gfloat            *z)
9632 {
9633   const ClutterTransformInfo *info;
9634   const AnchorCoord *anchor_coord;
9635   gdouble retval = 0;
9636
9637   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9638
9639   info = _clutter_actor_get_transform_info_or_defaults (self);
9640
9641   switch (axis)
9642     {
9643     case CLUTTER_X_AXIS:
9644       anchor_coord = &info->rx_center;
9645       retval = info->rx_angle;
9646       break;
9647
9648     case CLUTTER_Y_AXIS:
9649       anchor_coord = &info->ry_center;
9650       retval = info->ry_angle;
9651       break;
9652
9653     case CLUTTER_Z_AXIS:
9654       anchor_coord = &info->rz_center;
9655       retval = info->rz_angle;
9656       break;
9657
9658     default:
9659       anchor_coord = NULL;
9660       retval = 0.0;
9661       break;
9662     }
9663
9664   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9665
9666   return retval;
9667 }
9668
9669 /**
9670  * clutter_actor_get_z_rotation_gravity:
9671  * @self: A #ClutterActor
9672  *
9673  * Retrieves the center for the rotation around the Z axis as a
9674  * compass direction. If the center was specified in pixels or units
9675  * this will return %CLUTTER_GRAVITY_NONE.
9676  *
9677  * Return value: the Z rotation center
9678  *
9679  * Since: 1.0
9680  */
9681 ClutterGravity
9682 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9683 {
9684   const ClutterTransformInfo *info;
9685
9686   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9687
9688   info = _clutter_actor_get_transform_info_or_defaults (self);
9689
9690   return clutter_anchor_coord_get_gravity (&info->rz_center);
9691 }
9692
9693 /**
9694  * clutter_actor_set_clip:
9695  * @self: A #ClutterActor
9696  * @xoff: X offset of the clip rectangle
9697  * @yoff: Y offset of the clip rectangle
9698  * @width: Width of the clip rectangle
9699  * @height: Height of the clip rectangle
9700  *
9701  * Sets clip area for @self. The clip area is always computed from the
9702  * upper left corner of the actor, even if the anchor point is set
9703  * otherwise.
9704  *
9705  * Since: 0.6
9706  */
9707 void
9708 clutter_actor_set_clip (ClutterActor *self,
9709                         gfloat        xoff,
9710                         gfloat        yoff,
9711                         gfloat        width,
9712                         gfloat        height)
9713 {
9714   ClutterActorPrivate *priv;
9715
9716   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9717
9718   priv = self->priv;
9719
9720   if (priv->has_clip &&
9721       priv->clip.x == xoff &&
9722       priv->clip.y == yoff &&
9723       priv->clip.width == width &&
9724       priv->clip.height == height)
9725     return;
9726
9727   priv->clip.x = xoff;
9728   priv->clip.y = yoff;
9729   priv->clip.width = width;
9730   priv->clip.height = height;
9731
9732   priv->has_clip = TRUE;
9733
9734   clutter_actor_queue_redraw (self);
9735
9736   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9737   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9738 }
9739
9740 /**
9741  * clutter_actor_remove_clip:
9742  * @self: A #ClutterActor
9743  *
9744  * Removes clip area from @self.
9745  */
9746 void
9747 clutter_actor_remove_clip (ClutterActor *self)
9748 {
9749   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9750
9751   if (!self->priv->has_clip)
9752     return;
9753
9754   self->priv->has_clip = FALSE;
9755
9756   clutter_actor_queue_redraw (self);
9757
9758   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9759 }
9760
9761 /**
9762  * clutter_actor_has_clip:
9763  * @self: a #ClutterActor
9764  *
9765  * Determines whether the actor has a clip area set or not.
9766  *
9767  * Return value: %TRUE if the actor has a clip area set.
9768  *
9769  * Since: 0.1.1
9770  */
9771 gboolean
9772 clutter_actor_has_clip (ClutterActor *self)
9773 {
9774   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9775
9776   return self->priv->has_clip;
9777 }
9778
9779 /**
9780  * clutter_actor_get_clip:
9781  * @self: a #ClutterActor
9782  * @xoff: (out) (allow-none): return location for the X offset of
9783  *   the clip rectangle, or %NULL
9784  * @yoff: (out) (allow-none): return location for the Y offset of
9785  *   the clip rectangle, or %NULL
9786  * @width: (out) (allow-none): return location for the width of
9787  *   the clip rectangle, or %NULL
9788  * @height: (out) (allow-none): return location for the height of
9789  *   the clip rectangle, or %NULL
9790  *
9791  * Gets the clip area for @self, if any is set
9792  *
9793  * Since: 0.6
9794  */
9795 void
9796 clutter_actor_get_clip (ClutterActor *self,
9797                         gfloat       *xoff,
9798                         gfloat       *yoff,
9799                         gfloat       *width,
9800                         gfloat       *height)
9801 {
9802   ClutterActorPrivate *priv;
9803
9804   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9805
9806   priv = self->priv;
9807
9808   if (!priv->has_clip)
9809     return;
9810
9811   if (xoff != NULL)
9812     *xoff = priv->clip.x;
9813
9814   if (yoff != NULL)
9815     *yoff = priv->clip.y;
9816
9817   if (width != NULL)
9818     *width = priv->clip.width;
9819
9820   if (height != NULL)
9821     *height = priv->clip.height;
9822 }
9823
9824 /**
9825  * clutter_actor_get_children:
9826  * @self: a #ClutterActor
9827  *
9828  * Retrieves the list of children of @self.
9829  *
9830  * Return value: (transfer container) (element-type ClutterActor): A newly
9831  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9832  *   done.
9833  *
9834  * Since: 1.10
9835  */
9836 GList *
9837 clutter_actor_get_children (ClutterActor *self)
9838 {
9839   ClutterActor *iter;
9840   GList *res;
9841
9842   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9843
9844   /* we walk the list backward so that we can use prepend(),
9845    * which is O(1)
9846    */
9847   for (iter = self->priv->last_child, res = NULL;
9848        iter != NULL;
9849        iter = iter->priv->prev_sibling)
9850     {
9851       res = g_list_prepend (res, iter);
9852     }
9853
9854   return res;
9855 }
9856
9857 /*< private >
9858  * insert_child_at_depth:
9859  * @self: a #ClutterActor
9860  * @child: a #ClutterActor
9861  *
9862  * Inserts @child inside the list of children held by @self, using
9863  * the depth as the insertion criteria.
9864  *
9865  * This sadly makes the insertion not O(1), but we can keep the
9866  * list sorted so that the painters algorithm we use for painting
9867  * the children will work correctly.
9868  */
9869 static void
9870 insert_child_at_depth (ClutterActor *self,
9871                        ClutterActor *child,
9872                        gpointer      dummy G_GNUC_UNUSED)
9873 {
9874   ClutterActor *iter;
9875
9876   child->priv->parent = self;
9877
9878   /* special-case the first child */
9879   if (self->priv->n_children == 0)
9880     {
9881       self->priv->first_child = child;
9882       self->priv->last_child = child;
9883
9884       child->priv->next_sibling = NULL;
9885       child->priv->prev_sibling = NULL;
9886
9887       return;
9888     }
9889
9890   /* Find the right place to insert the child so that it will still be
9891      sorted and the child will be after all of the actors at the same
9892      dept */
9893   for (iter = self->priv->first_child;
9894        iter != NULL;
9895        iter = iter->priv->next_sibling)
9896     {
9897       if (iter->priv->z > child->priv->z)
9898         break;
9899     }
9900
9901   if (iter != NULL)
9902     {
9903       ClutterActor *tmp = iter->priv->prev_sibling;
9904
9905       if (tmp != NULL)
9906         tmp->priv->next_sibling = child;
9907
9908       /* Insert the node before the found one */
9909       child->priv->prev_sibling = iter->priv->prev_sibling;
9910       child->priv->next_sibling = iter;
9911       iter->priv->prev_sibling = child;
9912     }
9913   else
9914     {
9915       ClutterActor *tmp = self->priv->last_child;
9916
9917       if (tmp != NULL)
9918         tmp->priv->next_sibling = child;
9919
9920       /* insert the node at the end of the list */
9921       child->priv->prev_sibling = self->priv->last_child;
9922       child->priv->next_sibling = NULL;
9923     }
9924
9925   if (child->priv->prev_sibling == NULL)
9926     self->priv->first_child = child;
9927
9928   if (child->priv->next_sibling == NULL)
9929     self->priv->last_child = child;
9930 }
9931
9932 static void
9933 insert_child_at_index (ClutterActor *self,
9934                        ClutterActor *child,
9935                        gpointer      data_)
9936 {
9937   gint index_ = GPOINTER_TO_INT (data_);
9938
9939   child->priv->parent = self;
9940
9941   if (index_ == 0)
9942     {
9943       ClutterActor *tmp = self->priv->first_child;
9944
9945       if (tmp != NULL)
9946         tmp->priv->prev_sibling = child;
9947
9948       child->priv->prev_sibling = NULL;
9949       child->priv->next_sibling = tmp;
9950     }
9951   else if (index_ < 0 || index_ >= self->priv->n_children)
9952     {
9953       ClutterActor *tmp = self->priv->last_child;
9954
9955       if (tmp != NULL)
9956         tmp->priv->next_sibling = child;
9957
9958       child->priv->prev_sibling = tmp;
9959       child->priv->next_sibling = NULL;
9960     }
9961   else
9962     {
9963       ClutterActor *iter;
9964       int i;
9965
9966       for (iter = self->priv->first_child, i = 0;
9967            iter != NULL;
9968            iter = iter->priv->next_sibling, i += 1)
9969         {
9970           if (index_ == i)
9971             {
9972               ClutterActor *tmp = iter->priv->prev_sibling;
9973
9974               child->priv->prev_sibling = tmp;
9975               child->priv->next_sibling = iter;
9976
9977               iter->priv->prev_sibling = child;
9978
9979               if (tmp != NULL)
9980                 tmp->priv->next_sibling = child;
9981
9982               break;
9983             }
9984         }
9985     }
9986
9987   if (child->priv->prev_sibling == NULL)
9988     self->priv->first_child = child;
9989
9990   if (child->priv->next_sibling == NULL)
9991     self->priv->last_child = child;
9992 }
9993
9994 static void
9995 insert_child_above (ClutterActor *self,
9996                     ClutterActor *child,
9997                     gpointer      data)
9998 {
9999   ClutterActor *sibling = data;
10000
10001   child->priv->parent = self;
10002
10003   if (sibling == NULL)
10004     sibling = self->priv->last_child;
10005
10006   child->priv->prev_sibling = sibling;
10007
10008   if (sibling != NULL)
10009     {
10010       ClutterActor *tmp = sibling->priv->next_sibling;
10011
10012       child->priv->next_sibling = tmp;
10013
10014       if (tmp != NULL)
10015         tmp->priv->prev_sibling = child;
10016
10017       sibling->priv->next_sibling = child;
10018     }
10019   else
10020     child->priv->next_sibling = NULL;
10021
10022   if (child->priv->prev_sibling == NULL)
10023     self->priv->first_child = child;
10024
10025   if (child->priv->next_sibling == NULL)
10026     self->priv->last_child = child;
10027 }
10028
10029 static void
10030 insert_child_below (ClutterActor *self,
10031                     ClutterActor *child,
10032                     gpointer      data)
10033 {
10034   ClutterActor *sibling = data;
10035
10036   child->priv->parent = self;
10037
10038   if (sibling == NULL)
10039     sibling = self->priv->first_child;
10040
10041   child->priv->next_sibling = sibling;
10042
10043   if (sibling != NULL)
10044     {
10045       ClutterActor *tmp = sibling->priv->prev_sibling;
10046
10047       child->priv->prev_sibling = tmp;
10048
10049       if (tmp != NULL)
10050         tmp->priv->next_sibling = child;
10051
10052       sibling->priv->prev_sibling = child;
10053     }
10054   else
10055     child->priv->prev_sibling = NULL;
10056
10057   if (child->priv->prev_sibling == NULL)
10058     self->priv->first_child = child;
10059
10060   if (child->priv->next_sibling == NULL)
10061     self->priv->last_child = child;
10062 }
10063
10064 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10065                                            ClutterActor *child,
10066                                            gpointer      data);
10067
10068 typedef enum {
10069   ADD_CHILD_CREATE_META       = 1 << 0,
10070   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10071   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10072   ADD_CHILD_CHECK_STATE       = 1 << 3,
10073   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10074
10075   /* default flags for public API */
10076   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10077                                ADD_CHILD_EMIT_PARENT_SET |
10078                                ADD_CHILD_EMIT_ACTOR_ADDED |
10079                                ADD_CHILD_CHECK_STATE |
10080                                ADD_CHILD_NOTIFY_FIRST_LAST,
10081
10082   /* flags for legacy/deprecated API */
10083   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10084                                ADD_CHILD_CHECK_STATE |
10085                                ADD_CHILD_NOTIFY_FIRST_LAST
10086 } ClutterActorAddChildFlags;
10087
10088 /*< private >
10089  * clutter_actor_add_child_internal:
10090  * @self: a #ClutterActor
10091  * @child: a #ClutterActor
10092  * @flags: control flags for actions
10093  * @add_func: delegate function
10094  * @data: (closure): data to pass to @add_func
10095  *
10096  * Adds @child to the list of children of @self.
10097  *
10098  * The actual insertion inside the list is delegated to @add_func: this
10099  * function will just set up the state, perform basic checks, and emit
10100  * signals.
10101  *
10102  * The @flags argument is used to perform additional operations.
10103  */
10104 static inline void
10105 clutter_actor_add_child_internal (ClutterActor              *self,
10106                                   ClutterActor              *child,
10107                                   ClutterActorAddChildFlags  flags,
10108                                   ClutterActorAddChildFunc   add_func,
10109                                   gpointer                   data)
10110 {
10111   ClutterTextDirection text_dir;
10112   gboolean create_meta;
10113   gboolean emit_parent_set, emit_actor_added;
10114   gboolean check_state;
10115   gboolean notify_first_last;
10116   ClutterActor *old_first_child, *old_last_child;
10117
10118   if (child->priv->parent != NULL)
10119     {
10120       g_warning ("Cannot set a parent on an actor which has a parent. "
10121                  "You must use clutter_actor_remove_child() first.");
10122       return;
10123     }
10124
10125   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10126     {
10127       g_warning ("Cannot set a parent on a toplevel actor\n");
10128       return;
10129     }
10130
10131   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10132     {
10133       g_warning ("Cannot set a parent currently being destroyed");
10134       return;
10135     }
10136
10137   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10138   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10139   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10140   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10141   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10142
10143   old_first_child = self->priv->first_child;
10144   old_last_child = self->priv->last_child;
10145
10146   g_object_freeze_notify (G_OBJECT (self));
10147
10148   if (create_meta)
10149     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10150
10151   g_object_ref_sink (child);
10152   child->priv->parent = NULL;
10153   child->priv->next_sibling = NULL;
10154   child->priv->prev_sibling = NULL;
10155
10156   /* delegate the actual insertion */
10157   add_func (self, child, data);
10158
10159   g_assert (child->priv->parent == self);
10160
10161   self->priv->n_children += 1;
10162
10163   self->priv->age += 1;
10164
10165   /* if push_internal() has been called then we automatically set
10166    * the flag on the actor
10167    */
10168   if (self->priv->internal_child)
10169     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10170
10171   /* clutter_actor_reparent() will emit ::parent-set for us */
10172   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10173     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10174
10175   if (check_state)
10176     {
10177       /* If parent is mapped or realized, we need to also be mapped or
10178        * realized once we're inside the parent.
10179        */
10180       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10181
10182       /* propagate the parent's text direction to the child */
10183       text_dir = clutter_actor_get_text_direction (self);
10184       clutter_actor_set_text_direction (child, text_dir);
10185     }
10186
10187   if (child->priv->show_on_set_parent)
10188     clutter_actor_show (child);
10189
10190   if (CLUTTER_ACTOR_IS_MAPPED (child))
10191     clutter_actor_queue_redraw (child);
10192
10193   /* maintain the invariant that if an actor needs layout,
10194    * its parents do as well
10195    */
10196   if (child->priv->needs_width_request ||
10197       child->priv->needs_height_request ||
10198       child->priv->needs_allocation)
10199     {
10200       /* we work around the short-circuiting we do
10201        * in clutter_actor_queue_relayout() since we
10202        * want to force a relayout
10203        */
10204       child->priv->needs_width_request = TRUE;
10205       child->priv->needs_height_request = TRUE;
10206       child->priv->needs_allocation = TRUE;
10207
10208       clutter_actor_queue_relayout (child->priv->parent);
10209     }
10210
10211   if (emit_actor_added)
10212     g_signal_emit_by_name (self, "actor-added", child);
10213
10214   if (notify_first_last)
10215     {
10216       if (old_first_child != self->priv->first_child)
10217         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10218
10219       if (old_last_child != self->priv->last_child)
10220         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10221     }
10222
10223   g_object_thaw_notify (G_OBJECT (self));
10224 }
10225
10226 /**
10227  * clutter_actor_add_child:
10228  * @self: a #ClutterActor
10229  * @child: a #ClutterActor
10230  *
10231  * Adds @child to the children of @self.
10232  *
10233  * This function will acquire a reference on @child that will only
10234  * be released when calling clutter_actor_remove_child().
10235  *
10236  * This function will take into consideration the #ClutterActor:depth
10237  * of @child, and will keep the list of children sorted.
10238  *
10239  * This function will emit the #ClutterContainer::actor-added signal
10240  * on @self.
10241  *
10242  * Since: 1.10
10243  */
10244 void
10245 clutter_actor_add_child (ClutterActor *self,
10246                          ClutterActor *child)
10247 {
10248   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10249   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10250   g_return_if_fail (self != child);
10251   g_return_if_fail (child->priv->parent == NULL);
10252
10253   clutter_actor_add_child_internal (self, child,
10254                                     ADD_CHILD_DEFAULT_FLAGS,
10255                                     insert_child_at_depth,
10256                                     NULL);
10257 }
10258
10259 /**
10260  * clutter_actor_insert_child_at_index:
10261  * @self: a #ClutterActor
10262  * @child: a #ClutterActor
10263  * @index_: the index
10264  *
10265  * Inserts @child into the list of children of @self, using the
10266  * given @index_. If @index_ is greater than the number of children
10267  * in @self, or is less than 0, then the new child is added at the end.
10268  *
10269  * This function will acquire a reference on @child that will only
10270  * be released when calling clutter_actor_remove_child().
10271  *
10272  * This function will not take into consideration the #ClutterActor:depth
10273  * of @child.
10274  *
10275  * This function will emit the #ClutterContainer::actor-added signal
10276  * on @self.
10277  *
10278  * Since: 1.10
10279  */
10280 void
10281 clutter_actor_insert_child_at_index (ClutterActor *self,
10282                                      ClutterActor *child,
10283                                      gint          index_)
10284 {
10285   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10286   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10287   g_return_if_fail (self != child);
10288   g_return_if_fail (child->priv->parent == NULL);
10289
10290   clutter_actor_add_child_internal (self, child,
10291                                     ADD_CHILD_DEFAULT_FLAGS,
10292                                     insert_child_at_index,
10293                                     GINT_TO_POINTER (index_));
10294 }
10295
10296 /**
10297  * clutter_actor_insert_child_above:
10298  * @self: a #ClutterActor
10299  * @child: a #ClutterActor
10300  * @sibling: (allow-none): a child of @self, or %NULL
10301  *
10302  * Inserts @child into the list of children of @self, above another
10303  * child of @self or, if @sibling is %NULL, above all the children
10304  * of @self.
10305  *
10306  * This function will acquire a reference on @child that will only
10307  * be released when calling clutter_actor_remove_child().
10308  *
10309  * This function will not take into consideration the #ClutterActor:depth
10310  * of @child.
10311  *
10312  * This function will emit the #ClutterContainer::actor-added signal
10313  * on @self.
10314  *
10315  * Since: 1.10
10316  */
10317 void
10318 clutter_actor_insert_child_above (ClutterActor *self,
10319                                   ClutterActor *child,
10320                                   ClutterActor *sibling)
10321 {
10322   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10323   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10324   g_return_if_fail (self != child);
10325   g_return_if_fail (child != sibling);
10326   g_return_if_fail (child->priv->parent == NULL);
10327   g_return_if_fail (sibling == NULL ||
10328                     (CLUTTER_IS_ACTOR (sibling) &&
10329                      sibling->priv->parent == self));
10330
10331   clutter_actor_add_child_internal (self, child,
10332                                     ADD_CHILD_DEFAULT_FLAGS,
10333                                     insert_child_above,
10334                                     sibling);
10335 }
10336
10337 /**
10338  * clutter_actor_insert_child_below:
10339  * @self: a #ClutterActor
10340  * @child: a #ClutterActor
10341  * @sibling: (allow-none): a child of @self, or %NULL
10342  *
10343  * Inserts @child into the list of children of @self, below another
10344  * child of @self or, if @sibling is %NULL, below all the children
10345  * of @self.
10346  *
10347  * This function will acquire a reference on @child that will only
10348  * be released when calling clutter_actor_remove_child().
10349  *
10350  * This function will not take into consideration the #ClutterActor:depth
10351  * of @child.
10352  *
10353  * This function will emit the #ClutterContainer::actor-added signal
10354  * on @self.
10355  *
10356  * Since: 1.10
10357  */
10358 void
10359 clutter_actor_insert_child_below (ClutterActor *self,
10360                                   ClutterActor *child,
10361                                   ClutterActor *sibling)
10362 {
10363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10364   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10365   g_return_if_fail (self != child);
10366   g_return_if_fail (child != sibling);
10367   g_return_if_fail (child->priv->parent == NULL);
10368   g_return_if_fail (sibling == NULL ||
10369                     (CLUTTER_IS_ACTOR (sibling) &&
10370                      sibling->priv->parent == self));
10371
10372   clutter_actor_add_child_internal (self, child,
10373                                     ADD_CHILD_DEFAULT_FLAGS,
10374                                     insert_child_below,
10375                                     sibling);
10376 }
10377
10378 /**
10379  * clutter_actor_set_parent:
10380  * @self: A #ClutterActor
10381  * @parent: A new #ClutterActor parent
10382  *
10383  * Sets the parent of @self to @parent.
10384  *
10385  * This function will result in @parent acquiring a reference on @self,
10386  * eventually by sinking its floating reference first. The reference
10387  * will be released by clutter_actor_unparent().
10388  *
10389  * This function should only be called by legacy #ClutterActor<!-- -->s
10390  * implementing the #ClutterContainer interface.
10391  *
10392  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10393  */
10394 void
10395 clutter_actor_set_parent (ClutterActor *self,
10396                           ClutterActor *parent)
10397 {
10398   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10399   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10400   g_return_if_fail (self != parent);
10401   g_return_if_fail (self->priv->parent == NULL);
10402
10403   /* as this function will be called inside ClutterContainer::add
10404    * implementations or when building up a composite actor, we have
10405    * to preserve the old behaviour, and not create child meta or
10406    * emit the ::actor-added signal, to avoid recursion or double
10407    * emissions
10408    */
10409   clutter_actor_add_child_internal (parent, self,
10410                                     ADD_CHILD_LEGACY_FLAGS,
10411                                     insert_child_at_depth,
10412                                     NULL);
10413 }
10414
10415 /**
10416  * clutter_actor_get_parent:
10417  * @self: A #ClutterActor
10418  *
10419  * Retrieves the parent of @self.
10420  *
10421  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10422  *  if no parent is set
10423  */
10424 ClutterActor *
10425 clutter_actor_get_parent (ClutterActor *self)
10426 {
10427   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10428
10429   return self->priv->parent;
10430 }
10431
10432 /**
10433  * clutter_actor_get_paint_visibility:
10434  * @self: A #ClutterActor
10435  *
10436  * Retrieves the 'paint' visibility of an actor recursively checking for non
10437  * visible parents.
10438  *
10439  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10440  *
10441  * Return Value: %TRUE if the actor is visibile and will be painted.
10442  *
10443  * Since: 0.8.4
10444  */
10445 gboolean
10446 clutter_actor_get_paint_visibility (ClutterActor *actor)
10447 {
10448   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10449
10450   return CLUTTER_ACTOR_IS_MAPPED (actor);
10451 }
10452
10453 /**
10454  * clutter_actor_remove_child:
10455  * @self: a #ClutterActor
10456  * @child: a #ClutterActor
10457  *
10458  * Removes @child from the children of @self.
10459  *
10460  * This function will release the reference added by
10461  * clutter_actor_add_child(), so if you want to keep using @child
10462  * you will have to acquire a referenced on it before calling this
10463  * function.
10464  *
10465  * This function will emit the #ClutterContainer::actor-removed
10466  * signal on @self.
10467  *
10468  * Since: 1.10
10469  */
10470 void
10471 clutter_actor_remove_child (ClutterActor *self,
10472                             ClutterActor *child)
10473 {
10474   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10475   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10476   g_return_if_fail (self != child);
10477   g_return_if_fail (child->priv->parent != NULL);
10478   g_return_if_fail (child->priv->parent == self);
10479
10480   clutter_actor_remove_child_internal (self, child,
10481                                        REMOVE_CHILD_DEFAULT_FLAGS);
10482 }
10483
10484 /**
10485  * clutter_actor_remove_all_children:
10486  * @self: a #ClutterActor
10487  *
10488  * Removes all children of @self.
10489  *
10490  * This function releases the reference added by inserting a child actor
10491  * in the list of children of @self.
10492  *
10493  * If the reference count of a child drops to zero, the child will be
10494  * destroyed. If you want to ensure the destruction of all the children
10495  * of @self, use clutter_actor_destroy_all_children().
10496  *
10497  * Since: 1.10
10498  */
10499 void
10500 clutter_actor_remove_all_children (ClutterActor *self)
10501 {
10502   ClutterActorIter iter;
10503
10504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10505
10506   if (self->priv->n_children == 0)
10507     return;
10508
10509   g_object_freeze_notify (G_OBJECT (self));
10510
10511   clutter_actor_iter_init (&iter, self);
10512   while (clutter_actor_iter_next (&iter, NULL))
10513     clutter_actor_iter_remove (&iter);
10514
10515   g_object_thaw_notify (G_OBJECT (self));
10516
10517   /* sanity check */
10518   g_assert (self->priv->first_child == NULL);
10519   g_assert (self->priv->last_child == NULL);
10520   g_assert (self->priv->n_children == 0);
10521 }
10522
10523 /**
10524  * clutter_actor_destroy_all_children:
10525  * @self: a #ClutterActor
10526  *
10527  * Destroys all children of @self.
10528  *
10529  * This function releases the reference added by inserting a child
10530  * actor in the list of children of @self, and ensures that the
10531  * #ClutterActor::destroy signal is emitted on each child of the
10532  * actor.
10533  *
10534  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10535  * when its reference count drops to 0; the default handler of the
10536  * #ClutterActor::destroy signal will destroy all the children of an
10537  * actor. This function ensures that all children are destroyed, instead
10538  * of just removed from @self, unlike clutter_actor_remove_all_children()
10539  * which will merely release the reference and remove each child.
10540  *
10541  * Unless you acquired an additional reference on each child of @self
10542  * prior to calling clutter_actor_remove_all_children() and want to reuse
10543  * the actors, you should use clutter_actor_destroy_all_children() in
10544  * order to make sure that children are destroyed and signal handlers
10545  * are disconnected even in cases where circular references prevent this
10546  * from automatically happening through reference counting alone.
10547  *
10548  * Since: 1.10
10549  */
10550 void
10551 clutter_actor_destroy_all_children (ClutterActor *self)
10552 {
10553   ClutterActorIter iter;
10554
10555   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10556
10557   if (self->priv->n_children == 0)
10558     return;
10559
10560   g_object_freeze_notify (G_OBJECT (self));
10561
10562   clutter_actor_iter_init (&iter, self);
10563   while (clutter_actor_iter_next (&iter, NULL))
10564     clutter_actor_iter_destroy (&iter);
10565
10566   g_object_thaw_notify (G_OBJECT (self));
10567
10568   /* sanity check */
10569   g_assert (self->priv->first_child == NULL);
10570   g_assert (self->priv->last_child == NULL);
10571   g_assert (self->priv->n_children == 0);
10572 }
10573
10574 typedef struct _InsertBetweenData {
10575   ClutterActor *prev_sibling;
10576   ClutterActor *next_sibling;
10577 } InsertBetweenData;
10578
10579 static void
10580 insert_child_between (ClutterActor *self,
10581                       ClutterActor *child,
10582                       gpointer      data_)
10583 {
10584   InsertBetweenData *data = data_;
10585   ClutterActor *prev_sibling = data->prev_sibling;
10586   ClutterActor *next_sibling = data->next_sibling;
10587
10588   child->priv->parent = self;
10589   child->priv->prev_sibling = prev_sibling;
10590   child->priv->next_sibling = next_sibling;
10591
10592   if (prev_sibling != NULL)
10593     prev_sibling->priv->next_sibling = child;
10594
10595   if (next_sibling != NULL)
10596     next_sibling->priv->prev_sibling = child;
10597
10598   if (child->priv->prev_sibling == NULL)
10599     self->priv->first_child = child;
10600
10601   if (child->priv->next_sibling == NULL)
10602     self->priv->last_child = child;
10603 }
10604
10605 /**
10606  * clutter_actor_replace_child:
10607  * @self: a #ClutterActor
10608  * @old_child: the child of @self to replace
10609  * @new_child: the #ClutterActor to replace @old_child
10610  *
10611  * Replaces @old_child with @new_child in the list of children of @self.
10612  *
10613  * Since: 1.10
10614  */
10615 void
10616 clutter_actor_replace_child (ClutterActor *self,
10617                              ClutterActor *old_child,
10618                              ClutterActor *new_child)
10619 {
10620   ClutterActor *prev_sibling, *next_sibling;
10621   InsertBetweenData clos;
10622
10623   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10624   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10625   g_return_if_fail (old_child->priv->parent == self);
10626   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10627   g_return_if_fail (old_child != new_child);
10628   g_return_if_fail (new_child != self);
10629   g_return_if_fail (new_child->priv->parent == NULL);
10630
10631   prev_sibling = old_child->priv->prev_sibling;
10632   next_sibling = old_child->priv->next_sibling;
10633   clutter_actor_remove_child_internal (self, old_child,
10634                                        REMOVE_CHILD_DEFAULT_FLAGS);
10635
10636   clos.prev_sibling = prev_sibling;
10637   clos.next_sibling = next_sibling;
10638   clutter_actor_add_child_internal (self, new_child,
10639                                     ADD_CHILD_DEFAULT_FLAGS,
10640                                     insert_child_between,
10641                                     &clos);
10642 }
10643
10644 /**
10645  * clutter_actor_unparent:
10646  * @self: a #ClutterActor
10647  *
10648  * Removes the parent of @self.
10649  *
10650  * This will cause the parent of @self to release the reference
10651  * acquired when calling clutter_actor_set_parent(), so if you
10652  * want to keep @self you will have to acquire a reference of
10653  * your own, through g_object_ref().
10654  *
10655  * This function should only be called by legacy #ClutterActor<!-- -->s
10656  * implementing the #ClutterContainer interface.
10657  *
10658  * Since: 0.1.1
10659  *
10660  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10661  */
10662 void
10663 clutter_actor_unparent (ClutterActor *self)
10664 {
10665   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10666
10667   if (self->priv->parent == NULL)
10668     return;
10669
10670   clutter_actor_remove_child_internal (self->priv->parent, self,
10671                                        REMOVE_CHILD_LEGACY_FLAGS);
10672 }
10673
10674 /**
10675  * clutter_actor_reparent:
10676  * @self: a #ClutterActor
10677  * @new_parent: the new #ClutterActor parent
10678  *
10679  * Resets the parent actor of @self.
10680  *
10681  * This function is logically equivalent to calling clutter_actor_unparent()
10682  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10683  * ensures the child is not finalized when unparented, and emits the
10684  * #ClutterActor::parent-set signal only once.
10685  *
10686  * In reality, calling this function is less useful than it sounds, as some
10687  * application code may rely on changes in the intermediate state between
10688  * removal and addition of the actor from its old parent to the @new_parent.
10689  * Thus, it is strongly encouraged to avoid using this function in application
10690  * code.
10691  *
10692  * Since: 0.2
10693  *
10694  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10695  *   clutter_actor_add_child() instead; remember to take a reference on
10696  *   the actor being removed before calling clutter_actor_remove_child()
10697  *   to avoid the reference count dropping to zero and the actor being
10698  *   destroyed.
10699  */
10700 void
10701 clutter_actor_reparent (ClutterActor *self,
10702                         ClutterActor *new_parent)
10703 {
10704   ClutterActorPrivate *priv;
10705
10706   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10707   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10708   g_return_if_fail (self != new_parent);
10709
10710   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10711     {
10712       g_warning ("Cannot set a parent on a toplevel actor");
10713       return;
10714     }
10715
10716   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10717     {
10718       g_warning ("Cannot set a parent currently being destroyed");
10719       return;
10720     }
10721
10722   priv = self->priv;
10723
10724   if (priv->parent != new_parent)
10725     {
10726       ClutterActor *old_parent;
10727
10728       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10729
10730       old_parent = priv->parent;
10731
10732       g_object_ref (self);
10733
10734       if (old_parent != NULL)
10735         {
10736          /* go through the Container implementation if this is a regular
10737           * child and not an internal one
10738           */
10739          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10740            {
10741              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10742
10743              /* this will have to call unparent() */
10744              clutter_container_remove_actor (parent, self);
10745            }
10746          else
10747            clutter_actor_remove_child_internal (old_parent, self,
10748                                                 REMOVE_CHILD_LEGACY_FLAGS);
10749         }
10750
10751       /* Note, will call set_parent() */
10752       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10753         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10754       else
10755         clutter_actor_add_child_internal (new_parent, self,
10756                                           ADD_CHILD_LEGACY_FLAGS,
10757                                           insert_child_at_depth,
10758                                           NULL);
10759
10760       /* we emit the ::parent-set signal once */
10761       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10762
10763       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10764
10765       /* the IN_REPARENT flag suspends state updates */
10766       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10767
10768       g_object_unref (self);
10769    }
10770 }
10771
10772 /**
10773  * clutter_actor_contains:
10774  * @self: A #ClutterActor
10775  * @descendant: A #ClutterActor, possibly contained in @self
10776  *
10777  * Determines if @descendant is contained inside @self (either as an
10778  * immediate child, or as a deeper descendant). If @self and
10779  * @descendant point to the same actor then it will also return %TRUE.
10780  *
10781  * Return value: whether @descendent is contained within @self
10782  *
10783  * Since: 1.4
10784  */
10785 gboolean
10786 clutter_actor_contains (ClutterActor *self,
10787                         ClutterActor *descendant)
10788 {
10789   ClutterActor *actor;
10790
10791   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10792   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10793
10794   for (actor = descendant; actor; actor = actor->priv->parent)
10795     if (actor == self)
10796       return TRUE;
10797
10798   return FALSE;
10799 }
10800
10801 /**
10802  * clutter_actor_set_child_above_sibling:
10803  * @self: a #ClutterActor
10804  * @child: a #ClutterActor child of @self
10805  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10806  *
10807  * Sets @child to be above @sibling in the list of children of @self.
10808  *
10809  * If @sibling is %NULL, @child will be the new last child of @self.
10810  *
10811  * This function is logically equivalent to removing @child and using
10812  * clutter_actor_insert_child_above(), but it will not emit signals
10813  * or change state on @child.
10814  *
10815  * Since: 1.10
10816  */
10817 void
10818 clutter_actor_set_child_above_sibling (ClutterActor *self,
10819                                        ClutterActor *child,
10820                                        ClutterActor *sibling)
10821 {
10822   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10823   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10824   g_return_if_fail (child->priv->parent == self);
10825   g_return_if_fail (child != sibling);
10826   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10827
10828   if (sibling != NULL)
10829     g_return_if_fail (sibling->priv->parent == self);
10830
10831   /* we don't want to change the state of child, or emit signals, or
10832    * regenerate ChildMeta instances here, but we still want to follow
10833    * the correct sequence of steps encoded in remove_child() and
10834    * add_child(), so that correctness is ensured, and we only go
10835    * through one known code path.
10836    */
10837   g_object_ref (child);
10838   clutter_actor_remove_child_internal (self, child, 0);
10839   clutter_actor_add_child_internal (self, child,
10840                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10841                                     insert_child_above,
10842                                     sibling);
10843
10844   clutter_actor_queue_relayout (self);
10845 }
10846
10847 /**
10848  * clutter_actor_set_child_below_sibling:
10849  * @self: a #ClutterActor
10850  * @child: a #ClutterActor child of @self
10851  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10852  *
10853  * Sets @child to be below @sibling in the list of children of @self.
10854  *
10855  * If @sibling is %NULL, @child will be the new first child of @self.
10856  *
10857  * This function is logically equivalent to removing @self and using
10858  * clutter_actor_insert_child_below(), but it will not emit signals
10859  * or change state on @child.
10860  *
10861  * Since: 1.10
10862  */
10863 void
10864 clutter_actor_set_child_below_sibling (ClutterActor *self,
10865                                        ClutterActor *child,
10866                                        ClutterActor *sibling)
10867 {
10868   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10869   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10870   g_return_if_fail (child->priv->parent == self);
10871   g_return_if_fail (child != sibling);
10872   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10873
10874   if (sibling != NULL)
10875     g_return_if_fail (sibling->priv->parent == self);
10876
10877   /* see the comment in set_child_above_sibling() */
10878   g_object_ref (child);
10879   clutter_actor_remove_child_internal (self, child, 0);
10880   clutter_actor_add_child_internal (self, child,
10881                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10882                                     insert_child_below,
10883                                     sibling);
10884
10885   clutter_actor_queue_relayout (self);
10886 }
10887
10888 /**
10889  * clutter_actor_set_child_at_index:
10890  * @self: a #ClutterActor
10891  * @child: a #ClutterActor child of @self
10892  * @index_: the new index for @child
10893  *
10894  * Changes the index of @child in the list of children of @self.
10895  *
10896  * This function is logically equivalent to removing @child and
10897  * calling clutter_actor_insert_child_at_index(), but it will not
10898  * emit signals or change state on @child.
10899  *
10900  * Since: 1.10
10901  */
10902 void
10903 clutter_actor_set_child_at_index (ClutterActor *self,
10904                                   ClutterActor *child,
10905                                   gint          index_)
10906 {
10907   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10908   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10909   g_return_if_fail (child->priv->parent == self);
10910   g_return_if_fail (index_ <= self->priv->n_children);
10911
10912   g_object_ref (child);
10913   clutter_actor_remove_child_internal (self, child, 0);
10914   clutter_actor_add_child_internal (self, child,
10915                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10916                                     insert_child_at_index,
10917                                     GINT_TO_POINTER (index_));
10918
10919   clutter_actor_queue_relayout (self);
10920 }
10921
10922 /**
10923  * clutter_actor_raise:
10924  * @self: A #ClutterActor
10925  * @below: (allow-none): A #ClutterActor to raise above.
10926  *
10927  * Puts @self above @below.
10928  *
10929  * Both actors must have the same parent, and the parent must implement
10930  * the #ClutterContainer interface
10931  *
10932  * This function calls clutter_container_raise_child() internally.
10933  *
10934  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
10935  */
10936 void
10937 clutter_actor_raise (ClutterActor *self,
10938                      ClutterActor *below)
10939 {
10940   ClutterActor *parent;
10941
10942   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10943
10944   parent = clutter_actor_get_parent (self);
10945   if (parent == NULL)
10946     {
10947       g_warning ("%s: Actor '%s' is not inside a container",
10948                  G_STRFUNC,
10949                  _clutter_actor_get_debug_name (self));
10950       return;
10951     }
10952
10953   if (below != NULL)
10954     {
10955       if (parent != clutter_actor_get_parent (below))
10956         {
10957           g_warning ("%s Actor '%s' is not in the same container as "
10958                      "actor '%s'",
10959                      G_STRFUNC,
10960                      _clutter_actor_get_debug_name (self),
10961                      _clutter_actor_get_debug_name (below));
10962           return;
10963         }
10964     }
10965
10966   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
10967 }
10968
10969 /**
10970  * clutter_actor_lower:
10971  * @self: A #ClutterActor
10972  * @above: (allow-none): A #ClutterActor to lower below
10973  *
10974  * Puts @self below @above.
10975  *
10976  * Both actors must have the same parent, and the parent must implement
10977  * the #ClutterContainer interface.
10978  *
10979  * This function calls clutter_container_lower_child() internally.
10980  *
10981  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
10982  */
10983 void
10984 clutter_actor_lower (ClutterActor *self,
10985                      ClutterActor *above)
10986 {
10987   ClutterActor *parent;
10988
10989   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10990
10991   parent = clutter_actor_get_parent (self);
10992   if (parent == NULL)
10993     {
10994       g_warning ("%s: Actor of type %s is not inside a container",
10995                  G_STRFUNC,
10996                  _clutter_actor_get_debug_name (self));
10997       return;
10998     }
10999
11000   if (above)
11001     {
11002       if (parent != clutter_actor_get_parent (above))
11003         {
11004           g_warning ("%s: Actor '%s' is not in the same container as "
11005                      "actor '%s'",
11006                      G_STRFUNC,
11007                      _clutter_actor_get_debug_name (self),
11008                      _clutter_actor_get_debug_name (above));
11009           return;
11010         }
11011     }
11012
11013   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11014 }
11015
11016 /**
11017  * clutter_actor_raise_top:
11018  * @self: A #ClutterActor
11019  *
11020  * Raises @self to the top.
11021  *
11022  * This function calls clutter_actor_raise() internally.
11023  *
11024  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11025  *   a %NULL sibling, instead.
11026  */
11027 void
11028 clutter_actor_raise_top (ClutterActor *self)
11029 {
11030   clutter_actor_raise (self, NULL);
11031 }
11032
11033 /**
11034  * clutter_actor_lower_bottom:
11035  * @self: A #ClutterActor
11036  *
11037  * Lowers @self to the bottom.
11038  *
11039  * This function calls clutter_actor_lower() internally.
11040  *
11041  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11042  *   a %NULL sibling, instead.
11043  */
11044 void
11045 clutter_actor_lower_bottom (ClutterActor *self)
11046 {
11047   clutter_actor_lower (self, NULL);
11048 }
11049
11050 /*
11051  * Event handling
11052  */
11053
11054 /**
11055  * clutter_actor_event:
11056  * @actor: a #ClutterActor
11057  * @event: a #ClutterEvent
11058  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11059  *
11060  * This function is used to emit an event on the main stage.
11061  * You should rarely need to use this function, except for
11062  * synthetising events.
11063  *
11064  * Return value: the return value from the signal emission: %TRUE
11065  *   if the actor handled the event, or %FALSE if the event was
11066  *   not handled
11067  *
11068  * Since: 0.6
11069  */
11070 gboolean
11071 clutter_actor_event (ClutterActor *actor,
11072                      ClutterEvent *event,
11073                      gboolean      capture)
11074 {
11075   gboolean retval = FALSE;
11076   gint signal_num = -1;
11077
11078   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11079   g_return_val_if_fail (event != NULL, FALSE);
11080
11081   g_object_ref (actor);
11082
11083   if (capture)
11084     {
11085       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11086                      event,
11087                      &retval);
11088       goto out;
11089     }
11090
11091   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11092
11093   if (!retval)
11094     {
11095       switch (event->type)
11096         {
11097         case CLUTTER_NOTHING:
11098           break;
11099         case CLUTTER_BUTTON_PRESS:
11100           signal_num = BUTTON_PRESS_EVENT;
11101           break;
11102         case CLUTTER_BUTTON_RELEASE:
11103           signal_num = BUTTON_RELEASE_EVENT;
11104           break;
11105         case CLUTTER_SCROLL:
11106           signal_num = SCROLL_EVENT;
11107           break;
11108         case CLUTTER_KEY_PRESS:
11109           signal_num = KEY_PRESS_EVENT;
11110           break;
11111         case CLUTTER_KEY_RELEASE:
11112           signal_num = KEY_RELEASE_EVENT;
11113           break;
11114         case CLUTTER_MOTION:
11115           signal_num = MOTION_EVENT;
11116           break;
11117         case CLUTTER_ENTER:
11118           signal_num = ENTER_EVENT;
11119           break;
11120         case CLUTTER_LEAVE:
11121           signal_num = LEAVE_EVENT;
11122           break;
11123         case CLUTTER_DELETE:
11124         case CLUTTER_DESTROY_NOTIFY:
11125         case CLUTTER_CLIENT_MESSAGE:
11126         default:
11127           signal_num = -1;
11128           break;
11129         }
11130
11131       if (signal_num != -1)
11132         g_signal_emit (actor, actor_signals[signal_num], 0,
11133                        event, &retval);
11134     }
11135
11136 out:
11137   g_object_unref (actor);
11138
11139   return retval;
11140 }
11141
11142 /**
11143  * clutter_actor_set_reactive:
11144  * @actor: a #ClutterActor
11145  * @reactive: whether the actor should be reactive to events
11146  *
11147  * Sets @actor as reactive. Reactive actors will receive events.
11148  *
11149  * Since: 0.6
11150  */
11151 void
11152 clutter_actor_set_reactive (ClutterActor *actor,
11153                             gboolean      reactive)
11154 {
11155   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11156
11157   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11158     return;
11159
11160   if (reactive)
11161     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11162   else
11163     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11164
11165   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11166 }
11167
11168 /**
11169  * clutter_actor_get_reactive:
11170  * @actor: a #ClutterActor
11171  *
11172  * Checks whether @actor is marked as reactive.
11173  *
11174  * Return value: %TRUE if the actor is reactive
11175  *
11176  * Since: 0.6
11177  */
11178 gboolean
11179 clutter_actor_get_reactive (ClutterActor *actor)
11180 {
11181   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11182
11183   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11184 }
11185
11186 /**
11187  * clutter_actor_get_anchor_point:
11188  * @self: a #ClutterActor
11189  * @anchor_x: (out): return location for the X coordinate of the anchor point
11190  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11191  *
11192  * Gets the current anchor point of the @actor in pixels.
11193  *
11194  * Since: 0.6
11195  */
11196 void
11197 clutter_actor_get_anchor_point (ClutterActor *self,
11198                                 gfloat       *anchor_x,
11199                                 gfloat       *anchor_y)
11200 {
11201   const ClutterTransformInfo *info;
11202
11203   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11204
11205   info = _clutter_actor_get_transform_info_or_defaults (self);
11206   clutter_anchor_coord_get_units (self, &info->anchor,
11207                                   anchor_x,
11208                                   anchor_y,
11209                                   NULL);
11210 }
11211
11212 /**
11213  * clutter_actor_set_anchor_point:
11214  * @self: a #ClutterActor
11215  * @anchor_x: X coordinate of the anchor point
11216  * @anchor_y: Y coordinate of the anchor point
11217  *
11218  * Sets an anchor point for @self. The anchor point is a point in the
11219  * coordinate space of an actor to which the actor position within its
11220  * parent is relative; the default is (0, 0), i.e. the top-left corner
11221  * of the actor.
11222  *
11223  * Since: 0.6
11224  */
11225 void
11226 clutter_actor_set_anchor_point (ClutterActor *self,
11227                                 gfloat        anchor_x,
11228                                 gfloat        anchor_y)
11229 {
11230   ClutterTransformInfo *info;
11231   ClutterActorPrivate *priv;
11232   gboolean changed = FALSE;
11233   gfloat old_anchor_x, old_anchor_y;
11234   GObject *obj;
11235
11236   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11237
11238   obj = G_OBJECT (self);
11239   priv = self->priv;
11240   info = _clutter_actor_get_transform_info (self);
11241
11242   g_object_freeze_notify (obj);
11243
11244   clutter_anchor_coord_get_units (self, &info->anchor,
11245                                   &old_anchor_x,
11246                                   &old_anchor_y,
11247                                   NULL);
11248
11249   if (info->anchor.is_fractional)
11250     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11251
11252   if (old_anchor_x != anchor_x)
11253     {
11254       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11255       changed = TRUE;
11256     }
11257
11258   if (old_anchor_y != anchor_y)
11259     {
11260       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11261       changed = TRUE;
11262     }
11263
11264   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11265
11266   if (changed)
11267     {
11268       priv->transform_valid = FALSE;
11269       clutter_actor_queue_redraw (self);
11270     }
11271
11272   g_object_thaw_notify (obj);
11273 }
11274
11275 /**
11276  * clutter_actor_get_anchor_point_gravity:
11277  * @self: a #ClutterActor
11278  *
11279  * Retrieves the anchor position expressed as a #ClutterGravity. If
11280  * the anchor point was specified using pixels or units this will
11281  * return %CLUTTER_GRAVITY_NONE.
11282  *
11283  * Return value: the #ClutterGravity used by the anchor point
11284  *
11285  * Since: 1.0
11286  */
11287 ClutterGravity
11288 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11289 {
11290   const ClutterTransformInfo *info;
11291
11292   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11293
11294   info = _clutter_actor_get_transform_info_or_defaults (self);
11295
11296   return clutter_anchor_coord_get_gravity (&info->anchor);
11297 }
11298
11299 /**
11300  * clutter_actor_move_anchor_point:
11301  * @self: a #ClutterActor
11302  * @anchor_x: X coordinate of the anchor point
11303  * @anchor_y: Y coordinate of the anchor point
11304  *
11305  * Sets an anchor point for the actor, and adjusts the actor postion so that
11306  * the relative position of the actor toward its parent remains the same.
11307  *
11308  * Since: 0.6
11309  */
11310 void
11311 clutter_actor_move_anchor_point (ClutterActor *self,
11312                                  gfloat        anchor_x,
11313                                  gfloat        anchor_y)
11314 {
11315   gfloat old_anchor_x, old_anchor_y;
11316   const ClutterTransformInfo *info;
11317
11318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11319
11320   info = _clutter_actor_get_transform_info (self);
11321   clutter_anchor_coord_get_units (self, &info->anchor,
11322                                   &old_anchor_x,
11323                                   &old_anchor_y,
11324                                   NULL);
11325
11326   g_object_freeze_notify (G_OBJECT (self));
11327
11328   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11329
11330   if (self->priv->position_set)
11331     clutter_actor_move_by (self,
11332                            anchor_x - old_anchor_x,
11333                            anchor_y - old_anchor_y);
11334
11335   g_object_thaw_notify (G_OBJECT (self));
11336 }
11337
11338 /**
11339  * clutter_actor_move_anchor_point_from_gravity:
11340  * @self: a #ClutterActor
11341  * @gravity: #ClutterGravity.
11342  *
11343  * Sets an anchor point on the actor based on the given gravity, adjusting the
11344  * actor postion so that its relative position within its parent remains
11345  * unchanged.
11346  *
11347  * Since version 1.0 the anchor point will be stored as a gravity so
11348  * that if the actor changes size then the anchor point will move. For
11349  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11350  * and later double the size of the actor, the anchor point will move
11351  * to the bottom right.
11352  *
11353  * Since: 0.6
11354  */
11355 void
11356 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11357                                               ClutterGravity  gravity)
11358 {
11359   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11360   const ClutterTransformInfo *info;
11361   ClutterActorPrivate *priv;
11362
11363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11364
11365   priv = self->priv;
11366   info = _clutter_actor_get_transform_info (self);
11367
11368   g_object_freeze_notify (G_OBJECT (self));
11369
11370   clutter_anchor_coord_get_units (self, &info->anchor,
11371                                   &old_anchor_x,
11372                                   &old_anchor_y,
11373                                   NULL);
11374   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11375   clutter_anchor_coord_get_units (self, &info->anchor,
11376                                   &new_anchor_x,
11377                                   &new_anchor_y,
11378                                   NULL);
11379
11380   if (priv->position_set)
11381     clutter_actor_move_by (self,
11382                            new_anchor_x - old_anchor_x,
11383                            new_anchor_y - old_anchor_y);
11384
11385   g_object_thaw_notify (G_OBJECT (self));
11386 }
11387
11388 /**
11389  * clutter_actor_set_anchor_point_from_gravity:
11390  * @self: a #ClutterActor
11391  * @gravity: #ClutterGravity.
11392  *
11393  * Sets an anchor point on the actor, based on the given gravity (this is a
11394  * convenience function wrapping clutter_actor_set_anchor_point()).
11395  *
11396  * Since version 1.0 the anchor point will be stored as a gravity so
11397  * that if the actor changes size then the anchor point will move. For
11398  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11399  * and later double the size of the actor, the anchor point will move
11400  * to the bottom right.
11401  *
11402  * Since: 0.6
11403  */
11404 void
11405 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11406                                              ClutterGravity  gravity)
11407 {
11408   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11409
11410   if (gravity == CLUTTER_GRAVITY_NONE)
11411     clutter_actor_set_anchor_point (self, 0, 0);
11412   else
11413     {
11414       GObject *obj = G_OBJECT (self);
11415       ClutterTransformInfo *info;
11416
11417       g_object_freeze_notify (obj);
11418
11419       info = _clutter_actor_get_transform_info (self);
11420       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11421
11422       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11423       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11424       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11425
11426       self->priv->transform_valid = FALSE;
11427
11428       clutter_actor_queue_redraw (self);
11429
11430       g_object_thaw_notify (obj);
11431     }
11432 }
11433
11434 static void
11435 clutter_container_iface_init (ClutterContainerIface *iface)
11436 {
11437   /* we don't override anything, as ClutterContainer already has a default
11438    * implementation that we can use, and which calls into our own API.
11439    */
11440 }
11441
11442 typedef enum
11443 {
11444   PARSE_X,
11445   PARSE_Y,
11446   PARSE_WIDTH,
11447   PARSE_HEIGHT,
11448   PARSE_ANCHOR_X,
11449   PARSE_ANCHOR_Y
11450 } ParseDimension;
11451
11452 static gfloat
11453 parse_units (ClutterActor   *self,
11454              ParseDimension  dimension,
11455              JsonNode       *node)
11456 {
11457   GValue value = { 0, };
11458   gfloat retval = 0;
11459
11460   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11461     return 0;
11462
11463   json_node_get_value (node, &value);
11464
11465   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11466     {
11467       retval = (gfloat) g_value_get_int64 (&value);
11468     }
11469   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11470     {
11471       retval = g_value_get_double (&value);
11472     }
11473   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11474     {
11475       ClutterUnits units;
11476       gboolean res;
11477
11478       res = clutter_units_from_string (&units, g_value_get_string (&value));
11479       if (res)
11480         retval = clutter_units_to_pixels (&units);
11481       else
11482         {
11483           g_warning ("Invalid value '%s': integers, strings or floating point "
11484                      "values can be used for the x, y, width and height "
11485                      "properties. Valid modifiers for strings are 'px', 'mm', "
11486                      "'pt' and 'em'.",
11487                      g_value_get_string (&value));
11488           retval = 0;
11489         }
11490     }
11491   else
11492     {
11493       g_warning ("Invalid value of type '%s': integers, strings of floating "
11494                  "point values can be used for the x, y, width, height "
11495                  "anchor-x and anchor-y properties.",
11496                  g_type_name (G_VALUE_TYPE (&value)));
11497     }
11498
11499   g_value_unset (&value);
11500
11501   return retval;
11502 }
11503
11504 typedef struct {
11505   ClutterRotateAxis axis;
11506
11507   gdouble angle;
11508
11509   gfloat center_x;
11510   gfloat center_y;
11511   gfloat center_z;
11512 } RotationInfo;
11513
11514 static inline gboolean
11515 parse_rotation_array (ClutterActor *actor,
11516                       JsonArray    *array,
11517                       RotationInfo *info)
11518 {
11519   JsonNode *element;
11520
11521   if (json_array_get_length (array) != 2)
11522     return FALSE;
11523
11524   /* angle */
11525   element = json_array_get_element (array, 0);
11526   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11527     info->angle = json_node_get_double (element);
11528   else
11529     return FALSE;
11530
11531   /* center */
11532   element = json_array_get_element (array, 1);
11533   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11534     {
11535       JsonArray *center = json_node_get_array (element);
11536
11537       if (json_array_get_length (center) != 2)
11538         return FALSE;
11539
11540       switch (info->axis)
11541         {
11542         case CLUTTER_X_AXIS:
11543           info->center_y = parse_units (actor, PARSE_Y,
11544                                         json_array_get_element (center, 0));
11545           info->center_z = parse_units (actor, PARSE_Y,
11546                                         json_array_get_element (center, 1));
11547           return TRUE;
11548
11549         case CLUTTER_Y_AXIS:
11550           info->center_x = parse_units (actor, PARSE_X,
11551                                         json_array_get_element (center, 0));
11552           info->center_z = parse_units (actor, PARSE_X,
11553                                         json_array_get_element (center, 1));
11554           return TRUE;
11555
11556         case CLUTTER_Z_AXIS:
11557           info->center_x = parse_units (actor, PARSE_X,
11558                                         json_array_get_element (center, 0));
11559           info->center_y = parse_units (actor, PARSE_Y,
11560                                         json_array_get_element (center, 1));
11561           return TRUE;
11562         }
11563     }
11564
11565   return FALSE;
11566 }
11567
11568 static gboolean
11569 parse_rotation (ClutterActor *actor,
11570                 JsonNode     *node,
11571                 RotationInfo *info)
11572 {
11573   JsonArray *array;
11574   guint len, i;
11575   gboolean retval = FALSE;
11576
11577   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11578     {
11579       g_warning ("Invalid node of type '%s' found, expecting an array",
11580                  json_node_type_name (node));
11581       return FALSE;
11582     }
11583
11584   array = json_node_get_array (node);
11585   len = json_array_get_length (array);
11586
11587   for (i = 0; i < len; i++)
11588     {
11589       JsonNode *element = json_array_get_element (array, i);
11590       JsonObject *object;
11591       JsonNode *member;
11592
11593       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11594         {
11595           g_warning ("Invalid node of type '%s' found, expecting an object",
11596                      json_node_type_name (element));
11597           return FALSE;
11598         }
11599
11600       object = json_node_get_object (element);
11601
11602       if (json_object_has_member (object, "x-axis"))
11603         {
11604           member = json_object_get_member (object, "x-axis");
11605
11606           info->axis = CLUTTER_X_AXIS;
11607
11608           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11609             {
11610               info->angle = json_node_get_double (member);
11611               retval = TRUE;
11612             }
11613           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11614             retval = parse_rotation_array (actor,
11615                                            json_node_get_array (member),
11616                                            info);
11617           else
11618             retval = FALSE;
11619         }
11620       else if (json_object_has_member (object, "y-axis"))
11621         {
11622           member = json_object_get_member (object, "y-axis");
11623
11624           info->axis = CLUTTER_Y_AXIS;
11625
11626           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11627             {
11628               info->angle = json_node_get_double (member);
11629               retval = TRUE;
11630             }
11631           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11632             retval = parse_rotation_array (actor,
11633                                            json_node_get_array (member),
11634                                            info);
11635           else
11636             retval = FALSE;
11637         }
11638       else if (json_object_has_member (object, "z-axis"))
11639         {
11640           member = json_object_get_member (object, "z-axis");
11641
11642           info->axis = CLUTTER_Z_AXIS;
11643
11644           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11645             {
11646               info->angle = json_node_get_double (member);
11647               retval = TRUE;
11648             }
11649           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11650             retval = parse_rotation_array (actor,
11651                                            json_node_get_array (member),
11652                                            info);
11653           else
11654             retval = FALSE;
11655         }
11656     }
11657
11658   return retval;
11659 }
11660
11661 static GSList *
11662 parse_actor_metas (ClutterScript *script,
11663                    ClutterActor  *actor,
11664                    JsonNode      *node)
11665 {
11666   GList *elements, *l;
11667   GSList *retval = NULL;
11668
11669   if (!JSON_NODE_HOLDS_ARRAY (node))
11670     return NULL;
11671
11672   elements = json_array_get_elements (json_node_get_array (node));
11673
11674   for (l = elements; l != NULL; l = l->next)
11675     {
11676       JsonNode *element = l->data;
11677       const gchar *id_ = _clutter_script_get_id_from_node (element);
11678       GObject *meta;
11679
11680       if (id_ == NULL || *id_ == '\0')
11681         continue;
11682
11683       meta = clutter_script_get_object (script, id_);
11684       if (meta == NULL)
11685         continue;
11686
11687       retval = g_slist_prepend (retval, meta);
11688     }
11689
11690   g_list_free (elements);
11691
11692   return g_slist_reverse (retval);
11693 }
11694
11695 static GSList *
11696 parse_behaviours (ClutterScript *script,
11697                   ClutterActor  *actor,
11698                   JsonNode      *node)
11699 {
11700   GList *elements, *l;
11701   GSList *retval = NULL;
11702
11703   if (!JSON_NODE_HOLDS_ARRAY (node))
11704     return NULL;
11705
11706   elements = json_array_get_elements (json_node_get_array (node));
11707
11708   for (l = elements; l != NULL; l = l->next)
11709     {
11710       JsonNode *element = l->data;
11711       const gchar *id_ = _clutter_script_get_id_from_node (element);
11712       GObject *behaviour;
11713
11714       if (id_ == NULL || *id_ == '\0')
11715         continue;
11716
11717       behaviour = clutter_script_get_object (script, id_);
11718       if (behaviour == NULL)
11719         continue;
11720
11721       retval = g_slist_prepend (retval, behaviour);
11722     }
11723
11724   g_list_free (elements);
11725
11726   return g_slist_reverse (retval);
11727 }
11728
11729 static gboolean
11730 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11731                                  ClutterScript     *script,
11732                                  GValue            *value,
11733                                  const gchar       *name,
11734                                  JsonNode          *node)
11735 {
11736   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11737   gboolean retval = FALSE;
11738
11739   if ((name[0] == 'x' && name[1] == '\0') ||
11740       (name[0] == 'y' && name[1] == '\0') ||
11741       (strcmp (name, "width") == 0) ||
11742       (strcmp (name, "height") == 0) ||
11743       (strcmp (name, "anchor_x") == 0) ||
11744       (strcmp (name, "anchor_y") == 0))
11745     {
11746       ParseDimension dimension;
11747       gfloat units;
11748
11749       if (name[0] == 'x')
11750         dimension = PARSE_X;
11751       else if (name[0] == 'y')
11752         dimension = PARSE_Y;
11753       else if (name[0] == 'w')
11754         dimension = PARSE_WIDTH;
11755       else if (name[0] == 'h')
11756         dimension = PARSE_HEIGHT;
11757       else if (name[0] == 'a' && name[7] == 'x')
11758         dimension = PARSE_ANCHOR_X;
11759       else if (name[0] == 'a' && name[7] == 'y')
11760         dimension = PARSE_ANCHOR_Y;
11761       else
11762         return FALSE;
11763
11764       units = parse_units (actor, dimension, node);
11765
11766       /* convert back to pixels: all properties are pixel-based */
11767       g_value_init (value, G_TYPE_FLOAT);
11768       g_value_set_float (value, units);
11769
11770       retval = TRUE;
11771     }
11772   else if (strcmp (name, "rotation") == 0)
11773     {
11774       RotationInfo *info;
11775
11776       info = g_slice_new0 (RotationInfo);
11777       retval = parse_rotation (actor, node, info);
11778
11779       if (retval)
11780         {
11781           g_value_init (value, G_TYPE_POINTER);
11782           g_value_set_pointer (value, info);
11783         }
11784       else
11785         g_slice_free (RotationInfo, info);
11786     }
11787   else if (strcmp (name, "behaviours") == 0)
11788     {
11789       GSList *l;
11790
11791 #ifdef CLUTTER_ENABLE_DEBUG
11792       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11793         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11794                                      "and it should not be used in newly "
11795                                      "written ClutterScript definitions.");
11796 #endif
11797
11798       l = parse_behaviours (script, actor, node);
11799
11800       g_value_init (value, G_TYPE_POINTER);
11801       g_value_set_pointer (value, l);
11802
11803       retval = TRUE;
11804     }
11805   else if (strcmp (name, "actions") == 0 ||
11806            strcmp (name, "constraints") == 0 ||
11807            strcmp (name, "effects") == 0)
11808     {
11809       GSList *l;
11810
11811       l = parse_actor_metas (script, actor, node);
11812
11813       g_value_init (value, G_TYPE_POINTER);
11814       g_value_set_pointer (value, l);
11815
11816       retval = TRUE;
11817     }
11818
11819   return retval;
11820 }
11821
11822 static void
11823 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11824                                    ClutterScript     *script,
11825                                    const gchar       *name,
11826                                    const GValue      *value)
11827 {
11828   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11829
11830 #ifdef CLUTTER_ENABLE_DEBUG
11831   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11832     {
11833       gchar *tmp = g_strdup_value_contents (value);
11834
11835       CLUTTER_NOTE (SCRIPT,
11836                     "in ClutterActor::set_custom_property('%s') = %s",
11837                     name,
11838                     tmp);
11839
11840       g_free (tmp);
11841     }
11842 #endif /* CLUTTER_ENABLE_DEBUG */
11843
11844   if (strcmp (name, "rotation") == 0)
11845     {
11846       RotationInfo *info;
11847
11848       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11849         return;
11850
11851       info = g_value_get_pointer (value);
11852
11853       clutter_actor_set_rotation (actor,
11854                                   info->axis, info->angle,
11855                                   info->center_x,
11856                                   info->center_y,
11857                                   info->center_z);
11858
11859       g_slice_free (RotationInfo, info);
11860
11861       return;
11862     }
11863
11864   if (strcmp (name, "behaviours") == 0)
11865     {
11866       GSList *behaviours, *l;
11867
11868       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11869         return;
11870
11871       behaviours = g_value_get_pointer (value);
11872       for (l = behaviours; l != NULL; l = l->next)
11873         {
11874           ClutterBehaviour *behaviour = l->data;
11875
11876           clutter_behaviour_apply (behaviour, actor);
11877         }
11878
11879       g_slist_free (behaviours);
11880
11881       return;
11882     }
11883
11884   if (strcmp (name, "actions") == 0 ||
11885       strcmp (name, "constraints") == 0 ||
11886       strcmp (name, "effects") == 0)
11887     {
11888       GSList *metas, *l;
11889
11890       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11891         return;
11892
11893       metas = g_value_get_pointer (value);
11894       for (l = metas; l != NULL; l = l->next)
11895         {
11896           if (name[0] == 'a')
11897             clutter_actor_add_action (actor, l->data);
11898
11899           if (name[0] == 'c')
11900             clutter_actor_add_constraint (actor, l->data);
11901
11902           if (name[0] == 'e')
11903             clutter_actor_add_effect (actor, l->data);
11904         }
11905
11906       g_slist_free (metas);
11907
11908       return;
11909     }
11910
11911   g_object_set_property (G_OBJECT (scriptable), name, value);
11912 }
11913
11914 static void
11915 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
11916 {
11917   iface->parse_custom_node = clutter_actor_parse_custom_node;
11918   iface->set_custom_property = clutter_actor_set_custom_property;
11919 }
11920
11921 static ClutterActorMeta *
11922 get_meta_from_animation_property (ClutterActor  *actor,
11923                                   const gchar   *name,
11924                                   gchar        **name_p)
11925 {
11926   ClutterActorPrivate *priv = actor->priv;
11927   ClutterActorMeta *meta = NULL;
11928   gchar **tokens;
11929
11930   /* if this is not a special property, fall through */
11931   if (name[0] != '@')
11932     return NULL;
11933
11934   /* detect the properties named using the following spec:
11935    *
11936    *   @<section>.<meta-name>.<property-name>
11937    *
11938    * where <section> can be one of the following:
11939    *
11940    *   - actions
11941    *   - constraints
11942    *   - effects
11943    *
11944    * and <meta-name> is the name set on a specific ActorMeta
11945    */
11946
11947   tokens = g_strsplit (name + 1, ".", -1);
11948   if (tokens == NULL || g_strv_length (tokens) != 3)
11949     {
11950       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
11951                     name + 1);
11952       g_strfreev (tokens);
11953       return NULL;
11954     }
11955
11956   if (strcmp (tokens[0], "actions") == 0)
11957     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
11958
11959   if (strcmp (tokens[0], "constraints") == 0)
11960     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
11961
11962   if (strcmp (tokens[0], "effects") == 0)
11963     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
11964
11965   if (name_p != NULL)
11966     *name_p = g_strdup (tokens[2]);
11967
11968   CLUTTER_NOTE (ANIMATION,
11969                 "Looking for property '%s' of object '%s' in section '%s'",
11970                 tokens[2],
11971                 tokens[1],
11972                 tokens[0]);
11973
11974   g_strfreev (tokens);
11975
11976   return meta;
11977 }
11978
11979 static GParamSpec *
11980 clutter_actor_find_property (ClutterAnimatable *animatable,
11981                              const gchar       *property_name)
11982 {
11983   ClutterActorMeta *meta = NULL;
11984   GObjectClass *klass = NULL;
11985   GParamSpec *pspec = NULL;
11986   gchar *p_name = NULL;
11987
11988   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11989                                            property_name,
11990                                            &p_name);
11991
11992   if (meta != NULL)
11993     {
11994       klass = G_OBJECT_GET_CLASS (meta);
11995
11996       pspec = g_object_class_find_property (klass, p_name);
11997     }
11998   else
11999     {
12000       klass = G_OBJECT_GET_CLASS (animatable);
12001
12002       pspec = g_object_class_find_property (klass, property_name);
12003     }
12004
12005   g_free (p_name);
12006
12007   return pspec;
12008 }
12009
12010 static void
12011 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12012                                  const gchar       *property_name,
12013                                  GValue            *initial)
12014 {
12015   ClutterActorMeta *meta = NULL;
12016   gchar *p_name = NULL;
12017
12018   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12019                                            property_name,
12020                                            &p_name);
12021
12022   if (meta != NULL)
12023     g_object_get_property (G_OBJECT (meta), p_name, initial);
12024   else
12025     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12026
12027   g_free (p_name);
12028 }
12029
12030 static void
12031 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12032                                const gchar       *property_name,
12033                                const GValue      *final)
12034 {
12035   ClutterActorMeta *meta = NULL;
12036   gchar *p_name = NULL;
12037
12038   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12039                                            property_name,
12040                                            &p_name);
12041   if (meta != NULL)
12042     g_object_set_property (G_OBJECT (meta), p_name, final);
12043   else
12044     g_object_set_property (G_OBJECT (animatable), property_name, final);
12045
12046   g_free (p_name);
12047 }
12048
12049 static void
12050 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12051 {
12052   iface->find_property = clutter_actor_find_property;
12053   iface->get_initial_state = clutter_actor_get_initial_state;
12054   iface->set_final_state = clutter_actor_set_final_state;
12055 }
12056
12057 /**
12058  * clutter_actor_transform_stage_point:
12059  * @self: A #ClutterActor
12060  * @x: (in): x screen coordinate of the point to unproject
12061  * @y: (in): y screen coordinate of the point to unproject
12062  * @x_out: (out): return location for the unprojected x coordinance
12063  * @y_out: (out): return location for the unprojected y coordinance
12064  *
12065  * This function translates screen coordinates (@x, @y) to
12066  * coordinates relative to the actor. For example, it can be used to translate
12067  * screen events from global screen coordinates into actor-local coordinates.
12068  *
12069  * The conversion can fail, notably if the transform stack results in the
12070  * actor being projected on the screen as a mere line.
12071  *
12072  * The conversion should not be expected to be pixel-perfect due to the
12073  * nature of the operation. In general the error grows when the skewing
12074  * of the actor rectangle on screen increases.
12075  *
12076  * <note><para>This function can be computationally intensive.</para></note>
12077  *
12078  * <note><para>This function only works when the allocation is up-to-date,
12079  * i.e. inside of paint().</para></note>
12080  *
12081  * Return value: %TRUE if conversion was successful.
12082  *
12083  * Since: 0.6
12084  */
12085 gboolean
12086 clutter_actor_transform_stage_point (ClutterActor *self,
12087                                      gfloat        x,
12088                                      gfloat        y,
12089                                      gfloat       *x_out,
12090                                      gfloat       *y_out)
12091 {
12092   ClutterVertex v[4];
12093   float ST[3][3];
12094   float RQ[3][3];
12095   int du, dv, xi, yi;
12096   float px, py;
12097   float xf, yf, wf, det;
12098   ClutterActorPrivate *priv;
12099
12100   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12101
12102   priv = self->priv;
12103
12104   /* This implementation is based on the quad -> quad projection algorithm
12105    * described by Paul Heckbert in:
12106    *
12107    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12108    *
12109    * and the sample implementation at:
12110    *
12111    *   http://www.cs.cmu.edu/~ph/src/texfund/
12112    *
12113    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12114    * quad to rectangle only, which significantly simplifies things; the
12115    * function calls have been unrolled, and most of the math is done in fixed
12116    * point.
12117    */
12118
12119   clutter_actor_get_abs_allocation_vertices (self, v);
12120
12121   /* Keeping these as ints simplifies the multiplication (no significant
12122    * loss of precision here).
12123    */
12124   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12125   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12126
12127   if (!du || !dv)
12128     return FALSE;
12129
12130 #define UX2FP(x)        (x)
12131 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12132
12133   /* First, find mapping from unit uv square to xy quadrilateral; this
12134    * equivalent to the pmap_square_quad() functions in the sample
12135    * implementation, which we can simplify, since our target is always
12136    * a rectangle.
12137    */
12138   px = v[0].x - v[1].x + v[3].x - v[2].x;
12139   py = v[0].y - v[1].y + v[3].y - v[2].y;
12140
12141   if (!px && !py)
12142     {
12143       /* affine transform */
12144       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12145       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12146       RQ[2][0] = UX2FP (v[0].x);
12147       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12148       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12149       RQ[2][1] = UX2FP (v[0].y);
12150       RQ[0][2] = 0;
12151       RQ[1][2] = 0;
12152       RQ[2][2] = 1.0;
12153     }
12154   else
12155     {
12156       /* projective transform */
12157       double dx1, dx2, dy1, dy2, del;
12158
12159       dx1 = UX2FP (v[1].x - v[3].x);
12160       dx2 = UX2FP (v[2].x - v[3].x);
12161       dy1 = UX2FP (v[1].y - v[3].y);
12162       dy2 = UX2FP (v[2].y - v[3].y);
12163
12164       del = DET2FP (dx1, dx2, dy1, dy2);
12165       if (!del)
12166         return FALSE;
12167
12168       /*
12169        * The division here needs to be done in floating point for
12170        * precisions reasons.
12171        */
12172       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12173       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12174       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12175       RQ[2][2] = 1.0;
12176       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12177       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12178       RQ[2][0] = UX2FP (v[0].x);
12179       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12180       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12181       RQ[2][1] = UX2FP (v[0].y);
12182     }
12183
12184   /*
12185    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12186    * square. Since our rectangle is based at 0,0 we only need to scale.
12187    */
12188   RQ[0][0] /= du;
12189   RQ[1][0] /= dv;
12190   RQ[0][1] /= du;
12191   RQ[1][1] /= dv;
12192   RQ[0][2] /= du;
12193   RQ[1][2] /= dv;
12194
12195   /*
12196    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12197    * inverse of that.
12198    */
12199   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12200   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12201   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12202   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12203   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12204   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12205   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12206   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12207   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12208
12209   /*
12210    * Check the resulting matrix is OK.
12211    */
12212   det = (RQ[0][0] * ST[0][0])
12213       + (RQ[0][1] * ST[0][1])
12214       + (RQ[0][2] * ST[0][2]);
12215   if (!det)
12216     return FALSE;
12217
12218   /*
12219    * Now transform our point with the ST matrix; the notional w
12220    * coordinate is 1, hence the last part is simply added.
12221    */
12222   xi = (int) x;
12223   yi = (int) y;
12224
12225   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12226   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12227   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12228
12229   if (x_out)
12230     *x_out = xf / wf;
12231
12232   if (y_out)
12233     *y_out = yf / wf;
12234
12235 #undef UX2FP
12236 #undef DET2FP
12237
12238   return TRUE;
12239 }
12240
12241 /*
12242  * ClutterGeometry
12243  */
12244
12245 static ClutterGeometry*
12246 clutter_geometry_copy (const ClutterGeometry *geometry)
12247 {
12248   return g_slice_dup (ClutterGeometry, geometry);
12249 }
12250
12251 static void
12252 clutter_geometry_free (ClutterGeometry *geometry)
12253 {
12254   if (G_LIKELY (geometry != NULL))
12255     g_slice_free (ClutterGeometry, geometry);
12256 }
12257
12258 /**
12259  * clutter_geometry_union:
12260  * @geometry_a: a #ClutterGeometry
12261  * @geometry_b: another #ClutterGeometry
12262  * @result: (out): location to store the result
12263  *
12264  * Find the union of two rectangles represented as #ClutterGeometry.
12265  *
12266  * Since: 1.4
12267  */
12268 void
12269 clutter_geometry_union (const ClutterGeometry *geometry_a,
12270                         const ClutterGeometry *geometry_b,
12271                         ClutterGeometry       *result)
12272 {
12273   /* We don't try to handle rectangles that can't be represented
12274    * as a signed integer box */
12275   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12276   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12277   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12278                   geometry_b->x + (gint)geometry_b->width);
12279   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12280                   geometry_b->y + (gint)geometry_b->height);
12281   result->x = x_1;
12282   result->y = y_1;
12283   result->width = x_2 - x_1;
12284   result->height = y_2 - y_1;
12285 }
12286
12287 /**
12288  * clutter_geometry_intersects:
12289  * @geometry0: The first geometry to test
12290  * @geometry1: The second geometry to test
12291  *
12292  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12293  * they do else %FALSE.
12294  *
12295  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12296  * %FALSE.
12297  *
12298  * Since: 1.4
12299  */
12300 gboolean
12301 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12302                              const ClutterGeometry *geometry1)
12303 {
12304   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12305       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12306       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12307       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12308     return FALSE;
12309   else
12310     return TRUE;
12311 }
12312
12313 static gboolean
12314 clutter_geometry_progress (const GValue *a,
12315                            const GValue *b,
12316                            gdouble       progress,
12317                            GValue       *retval)
12318 {
12319   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12320   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12321   ClutterGeometry res = { 0, };
12322   gint a_width = a_geom->width;
12323   gint b_width = b_geom->width;
12324   gint a_height = a_geom->height;
12325   gint b_height = b_geom->height;
12326
12327   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12328   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12329
12330   res.width = a_width + (b_width - a_width) * progress;
12331   res.height = a_height + (b_height - a_height) * progress;
12332
12333   g_value_set_boxed (retval, &res);
12334
12335   return TRUE;
12336 }
12337
12338 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12339                                clutter_geometry_copy,
12340                                clutter_geometry_free,
12341                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12342
12343 /*
12344  * ClutterVertices
12345  */
12346
12347 /**
12348  * clutter_vertex_new:
12349  * @x: X coordinate
12350  * @y: Y coordinate
12351  * @z: Z coordinate
12352  *
12353  * Creates a new #ClutterVertex for the point in 3D space
12354  * identified by the 3 coordinates @x, @y, @z
12355  *
12356  * Return value: the newly allocate #ClutterVertex. Use
12357  *   clutter_vertex_free() to free the resources
12358  *
12359  * Since: 1.0
12360  */
12361 ClutterVertex *
12362 clutter_vertex_new (gfloat x,
12363                     gfloat y,
12364                     gfloat z)
12365 {
12366   ClutterVertex *vertex;
12367
12368   vertex = g_slice_new (ClutterVertex);
12369   vertex->x = x;
12370   vertex->y = y;
12371   vertex->z = z;
12372
12373   return vertex;
12374 }
12375
12376 /**
12377  * clutter_vertex_copy:
12378  * @vertex: a #ClutterVertex
12379  *
12380  * Copies @vertex
12381  *
12382  * Return value: a newly allocated copy of #ClutterVertex. Use
12383  *   clutter_vertex_free() to free the allocated resources
12384  *
12385  * Since: 1.0
12386  */
12387 ClutterVertex *
12388 clutter_vertex_copy (const ClutterVertex *vertex)
12389 {
12390   if (G_LIKELY (vertex != NULL))
12391     return g_slice_dup (ClutterVertex, vertex);
12392
12393   return NULL;
12394 }
12395
12396 /**
12397  * clutter_vertex_free:
12398  * @vertex: a #ClutterVertex
12399  *
12400  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12401  *
12402  * Since: 1.0
12403  */
12404 void
12405 clutter_vertex_free (ClutterVertex *vertex)
12406 {
12407   if (G_UNLIKELY (vertex != NULL))
12408     g_slice_free (ClutterVertex, vertex);
12409 }
12410
12411 /**
12412  * clutter_vertex_equal:
12413  * @vertex_a: a #ClutterVertex
12414  * @vertex_b: a #ClutterVertex
12415  *
12416  * Compares @vertex_a and @vertex_b for equality
12417  *
12418  * Return value: %TRUE if the passed #ClutterVertex are equal
12419  *
12420  * Since: 1.0
12421  */
12422 gboolean
12423 clutter_vertex_equal (const ClutterVertex *vertex_a,
12424                       const ClutterVertex *vertex_b)
12425 {
12426   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12427
12428   if (vertex_a == vertex_b)
12429     return TRUE;
12430
12431   return vertex_a->x == vertex_b->x &&
12432          vertex_a->y == vertex_b->y &&
12433          vertex_a->z == vertex_b->z;
12434 }
12435
12436 static gboolean
12437 clutter_vertex_progress (const GValue *a,
12438                          const GValue *b,
12439                          gdouble       progress,
12440                          GValue       *retval)
12441 {
12442   const ClutterVertex *av = g_value_get_boxed (a);
12443   const ClutterVertex *bv = g_value_get_boxed (b);
12444   ClutterVertex res = { 0, };
12445
12446   res.x = av->x + (bv->x - av->x) * progress;
12447   res.y = av->y + (bv->y - av->y) * progress;
12448   res.z = av->z + (bv->z - av->z) * progress;
12449
12450   g_value_set_boxed (retval, &res);
12451
12452   return TRUE;
12453 }
12454
12455 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12456                                clutter_vertex_copy,
12457                                clutter_vertex_free,
12458                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12459
12460 /**
12461  * clutter_actor_is_rotated:
12462  * @self: a #ClutterActor
12463  *
12464  * Checks whether any rotation is applied to the actor.
12465  *
12466  * Return value: %TRUE if the actor is rotated.
12467  *
12468  * Since: 0.6
12469  */
12470 gboolean
12471 clutter_actor_is_rotated (ClutterActor *self)
12472 {
12473   const ClutterTransformInfo *info;
12474
12475   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12476
12477   info = _clutter_actor_get_transform_info_or_defaults (self);
12478
12479   if (info->rx_angle || info->ry_angle || info->rz_angle)
12480     return TRUE;
12481
12482   return FALSE;
12483 }
12484
12485 /**
12486  * clutter_actor_is_scaled:
12487  * @self: a #ClutterActor
12488  *
12489  * Checks whether the actor is scaled in either dimension.
12490  *
12491  * Return value: %TRUE if the actor is scaled.
12492  *
12493  * Since: 0.6
12494  */
12495 gboolean
12496 clutter_actor_is_scaled (ClutterActor *self)
12497 {
12498   const ClutterTransformInfo *info;
12499
12500   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12501
12502   info = _clutter_actor_get_transform_info_or_defaults (self);
12503
12504   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12505     return TRUE;
12506
12507   return FALSE;
12508 }
12509
12510 ClutterActor *
12511 _clutter_actor_get_stage_internal (ClutterActor *actor)
12512 {
12513   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12514     actor = actor->priv->parent;
12515
12516   return actor;
12517 }
12518
12519 /**
12520  * clutter_actor_get_stage:
12521  * @actor: a #ClutterActor
12522  *
12523  * Retrieves the #ClutterStage where @actor is contained.
12524  *
12525  * Return value: (transfer none) (type Clutter.Stage): the stage
12526  *   containing the actor, or %NULL
12527  *
12528  * Since: 0.8
12529  */
12530 ClutterActor *
12531 clutter_actor_get_stage (ClutterActor *actor)
12532 {
12533   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12534
12535   return _clutter_actor_get_stage_internal (actor);
12536 }
12537
12538 /**
12539  * clutter_actor_allocate_available_size:
12540  * @self: a #ClutterActor
12541  * @x: the actor's X coordinate
12542  * @y: the actor's Y coordinate
12543  * @available_width: the maximum available width, or -1 to use the
12544  *   actor's natural width
12545  * @available_height: the maximum available height, or -1 to use the
12546  *   actor's natural height
12547  * @flags: flags controlling the allocation
12548  *
12549  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12550  * preferred size, but limiting it to the maximum available width
12551  * and height provided.
12552  *
12553  * This function will do the right thing when dealing with the
12554  * actor's request mode.
12555  *
12556  * The implementation of this function is equivalent to:
12557  *
12558  * |[
12559  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12560  *     {
12561  *       clutter_actor_get_preferred_width (self, available_height,
12562  *                                          &amp;min_width,
12563  *                                          &amp;natural_width);
12564  *       width = CLAMP (natural_width, min_width, available_width);
12565  *
12566  *       clutter_actor_get_preferred_height (self, width,
12567  *                                           &amp;min_height,
12568  *                                           &amp;natural_height);
12569  *       height = CLAMP (natural_height, min_height, available_height);
12570  *     }
12571  *   else
12572  *     {
12573  *       clutter_actor_get_preferred_height (self, available_width,
12574  *                                           &amp;min_height,
12575  *                                           &amp;natural_height);
12576  *       height = CLAMP (natural_height, min_height, available_height);
12577  *
12578  *       clutter_actor_get_preferred_width (self, height,
12579  *                                          &amp;min_width,
12580  *                                          &amp;natural_width);
12581  *       width = CLAMP (natural_width, min_width, available_width);
12582  *     }
12583  *
12584  *   box.x1 = x; box.y1 = y;
12585  *   box.x2 = box.x1 + available_width;
12586  *   box.y2 = box.y1 + available_height;
12587  *   clutter_actor_allocate (self, &amp;box, flags);
12588  * ]|
12589  *
12590  * This function can be used by fluid layout managers to allocate
12591  * an actor's preferred size without making it bigger than the area
12592  * available for the container.
12593  *
12594  * Since: 1.0
12595  */
12596 void
12597 clutter_actor_allocate_available_size (ClutterActor           *self,
12598                                        gfloat                  x,
12599                                        gfloat                  y,
12600                                        gfloat                  available_width,
12601                                        gfloat                  available_height,
12602                                        ClutterAllocationFlags  flags)
12603 {
12604   ClutterActorPrivate *priv;
12605   gfloat width, height;
12606   gfloat min_width, min_height;
12607   gfloat natural_width, natural_height;
12608   ClutterActorBox box;
12609
12610   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12611
12612   priv = self->priv;
12613
12614   width = height = 0.0;
12615
12616   switch (priv->request_mode)
12617     {
12618     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12619       clutter_actor_get_preferred_width (self, available_height,
12620                                          &min_width,
12621                                          &natural_width);
12622       width  = CLAMP (natural_width, min_width, available_width);
12623
12624       clutter_actor_get_preferred_height (self, width,
12625                                           &min_height,
12626                                           &natural_height);
12627       height = CLAMP (natural_height, min_height, available_height);
12628       break;
12629
12630     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12631       clutter_actor_get_preferred_height (self, available_width,
12632                                           &min_height,
12633                                           &natural_height);
12634       height = CLAMP (natural_height, min_height, available_height);
12635
12636       clutter_actor_get_preferred_width (self, height,
12637                                          &min_width,
12638                                          &natural_width);
12639       width  = CLAMP (natural_width, min_width, available_width);
12640       break;
12641     }
12642
12643
12644   box.x1 = x;
12645   box.y1 = y;
12646   box.x2 = box.x1 + width;
12647   box.y2 = box.y1 + height;
12648   clutter_actor_allocate (self, &box, flags);
12649 }
12650
12651 /**
12652  * clutter_actor_allocate_preferred_size:
12653  * @self: a #ClutterActor
12654  * @flags: flags controlling the allocation
12655  *
12656  * Allocates the natural size of @self.
12657  *
12658  * This function is a utility call for #ClutterActor implementations
12659  * that allocates the actor's preferred natural size. It can be used
12660  * by fixed layout managers (like #ClutterGroup or so called
12661  * 'composite actors') inside the ClutterActor::allocate
12662  * implementation to give each child exactly how much space it
12663  * requires.
12664  *
12665  * This function is not meant to be used by applications. It is also
12666  * not meant to be used outside the implementation of the
12667  * ClutterActor::allocate virtual function.
12668  *
12669  * Since: 0.8
12670  */
12671 void
12672 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12673                                        ClutterAllocationFlags  flags)
12674 {
12675   gfloat actor_x, actor_y;
12676   gfloat natural_width, natural_height;
12677   ClutterActorBox actor_box;
12678
12679   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12680
12681   actor_x = clutter_actor_get_x (self);
12682   actor_y = clutter_actor_get_y (self);
12683
12684   clutter_actor_get_preferred_size (self,
12685                                     NULL, NULL,
12686                                     &natural_width,
12687                                     &natural_height);
12688
12689   actor_box.x1 = actor_x;
12690   actor_box.y1 = actor_y;
12691   actor_box.x2 = actor_box.x1 + natural_width;
12692   actor_box.y2 = actor_box.y1 + natural_height;
12693
12694   clutter_actor_allocate (self, &actor_box, flags);
12695 }
12696
12697 /**
12698  * clutter_actor_allocate_align_fill:
12699  * @self: a #ClutterActor
12700  * @box: a #ClutterActorBox, containing the available width and height
12701  * @x_align: the horizontal alignment, between 0 and 1
12702  * @y_align: the vertical alignment, between 0 and 1
12703  * @x_fill: whether the actor should fill horizontally
12704  * @y_fill: whether the actor should fill vertically
12705  * @flags: allocation flags to be passed to clutter_actor_allocate()
12706  *
12707  * Allocates @self by taking into consideration the available allocation
12708  * area; an alignment factor on either axis; and whether the actor should
12709  * fill the allocation on either axis.
12710  *
12711  * The @box should contain the available allocation width and height;
12712  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12713  * allocation will be offset by their value.
12714  *
12715  * This function takes into consideration the geometry request specified by
12716  * the #ClutterActor:request-mode property, and the text direction.
12717  *
12718  * This function is useful for fluid layout managers, like #ClutterBinLayout
12719  * or #ClutterTableLayout
12720  *
12721  * Since: 1.4
12722  */
12723 void
12724 clutter_actor_allocate_align_fill (ClutterActor           *self,
12725                                    const ClutterActorBox  *box,
12726                                    gdouble                 x_align,
12727                                    gdouble                 y_align,
12728                                    gboolean                x_fill,
12729                                    gboolean                y_fill,
12730                                    ClutterAllocationFlags  flags)
12731 {
12732   ClutterActorPrivate *priv;
12733   ClutterActorBox allocation = { 0, };
12734   gfloat x_offset, y_offset;
12735   gfloat available_width, available_height;
12736   gfloat child_width, child_height;
12737
12738   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12739   g_return_if_fail (box != NULL);
12740   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12741   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12742
12743   priv = self->priv;
12744
12745   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12746   clutter_actor_box_get_size (box, &available_width, &available_height);
12747
12748   if (available_width < 0)
12749     available_width = 0;
12750
12751   if (available_height < 0)
12752     available_height = 0;
12753
12754   if (x_fill)
12755     {
12756       allocation.x1 = x_offset;
12757       allocation.x2 = allocation.x1 + available_width;
12758     }
12759
12760   if (y_fill)
12761     {
12762       allocation.y1 = y_offset;
12763       allocation.y2 = allocation.y1 + available_height;
12764     }
12765
12766   /* if we are filling horizontally and vertically then we're done */
12767   if (x_fill && y_fill)
12768     goto out;
12769
12770   child_width = child_height = 0.0f;
12771
12772   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12773     {
12774       gfloat min_width, natural_width;
12775       gfloat min_height, natural_height;
12776
12777       clutter_actor_get_preferred_width (self, available_height,
12778                                          &min_width,
12779                                          &natural_width);
12780
12781       child_width = CLAMP (natural_width, min_width, available_width);
12782
12783       if (!y_fill)
12784         {
12785           clutter_actor_get_preferred_height (self, child_width,
12786                                               &min_height,
12787                                               &natural_height);
12788
12789           child_height = CLAMP (natural_height, min_height, available_height);
12790         }
12791     }
12792   else
12793     {
12794       gfloat min_width, natural_width;
12795       gfloat min_height, natural_height;
12796
12797       clutter_actor_get_preferred_height (self, available_width,
12798                                           &min_height,
12799                                           &natural_height);
12800
12801       child_height = CLAMP (natural_height, min_height, available_height);
12802
12803       if (!x_fill)
12804         {
12805           clutter_actor_get_preferred_width (self, child_height,
12806                                              &min_width,
12807                                              &natural_width);
12808
12809           child_width = CLAMP (natural_width, min_width, available_width);
12810         }
12811     }
12812
12813   /* invert the horizontal alignment for RTL languages */
12814   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12815     x_align = 1.0 - x_align;
12816
12817   if (!x_fill)
12818     {
12819       allocation.x1 = x_offset
12820                     + ((available_width - child_width) * x_align);
12821       allocation.x2 = allocation.x1 + child_width;
12822     }
12823
12824   if (!y_fill)
12825     {
12826       allocation.y1 = y_offset
12827                     + ((available_height - child_height) * y_align);
12828       allocation.y2 = allocation.y1 + child_height;
12829     }
12830
12831 out:
12832   clutter_actor_box_clamp_to_pixel (&allocation);
12833   clutter_actor_allocate (self, &allocation, flags);
12834 }
12835
12836 /**
12837  * clutter_actor_grab_key_focus:
12838  * @self: a #ClutterActor
12839  *
12840  * Sets the key focus of the #ClutterStage including @self
12841  * to this #ClutterActor.
12842  *
12843  * Since: 1.0
12844  */
12845 void
12846 clutter_actor_grab_key_focus (ClutterActor *self)
12847 {
12848   ClutterActor *stage;
12849
12850   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12851
12852   stage = _clutter_actor_get_stage_internal (self);
12853   if (stage != NULL)
12854     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12855 }
12856
12857 /**
12858  * clutter_actor_get_pango_context:
12859  * @self: a #ClutterActor
12860  *
12861  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12862  * is already configured using the appropriate font map, resolution
12863  * and font options.
12864  *
12865  * Unlike clutter_actor_create_pango_context(), this context is owend
12866  * by the #ClutterActor and it will be updated each time the options
12867  * stored by the #ClutterBackend change.
12868  *
12869  * You can use the returned #PangoContext to create a #PangoLayout
12870  * and render text using cogl_pango_render_layout() to reuse the
12871  * glyphs cache also used by Clutter.
12872  *
12873  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12874  *   The returned #PangoContext is owned by the actor and should not be
12875  *   unreferenced by the application code
12876  *
12877  * Since: 1.0
12878  */
12879 PangoContext *
12880 clutter_actor_get_pango_context (ClutterActor *self)
12881 {
12882   ClutterActorPrivate *priv;
12883
12884   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12885
12886   priv = self->priv;
12887
12888   if (priv->pango_context != NULL)
12889     return priv->pango_context;
12890
12891   priv->pango_context = _clutter_context_get_pango_context ();
12892   g_object_ref (priv->pango_context);
12893
12894   return priv->pango_context;
12895 }
12896
12897 /**
12898  * clutter_actor_create_pango_context:
12899  * @self: a #ClutterActor
12900  *
12901  * Creates a #PangoContext for the given actor. The #PangoContext
12902  * is already configured using the appropriate font map, resolution
12903  * and font options.
12904  *
12905  * See also clutter_actor_get_pango_context().
12906  *
12907  * Return value: (transfer full): the newly created #PangoContext.
12908  *   Use g_object_unref() on the returned value to deallocate its
12909  *   resources
12910  *
12911  * Since: 1.0
12912  */
12913 PangoContext *
12914 clutter_actor_create_pango_context (ClutterActor *self)
12915 {
12916   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12917
12918   return _clutter_context_create_pango_context ();
12919 }
12920
12921 /**
12922  * clutter_actor_create_pango_layout:
12923  * @self: a #ClutterActor
12924  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
12925  *
12926  * Creates a new #PangoLayout from the same #PangoContext used
12927  * by the #ClutterActor. The #PangoLayout is already configured
12928  * with the font map, resolution and font options, and the
12929  * given @text.
12930  *
12931  * If you want to keep around a #PangoLayout created by this
12932  * function you will have to connect to the #ClutterBackend::font-changed
12933  * and #ClutterBackend::resolution-changed signals, and call
12934  * pango_layout_context_changed() in response to them.
12935  *
12936  * Return value: (transfer full): the newly created #PangoLayout.
12937  *   Use g_object_unref() when done
12938  *
12939  * Since: 1.0
12940  */
12941 PangoLayout *
12942 clutter_actor_create_pango_layout (ClutterActor *self,
12943                                    const gchar  *text)
12944 {
12945   PangoContext *context;
12946   PangoLayout *layout;
12947
12948   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12949
12950   context = clutter_actor_get_pango_context (self);
12951   layout = pango_layout_new (context);
12952
12953   if (text)
12954     pango_layout_set_text (layout, text, -1);
12955
12956   return layout;
12957 }
12958
12959 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
12960  * ClutterOffscreenEffect.
12961  */
12962 void
12963 _clutter_actor_set_opacity_override (ClutterActor *self,
12964                                      gint          opacity)
12965 {
12966   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12967
12968   self->priv->opacity_override = opacity;
12969 }
12970
12971 gint
12972 _clutter_actor_get_opacity_override (ClutterActor *self)
12973 {
12974   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
12975
12976   return self->priv->opacity_override;
12977 }
12978
12979 /* Allows you to disable applying the actors model view transform during
12980  * a paint. Used by ClutterClone. */
12981 void
12982 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
12983                                                 gboolean      enable)
12984 {
12985   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12986
12987   self->priv->enable_model_view_transform = enable;
12988 }
12989
12990 void
12991 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
12992                                           gboolean      enable)
12993 {
12994   ClutterActorPrivate *priv;
12995
12996   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12997
12998   priv = self->priv;
12999
13000   priv->enable_paint_unmapped = enable;
13001
13002   if (priv->enable_paint_unmapped)
13003     {
13004       /* Make sure that the parents of the widget are realized first;
13005        * otherwise checks in clutter_actor_update_map_state() will
13006        * fail.
13007        */
13008       clutter_actor_realize (self);
13009
13010       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13011     }
13012   else
13013     {
13014       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13015     }
13016 }
13017
13018 static void
13019 clutter_anchor_coord_get_units (ClutterActor      *self,
13020                                 const AnchorCoord *coord,
13021                                 gfloat            *x,
13022                                 gfloat            *y,
13023                                 gfloat            *z)
13024 {
13025   if (coord->is_fractional)
13026     {
13027       gfloat actor_width, actor_height;
13028
13029       clutter_actor_get_size (self, &actor_width, &actor_height);
13030
13031       if (x)
13032         *x = actor_width * coord->v.fraction.x;
13033
13034       if (y)
13035         *y = actor_height * coord->v.fraction.y;
13036
13037       if (z)
13038         *z = 0;
13039     }
13040   else
13041     {
13042       if (x)
13043         *x = coord->v.units.x;
13044
13045       if (y)
13046         *y = coord->v.units.y;
13047
13048       if (z)
13049         *z = coord->v.units.z;
13050     }
13051 }
13052
13053 static void
13054 clutter_anchor_coord_set_units (AnchorCoord *coord,
13055                                 gfloat       x,
13056                                 gfloat       y,
13057                                 gfloat       z)
13058 {
13059   coord->is_fractional = FALSE;
13060   coord->v.units.x = x;
13061   coord->v.units.y = y;
13062   coord->v.units.z = z;
13063 }
13064
13065 static ClutterGravity
13066 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13067 {
13068   if (coord->is_fractional)
13069     {
13070       if (coord->v.fraction.x == 0.0)
13071         {
13072           if (coord->v.fraction.y == 0.0)
13073             return CLUTTER_GRAVITY_NORTH_WEST;
13074           else if (coord->v.fraction.y == 0.5)
13075             return CLUTTER_GRAVITY_WEST;
13076           else if (coord->v.fraction.y == 1.0)
13077             return CLUTTER_GRAVITY_SOUTH_WEST;
13078           else
13079             return CLUTTER_GRAVITY_NONE;
13080         }
13081       else if (coord->v.fraction.x == 0.5)
13082         {
13083           if (coord->v.fraction.y == 0.0)
13084             return CLUTTER_GRAVITY_NORTH;
13085           else if (coord->v.fraction.y == 0.5)
13086             return CLUTTER_GRAVITY_CENTER;
13087           else if (coord->v.fraction.y == 1.0)
13088             return CLUTTER_GRAVITY_SOUTH;
13089           else
13090             return CLUTTER_GRAVITY_NONE;
13091         }
13092       else if (coord->v.fraction.x == 1.0)
13093         {
13094           if (coord->v.fraction.y == 0.0)
13095             return CLUTTER_GRAVITY_NORTH_EAST;
13096           else if (coord->v.fraction.y == 0.5)
13097             return CLUTTER_GRAVITY_EAST;
13098           else if (coord->v.fraction.y == 1.0)
13099             return CLUTTER_GRAVITY_SOUTH_EAST;
13100           else
13101             return CLUTTER_GRAVITY_NONE;
13102         }
13103       else
13104         return CLUTTER_GRAVITY_NONE;
13105     }
13106   else
13107     return CLUTTER_GRAVITY_NONE;
13108 }
13109
13110 static void
13111 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13112                                   ClutterGravity  gravity)
13113 {
13114   switch (gravity)
13115     {
13116     case CLUTTER_GRAVITY_NORTH:
13117       coord->v.fraction.x = 0.5;
13118       coord->v.fraction.y = 0.0;
13119       break;
13120
13121     case CLUTTER_GRAVITY_NORTH_EAST:
13122       coord->v.fraction.x = 1.0;
13123       coord->v.fraction.y = 0.0;
13124       break;
13125
13126     case CLUTTER_GRAVITY_EAST:
13127       coord->v.fraction.x = 1.0;
13128       coord->v.fraction.y = 0.5;
13129       break;
13130
13131     case CLUTTER_GRAVITY_SOUTH_EAST:
13132       coord->v.fraction.x = 1.0;
13133       coord->v.fraction.y = 1.0;
13134       break;
13135
13136     case CLUTTER_GRAVITY_SOUTH:
13137       coord->v.fraction.x = 0.5;
13138       coord->v.fraction.y = 1.0;
13139       break;
13140
13141     case CLUTTER_GRAVITY_SOUTH_WEST:
13142       coord->v.fraction.x = 0.0;
13143       coord->v.fraction.y = 1.0;
13144       break;
13145
13146     case CLUTTER_GRAVITY_WEST:
13147       coord->v.fraction.x = 0.0;
13148       coord->v.fraction.y = 0.5;
13149       break;
13150
13151     case CLUTTER_GRAVITY_NORTH_WEST:
13152       coord->v.fraction.x = 0.0;
13153       coord->v.fraction.y = 0.0;
13154       break;
13155
13156     case CLUTTER_GRAVITY_CENTER:
13157       coord->v.fraction.x = 0.5;
13158       coord->v.fraction.y = 0.5;
13159       break;
13160
13161     default:
13162       coord->v.fraction.x = 0.0;
13163       coord->v.fraction.y = 0.0;
13164       break;
13165     }
13166
13167   coord->is_fractional = TRUE;
13168 }
13169
13170 static gboolean
13171 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13172 {
13173   if (coord->is_fractional)
13174     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13175   else
13176     return (coord->v.units.x == 0.0
13177             && coord->v.units.y == 0.0
13178             && coord->v.units.z == 0.0);
13179 }
13180
13181 /**
13182  * clutter_actor_get_flags:
13183  * @self: a #ClutterActor
13184  *
13185  * Retrieves the flags set on @self
13186  *
13187  * Return value: a bitwise or of #ClutterActorFlags or 0
13188  *
13189  * Since: 1.0
13190  */
13191 ClutterActorFlags
13192 clutter_actor_get_flags (ClutterActor *self)
13193 {
13194   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13195
13196   return self->flags;
13197 }
13198
13199 /**
13200  * clutter_actor_set_flags:
13201  * @self: a #ClutterActor
13202  * @flags: the flags to set
13203  *
13204  * Sets @flags on @self
13205  *
13206  * This function will emit notifications for the changed properties
13207  *
13208  * Since: 1.0
13209  */
13210 void
13211 clutter_actor_set_flags (ClutterActor      *self,
13212                          ClutterActorFlags  flags)
13213 {
13214   ClutterActorFlags old_flags;
13215   GObject *obj;
13216   gboolean was_reactive_set, reactive_set;
13217   gboolean was_realized_set, realized_set;
13218   gboolean was_mapped_set, mapped_set;
13219   gboolean was_visible_set, visible_set;
13220
13221   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13222
13223   if (self->flags == flags)
13224     return;
13225
13226   obj = G_OBJECT (self);
13227   g_object_ref (obj);
13228   g_object_freeze_notify (obj);
13229
13230   old_flags = self->flags;
13231
13232   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13233   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13234   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13235   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13236
13237   self->flags |= flags;
13238
13239   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13240   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13241   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13242   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13243
13244   if (reactive_set != was_reactive_set)
13245     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13246
13247   if (realized_set != was_realized_set)
13248     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13249
13250   if (mapped_set != was_mapped_set)
13251     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13252
13253   if (visible_set != was_visible_set)
13254     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13255
13256   g_object_thaw_notify (obj);
13257   g_object_unref (obj);
13258 }
13259
13260 /**
13261  * clutter_actor_unset_flags:
13262  * @self: a #ClutterActor
13263  * @flags: the flags to unset
13264  *
13265  * Unsets @flags on @self
13266  *
13267  * This function will emit notifications for the changed properties
13268  *
13269  * Since: 1.0
13270  */
13271 void
13272 clutter_actor_unset_flags (ClutterActor      *self,
13273                            ClutterActorFlags  flags)
13274 {
13275   ClutterActorFlags old_flags;
13276   GObject *obj;
13277   gboolean was_reactive_set, reactive_set;
13278   gboolean was_realized_set, realized_set;
13279   gboolean was_mapped_set, mapped_set;
13280   gboolean was_visible_set, visible_set;
13281
13282   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13283
13284   obj = G_OBJECT (self);
13285   g_object_freeze_notify (obj);
13286
13287   old_flags = self->flags;
13288
13289   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13290   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13291   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13292   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13293
13294   self->flags &= ~flags;
13295
13296   if (self->flags == old_flags)
13297     return;
13298
13299   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13300   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13301   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13302   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13303
13304   if (reactive_set != was_reactive_set)
13305     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13306
13307   if (realized_set != was_realized_set)
13308     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13309
13310   if (mapped_set != was_mapped_set)
13311     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13312
13313   if (visible_set != was_visible_set)
13314     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13315
13316   g_object_thaw_notify (obj);
13317 }
13318
13319 /**
13320  * clutter_actor_get_transformation_matrix:
13321  * @self: a #ClutterActor
13322  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13323  *
13324  * Retrieves the transformations applied to @self relative to its
13325  * parent.
13326  *
13327  * Since: 1.0
13328  */
13329 void
13330 clutter_actor_get_transformation_matrix (ClutterActor *self,
13331                                          CoglMatrix   *matrix)
13332 {
13333   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13334
13335   cogl_matrix_init_identity (matrix);
13336
13337   _clutter_actor_apply_modelview_transform (self, matrix);
13338 }
13339
13340 void
13341 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13342                                    gboolean      is_in_clone_paint)
13343 {
13344   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13345   self->priv->in_clone_paint = is_in_clone_paint;
13346 }
13347
13348 /**
13349  * clutter_actor_is_in_clone_paint:
13350  * @self: a #ClutterActor
13351  *
13352  * Checks whether @self is being currently painted by a #ClutterClone
13353  *
13354  * This function is useful only inside the ::paint virtual function
13355  * implementations or within handlers for the #ClutterActor::paint
13356  * signal
13357  *
13358  * This function should not be used by applications
13359  *
13360  * Return value: %TRUE if the #ClutterActor is currently being painted
13361  *   by a #ClutterClone, and %FALSE otherwise
13362  *
13363  * Since: 1.0
13364  */
13365 gboolean
13366 clutter_actor_is_in_clone_paint (ClutterActor *self)
13367 {
13368   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13369
13370   return self->priv->in_clone_paint;
13371 }
13372
13373 static gboolean
13374 set_direction_recursive (ClutterActor *actor,
13375                          gpointer      user_data)
13376 {
13377   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13378
13379   clutter_actor_set_text_direction (actor, text_dir);
13380
13381   return TRUE;
13382 }
13383
13384 /**
13385  * clutter_actor_set_text_direction:
13386  * @self: a #ClutterActor
13387  * @text_dir: the text direction for @self
13388  *
13389  * Sets the #ClutterTextDirection for an actor
13390  *
13391  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13392  *
13393  * If @self implements #ClutterContainer then this function will recurse
13394  * inside all the children of @self (including the internal ones).
13395  *
13396  * Composite actors not implementing #ClutterContainer, or actors requiring
13397  * special handling when the text direction changes, should connect to
13398  * the #GObject::notify signal for the #ClutterActor:text-direction property
13399  *
13400  * Since: 1.2
13401  */
13402 void
13403 clutter_actor_set_text_direction (ClutterActor         *self,
13404                                   ClutterTextDirection  text_dir)
13405 {
13406   ClutterActorPrivate *priv;
13407
13408   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13409   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13410
13411   priv = self->priv;
13412
13413   if (priv->text_direction != text_dir)
13414     {
13415       priv->text_direction = text_dir;
13416
13417       /* we need to emit the notify::text-direction first, so that
13418        * the sub-classes can catch that and do specific handling of
13419        * the text direction; see clutter_text_direction_changed_cb()
13420        * inside clutter-text.c
13421        */
13422       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13423
13424       _clutter_actor_foreach_child (self, set_direction_recursive,
13425                                     GINT_TO_POINTER (text_dir));
13426
13427       clutter_actor_queue_relayout (self);
13428     }
13429 }
13430
13431 void
13432 _clutter_actor_set_has_pointer (ClutterActor *self,
13433                                 gboolean      has_pointer)
13434 {
13435   ClutterActorPrivate *priv = self->priv;
13436
13437   if (priv->has_pointer != has_pointer)
13438     {
13439       priv->has_pointer = has_pointer;
13440
13441       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13442     }
13443 }
13444
13445 /**
13446  * clutter_actor_get_text_direction:
13447  * @self: a #ClutterActor
13448  *
13449  * Retrieves the value set using clutter_actor_set_text_direction()
13450  *
13451  * If no text direction has been previously set, the default text
13452  * direction, as returned by clutter_get_default_text_direction(), will
13453  * be returned instead
13454  *
13455  * Return value: the #ClutterTextDirection for the actor
13456  *
13457  * Since: 1.2
13458  */
13459 ClutterTextDirection
13460 clutter_actor_get_text_direction (ClutterActor *self)
13461 {
13462   ClutterActorPrivate *priv;
13463
13464   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13465                         CLUTTER_TEXT_DIRECTION_LTR);
13466
13467   priv = self->priv;
13468
13469   /* if no direction has been set yet use the default */
13470   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13471     priv->text_direction = clutter_get_default_text_direction ();
13472
13473   return priv->text_direction;
13474 }
13475
13476 /**
13477  * clutter_actor_push_internal:
13478  * @self: a #ClutterActor
13479  *
13480  * Should be used by actors implementing the #ClutterContainer and with
13481  * internal children added through clutter_actor_set_parent(), for instance:
13482  *
13483  * |[
13484  *   static void
13485  *   my_actor_init (MyActor *self)
13486  *   {
13487  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13488  *
13489  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13490  *
13491  *     /&ast; calling clutter_actor_set_parent() now will result in
13492  *      &ast; the internal flag being set on a child of MyActor
13493  *      &ast;/
13494  *
13495  *     /&ast; internal child - a background texture &ast;/
13496  *     self->priv->background_tex = clutter_texture_new ();
13497  *     clutter_actor_set_parent (self->priv->background_tex,
13498  *                               CLUTTER_ACTOR (self));
13499  *
13500  *     /&ast; internal child - a label &ast;/
13501  *     self->priv->label = clutter_text_new ();
13502  *     clutter_actor_set_parent (self->priv->label,
13503  *                               CLUTTER_ACTOR (self));
13504  *
13505  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13506  *
13507  *     /&ast; calling clutter_actor_set_parent() now will not result in
13508  *      &ast; the internal flag being set on a child of MyActor
13509  *      &ast;/
13510  *   }
13511  * ]|
13512  *
13513  * This function will be used by Clutter to toggle an "internal child"
13514  * flag whenever clutter_actor_set_parent() is called; internal children
13515  * are handled differently by Clutter, specifically when destroying their
13516  * parent.
13517  *
13518  * Call clutter_actor_pop_internal() when you finished adding internal
13519  * children.
13520  *
13521  * Nested calls to clutter_actor_push_internal() are allowed, but each
13522  * one must by followed by a clutter_actor_pop_internal() call.
13523  *
13524  * Since: 1.2
13525  *
13526  * Deprecated: 1.10: All children of an actor are accessible through
13527  *   the #ClutterActor API, and #ClutterActor implements the
13528  *   #ClutterContainer interface, so this function is only useful
13529  *   for legacy containers overriding the default implementation.
13530  */
13531 void
13532 clutter_actor_push_internal (ClutterActor *self)
13533 {
13534   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13535
13536   self->priv->internal_child += 1;
13537 }
13538
13539 /**
13540  * clutter_actor_pop_internal:
13541  * @self: a #ClutterActor
13542  *
13543  * Disables the effects of clutter_actor_push_internal().
13544  *
13545  * Since: 1.2
13546  *
13547  * Deprecated: 1.10: All children of an actor are accessible through
13548  *   the #ClutterActor API. This function is only useful for legacy
13549  *   containers overriding the default implementation of the
13550  *   #ClutterContainer interface.
13551  */
13552 void
13553 clutter_actor_pop_internal (ClutterActor *self)
13554 {
13555   ClutterActorPrivate *priv;
13556
13557   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13558
13559   priv = self->priv;
13560
13561   if (priv->internal_child == 0)
13562     {
13563       g_warning ("Mismatched %s: you need to call "
13564                  "clutter_actor_push_composite() at least once before "
13565                  "calling this function", G_STRFUNC);
13566       return;
13567     }
13568
13569   priv->internal_child -= 1;
13570 }
13571
13572 /**
13573  * clutter_actor_has_pointer:
13574  * @self: a #ClutterActor
13575  *
13576  * Checks whether an actor contains the pointer of a
13577  * #ClutterInputDevice
13578  *
13579  * Return value: %TRUE if the actor contains the pointer, and
13580  *   %FALSE otherwise
13581  *
13582  * Since: 1.2
13583  */
13584 gboolean
13585 clutter_actor_has_pointer (ClutterActor *self)
13586 {
13587   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13588
13589   return self->priv->has_pointer;
13590 }
13591
13592 /* XXX: This is a workaround for not being able to break the ABI of
13593  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13594  * clutter_actor_queue_clipped_redraw() for details.
13595  */
13596 ClutterPaintVolume *
13597 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13598 {
13599   return g_object_get_data (G_OBJECT (self),
13600                             "-clutter-actor-queue-redraw-clip");
13601 }
13602
13603 void
13604 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13605                                       ClutterPaintVolume *clip)
13606 {
13607   g_object_set_data (G_OBJECT (self),
13608                      "-clutter-actor-queue-redraw-clip",
13609                      clip);
13610 }
13611
13612 /**
13613  * clutter_actor_has_allocation:
13614  * @self: a #ClutterActor
13615  *
13616  * Checks if the actor has an up-to-date allocation assigned to
13617  * it. This means that the actor should have an allocation: it's
13618  * visible and has a parent. It also means that there is no
13619  * outstanding relayout request in progress for the actor or its
13620  * children (There might be other outstanding layout requests in
13621  * progress that will cause the actor to get a new allocation
13622  * when the stage is laid out, however).
13623  *
13624  * If this function returns %FALSE, then the actor will normally
13625  * be allocated before it is next drawn on the screen.
13626  *
13627  * Return value: %TRUE if the actor has an up-to-date allocation
13628  *
13629  * Since: 1.4
13630  */
13631 gboolean
13632 clutter_actor_has_allocation (ClutterActor *self)
13633 {
13634   ClutterActorPrivate *priv;
13635
13636   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13637
13638   priv = self->priv;
13639
13640   return priv->parent != NULL &&
13641          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13642          !priv->needs_allocation;
13643 }
13644
13645 /**
13646  * clutter_actor_add_action:
13647  * @self: a #ClutterActor
13648  * @action: a #ClutterAction
13649  *
13650  * Adds @action to the list of actions applied to @self
13651  *
13652  * A #ClutterAction can only belong to one actor at a time
13653  *
13654  * The #ClutterActor will hold a reference on @action until either
13655  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13656  * is called
13657  *
13658  * Since: 1.4
13659  */
13660 void
13661 clutter_actor_add_action (ClutterActor  *self,
13662                           ClutterAction *action)
13663 {
13664   ClutterActorPrivate *priv;
13665
13666   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13667   g_return_if_fail (CLUTTER_IS_ACTION (action));
13668
13669   priv = self->priv;
13670
13671   if (priv->actions == NULL)
13672     {
13673       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13674       priv->actions->actor = self;
13675     }
13676
13677   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13678
13679   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13680 }
13681
13682 /**
13683  * clutter_actor_add_action_with_name:
13684  * @self: a #ClutterActor
13685  * @name: the name to set on the action
13686  * @action: a #ClutterAction
13687  *
13688  * A convenience function for setting the name of a #ClutterAction
13689  * while adding it to the list of actions applied to @self
13690  *
13691  * This function is the logical equivalent of:
13692  *
13693  * |[
13694  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13695  *   clutter_actor_add_action (self, action);
13696  * ]|
13697  *
13698  * Since: 1.4
13699  */
13700 void
13701 clutter_actor_add_action_with_name (ClutterActor  *self,
13702                                     const gchar   *name,
13703                                     ClutterAction *action)
13704 {
13705   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13706   g_return_if_fail (name != NULL);
13707   g_return_if_fail (CLUTTER_IS_ACTION (action));
13708
13709   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13710   clutter_actor_add_action (self, action);
13711 }
13712
13713 /**
13714  * clutter_actor_remove_action:
13715  * @self: a #ClutterActor
13716  * @action: a #ClutterAction
13717  *
13718  * Removes @action from the list of actions applied to @self
13719  *
13720  * The reference held by @self on the #ClutterAction will be released
13721  *
13722  * Since: 1.4
13723  */
13724 void
13725 clutter_actor_remove_action (ClutterActor  *self,
13726                              ClutterAction *action)
13727 {
13728   ClutterActorPrivate *priv;
13729
13730   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13731   g_return_if_fail (CLUTTER_IS_ACTION (action));
13732
13733   priv = self->priv;
13734
13735   if (priv->actions == NULL)
13736     return;
13737
13738   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13739
13740   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13741 }
13742
13743 /**
13744  * clutter_actor_remove_action_by_name:
13745  * @self: a #ClutterActor
13746  * @name: the name of the action to remove
13747  *
13748  * Removes the #ClutterAction with the given name from the list
13749  * of actions applied to @self
13750  *
13751  * Since: 1.4
13752  */
13753 void
13754 clutter_actor_remove_action_by_name (ClutterActor *self,
13755                                      const gchar  *name)
13756 {
13757   ClutterActorPrivate *priv;
13758   ClutterActorMeta *meta;
13759
13760   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13761   g_return_if_fail (name != NULL);
13762
13763   priv = self->priv;
13764
13765   if (priv->actions == NULL)
13766     return;
13767
13768   meta = _clutter_meta_group_get_meta (priv->actions, name);
13769   if (meta == NULL)
13770     return;
13771
13772   _clutter_meta_group_remove_meta (priv->actions, meta);
13773
13774   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13775 }
13776
13777 /**
13778  * clutter_actor_get_actions:
13779  * @self: a #ClutterActor
13780  *
13781  * Retrieves the list of actions applied to @self
13782  *
13783  * Return value: (transfer container) (element-type Clutter.Action): a copy
13784  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13785  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13786  *   allocated by the returned #GList
13787  *
13788  * Since: 1.4
13789  */
13790 GList *
13791 clutter_actor_get_actions (ClutterActor *self)
13792 {
13793   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13794
13795   if (self->priv->actions == NULL)
13796     return NULL;
13797
13798   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13799 }
13800
13801 /**
13802  * clutter_actor_get_action:
13803  * @self: a #ClutterActor
13804  * @name: the name of the action to retrieve
13805  *
13806  * Retrieves the #ClutterAction with the given name in the list
13807  * of actions applied to @self
13808  *
13809  * Return value: (transfer none): a #ClutterAction for the given
13810  *   name, or %NULL. The returned #ClutterAction is owned by the
13811  *   actor and it should not be unreferenced directly
13812  *
13813  * Since: 1.4
13814  */
13815 ClutterAction *
13816 clutter_actor_get_action (ClutterActor *self,
13817                           const gchar  *name)
13818 {
13819   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13820   g_return_val_if_fail (name != NULL, NULL);
13821
13822   if (self->priv->actions == NULL)
13823     return NULL;
13824
13825   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13826 }
13827
13828 /**
13829  * clutter_actor_clear_actions:
13830  * @self: a #ClutterActor
13831  *
13832  * Clears the list of actions applied to @self
13833  *
13834  * Since: 1.4
13835  */
13836 void
13837 clutter_actor_clear_actions (ClutterActor *self)
13838 {
13839   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13840
13841   if (self->priv->actions == NULL)
13842     return;
13843
13844   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13845 }
13846
13847 /**
13848  * clutter_actor_add_constraint:
13849  * @self: a #ClutterActor
13850  * @constraint: a #ClutterConstraint
13851  *
13852  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13853  * to @self
13854  *
13855  * The #ClutterActor will hold a reference on the @constraint until
13856  * either clutter_actor_remove_constraint() or
13857  * clutter_actor_clear_constraints() is called.
13858  *
13859  * Since: 1.4
13860  */
13861 void
13862 clutter_actor_add_constraint (ClutterActor      *self,
13863                               ClutterConstraint *constraint)
13864 {
13865   ClutterActorPrivate *priv;
13866
13867   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13868   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13869
13870   priv = self->priv;
13871
13872   if (priv->constraints == NULL)
13873     {
13874       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13875       priv->constraints->actor = self;
13876     }
13877
13878   _clutter_meta_group_add_meta (priv->constraints,
13879                                 CLUTTER_ACTOR_META (constraint));
13880   clutter_actor_queue_relayout (self);
13881
13882   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13883 }
13884
13885 /**
13886  * clutter_actor_add_constraint_with_name:
13887  * @self: a #ClutterActor
13888  * @name: the name to set on the constraint
13889  * @constraint: a #ClutterConstraint
13890  *
13891  * A convenience function for setting the name of a #ClutterConstraint
13892  * while adding it to the list of constraints applied to @self
13893  *
13894  * This function is the logical equivalent of:
13895  *
13896  * |[
13897  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13898  *   clutter_actor_add_constraint (self, constraint);
13899  * ]|
13900  *
13901  * Since: 1.4
13902  */
13903 void
13904 clutter_actor_add_constraint_with_name (ClutterActor      *self,
13905                                         const gchar       *name,
13906                                         ClutterConstraint *constraint)
13907 {
13908   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13909   g_return_if_fail (name != NULL);
13910   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13911
13912   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13913   clutter_actor_add_constraint (self, constraint);
13914 }
13915
13916 /**
13917  * clutter_actor_remove_constraint:
13918  * @self: a #ClutterActor
13919  * @constraint: a #ClutterConstraint
13920  *
13921  * Removes @constraint from the list of constraints applied to @self
13922  *
13923  * The reference held by @self on the #ClutterConstraint will be released
13924  *
13925  * Since: 1.4
13926  */
13927 void
13928 clutter_actor_remove_constraint (ClutterActor      *self,
13929                                  ClutterConstraint *constraint)
13930 {
13931   ClutterActorPrivate *priv;
13932
13933   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13934   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13935
13936   priv = self->priv;
13937
13938   if (priv->constraints == NULL)
13939     return;
13940
13941   _clutter_meta_group_remove_meta (priv->constraints,
13942                                    CLUTTER_ACTOR_META (constraint));
13943   clutter_actor_queue_relayout (self);
13944
13945   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13946 }
13947
13948 /**
13949  * clutter_actor_remove_constraint_by_name:
13950  * @self: a #ClutterActor
13951  * @name: the name of the constraint to remove
13952  *
13953  * Removes the #ClutterConstraint with the given name from the list
13954  * of constraints applied to @self
13955  *
13956  * Since: 1.4
13957  */
13958 void
13959 clutter_actor_remove_constraint_by_name (ClutterActor *self,
13960                                          const gchar  *name)
13961 {
13962   ClutterActorPrivate *priv;
13963   ClutterActorMeta *meta;
13964
13965   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13966   g_return_if_fail (name != NULL);
13967
13968   priv = self->priv;
13969
13970   if (priv->constraints == NULL)
13971     return;
13972
13973   meta = _clutter_meta_group_get_meta (priv->constraints, name);
13974   if (meta == NULL)
13975     return;
13976
13977   _clutter_meta_group_remove_meta (priv->constraints, meta);
13978   clutter_actor_queue_relayout (self);
13979 }
13980
13981 /**
13982  * clutter_actor_get_constraints:
13983  * @self: a #ClutterActor
13984  *
13985  * Retrieves the list of constraints applied to @self
13986  *
13987  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
13988  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
13989  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13990  *   allocated by the returned #GList
13991  *
13992  * Since: 1.4
13993  */
13994 GList *
13995 clutter_actor_get_constraints (ClutterActor *self)
13996 {
13997   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13998
13999   if (self->priv->constraints == NULL)
14000     return NULL;
14001
14002   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14003 }
14004
14005 /**
14006  * clutter_actor_get_constraint:
14007  * @self: a #ClutterActor
14008  * @name: the name of the constraint to retrieve
14009  *
14010  * Retrieves the #ClutterConstraint with the given name in the list
14011  * of constraints applied to @self
14012  *
14013  * Return value: (transfer none): a #ClutterConstraint for the given
14014  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14015  *   actor and it should not be unreferenced directly
14016  *
14017  * Since: 1.4
14018  */
14019 ClutterConstraint *
14020 clutter_actor_get_constraint (ClutterActor *self,
14021                               const gchar  *name)
14022 {
14023   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14024   g_return_val_if_fail (name != NULL, NULL);
14025
14026   if (self->priv->constraints == NULL)
14027     return NULL;
14028
14029   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14030 }
14031
14032 /**
14033  * clutter_actor_clear_constraints:
14034  * @self: a #ClutterActor
14035  *
14036  * Clears the list of constraints applied to @self
14037  *
14038  * Since: 1.4
14039  */
14040 void
14041 clutter_actor_clear_constraints (ClutterActor *self)
14042 {
14043   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14044
14045   if (self->priv->constraints == NULL)
14046     return;
14047
14048   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14049
14050   clutter_actor_queue_relayout (self);
14051 }
14052
14053 /**
14054  * clutter_actor_set_clip_to_allocation:
14055  * @self: a #ClutterActor
14056  * @clip_set: %TRUE to apply a clip tracking the allocation
14057  *
14058  * Sets whether @self should be clipped to the same size as its
14059  * allocation
14060  *
14061  * Since: 1.4
14062  */
14063 void
14064 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14065                                       gboolean      clip_set)
14066 {
14067   ClutterActorPrivate *priv;
14068
14069   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14070
14071   clip_set = !!clip_set;
14072
14073   priv = self->priv;
14074
14075   if (priv->clip_to_allocation != clip_set)
14076     {
14077       priv->clip_to_allocation = clip_set;
14078
14079       clutter_actor_queue_redraw (self);
14080
14081       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14082     }
14083 }
14084
14085 /**
14086  * clutter_actor_get_clip_to_allocation:
14087  * @self: a #ClutterActor
14088  *
14089  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14090  *
14091  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14092  *
14093  * Since: 1.4
14094  */
14095 gboolean
14096 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14097 {
14098   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14099
14100   return self->priv->clip_to_allocation;
14101 }
14102
14103 /**
14104  * clutter_actor_add_effect:
14105  * @self: a #ClutterActor
14106  * @effect: a #ClutterEffect
14107  *
14108  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14109  *
14110  * The #ClutterActor will hold a reference on the @effect until either
14111  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14112  * called.
14113  *
14114  * Since: 1.4
14115  */
14116 void
14117 clutter_actor_add_effect (ClutterActor  *self,
14118                           ClutterEffect *effect)
14119 {
14120   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14121   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14122
14123   _clutter_actor_add_effect_internal (self, effect);
14124
14125   clutter_actor_queue_redraw (self);
14126
14127   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14128 }
14129
14130 /**
14131  * clutter_actor_add_effect_with_name:
14132  * @self: a #ClutterActor
14133  * @name: the name to set on the effect
14134  * @effect: a #ClutterEffect
14135  *
14136  * A convenience function for setting the name of a #ClutterEffect
14137  * while adding it to the list of effectss applied to @self
14138  *
14139  * This function is the logical equivalent of:
14140  *
14141  * |[
14142  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14143  *   clutter_actor_add_effect (self, effect);
14144  * ]|
14145  *
14146  * Since: 1.4
14147  */
14148 void
14149 clutter_actor_add_effect_with_name (ClutterActor  *self,
14150                                     const gchar   *name,
14151                                     ClutterEffect *effect)
14152 {
14153   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14154   g_return_if_fail (name != NULL);
14155   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14156
14157   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14158   clutter_actor_add_effect (self, effect);
14159 }
14160
14161 /**
14162  * clutter_actor_remove_effect:
14163  * @self: a #ClutterActor
14164  * @effect: a #ClutterEffect
14165  *
14166  * Removes @effect from the list of effects applied to @self
14167  *
14168  * The reference held by @self on the #ClutterEffect will be released
14169  *
14170  * Since: 1.4
14171  */
14172 void
14173 clutter_actor_remove_effect (ClutterActor  *self,
14174                              ClutterEffect *effect)
14175 {
14176   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14177   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14178
14179   _clutter_actor_remove_effect_internal (self, effect);
14180
14181   clutter_actor_queue_redraw (self);
14182
14183   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14184 }
14185
14186 /**
14187  * clutter_actor_remove_effect_by_name:
14188  * @self: a #ClutterActor
14189  * @name: the name of the effect to remove
14190  *
14191  * Removes the #ClutterEffect with the given name from the list
14192  * of effects applied to @self
14193  *
14194  * Since: 1.4
14195  */
14196 void
14197 clutter_actor_remove_effect_by_name (ClutterActor *self,
14198                                      const gchar  *name)
14199 {
14200   ClutterActorPrivate *priv;
14201   ClutterActorMeta *meta;
14202
14203   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14204   g_return_if_fail (name != NULL);
14205
14206   priv = self->priv;
14207
14208   if (priv->effects == NULL)
14209     return;
14210
14211   meta = _clutter_meta_group_get_meta (priv->effects, name);
14212   if (meta == NULL)
14213     return;
14214
14215   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14216 }
14217
14218 /**
14219  * clutter_actor_get_effects:
14220  * @self: a #ClutterActor
14221  *
14222  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14223  *
14224  * Return value: (transfer container) (element-type Clutter.Effect): a list
14225  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14226  *   list are owned by Clutter and they should not be freed. You should
14227  *   free the returned list using g_list_free() when done
14228  *
14229  * Since: 1.4
14230  */
14231 GList *
14232 clutter_actor_get_effects (ClutterActor *self)
14233 {
14234   ClutterActorPrivate *priv;
14235
14236   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14237
14238   priv = self->priv;
14239
14240   if (priv->effects == NULL)
14241     return NULL;
14242
14243   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14244 }
14245
14246 /**
14247  * clutter_actor_get_effect:
14248  * @self: a #ClutterActor
14249  * @name: the name of the effect to retrieve
14250  *
14251  * Retrieves the #ClutterEffect with the given name in the list
14252  * of effects applied to @self
14253  *
14254  * Return value: (transfer none): a #ClutterEffect for the given
14255  *   name, or %NULL. The returned #ClutterEffect is owned by the
14256  *   actor and it should not be unreferenced directly
14257  *
14258  * Since: 1.4
14259  */
14260 ClutterEffect *
14261 clutter_actor_get_effect (ClutterActor *self,
14262                           const gchar  *name)
14263 {
14264   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14265   g_return_val_if_fail (name != NULL, NULL);
14266
14267   if (self->priv->effects == NULL)
14268     return NULL;
14269
14270   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14271 }
14272
14273 /**
14274  * clutter_actor_clear_effects:
14275  * @self: a #ClutterActor
14276  *
14277  * Clears the list of effects applied to @self
14278  *
14279  * Since: 1.4
14280  */
14281 void
14282 clutter_actor_clear_effects (ClutterActor *self)
14283 {
14284   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14285
14286   if (self->priv->effects == NULL)
14287     return;
14288
14289   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14290
14291   clutter_actor_queue_redraw (self);
14292 }
14293
14294 /**
14295  * clutter_actor_has_key_focus:
14296  * @self: a #ClutterActor
14297  *
14298  * Checks whether @self is the #ClutterActor that has key focus
14299  *
14300  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14301  *
14302  * Since: 1.4
14303  */
14304 gboolean
14305 clutter_actor_has_key_focus (ClutterActor *self)
14306 {
14307   ClutterActor *stage;
14308
14309   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14310
14311   stage = _clutter_actor_get_stage_internal (self);
14312   if (stage == NULL)
14313     return FALSE;
14314
14315   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14316 }
14317
14318 static gboolean
14319 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14320                                       ClutterPaintVolume *pv)
14321 {
14322   ClutterActorPrivate *priv = self->priv;
14323
14324   /* Actors are only expected to report a valid paint volume
14325    * while they have a valid allocation. */
14326   if (G_UNLIKELY (priv->needs_allocation))
14327     {
14328       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14329                     "Actor needs allocation",
14330                     _clutter_actor_get_debug_name (self));
14331       return FALSE;
14332     }
14333
14334   /* Check if there are any handlers connected to the paint
14335    * signal. If there are then all bets are off for what the paint
14336    * volume for this actor might possibly be!
14337    *
14338    * XXX: It's expected that this is going to end up being quite a
14339    * costly check to have to do here, but we haven't come up with
14340    * another solution that can reliably catch paint signal handlers at
14341    * the right time to either avoid artefacts due to invalid stage
14342    * clipping or due to incorrect culling.
14343    *
14344    * Previously we checked in clutter_actor_paint(), but at that time
14345    * we may already be using a stage clip that could be derived from
14346    * an invalid paint-volume. We used to try and handle that by
14347    * queuing a follow up, unclipped, redraw but still the previous
14348    * checking wasn't enough to catch invalid volumes involved in
14349    * culling (considering that containers may derive their volume from
14350    * children that haven't yet been painted)
14351    *
14352    * Longer term, improved solutions could be:
14353    * - Disallow painting in the paint signal, only allow using it
14354    *   for tracking when paints happen. We can add another API that
14355    *   allows monkey patching the paint of arbitrary actors but in a
14356    *   more controlled way and that also supports modifying the
14357    *   paint-volume.
14358    * - If we could be notified somehow when signal handlers are
14359    *   connected we wouldn't have to poll for handlers like this.
14360    */
14361   if (g_signal_has_handler_pending (self,
14362                                     actor_signals[PAINT],
14363                                     0,
14364                                     TRUE))
14365     {
14366       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14367                     "Actor has \"paint\" signal handlers",
14368                     _clutter_actor_get_debug_name (self));
14369       return FALSE;
14370     }
14371
14372   _clutter_paint_volume_init_static (pv, self);
14373
14374   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14375     {
14376       clutter_paint_volume_free (pv);
14377       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14378                     "Actor failed to report a volume",
14379                     _clutter_actor_get_debug_name (self));
14380       return FALSE;
14381     }
14382
14383   /* since effects can modify the paint volume, we allow them to actually
14384    * do this by making get_paint_volume() "context sensitive"
14385    */
14386   if (priv->effects != NULL)
14387     {
14388       if (priv->current_effect != NULL)
14389         {
14390           const GList *effects, *l;
14391
14392           /* if we are being called from within the paint sequence of
14393            * an actor, get the paint volume up to the current effect
14394            */
14395           effects = _clutter_meta_group_peek_metas (priv->effects);
14396           for (l = effects;
14397                l != NULL || (l != NULL && l->data != priv->current_effect);
14398                l = l->next)
14399             {
14400               if (!_clutter_effect_get_paint_volume (l->data, pv))
14401                 {
14402                   clutter_paint_volume_free (pv);
14403                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14404                                 "Effect (%s) failed to report a volume",
14405                                 _clutter_actor_get_debug_name (self),
14406                                 _clutter_actor_meta_get_debug_name (l->data));
14407                   return FALSE;
14408                 }
14409             }
14410         }
14411       else
14412         {
14413           const GList *effects, *l;
14414
14415           /* otherwise, get the cumulative volume */
14416           effects = _clutter_meta_group_peek_metas (priv->effects);
14417           for (l = effects; l != NULL; l = l->next)
14418             if (!_clutter_effect_get_paint_volume (l->data, pv))
14419               {
14420                 clutter_paint_volume_free (pv);
14421                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14422                               "Effect (%s) failed to report a volume",
14423                               _clutter_actor_get_debug_name (self),
14424                               _clutter_actor_meta_get_debug_name (l->data));
14425                 return FALSE;
14426               }
14427         }
14428     }
14429
14430   return TRUE;
14431 }
14432
14433 /* The public clutter_actor_get_paint_volume API returns a const
14434  * pointer since we return a pointer directly to the cached
14435  * PaintVolume associated with the actor and don't want the user to
14436  * inadvertently modify it, but for internal uses we sometimes need
14437  * access to the same PaintVolume but need to apply some book-keeping
14438  * modifications to it so we don't want a const pointer.
14439  */
14440 static ClutterPaintVolume *
14441 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14442 {
14443   ClutterActorPrivate *priv;
14444
14445   priv = self->priv;
14446
14447   if (priv->paint_volume_valid)
14448     clutter_paint_volume_free (&priv->paint_volume);
14449
14450   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14451     {
14452       priv->paint_volume_valid = TRUE;
14453       return &priv->paint_volume;
14454     }
14455   else
14456     {
14457       priv->paint_volume_valid = FALSE;
14458       return NULL;
14459     }
14460 }
14461
14462 /**
14463  * clutter_actor_get_paint_volume:
14464  * @self: a #ClutterActor
14465  *
14466  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14467  * when a paint volume can't be determined.
14468  *
14469  * The paint volume is defined as the 3D space occupied by an actor
14470  * when being painted.
14471  *
14472  * This function will call the <function>get_paint_volume()</function>
14473  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14474  * should not usually care about overriding the default implementation,
14475  * unless they are, for instance: painting outside their allocation, or
14476  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14477  * 3D depth).
14478  *
14479  * <note>2D actors overriding <function>get_paint_volume()</function>
14480  * ensure their volume has a depth of 0. (This will be true so long as
14481  * you don't call clutter_paint_volume_set_depth().)</note>
14482  *
14483  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14484  *   or %NULL if no volume could be determined.
14485  *
14486  * Since: 1.6
14487  */
14488 const ClutterPaintVolume *
14489 clutter_actor_get_paint_volume (ClutterActor *self)
14490 {
14491   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14492
14493   return _clutter_actor_get_paint_volume_mutable (self);
14494 }
14495
14496 /**
14497  * clutter_actor_get_transformed_paint_volume:
14498  * @self: a #ClutterActor
14499  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14500  *    (or %NULL for the stage)
14501  *
14502  * Retrieves the 3D paint volume of an actor like
14503  * clutter_actor_get_paint_volume() does (Please refer to the
14504  * documentation of clutter_actor_get_paint_volume() for more
14505  * details.) and it additionally transforms the paint volume into the
14506  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14507  * is passed for @relative_to_ancestor)
14508  *
14509  * This can be used by containers that base their paint volume on
14510  * the volume of their children. Such containers can query the
14511  * transformed paint volume of all of its children and union them
14512  * together using clutter_paint_volume_union().
14513  *
14514  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14515  *   or %NULL if no volume could be determined.
14516  *
14517  * Since: 1.6
14518  */
14519 const ClutterPaintVolume *
14520 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14521                                             ClutterActor *relative_to_ancestor)
14522 {
14523   const ClutterPaintVolume *volume;
14524   ClutterActor *stage;
14525   ClutterPaintVolume *transformed_volume;
14526
14527   stage = _clutter_actor_get_stage_internal (self);
14528   if (G_UNLIKELY (stage == NULL))
14529     return NULL;
14530
14531   if (relative_to_ancestor == NULL)
14532     relative_to_ancestor = stage;
14533
14534   volume = clutter_actor_get_paint_volume (self);
14535   if (volume == NULL)
14536     return NULL;
14537
14538   transformed_volume =
14539     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14540
14541   _clutter_paint_volume_copy_static (volume, transformed_volume);
14542
14543   _clutter_paint_volume_transform_relative (transformed_volume,
14544                                             relative_to_ancestor);
14545
14546   return transformed_volume;
14547 }
14548
14549 /**
14550  * clutter_actor_get_paint_box:
14551  * @self: a #ClutterActor
14552  * @box: (out): return location for a #ClutterActorBox
14553  *
14554  * Retrieves the paint volume of the passed #ClutterActor, and
14555  * transforms it into a 2D bounding box in stage coordinates.
14556  *
14557  * This function is useful to determine the on screen area occupied by
14558  * the actor. The box is only an approximation and may often be
14559  * considerably larger due to the optimizations used to calculate the
14560  * box. The box is never smaller though, so it can reliably be used
14561  * for culling.
14562  *
14563  * There are times when a 2D paint box can't be determined, e.g.
14564  * because the actor isn't yet parented under a stage or because
14565  * the actor is unable to determine a paint volume.
14566  *
14567  * Return value: %TRUE if a 2D paint box could be determined, else
14568  * %FALSE.
14569  *
14570  * Since: 1.6
14571  */
14572 gboolean
14573 clutter_actor_get_paint_box (ClutterActor    *self,
14574                              ClutterActorBox *box)
14575 {
14576   ClutterActor *stage;
14577   ClutterPaintVolume *pv;
14578
14579   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14580   g_return_val_if_fail (box != NULL, FALSE);
14581
14582   stage = _clutter_actor_get_stage_internal (self);
14583   if (G_UNLIKELY (!stage))
14584     return FALSE;
14585
14586   pv = _clutter_actor_get_paint_volume_mutable (self);
14587   if (G_UNLIKELY (!pv))
14588     return FALSE;
14589
14590   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14591
14592   return TRUE;
14593 }
14594
14595 /**
14596  * clutter_actor_has_overlaps:
14597  * @self: A #ClutterActor
14598  *
14599  * Asks the actor's implementation whether it may contain overlapping
14600  * primitives.
14601  *
14602  * For example; Clutter may use this to determine whether the painting
14603  * should be redirected to an offscreen buffer to correctly implement
14604  * the opacity property.
14605  *
14606  * Custom actors can override the default response by implementing the
14607  * #ClutterActor <function>has_overlaps</function> virtual function. See
14608  * clutter_actor_set_offscreen_redirect() for more information.
14609  *
14610  * Return value: %TRUE if the actor may have overlapping primitives, and
14611  *   %FALSE otherwise
14612  *
14613  * Since: 1.8
14614  */
14615 gboolean
14616 clutter_actor_has_overlaps (ClutterActor *self)
14617 {
14618   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14619
14620   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14621 }
14622
14623 /**
14624  * clutter_actor_has_effects:
14625  * @self: A #ClutterActor
14626  *
14627  * Returns whether the actor has any effects applied.
14628  *
14629  * Return value: %TRUE if the actor has any effects,
14630  *   %FALSE otherwise
14631  *
14632  * Since: 1.10
14633  */
14634 gboolean
14635 clutter_actor_has_effects (ClutterActor *self)
14636 {
14637   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14638
14639   if (self->priv->effects == NULL)
14640     return FALSE;
14641
14642   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14643 }
14644
14645 /**
14646  * clutter_actor_has_constraints:
14647  * @self: A #ClutterActor
14648  *
14649  * Returns whether the actor has any constraints applied.
14650  *
14651  * Return value: %TRUE if the actor has any constraints,
14652  *   %FALSE otherwise
14653  *
14654  * Since: 1.10
14655  */
14656 gboolean
14657 clutter_actor_has_constraints (ClutterActor *self)
14658 {
14659   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14660
14661   return self->priv->constraints != NULL;
14662 }
14663
14664 /**
14665  * clutter_actor_has_actions:
14666  * @self: A #ClutterActor
14667  *
14668  * Returns whether the actor has any actions applied.
14669  *
14670  * Return value: %TRUE if the actor has any actions,
14671  *   %FALSE otherwise
14672  *
14673  * Since: 1.10
14674  */
14675 gboolean
14676 clutter_actor_has_actions (ClutterActor *self)
14677 {
14678   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14679
14680   return self->priv->actions != NULL;
14681 }
14682
14683 /**
14684  * clutter_actor_get_n_children:
14685  * @self: a #ClutterActor
14686  *
14687  * Retrieves the number of children of @self.
14688  *
14689  * Return value: the number of children of an actor
14690  *
14691  * Since: 1.10
14692  */
14693 gint
14694 clutter_actor_get_n_children (ClutterActor *self)
14695 {
14696   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14697
14698   return self->priv->n_children;
14699 }
14700
14701 /**
14702  * clutter_actor_get_child_at_index:
14703  * @self: a #ClutterActor
14704  * @index_: the position in the list of children
14705  *
14706  * Retrieves the actor at the given @index_ inside the list of
14707  * children of @self.
14708  *
14709  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14710  *
14711  * Since: 1.10
14712  */
14713 ClutterActor *
14714 clutter_actor_get_child_at_index (ClutterActor *self,
14715                                   gint          index_)
14716 {
14717   ClutterActor *iter;
14718   int i;
14719
14720   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14721   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14722
14723   for (iter = self->priv->first_child, i = 0;
14724        iter != NULL && i < index_;
14725        iter = iter->priv->next_sibling, i += 1)
14726     ;
14727
14728   return iter;
14729 }
14730
14731 /*< private >
14732  * _clutter_actor_foreach_child:
14733  * @actor: The actor whos children you want to iterate
14734  * @callback: The function to call for each child
14735  * @user_data: Private data to pass to @callback
14736  *
14737  * Calls a given @callback once for each child of the specified @actor and
14738  * passing the @user_data pointer each time.
14739  *
14740  * Return value: returns %TRUE if all children were iterated, else
14741  *    %FALSE if a callback broke out of iteration early.
14742  */
14743 gboolean
14744 _clutter_actor_foreach_child (ClutterActor           *self,
14745                               ClutterForeachCallback  callback,
14746                               gpointer                user_data)
14747 {
14748   ClutterActorPrivate *priv = self->priv;
14749   ClutterActor *iter;
14750   gboolean cont;
14751
14752   for (cont = TRUE, iter = priv->first_child;
14753        cont && iter != NULL;
14754        iter = iter->priv->next_sibling)
14755     {
14756       cont = callback (iter, user_data);
14757     }
14758
14759   return cont;
14760 }
14761
14762 /* For debugging purposes this gives us a simple way to print out
14763  * the scenegraph e.g in gdb using:
14764  * [|
14765  *   _clutter_actor_traverse (stage,
14766  *                            0,
14767  *                            _clutter_debug_print_actor_cb,
14768  *                            NULL,
14769  *                            NULL);
14770  * |]
14771  */
14772 ClutterActorTraverseVisitFlags
14773 _clutter_debug_print_actor_cb (ClutterActor *actor,
14774                                int depth,
14775                                void *user_data)
14776 {
14777   g_print ("%*s%s:%p\n",
14778            depth * 2, "",
14779            _clutter_actor_get_debug_name (actor),
14780            actor);
14781
14782   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14783 }
14784
14785 static void
14786 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14787                                  ClutterTraverseCallback callback,
14788                                  gpointer                user_data)
14789 {
14790   GQueue *queue = g_queue_new ();
14791   ClutterActor dummy;
14792   int current_depth = 0;
14793
14794   g_queue_push_tail (queue, actor);
14795   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14796
14797   while ((actor = g_queue_pop_head (queue)))
14798     {
14799       ClutterActorTraverseVisitFlags flags;
14800
14801       if (actor == &dummy)
14802         {
14803           current_depth++;
14804           g_queue_push_tail (queue, &dummy);
14805           continue;
14806         }
14807
14808       flags = callback (actor, current_depth, user_data);
14809       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14810         break;
14811       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14812         {
14813           ClutterActor *iter;
14814
14815           for (iter = actor->priv->first_child;
14816                iter != NULL;
14817                iter = iter->priv->next_sibling)
14818             {
14819               g_queue_push_tail (queue, iter);
14820             }
14821         }
14822     }
14823
14824   g_queue_free (queue);
14825 }
14826
14827 static ClutterActorTraverseVisitFlags
14828 _clutter_actor_traverse_depth (ClutterActor           *actor,
14829                                ClutterTraverseCallback before_children_callback,
14830                                ClutterTraverseCallback after_children_callback,
14831                                int                     current_depth,
14832                                gpointer                user_data)
14833 {
14834   ClutterActorTraverseVisitFlags flags;
14835
14836   flags = before_children_callback (actor, current_depth, user_data);
14837   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14838     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14839
14840   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14841     {
14842       ClutterActor *iter;
14843
14844       for (iter = actor->priv->first_child;
14845            iter != NULL;
14846            iter = iter->priv->next_sibling)
14847         {
14848           flags = _clutter_actor_traverse_depth (iter,
14849                                                  before_children_callback,
14850                                                  after_children_callback,
14851                                                  current_depth + 1,
14852                                                  user_data);
14853
14854           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14855             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14856         }
14857     }
14858
14859   if (after_children_callback)
14860     return after_children_callback (actor, current_depth, user_data);
14861   else
14862     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14863 }
14864
14865 /* _clutter_actor_traverse:
14866  * @actor: The actor to start traversing the graph from
14867  * @flags: These flags may affect how the traversal is done
14868  * @before_children_callback: A function to call before visiting the
14869  *   children of the current actor.
14870  * @after_children_callback: A function to call after visiting the
14871  *   children of the current actor. (Ignored if
14872  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14873  * @user_data: The private data to pass to the callbacks
14874  *
14875  * Traverses the scenegraph starting at the specified @actor and
14876  * descending through all its children and its children's children.
14877  * For each actor traversed @before_children_callback and
14878  * @after_children_callback are called with the specified
14879  * @user_data, before and after visiting that actor's children.
14880  *
14881  * The callbacks can return flags that affect the ongoing traversal
14882  * such as by skipping over an actors children or bailing out of
14883  * any further traversing.
14884  */
14885 void
14886 _clutter_actor_traverse (ClutterActor              *actor,
14887                          ClutterActorTraverseFlags  flags,
14888                          ClutterTraverseCallback    before_children_callback,
14889                          ClutterTraverseCallback    after_children_callback,
14890                          gpointer                   user_data)
14891 {
14892   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
14893     _clutter_actor_traverse_breadth (actor,
14894                                      before_children_callback,
14895                                      user_data);
14896   else /* DEPTH_FIRST */
14897     _clutter_actor_traverse_depth (actor,
14898                                    before_children_callback,
14899                                    after_children_callback,
14900                                    0, /* start depth */
14901                                    user_data);
14902 }
14903
14904 static void
14905 on_layout_manager_changed (ClutterLayoutManager *manager,
14906                            ClutterActor         *self)
14907 {
14908   clutter_actor_queue_relayout (self);
14909 }
14910
14911 /**
14912  * clutter_actor_set_layout_manager:
14913  * @self: a #ClutterActor
14914  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
14915  *
14916  * Sets the #ClutterLayoutManager delegate object that will be used to
14917  * lay out the children of @self.
14918  *
14919  * The #ClutterActor will take a reference on the passed @manager which
14920  * will be released either when the layout manager is removed, or when
14921  * the actor is destroyed.
14922  *
14923  * Since: 1.10
14924  */
14925 void
14926 clutter_actor_set_layout_manager (ClutterActor         *self,
14927                                   ClutterLayoutManager *manager)
14928 {
14929   ClutterActorPrivate *priv;
14930
14931   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14932   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
14933
14934   priv = self->priv;
14935
14936   if (priv->layout_manager != NULL)
14937     {
14938       g_signal_handlers_disconnect_by_func (priv->layout_manager,
14939                                             G_CALLBACK (on_layout_manager_changed),
14940                                             self);
14941       clutter_layout_manager_set_container (priv->layout_manager, NULL);
14942       g_object_unref (priv->layout_manager);
14943     }
14944
14945   priv->layout_manager = manager;
14946
14947   if (priv->layout_manager != NULL)
14948     {
14949       g_object_ref_sink (priv->layout_manager);
14950       clutter_layout_manager_set_container (priv->layout_manager,
14951                                             CLUTTER_CONTAINER (self));
14952       g_signal_connect (priv->layout_manager, "layout-changed",
14953                         G_CALLBACK (on_layout_manager_changed),
14954                         self);
14955     }
14956
14957   clutter_actor_queue_relayout (self);
14958
14959   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
14960 }
14961
14962 /**
14963  * clutter_actor_get_layout_manager:
14964  * @self: a #ClutterActor
14965  *
14966  * Retrieves the #ClutterLayoutManager used by @self.
14967  *
14968  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
14969  *   or %NULL
14970  *
14971  * Since: 1.10
14972  */
14973 ClutterLayoutManager *
14974 clutter_actor_get_layout_manager (ClutterActor *self)
14975 {
14976   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14977
14978   return self->priv->layout_manager;
14979 }
14980
14981 static const ClutterLayoutInfo default_layout_info = {
14982   0.f,                          /* fixed-x */
14983   0.f,                          /* fixed-y */
14984   { 0, 0, 0, 0 },               /* margin */
14985   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
14986   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
14987   0.f, 0.f,                     /* min_width, natural_width */
14988   0.f, 0.f,                     /* natual_width, natural_height */
14989 };
14990
14991 static void
14992 layout_info_free (gpointer data)
14993 {
14994   if (G_LIKELY (data != NULL))
14995     g_slice_free (ClutterLayoutInfo, data);
14996 }
14997
14998 /*< private >
14999  * _clutter_actor_get_layout_info:
15000  * @self: a #ClutterActor
15001  *
15002  * Retrieves a pointer to the ClutterLayoutInfo structure.
15003  *
15004  * If the actor does not have a ClutterLayoutInfo associated to it, one
15005  * will be created and initialized to the default values.
15006  *
15007  * This function should be used for setters.
15008  *
15009  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15010  * instead.
15011  *
15012  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15013  */
15014 ClutterLayoutInfo *
15015 _clutter_actor_get_layout_info (ClutterActor *self)
15016 {
15017   ClutterLayoutInfo *retval;
15018
15019   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15020   if (retval == NULL)
15021     {
15022       retval = g_slice_new (ClutterLayoutInfo);
15023
15024       *retval = default_layout_info;
15025
15026       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15027                                retval,
15028                                layout_info_free);
15029     }
15030
15031   return retval;
15032 }
15033
15034 /*< private >
15035  * _clutter_actor_get_layout_info_or_defaults:
15036  * @self: a #ClutterActor
15037  *
15038  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15039  *
15040  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15041  * then the default structure will be returned.
15042  *
15043  * This function should only be used for getters.
15044  *
15045  * Return value: a const pointer to the ClutterLayoutInfo structure
15046  */
15047 const ClutterLayoutInfo *
15048 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15049 {
15050   const ClutterLayoutInfo *info;
15051
15052   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15053   if (info == NULL)
15054     return &default_layout_info;
15055
15056   return info;
15057 }
15058
15059 /**
15060  * clutter_actor_set_x_align:
15061  * @self: a #ClutterActor
15062  * @x_align: the horizontal alignment policy
15063  *
15064  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15065  * actor received extra horizontal space.
15066  *
15067  * See also the #ClutterActor:x-align property.
15068  *
15069  * Since: 1.10
15070  */
15071 void
15072 clutter_actor_set_x_align (ClutterActor      *self,
15073                            ClutterActorAlign  x_align)
15074 {
15075   ClutterLayoutInfo *info;
15076
15077   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15078
15079   info = _clutter_actor_get_layout_info (self);
15080
15081   if (info->x_align != x_align)
15082     {
15083       info->x_align = x_align;
15084
15085       clutter_actor_queue_relayout (self);
15086
15087       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15088     }
15089 }
15090
15091 /**
15092  * clutter_actor_get_x_align:
15093  * @self: a #ClutterActor
15094  *
15095  * Retrieves the horizontal alignment policy set using
15096  * clutter_actor_set_x_align().
15097  *
15098  * Return value: the horizontal alignment policy.
15099  *
15100  * Since: 1.10
15101  */
15102 ClutterActorAlign
15103 clutter_actor_get_x_align (ClutterActor *self)
15104 {
15105   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15106
15107   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15108 }
15109
15110 /**
15111  * clutter_actor_set_y_align:
15112  * @self: a #ClutterActor
15113  * @y_align: the vertical alignment policy
15114  *
15115  * Sets the vertical alignment policy of a #ClutterActor, in case the
15116  * actor received extra vertical space.
15117  *
15118  * See also the #ClutterActor:y-align property.
15119  *
15120  * Since: 1.10
15121  */
15122 void
15123 clutter_actor_set_y_align (ClutterActor      *self,
15124                            ClutterActorAlign  y_align)
15125 {
15126   ClutterLayoutInfo *info;
15127
15128   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15129
15130   info = _clutter_actor_get_layout_info (self);
15131
15132   if (info->y_align != y_align)
15133     {
15134       info->y_align = y_align;
15135
15136       clutter_actor_queue_relayout (self);
15137
15138       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15139     }
15140 }
15141
15142 /**
15143  * clutter_actor_get_y_align:
15144  * @self: a #ClutterActor
15145  *
15146  * Retrieves the vertical alignment policy set using
15147  * clutter_actor_set_y_align().
15148  *
15149  * Return value: the vertical alignment policy.
15150  *
15151  * Since: 1.10
15152  */
15153 ClutterActorAlign
15154 clutter_actor_get_y_align (ClutterActor *self)
15155 {
15156   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15157
15158   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15159 }
15160
15161
15162 /**
15163  * clutter_margin_new:
15164  *
15165  * Creates a new #ClutterMargin.
15166  *
15167  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15168  *   clutter_margin_free() to free the resources associated with it when
15169  *   done.
15170  *
15171  * Since: 1.10
15172  */
15173 ClutterMargin *
15174 clutter_margin_new (void)
15175 {
15176   return g_slice_new0 (ClutterMargin);
15177 }
15178
15179 /**
15180  * clutter_margin_copy:
15181  * @margin_: a #ClutterMargin
15182  *
15183  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15184  * the newly created structure.
15185  *
15186  * Return value: (transfer full): a copy of the #ClutterMargin.
15187  *
15188  * Since: 1.10
15189  */
15190 ClutterMargin *
15191 clutter_margin_copy (const ClutterMargin *margin_)
15192 {
15193   if (G_LIKELY (margin_ != NULL))
15194     return g_slice_dup (ClutterMargin, margin_);
15195
15196   return NULL;
15197 }
15198
15199 /**
15200  * clutter_margin_free:
15201  * @margin_: a #ClutterMargin
15202  *
15203  * Frees the resources allocated by clutter_margin_new() and
15204  * clutter_margin_copy().
15205  *
15206  * Since: 1.10
15207  */
15208 void
15209 clutter_margin_free (ClutterMargin *margin_)
15210 {
15211   if (G_LIKELY (margin_ != NULL))
15212     g_slice_free (ClutterMargin, margin_);
15213 }
15214
15215 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15216                      clutter_margin_copy,
15217                      clutter_margin_free)
15218
15219 /**
15220  * clutter_actor_set_margin:
15221  * @self: a #ClutterActor
15222  * @margin: a #ClutterMargin
15223  *
15224  * Sets all the components of the margin of a #ClutterActor.
15225  *
15226  * Since: 1.10
15227  */
15228 void
15229 clutter_actor_set_margin (ClutterActor        *self,
15230                           const ClutterMargin *margin)
15231 {
15232   ClutterLayoutInfo *info;
15233   gboolean changed;
15234   GObject *obj;
15235
15236   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15237   g_return_if_fail (margin != NULL);
15238
15239   obj = G_OBJECT (self);
15240   changed = FALSE;
15241
15242   g_object_freeze_notify (obj);
15243
15244   info = _clutter_actor_get_layout_info (self);
15245
15246   if (info->margin.top != margin->top)
15247     {
15248       info->margin.top = margin->top;
15249       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15250       changed = TRUE;
15251     }
15252
15253   if (info->margin.right != margin->right)
15254     {
15255       info->margin.right = margin->right;
15256       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15257       changed = TRUE;
15258     }
15259
15260   if (info->margin.bottom != margin->bottom)
15261     {
15262       info->margin.bottom = margin->bottom;
15263       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15264       changed = TRUE;
15265     }
15266
15267   if (info->margin.left != margin->left)
15268     {
15269       info->margin.left = margin->left;
15270       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15271       changed = TRUE;
15272     }
15273
15274   if (changed)
15275     clutter_actor_queue_relayout (self);
15276
15277   g_object_thaw_notify (obj);
15278 }
15279
15280 /**
15281  * clutter_actor_get_margin:
15282  * @self: a #ClutterActor
15283  * @margin: (out caller-allocates): return location for a #ClutterMargin
15284  *
15285  * Retrieves all the components of the margin of a #ClutterActor.
15286  *
15287  * Since: 1.10
15288  */
15289 void
15290 clutter_actor_get_margin (ClutterActor  *self,
15291                           ClutterMargin *margin)
15292 {
15293   const ClutterLayoutInfo *info;
15294
15295   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15296   g_return_if_fail (margin != NULL);
15297
15298   info = _clutter_actor_get_layout_info_or_defaults (self);
15299
15300   *margin = info->margin;
15301 }
15302
15303 /**
15304  * clutter_actor_set_margin_top:
15305  * @self: a #ClutterActor
15306  * @margin: the top margin
15307  *
15308  * Sets the margin from the top of a #ClutterActor.
15309  *
15310  * Since: 1.10
15311  */
15312 void
15313 clutter_actor_set_margin_top (ClutterActor *self,
15314                               gfloat        margin)
15315 {
15316   ClutterLayoutInfo *info;
15317
15318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15319   g_return_if_fail (margin >= 0.f);
15320
15321   info = _clutter_actor_get_layout_info (self);
15322
15323   if (info->margin.top == margin)
15324     return;
15325
15326   info->margin.top = margin;
15327
15328   clutter_actor_queue_relayout (self);
15329
15330   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15331 }
15332
15333 /**
15334  * clutter_actor_get_margin_top:
15335  * @self: a #ClutterActor
15336  *
15337  * Retrieves the top margin of a #ClutterActor.
15338  *
15339  * Return value: the top margin
15340  *
15341  * Since: 1.10
15342  */
15343 gfloat
15344 clutter_actor_get_margin_top (ClutterActor *self)
15345 {
15346   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15347
15348   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15349 }
15350
15351 /**
15352  * clutter_actor_set_margin_bottom:
15353  * @self: a #ClutterActor
15354  * @margin: the bottom margin
15355  *
15356  * Sets the margin from the bottom of a #ClutterActor.
15357  *
15358  * Since: 1.10
15359  */
15360 void
15361 clutter_actor_set_margin_bottom (ClutterActor *self,
15362                                  gfloat        margin)
15363 {
15364   ClutterLayoutInfo *info;
15365
15366   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15367   g_return_if_fail (margin >= 0.f);
15368
15369   info = _clutter_actor_get_layout_info (self);
15370
15371   if (info->margin.bottom == margin)
15372     return;
15373
15374   info->margin.bottom = margin;
15375
15376   clutter_actor_queue_relayout (self);
15377
15378   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15379 }
15380
15381 /**
15382  * clutter_actor_get_margin_bottom:
15383  * @self: a #ClutterActor
15384  *
15385  * Retrieves the bottom margin of a #ClutterActor.
15386  *
15387  * Return value: the bottom margin
15388  *
15389  * Since: 1.10
15390  */
15391 gfloat
15392 clutter_actor_get_margin_bottom (ClutterActor *self)
15393 {
15394   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15395
15396   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15397 }
15398
15399 /**
15400  * clutter_actor_set_margin_left:
15401  * @self: a #ClutterActor
15402  * @margin: the left margin
15403  *
15404  * Sets the margin from the left of a #ClutterActor.
15405  *
15406  * Since: 1.10
15407  */
15408 void
15409 clutter_actor_set_margin_left (ClutterActor *self,
15410                                gfloat        margin)
15411 {
15412   ClutterLayoutInfo *info;
15413
15414   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15415   g_return_if_fail (margin >= 0.f);
15416
15417   info = _clutter_actor_get_layout_info (self);
15418
15419   if (info->margin.left == margin)
15420     return;
15421
15422   info->margin.left = margin;
15423
15424   clutter_actor_queue_relayout (self);
15425
15426   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15427 }
15428
15429 /**
15430  * clutter_actor_get_margin_left:
15431  * @self: a #ClutterActor
15432  *
15433  * Retrieves the left margin of a #ClutterActor.
15434  *
15435  * Return value: the left margin
15436  *
15437  * Since: 1.10
15438  */
15439 gfloat
15440 clutter_actor_get_margin_left (ClutterActor *self)
15441 {
15442   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15443
15444   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15445 }
15446
15447 /**
15448  * clutter_actor_set_margin_right:
15449  * @self: a #ClutterActor
15450  * @margin: the right margin
15451  *
15452  * Sets the margin from the right of a #ClutterActor.
15453  *
15454  * Since: 1.10
15455  */
15456 void
15457 clutter_actor_set_margin_right (ClutterActor *self,
15458                                 gfloat        margin)
15459 {
15460   ClutterLayoutInfo *info;
15461
15462   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15463   g_return_if_fail (margin >= 0.f);
15464
15465   info = _clutter_actor_get_layout_info (self);
15466
15467   if (info->margin.right == margin)
15468     return;
15469
15470   info->margin.right = margin;
15471
15472   clutter_actor_queue_relayout (self);
15473
15474   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15475 }
15476
15477 /**
15478  * clutter_actor_get_margin_right:
15479  * @self: a #ClutterActor
15480  *
15481  * Retrieves the right margin of a #ClutterActor.
15482  *
15483  * Return value: the right margin
15484  *
15485  * Since: 1.10
15486  */
15487 gfloat
15488 clutter_actor_get_margin_right (ClutterActor *self)
15489 {
15490   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15491
15492   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15493 }
15494
15495 /**
15496  * clutter_actor_set_background_color:
15497  * @self: a #ClutterActor
15498  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15499  *  set color
15500  *
15501  * Sets the background color of a #ClutterActor.
15502  *
15503  * The background color will be used to cover the whole allocation of the
15504  * actor. The default background color of an actor is transparent.
15505  *
15506  * To check whether an actor has a background color, you can use the
15507  * #ClutterActor:background-color-set actor property.
15508  *
15509  * Since: 1.10
15510  */
15511 void
15512 clutter_actor_set_background_color (ClutterActor       *self,
15513                                     const ClutterColor *color)
15514 {
15515   ClutterActorPrivate *priv;
15516
15517   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15518
15519   priv = self->priv;
15520
15521   if (color == NULL)
15522     {
15523       priv->bg_color_set = FALSE;
15524       g_object_notify_by_pspec (G_OBJECT (self),
15525                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15526       return;
15527     }
15528
15529   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15530     return;
15531
15532   priv->bg_color = *color;
15533   priv->bg_color_set = TRUE;
15534
15535   clutter_actor_queue_redraw (self);
15536
15537   g_object_notify_by_pspec (G_OBJECT (self),
15538                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15539   g_object_notify_by_pspec (G_OBJECT (self),
15540                             obj_props[PROP_BACKGROUND_COLOR]);
15541 }
15542
15543 /**
15544  * clutter_actor_get_background_color:
15545  * @self: a #ClutterActor
15546  * @color: (out caller-allocates): return location for a #ClutterColor
15547  *
15548  * Retrieves the color set using clutter_actor_set_background_color().
15549  *
15550  * Since: 1.10
15551  */
15552 void
15553 clutter_actor_get_background_color (ClutterActor *self,
15554                                     ClutterColor *color)
15555 {
15556   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15557   g_return_if_fail (color != NULL);
15558
15559   *color = self->priv->bg_color;
15560 }
15561
15562 /**
15563  * clutter_actor_get_previous_sibling:
15564  * @self: a #ClutterActor
15565  *
15566  * Retrieves the sibling of @self that comes before it in the list
15567  * of children of @self's parent.
15568  *
15569  * The returned pointer is only valid until the scene graph changes; it
15570  * is not safe to modify the list of children of @self while iterating
15571  * it.
15572  *
15573  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15574  *
15575  * Since: 1.10
15576  */
15577 ClutterActor *
15578 clutter_actor_get_previous_sibling (ClutterActor *self)
15579 {
15580   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15581
15582   return self->priv->prev_sibling;
15583 }
15584
15585 /**
15586  * clutter_actor_get_next_sibling:
15587  * @self: a #ClutterActor
15588  *
15589  * Retrieves the sibling of @self that comes after it in the list
15590  * of children of @self's parent.
15591  *
15592  * The returned pointer is only valid until the scene graph changes; it
15593  * is not safe to modify the list of children of @self while iterating
15594  * it.
15595  *
15596  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15597  *
15598  * Since: 1.10
15599  */
15600 ClutterActor *
15601 clutter_actor_get_next_sibling (ClutterActor *self)
15602 {
15603   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15604
15605   return self->priv->next_sibling;
15606 }
15607
15608 /**
15609  * clutter_actor_get_first_child:
15610  * @self: a #ClutterActor
15611  *
15612  * Retrieves the first child of @self.
15613  *
15614  * The returned pointer is only valid until the scene graph changes; it
15615  * is not safe to modify the list of children of @self while iterating
15616  * it.
15617  *
15618  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15619  *
15620  * Since: 1.10
15621  */
15622 ClutterActor *
15623 clutter_actor_get_first_child (ClutterActor *self)
15624 {
15625   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15626
15627   return self->priv->first_child;
15628 }
15629
15630 /**
15631  * clutter_actor_get_last_child:
15632  * @self: a #ClutterActor
15633  *
15634  * Retrieves the last child of @self.
15635  *
15636  * The returned pointer is only valid until the scene graph changes; it
15637  * is not safe to modify the list of children of @self while iterating
15638  * it.
15639  *
15640  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15641  *
15642  * Since: 1.10
15643  */
15644 ClutterActor *
15645 clutter_actor_get_last_child (ClutterActor *self)
15646 {
15647   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15648
15649   return self->priv->last_child;
15650 }
15651
15652 /* easy way to have properly named fields instead of the dummy ones
15653  * we use in the public structure
15654  */
15655 typedef struct _RealActorIter
15656 {
15657   ClutterActor *root;           /* dummy1 */
15658   ClutterActor *current;        /* dummy2 */
15659   gpointer padding_1;           /* dummy3 */
15660   gint age;                     /* dummy4 */
15661   gpointer padding_2;           /* dummy5 */
15662 } RealActorIter;
15663
15664 /**
15665  * clutter_actor_iter_init:
15666  * @iter: a #ClutterActorIter
15667  * @root: a #ClutterActor
15668  *
15669  * Initializes a #ClutterActorIter, which can then be used to iterate
15670  * efficiently over a section of the scene graph, and associates it
15671  * with @root.
15672  *
15673  * Modifying the scene graph section that contains @root will invalidate
15674  * the iterator.
15675  *
15676  * |[
15677  *   ClutterActorIter iter;
15678  *   ClutterActor *child;
15679  *
15680  *   clutter_actor_iter_init (&iter, container);
15681  *   while (clutter_actor_iter_next (&iter, &child))
15682  *     {
15683  *       /&ast; do something with child &ast;/
15684  *     }
15685  * ]|
15686  *
15687  * Since: 1.10
15688  */
15689 void
15690 clutter_actor_iter_init (ClutterActorIter *iter,
15691                          ClutterActor     *root)
15692 {
15693   RealActorIter *ri = (RealActorIter *) iter;
15694
15695   g_return_if_fail (iter != NULL);
15696   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15697
15698   ri->root = root;
15699   ri->current = NULL;
15700   ri->age = root->priv->age;
15701 }
15702
15703 /**
15704  * clutter_actor_iter_next:
15705  * @iter: a #ClutterActorIter
15706  * @child: (out): return location for a #ClutterActor
15707  *
15708  * Advances the @iter and retrieves the next child of the root #ClutterActor
15709  * that was used to initialize the #ClutterActorIterator.
15710  *
15711  * If the iterator can advance, this function returns %TRUE and sets the
15712  * @child argument.
15713  *
15714  * If the iterator cannot advance, this function returns %FALSE, and
15715  * the contents of @child are undefined.
15716  *
15717  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15718  *
15719  * Since: 1.10
15720  */
15721 gboolean
15722 clutter_actor_iter_next (ClutterActorIter  *iter,
15723                          ClutterActor     **child)
15724 {
15725   RealActorIter *ri = (RealActorIter *) iter;
15726
15727   g_return_val_if_fail (iter != NULL, FALSE);
15728   g_return_val_if_fail (ri->root != NULL, FALSE);
15729 #ifndef G_DISABLE_ASSERT
15730   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15731 #endif
15732
15733   if (ri->current == NULL)
15734     ri->current = ri->root->priv->first_child;
15735   else
15736     ri->current = ri->current->priv->next_sibling;
15737
15738   if (child != NULL)
15739     *child = ri->current;
15740
15741   return ri->current != NULL;
15742 }
15743
15744 /**
15745  * clutter_actor_iter_next:
15746  * @iter: a #ClutterActorIter
15747  * @child: (out): return location for a #ClutterActor
15748  *
15749  * Advances the @iter and retrieves the previous child of the root
15750  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15751  *
15752  * If the iterator can advance, this function returns %TRUE and sets the
15753  * @child argument.
15754  *
15755  * If the iterator cannot advance, this function returns %FALSE, and
15756  * the contents of @child are undefined.
15757  *
15758  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15759  *
15760  * Since: 1.10
15761  */
15762 gboolean
15763 clutter_actor_iter_prev (ClutterActorIter  *iter,
15764                          ClutterActor     **child)
15765 {
15766   RealActorIter *ri = (RealActorIter *) iter;
15767
15768   g_return_val_if_fail (iter != NULL, FALSE);
15769   g_return_val_if_fail (ri->root != NULL, FALSE);
15770 #ifndef G_DISABLE_ASSERT
15771   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15772 #endif
15773
15774   if (ri->current == NULL)
15775     ri->current = ri->root->priv->last_child;
15776   else
15777     ri->current = ri->current->priv->prev_sibling;
15778
15779   if (child != NULL)
15780     *child = ri->current;
15781
15782   return ri->current != NULL;
15783 }
15784
15785 /**
15786  * clutter_actor_iter_remove:
15787  * @iter: a #ClutterActorIter
15788  *
15789  * Safely removes the #ClutterActor currently pointer to by the iterator
15790  * from its parent.
15791  *
15792  * This function can only be called after clutter_actor_iter_next() or
15793  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15794  * than once for the same actor.
15795  *
15796  * This function will call clutter_actor_remove_child() internally.
15797  *
15798  * Since: 1.10
15799  */
15800 void
15801 clutter_actor_iter_remove (ClutterActorIter *iter)
15802 {
15803   RealActorIter *ri = (RealActorIter *) iter;
15804   ClutterActor *cur;
15805
15806   g_return_if_fail (iter != NULL);
15807   g_return_if_fail (ri->root != NULL);
15808 #ifndef G_DISABLE_ASSERT
15809   g_return_if_fail (ri->age == ri->root->priv->age);
15810 #endif
15811   g_return_if_fail (ri->current != NULL);
15812
15813   cur = ri->current;
15814
15815   if (cur != NULL)
15816     {
15817       ri->current = cur->priv->prev_sibling;
15818
15819       clutter_actor_remove_child_internal (ri->root, cur,
15820                                            REMOVE_CHILD_DEFAULT_FLAGS);
15821
15822       ri->age += 1;
15823     }
15824 }
15825
15826 /**
15827  * clutter_actor_iter_destroy:
15828  * @iter: a #ClutterActorIter
15829  *
15830  * Safely destroys the #ClutterActor currently pointer to by the iterator
15831  * from its parent.
15832  *
15833  * This function can only be called after clutter_actor_iter_next() or
15834  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15835  * than once for the same actor.
15836  *
15837  * This function will call clutter_actor_destroy() internally.
15838  *
15839  * Since: 1.10
15840  */
15841 void
15842 clutter_actor_iter_destroy (ClutterActorIter *iter)
15843 {
15844   RealActorIter *ri = (RealActorIter *) iter;
15845   ClutterActor *cur;
15846
15847   g_return_if_fail (iter != NULL);
15848   g_return_if_fail (ri->root != NULL);
15849 #ifndef G_DISABLE_ASSERT
15850   g_return_if_fail (ri->age == ri->root->priv->age);
15851 #endif
15852   g_return_if_fail (ri->current != NULL);
15853
15854   cur = ri->current;
15855
15856   if (cur != NULL)
15857     {
15858       ri->current = cur->priv->prev_sibling;
15859
15860       clutter_actor_destroy (cur);
15861
15862       ri->age += 1;
15863     }
15864 }