actor: Add a method for computing the default paint volume
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="bin-layout">
113  *     <title>Actors</title>
114  *     <graphic fileref="test-actor.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  */
243
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
327
328 #include "clutter-actor-private.h"
329
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-main.h"
342 #include "clutter-marshal.h"
343 #include "clutter-flatten-effect.h"
344 #include "clutter-paint-volume-private.h"
345 #include "clutter-private.h"
346 #include "clutter-profile.h"
347 #include "clutter-scriptable.h"
348 #include "clutter-script-private.h"
349 #include "clutter-stage-private.h"
350 #include "clutter-units.h"
351
352 #include "deprecated/clutter-behaviour.h"
353 #include "deprecated/clutter-container.h"
354
355 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
356 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
357
358 /* Internal enum used to control mapped state update.  This is a hint
359  * which indicates when to do something other than just enforce
360  * invariants.
361  */
362 typedef enum {
363   MAP_STATE_CHECK,           /* just enforce invariants. */
364   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
365                               * used when about to unparent.
366                               */
367   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
368                               * used to set mapped on toplevels.
369                               */
370   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
371                               * used just before unmapping parent.
372                               */
373 } MapStateChange;
374
375 /* 3 entries should be a good compromise, few layout managers
376  * will ask for 3 different preferred size in each allocation cycle */
377 #define N_CACHED_SIZE_REQUESTS 3
378
379 struct _ClutterActorPrivate
380 {
381   /* request mode */
382   ClutterRequestMode request_mode;
383
384   /* our cached size requests for different width / height */
385   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
386   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
387
388   /* An age of 0 means the entry is not set */
389   guint cached_height_age;
390   guint cached_width_age;
391
392   /* the bounding box of the actor, relative to the parent's
393    * allocation
394    */
395   ClutterActorBox allocation;
396   ClutterAllocationFlags allocation_flags;
397
398   /* depth */
399   gfloat z;
400
401   /* clip, in actor coordinates */
402   cairo_rectangle_t clip;
403
404   /* the cached transformation matrix; see apply_transform() */
405   CoglMatrix transform;
406
407   guint8 opacity;
408   gint opacity_override;
409
410   ClutterOffscreenRedirect offscreen_redirect;
411
412   /* This is an internal effect used to implement the
413      offscreen-redirect property */
414   ClutterEffect *flatten_effect;
415
416   /* scene graph */
417   ClutterActor *parent;
418   ClutterActor *prev_sibling;
419   ClutterActor *next_sibling;
420   ClutterActor *first_child;
421   ClutterActor *last_child;
422
423   gint n_children;
424
425   /* tracks whenever the children of an actor are changed; the
426    * age is incremented by 1 whenever an actor is added or
427    * removed. the age is not incremented when the first or the
428    * last child pointers are changed, or when grandchildren of
429    * an actor are changed.
430    */
431   gint age;
432
433   gchar *name; /* a non-unique name, used for debugging */
434   guint32 id; /* unique id, used for backward compatibility */
435
436   gint32 pick_id; /* per-stage unique id, used for picking */
437
438   /* a back-pointer to the Pango context that we can use
439    * to create pre-configured PangoLayout
440    */
441   PangoContext *pango_context;
442
443   /* the text direction configured for this child - either by
444    * application code, or by the actor's parent
445    */
446   ClutterTextDirection text_direction;
447
448   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
449   gint internal_child;
450
451   /* meta classes */
452   ClutterMetaGroup *actions;
453   ClutterMetaGroup *constraints;
454   ClutterMetaGroup *effects;
455
456   /* delegate object used to allocate the children of this actor */
457   ClutterLayoutManager *layout_manager;
458
459   /* used when painting, to update the paint volume */
460   ClutterEffect *current_effect;
461
462   /* This is used to store an effect which needs to be redrawn. A
463      redraw can be queued to start from a particular effect. This is
464      used by parametrised effects that can cache an image of the
465      actor. If a parameter of the effect changes then it only needs to
466      redraw the cached image, not the actual actor. The pointer is
467      only valid if is_dirty == TRUE. If the pointer is NULL then the
468      whole actor is dirty. */
469   ClutterEffect *effect_to_redraw;
470
471   /* This is used when painting effects to implement the
472      clutter_actor_continue_paint() function. It points to the node in
473      the list of effects that is next in the chain */
474   const GList *next_effect_to_paint;
475
476   ClutterPaintVolume paint_volume;
477
478   /* NB: This volume isn't relative to this actor, it is in eye
479    * coordinates so that it can remain valid after the actor changes.
480    */
481   ClutterPaintVolume last_paint_volume;
482
483   ClutterStageQueueRedrawEntry *queue_redraw_entry;
484
485   ClutterColor bg_color;
486
487   /* bitfields */
488
489   /* fixed position and sizes */
490   guint position_set                : 1;
491   guint min_width_set               : 1;
492   guint min_height_set              : 1;
493   guint natural_width_set           : 1;
494   guint natural_height_set          : 1;
495   /* cached request is invalid (implies allocation is too) */
496   guint needs_width_request         : 1;
497   /* cached request is invalid (implies allocation is too) */
498   guint needs_height_request        : 1;
499   /* cached allocation is invalid (request has changed, probably) */
500   guint needs_allocation            : 1;
501   guint show_on_set_parent          : 1;
502   guint has_clip                    : 1;
503   guint clip_to_allocation          : 1;
504   guint enable_model_view_transform : 1;
505   guint enable_paint_unmapped       : 1;
506   guint has_pointer                 : 1;
507   guint propagated_one_redraw       : 1;
508   guint paint_volume_valid          : 1;
509   guint last_paint_volume_valid     : 1;
510   guint in_clone_paint              : 1;
511   guint transform_valid             : 1;
512   /* This is TRUE if anything has queued a redraw since we were last
513      painted. In this case effect_to_redraw will point to an effect
514      the redraw was queued from or it will be NULL if the redraw was
515      queued without an effect. */
516   guint is_dirty                    : 1;
517   guint bg_color_set                : 1;
518 };
519
520 enum
521 {
522   PROP_0,
523
524   PROP_NAME,
525
526   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
527    * when set they force a size request, when gotten they
528    * get the allocation if the allocation is valid, and the
529    * request otherwise
530    */
531   PROP_X,
532   PROP_Y,
533   PROP_WIDTH,
534   PROP_HEIGHT,
535
536   /* Then the rest of these size-related properties are the "actual"
537    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
538    */
539   PROP_FIXED_X,
540   PROP_FIXED_Y,
541
542   PROP_FIXED_POSITION_SET,
543
544   PROP_MIN_WIDTH,
545   PROP_MIN_WIDTH_SET,
546
547   PROP_MIN_HEIGHT,
548   PROP_MIN_HEIGHT_SET,
549
550   PROP_NATURAL_WIDTH,
551   PROP_NATURAL_WIDTH_SET,
552
553   PROP_NATURAL_HEIGHT,
554   PROP_NATURAL_HEIGHT_SET,
555
556   PROP_REQUEST_MODE,
557
558   /* Allocation properties are read-only */
559   PROP_ALLOCATION,
560
561   PROP_DEPTH,
562
563   PROP_CLIP,
564   PROP_HAS_CLIP,
565   PROP_CLIP_TO_ALLOCATION,
566
567   PROP_OPACITY,
568
569   PROP_OFFSCREEN_REDIRECT,
570
571   PROP_VISIBLE,
572   PROP_MAPPED,
573   PROP_REALIZED,
574   PROP_REACTIVE,
575
576   PROP_SCALE_X,
577   PROP_SCALE_Y,
578   PROP_SCALE_CENTER_X,
579   PROP_SCALE_CENTER_Y,
580   PROP_SCALE_GRAVITY,
581
582   PROP_ROTATION_ANGLE_X,
583   PROP_ROTATION_ANGLE_Y,
584   PROP_ROTATION_ANGLE_Z,
585   PROP_ROTATION_CENTER_X,
586   PROP_ROTATION_CENTER_Y,
587   PROP_ROTATION_CENTER_Z,
588   /* This property only makes sense for the z rotation because the
589      others would depend on the actor having a size along the
590      z-axis */
591   PROP_ROTATION_CENTER_Z_GRAVITY,
592
593   PROP_ANCHOR_X,
594   PROP_ANCHOR_Y,
595   PROP_ANCHOR_GRAVITY,
596
597   PROP_SHOW_ON_SET_PARENT,
598
599   PROP_TEXT_DIRECTION,
600   PROP_HAS_POINTER,
601
602   PROP_ACTIONS,
603   PROP_CONSTRAINTS,
604   PROP_EFFECT,
605
606   PROP_LAYOUT_MANAGER,
607
608   PROP_X_ALIGN,
609   PROP_Y_ALIGN,
610   PROP_MARGIN_TOP,
611   PROP_MARGIN_BOTTOM,
612   PROP_MARGIN_LEFT,
613   PROP_MARGIN_RIGHT,
614
615   PROP_BACKGROUND_COLOR,
616   PROP_BACKGROUND_COLOR_SET,
617
618   PROP_FIRST_CHILD,
619   PROP_LAST_CHILD,
620
621   PROP_LAST
622 };
623
624 static GParamSpec *obj_props[PROP_LAST];
625
626 enum
627 {
628   SHOW,
629   HIDE,
630   DESTROY,
631   PARENT_SET,
632   KEY_FOCUS_IN,
633   KEY_FOCUS_OUT,
634   PAINT,
635   PICK,
636   REALIZE,
637   UNREALIZE,
638   QUEUE_REDRAW,
639   QUEUE_RELAYOUT,
640   EVENT,
641   CAPTURED_EVENT,
642   BUTTON_PRESS_EVENT,
643   BUTTON_RELEASE_EVENT,
644   SCROLL_EVENT,
645   KEY_PRESS_EVENT,
646   KEY_RELEASE_EVENT,
647   MOTION_EVENT,
648   ENTER_EVENT,
649   LEAVE_EVENT,
650   ALLOCATION_CHANGED,
651
652   LAST_SIGNAL
653 };
654
655 static guint actor_signals[LAST_SIGNAL] = { 0, };
656
657 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
658 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
659 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
660 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
661
662 /* These setters are all static for now, maybe they should be in the
663  * public API, but they are perhaps obscure enough to leave only as
664  * properties
665  */
666 static void clutter_actor_set_min_width          (ClutterActor *self,
667                                                   gfloat        min_width);
668 static void clutter_actor_set_min_height         (ClutterActor *self,
669                                                   gfloat        min_height);
670 static void clutter_actor_set_natural_width      (ClutterActor *self,
671                                                   gfloat        natural_width);
672 static void clutter_actor_set_natural_height     (ClutterActor *self,
673                                                   gfloat        natural_height);
674 static void clutter_actor_set_min_width_set      (ClutterActor *self,
675                                                   gboolean      use_min_width);
676 static void clutter_actor_set_min_height_set     (ClutterActor *self,
677                                                   gboolean      use_min_height);
678 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
679                                                   gboolean  use_natural_width);
680 static void clutter_actor_set_natural_height_set (ClutterActor *self,
681                                                   gboolean  use_natural_height);
682 static void clutter_actor_update_map_state       (ClutterActor  *self,
683                                                   MapStateChange change);
684 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
685
686 /* Helper routines for managing anchor coords */
687 static void clutter_anchor_coord_get_units (ClutterActor      *self,
688                                             const AnchorCoord *coord,
689                                             gfloat            *x,
690                                             gfloat            *y,
691                                             gfloat            *z);
692 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
693                                             gfloat             x,
694                                             gfloat             y,
695                                             gfloat             z);
696
697 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
698 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
699                                                         ClutterGravity     gravity);
700
701 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
702
703 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
704
705 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
706                                                                ClutterActor *ancestor,
707                                                                CoglMatrix *matrix);
708
709 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
710
711 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
712
713 static void on_layout_manager_changed (ClutterLayoutManager *manager,
714                                        ClutterActor         *self);
715
716 /* Helper macro which translates by the anchor coord, applies the
717    given transformation and then translates back */
718 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
719   gfloat _tx, _ty, _tz;                                                \
720   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
721   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
722   { _transform; }                                                      \
723   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
724
725 static GQuark quark_shader_data = 0;
726 static GQuark quark_actor_layout_info = 0;
727 static GQuark quark_actor_transform_info = 0;
728
729 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
730                          clutter_actor,
731                          G_TYPE_INITIALLY_UNOWNED,
732                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
733                                                 clutter_container_iface_init)
734                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
735                                                 clutter_scriptable_iface_init)
736                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
737                                                 clutter_animatable_iface_init)
738                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
739                                                 atk_implementor_iface_init));
740
741 /*< private >
742  * clutter_actor_get_debug_name:
743  * @actor: a #ClutterActor
744  *
745  * Retrieves a printable name of @actor for debugging messages
746  *
747  * Return value: a string with a printable name
748  */
749 const gchar *
750 _clutter_actor_get_debug_name (ClutterActor *actor)
751 {
752   return actor->priv->name != NULL ? actor->priv->name
753                                    : G_OBJECT_TYPE_NAME (actor);
754 }
755
756 #ifdef CLUTTER_ENABLE_DEBUG
757 /* XXX - this is for debugging only, remove once working (or leave
758  * in only in some debug mode). Should leave it for a little while
759  * until we're confident in the new map/realize/visible handling.
760  */
761 static inline void
762 clutter_actor_verify_map_state (ClutterActor *self)
763 {
764   ClutterActorPrivate *priv = self->priv;
765
766   if (CLUTTER_ACTOR_IS_REALIZED (self))
767     {
768       /* all bets are off during reparent when we're potentially realized,
769        * but should not be according to invariants
770        */
771       if (!CLUTTER_ACTOR_IN_REPARENT (self))
772         {
773           if (priv->parent == NULL)
774             {
775               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
776                 {
777                 }
778               else
779                 g_warning ("Realized non-toplevel actor '%s' should "
780                            "have a parent",
781                            _clutter_actor_get_debug_name (self));
782             }
783           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
784             {
785               g_warning ("Realized actor %s has an unrealized parent %s",
786                          _clutter_actor_get_debug_name (self),
787                          _clutter_actor_get_debug_name (priv->parent));
788             }
789         }
790     }
791
792   if (CLUTTER_ACTOR_IS_MAPPED (self))
793     {
794       if (!CLUTTER_ACTOR_IS_REALIZED (self))
795         g_warning ("Actor '%s' is mapped but not realized",
796                    _clutter_actor_get_debug_name (self));
797
798       /* remaining bets are off during reparent when we're potentially
799        * mapped, but should not be according to invariants
800        */
801       if (!CLUTTER_ACTOR_IN_REPARENT (self))
802         {
803           if (priv->parent == NULL)
804             {
805               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
806                 {
807                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
808                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
809                     {
810                       g_warning ("Toplevel actor '%s' is mapped "
811                                  "but not visible",
812                                  _clutter_actor_get_debug_name (self));
813                     }
814                 }
815               else
816                 {
817                   g_warning ("Mapped actor '%s' should have a parent",
818                              _clutter_actor_get_debug_name (self));
819                 }
820             }
821           else
822             {
823               ClutterActor *iter = self;
824
825               /* check for the enable_paint_unmapped flag on the actor
826                * and parents; if the flag is enabled at any point of this
827                * branch of the scene graph then all the later checks
828                * become pointless
829                */
830               while (iter != NULL)
831                 {
832                   if (iter->priv->enable_paint_unmapped)
833                     return;
834
835                   iter = iter->priv->parent;
836                 }
837
838               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
839                 {
840                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
841                              "is not visible",
842                              _clutter_actor_get_debug_name (self),
843                              _clutter_actor_get_debug_name (priv->parent));
844                 }
845
846               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
847                 {
848                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
849                              "is not realized",
850                              _clutter_actor_get_debug_name (self),
851                              _clutter_actor_get_debug_name (priv->parent));
852                 }
853
854               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
855                 {
856                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
857                     g_warning ("Actor '%s' is mapped but its non-toplevel "
858                                "parent '%s' is not mapped",
859                                _clutter_actor_get_debug_name (self),
860                                _clutter_actor_get_debug_name (priv->parent));
861                 }
862             }
863         }
864     }
865 }
866
867 #endif /* CLUTTER_ENABLE_DEBUG */
868
869 static void
870 clutter_actor_set_mapped (ClutterActor *self,
871                           gboolean      mapped)
872 {
873   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
874     return;
875
876   if (mapped)
877     {
878       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
879       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
880     }
881   else
882     {
883       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
884       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
885     }
886 }
887
888 /* this function updates the mapped and realized states according to
889  * invariants, in the appropriate order.
890  */
891 static void
892 clutter_actor_update_map_state (ClutterActor  *self,
893                                 MapStateChange change)
894 {
895   gboolean was_mapped;
896
897   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
898
899   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
900     {
901       /* the mapped flag on top-level actors must be set by the
902        * per-backend implementation because it might be asynchronous.
903        *
904        * That is, the MAPPED flag on toplevels currently tracks the X
905        * server mapped-ness of the window, while the expected behavior
906        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
907        * This creates some weird complexity by breaking the invariant
908        * that if we're visible and all ancestors shown then we are
909        * also mapped - instead, we are mapped if all ancestors
910        * _possibly excepting_ the stage are mapped. The stage
911        * will map/unmap for example when it is minimized or
912        * moved to another workspace.
913        *
914        * So, the only invariant on the stage is that if visible it
915        * should be realized, and that it has to be visible to be
916        * mapped.
917        */
918       if (CLUTTER_ACTOR_IS_VISIBLE (self))
919         clutter_actor_realize (self);
920
921       switch (change)
922         {
923         case MAP_STATE_CHECK:
924           break;
925
926         case MAP_STATE_MAKE_MAPPED:
927           g_assert (!was_mapped);
928           clutter_actor_set_mapped (self, TRUE);
929           break;
930
931         case MAP_STATE_MAKE_UNMAPPED:
932           g_assert (was_mapped);
933           clutter_actor_set_mapped (self, FALSE);
934           break;
935
936         case MAP_STATE_MAKE_UNREALIZED:
937           /* we only use MAKE_UNREALIZED in unparent,
938            * and unparenting a stage isn't possible.
939            * If someone wants to just unrealize a stage
940            * then clutter_actor_unrealize() doesn't
941            * go through this codepath.
942            */
943           g_warning ("Trying to force unrealize stage is not allowed");
944           break;
945         }
946
947       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
948           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
949           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
950         {
951           g_warning ("Clutter toplevel of type '%s' is not visible, but "
952                      "it is somehow still mapped",
953                      _clutter_actor_get_debug_name (self));
954         }
955     }
956   else
957     {
958       ClutterActorPrivate *priv = self->priv;
959       ClutterActor *parent = priv->parent;
960       gboolean should_be_mapped;
961       gboolean may_be_realized;
962       gboolean must_be_realized;
963
964       should_be_mapped = FALSE;
965       may_be_realized = TRUE;
966       must_be_realized = FALSE;
967
968       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
969         {
970           may_be_realized = FALSE;
971         }
972       else
973         {
974           /* Maintain invariant that if parent is mapped, and we are
975            * visible, then we are mapped ...  unless parent is a
976            * stage, in which case we map regardless of parent's map
977            * state but do require stage to be visible and realized.
978            *
979            * If parent is realized, that does not force us to be
980            * realized; but if parent is unrealized, that does force
981            * us to be unrealized.
982            *
983            * The reason we don't force children to realize with
984            * parents is _clutter_actor_rerealize(); if we require that
985            * a realized parent means children are realized, then to
986            * unrealize an actor we would have to unrealize its
987            * parents, which would end up meaning unrealizing and
988            * hiding the entire stage. So we allow unrealizing a
989            * child (as long as that child is not mapped) while that
990            * child still has a realized parent.
991            *
992            * Also, if we unrealize from leaf nodes to root, and
993            * realize from root to leaf, the invariants are never
994            * violated if we allow children to be unrealized
995            * while parents are realized.
996            *
997            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
998            * to force us to unmap, even though parent is still
999            * mapped. This is because we're unmapping from leaf nodes
1000            * up to root nodes.
1001            */
1002           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1003               change != MAP_STATE_MAKE_UNMAPPED)
1004             {
1005               gboolean parent_is_visible_realized_toplevel;
1006
1007               parent_is_visible_realized_toplevel =
1008                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1009                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1010                  CLUTTER_ACTOR_IS_REALIZED (parent));
1011
1012               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1013                   parent_is_visible_realized_toplevel)
1014                 {
1015                   must_be_realized = TRUE;
1016                   should_be_mapped = TRUE;
1017                 }
1018             }
1019
1020           /* if the actor has been set to be painted even if unmapped
1021            * then we should map it and check for realization as well;
1022            * this is an override for the branch of the scene graph
1023            * which begins with this node
1024            */
1025           if (priv->enable_paint_unmapped)
1026             {
1027               if (priv->parent == NULL)
1028                 g_warning ("Attempting to map an unparented actor '%s'",
1029                            _clutter_actor_get_debug_name (self));
1030
1031               should_be_mapped = TRUE;
1032               must_be_realized = TRUE;
1033             }
1034
1035           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1036             may_be_realized = FALSE;
1037         }
1038
1039       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1040         {
1041           if (parent == NULL)
1042             g_warning ("Attempting to map a child that does not "
1043                        "meet the necessary invariants: the actor '%s' "
1044                        "has no parent",
1045                        _clutter_actor_get_debug_name (self));
1046           else
1047             g_warning ("Attempting to map a child that does not "
1048                        "meet the necessary invariants: the actor '%s' "
1049                        "is parented to an unmapped actor '%s'",
1050                        _clutter_actor_get_debug_name (self),
1051                        _clutter_actor_get_debug_name (priv->parent));
1052         }
1053
1054       /* If in reparent, we temporarily suspend unmap and unrealize.
1055        *
1056        * We want to go in the order "realize, map" and "unmap, unrealize"
1057        */
1058
1059       /* Unmap */
1060       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1061         clutter_actor_set_mapped (self, FALSE);
1062
1063       /* Realize */
1064       if (must_be_realized)
1065         clutter_actor_realize (self);
1066
1067       /* if we must be realized then we may be, presumably */
1068       g_assert (!(must_be_realized && !may_be_realized));
1069
1070       /* Unrealize */
1071       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1072         clutter_actor_unrealize_not_hiding (self);
1073
1074       /* Map */
1075       if (should_be_mapped)
1076         {
1077           if (!must_be_realized)
1078             g_warning ("Somehow we think actor '%s' should be mapped but "
1079                        "not realized, which isn't allowed",
1080                        _clutter_actor_get_debug_name (self));
1081
1082           /* realization is allowed to fail (though I don't know what
1083            * an app is supposed to do about that - shouldn't it just
1084            * be a g_error? anyway, we have to avoid mapping if this
1085            * happens)
1086            */
1087           if (CLUTTER_ACTOR_IS_REALIZED (self))
1088             clutter_actor_set_mapped (self, TRUE);
1089         }
1090     }
1091
1092 #ifdef CLUTTER_ENABLE_DEBUG
1093   /* check all invariants were kept */
1094   clutter_actor_verify_map_state (self);
1095 #endif
1096 }
1097
1098 static void
1099 clutter_actor_real_map (ClutterActor *self)
1100 {
1101   ClutterActorPrivate *priv = self->priv;
1102   ClutterActor *stage, *iter;
1103
1104   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1105
1106   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1107                 _clutter_actor_get_debug_name (self));
1108
1109   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1110
1111   stage = _clutter_actor_get_stage_internal (self);
1112   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1113
1114   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1115                 priv->pick_id,
1116                 _clutter_actor_get_debug_name (self));
1117
1118   /* notify on parent mapped before potentially mapping
1119    * children, so apps see a top-down notification.
1120    */
1121   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1122
1123   for (iter = self->priv->first_child;
1124        iter != NULL;
1125        iter = iter->priv->next_sibling)
1126     {
1127       clutter_actor_map (iter);
1128     }
1129 }
1130
1131 /**
1132  * clutter_actor_map:
1133  * @self: A #ClutterActor
1134  *
1135  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1136  * and realizes its children if they are visible. Does nothing if the
1137  * actor is not visible.
1138  *
1139  * Calling this function is strongly disencouraged: the default
1140  * implementation of #ClutterActorClass.map() will map all the children
1141  * of an actor when mapping its parent.
1142  *
1143  * When overriding map, it is mandatory to chain up to the parent
1144  * implementation.
1145  *
1146  * Since: 1.0
1147  */
1148 void
1149 clutter_actor_map (ClutterActor *self)
1150 {
1151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1152
1153   if (CLUTTER_ACTOR_IS_MAPPED (self))
1154     return;
1155
1156   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1157     return;
1158
1159   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1160 }
1161
1162 static void
1163 clutter_actor_real_unmap (ClutterActor *self)
1164 {
1165   ClutterActorPrivate *priv = self->priv;
1166   ClutterActor *iter;
1167
1168   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1169
1170   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1171                 _clutter_actor_get_debug_name (self));
1172
1173   for (iter = self->priv->first_child;
1174        iter != NULL;
1175        iter = iter->priv->next_sibling)
1176     {
1177       clutter_actor_unmap (iter);
1178     }
1179
1180   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1181
1182   /* clear the contents of the last paint volume, so that hiding + moving +
1183    * showing will not result in the wrong area being repainted
1184    */
1185   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1186   priv->last_paint_volume_valid = TRUE;
1187
1188   /* notify on parent mapped after potentially unmapping
1189    * children, so apps see a bottom-up notification.
1190    */
1191   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1192
1193   /* relinquish keyboard focus if we were unmapped while owning it */
1194   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1195     {
1196       ClutterStage *stage;
1197
1198       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1199
1200       if (stage != NULL)
1201         _clutter_stage_release_pick_id (stage, priv->pick_id);
1202
1203       priv->pick_id = -1;
1204
1205       if (stage != NULL &&
1206           clutter_stage_get_key_focus (stage) == self)
1207         {
1208           clutter_stage_set_key_focus (stage, NULL);
1209         }
1210     }
1211 }
1212
1213 /**
1214  * clutter_actor_unmap:
1215  * @self: A #ClutterActor
1216  *
1217  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1218  * unmaps its children if they were mapped.
1219  *
1220  * Calling this function is not encouraged: the default #ClutterActor
1221  * implementation of #ClutterActorClass.unmap() will also unmap any
1222  * eventual children by default when their parent is unmapped.
1223  *
1224  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1225  * chain up to the parent implementation.
1226  *
1227  * <note>It is important to note that the implementation of the
1228  * #ClutterActorClass.unmap() virtual function may be called after
1229  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1230  * implementation, but it is guaranteed to be called before the
1231  * #GObjectClass.finalize() implementation.</note>
1232  *
1233  * Since: 1.0
1234  */
1235 void
1236 clutter_actor_unmap (ClutterActor *self)
1237 {
1238   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1239
1240   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1241     return;
1242
1243   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1244 }
1245
1246 static void
1247 clutter_actor_real_show (ClutterActor *self)
1248 {
1249   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1250     {
1251       ClutterActorPrivate *priv = self->priv;
1252
1253       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1254
1255       /* we notify on the "visible" flag in the clutter_actor_show()
1256        * wrapper so the entire show signal emission completes first
1257        * (?)
1258        */
1259       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1260
1261       /* we queue a relayout unless the actor is inside a
1262        * container that explicitly told us not to
1263        */
1264       if (priv->parent != NULL &&
1265           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1266         {
1267           /* While an actor is hidden the parent may not have
1268            * allocated/requested so we need to start from scratch
1269            * and avoid the short-circuiting in
1270            * clutter_actor_queue_relayout().
1271            */
1272           priv->needs_width_request  = FALSE;
1273           priv->needs_height_request = FALSE;
1274           priv->needs_allocation     = FALSE;
1275           clutter_actor_queue_relayout (self);
1276         }
1277     }
1278 }
1279
1280 static inline void
1281 set_show_on_set_parent (ClutterActor *self,
1282                         gboolean      set_show)
1283 {
1284   ClutterActorPrivate *priv = self->priv;
1285
1286   set_show = !!set_show;
1287
1288   if (priv->show_on_set_parent == set_show)
1289     return;
1290
1291   if (priv->parent == NULL)
1292     {
1293       priv->show_on_set_parent = set_show;
1294       g_object_notify_by_pspec (G_OBJECT (self),
1295                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1296     }
1297 }
1298
1299 /**
1300  * clutter_actor_show:
1301  * @self: A #ClutterActor
1302  *
1303  * Flags an actor to be displayed. An actor that isn't shown will not
1304  * be rendered on the stage.
1305  *
1306  * Actors are visible by default.
1307  *
1308  * If this function is called on an actor without a parent, the
1309  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1310  * effect.
1311  */
1312 void
1313 clutter_actor_show (ClutterActor *self)
1314 {
1315   ClutterActorPrivate *priv;
1316
1317   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1318
1319   /* simple optimization */
1320   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1321     {
1322       /* we still need to set the :show-on-set-parent property, in
1323        * case show() is called on an unparented actor
1324        */
1325       set_show_on_set_parent (self, TRUE);
1326       return;
1327     }
1328
1329 #ifdef CLUTTER_ENABLE_DEBUG
1330   clutter_actor_verify_map_state (self);
1331 #endif
1332
1333   priv = self->priv;
1334
1335   g_object_freeze_notify (G_OBJECT (self));
1336
1337   set_show_on_set_parent (self, TRUE);
1338
1339   g_signal_emit (self, actor_signals[SHOW], 0);
1340   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1341
1342   if (priv->parent != NULL)
1343     clutter_actor_queue_redraw (priv->parent);
1344
1345   g_object_thaw_notify (G_OBJECT (self));
1346 }
1347
1348 /**
1349  * clutter_actor_show_all:
1350  * @self: a #ClutterActor
1351  *
1352  * Calls clutter_actor_show() on all children of an actor (if any).
1353  *
1354  * Since: 0.2
1355  *
1356  * Deprecated: 1.10: Actors are visible by default
1357  */
1358 void
1359 clutter_actor_show_all (ClutterActor *self)
1360 {
1361   ClutterActorClass *klass;
1362
1363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1364
1365   klass = CLUTTER_ACTOR_GET_CLASS (self);
1366   if (klass->show_all)
1367     klass->show_all (self);
1368 }
1369
1370 static void
1371 clutter_actor_real_hide (ClutterActor *self)
1372 {
1373   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1374     {
1375       ClutterActorPrivate *priv = self->priv;
1376
1377       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1378
1379       /* we notify on the "visible" flag in the clutter_actor_hide()
1380        * wrapper so the entire hide signal emission completes first
1381        * (?)
1382        */
1383       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1384
1385       /* we queue a relayout unless the actor is inside a
1386        * container that explicitly told us not to
1387        */
1388       if (priv->parent != NULL &&
1389           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1390         clutter_actor_queue_relayout (priv->parent);
1391     }
1392 }
1393
1394 /**
1395  * clutter_actor_hide:
1396  * @self: A #ClutterActor
1397  *
1398  * Flags an actor to be hidden. A hidden actor will not be
1399  * rendered on the stage.
1400  *
1401  * Actors are visible by default.
1402  *
1403  * If this function is called on an actor without a parent, the
1404  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1405  * as a side-effect.
1406  */
1407 void
1408 clutter_actor_hide (ClutterActor *self)
1409 {
1410   ClutterActorPrivate *priv;
1411
1412   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1413
1414   /* simple optimization */
1415   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1416     {
1417       /* we still need to set the :show-on-set-parent property, in
1418        * case hide() is called on an unparented actor
1419        */
1420       set_show_on_set_parent (self, FALSE);
1421       return;
1422     }
1423
1424 #ifdef CLUTTER_ENABLE_DEBUG
1425   clutter_actor_verify_map_state (self);
1426 #endif
1427
1428   priv = self->priv;
1429
1430   g_object_freeze_notify (G_OBJECT (self));
1431
1432   set_show_on_set_parent (self, FALSE);
1433
1434   g_signal_emit (self, actor_signals[HIDE], 0);
1435   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1436
1437   if (priv->parent != NULL)
1438     clutter_actor_queue_redraw (priv->parent);
1439
1440   g_object_thaw_notify (G_OBJECT (self));
1441 }
1442
1443 /**
1444  * clutter_actor_hide_all:
1445  * @self: a #ClutterActor
1446  *
1447  * Calls clutter_actor_hide() on all child actors (if any).
1448  *
1449  * Since: 0.2
1450  *
1451  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1452  *   prevent its children from being painted as well.
1453  */
1454 void
1455 clutter_actor_hide_all (ClutterActor *self)
1456 {
1457   ClutterActorClass *klass;
1458
1459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1460
1461   klass = CLUTTER_ACTOR_GET_CLASS (self);
1462   if (klass->hide_all)
1463     klass->hide_all (self);
1464 }
1465
1466 /**
1467  * clutter_actor_realize:
1468  * @self: A #ClutterActor
1469  *
1470  * Realization informs the actor that it is attached to a stage. It
1471  * can use this to allocate resources if it wanted to delay allocation
1472  * until it would be rendered. However it is perfectly acceptable for
1473  * an actor to create resources before being realized because Clutter
1474  * only ever has a single rendering context so that actor is free to
1475  * be moved from one stage to another.
1476  *
1477  * This function does nothing if the actor is already realized.
1478  *
1479  * Because a realized actor must have realized parent actors, calling
1480  * clutter_actor_realize() will also realize all parents of the actor.
1481  *
1482  * This function does not realize child actors, except in the special
1483  * case that realizing the stage, when the stage is visible, will
1484  * suddenly map (and thus realize) the children of the stage.
1485  **/
1486 void
1487 clutter_actor_realize (ClutterActor *self)
1488 {
1489   ClutterActorPrivate *priv;
1490
1491   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1492
1493   priv = self->priv;
1494
1495 #ifdef CLUTTER_ENABLE_DEBUG
1496   clutter_actor_verify_map_state (self);
1497 #endif
1498
1499   if (CLUTTER_ACTOR_IS_REALIZED (self))
1500     return;
1501
1502   /* To be realized, our parent actors must be realized first.
1503    * This will only succeed if we're inside a toplevel.
1504    */
1505   if (priv->parent != NULL)
1506     clutter_actor_realize (priv->parent);
1507
1508   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1509     {
1510       /* toplevels can be realized at any time */
1511     }
1512   else
1513     {
1514       /* "Fail" the realization if parent is missing or unrealized;
1515        * this should really be a g_warning() not some kind of runtime
1516        * failure; how can an app possibly recover? Instead it's a bug
1517        * in the app and the app should get an explanatory warning so
1518        * someone can fix it. But for now it's too hard to fix this
1519        * because e.g. ClutterTexture needs reworking.
1520        */
1521       if (priv->parent == NULL ||
1522           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1523         return;
1524     }
1525
1526   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1527
1528   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1529   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1530
1531   g_signal_emit (self, actor_signals[REALIZE], 0);
1532
1533   /* Stage actor is allowed to unset the realized flag again in its
1534    * default signal handler, though that is a pathological situation.
1535    */
1536
1537   /* If realization "failed" we'll have to update child state. */
1538   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1539 }
1540
1541 static void
1542 clutter_actor_real_unrealize (ClutterActor *self)
1543 {
1544   /* we must be unmapped (implying our children are also unmapped) */
1545   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1546 }
1547
1548 /**
1549  * clutter_actor_unrealize:
1550  * @self: A #ClutterActor
1551  *
1552  * Unrealization informs the actor that it may be being destroyed or
1553  * moved to another stage. The actor may want to destroy any
1554  * underlying graphics resources at this point. However it is
1555  * perfectly acceptable for it to retain the resources until the actor
1556  * is destroyed because Clutter only ever uses a single rendering
1557  * context and all of the graphics resources are valid on any stage.
1558  *
1559  * Because mapped actors must be realized, actors may not be
1560  * unrealized if they are mapped. This function hides the actor to be
1561  * sure it isn't mapped, an application-visible side effect that you
1562  * may not be expecting.
1563  *
1564  * This function should not be called by application code.
1565  */
1566 void
1567 clutter_actor_unrealize (ClutterActor *self)
1568 {
1569   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1570   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1571
1572 /* This function should not really be in the public API, because
1573  * there isn't a good reason to call it. ClutterActor will already
1574  * unrealize things for you when it's important to do so.
1575  *
1576  * If you were using clutter_actor_unrealize() in a dispose
1577  * implementation, then don't, just chain up to ClutterActor's
1578  * dispose.
1579  *
1580  * If you were using clutter_actor_unrealize() to implement
1581  * unrealizing children of your container, then don't, ClutterActor
1582  * will already take care of that.
1583  *
1584  * If you were using clutter_actor_unrealize() to re-realize to
1585  * create your resources in a different way, then use
1586  * _clutter_actor_rerealize() (inside Clutter) or just call your
1587  * code that recreates your resources directly (outside Clutter).
1588  */
1589
1590 #ifdef CLUTTER_ENABLE_DEBUG
1591   clutter_actor_verify_map_state (self);
1592 #endif
1593
1594   clutter_actor_hide (self);
1595
1596   clutter_actor_unrealize_not_hiding (self);
1597 }
1598
1599 static ClutterActorTraverseVisitFlags
1600 unrealize_actor_before_children_cb (ClutterActor *self,
1601                                     int depth,
1602                                     void *user_data)
1603 {
1604   /* If an actor is already unrealized we know its children have also
1605    * already been unrealized... */
1606   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1607     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1608
1609   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1610
1611   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1612 }
1613
1614 static ClutterActorTraverseVisitFlags
1615 unrealize_actor_after_children_cb (ClutterActor *self,
1616                                    int depth,
1617                                    void *user_data)
1618 {
1619   /* We want to unset the realized flag only _after_
1620    * child actors are unrealized, to maintain invariants.
1621    */
1622   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1623   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1624   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1625 }
1626
1627 /*
1628  * clutter_actor_unrealize_not_hiding:
1629  * @self: A #ClutterActor
1630  *
1631  * Unrealization informs the actor that it may be being destroyed or
1632  * moved to another stage. The actor may want to destroy any
1633  * underlying graphics resources at this point. However it is
1634  * perfectly acceptable for it to retain the resources until the actor
1635  * is destroyed because Clutter only ever uses a single rendering
1636  * context and all of the graphics resources are valid on any stage.
1637  *
1638  * Because mapped actors must be realized, actors may not be
1639  * unrealized if they are mapped. You must hide the actor or one of
1640  * its parents before attempting to unrealize.
1641  *
1642  * This function is separate from clutter_actor_unrealize() because it
1643  * does not automatically hide the actor.
1644  * Actors need not be hidden to be unrealized, they just need to
1645  * be unmapped. In fact we don't want to mess up the application's
1646  * setting of the "visible" flag, so hiding is very undesirable.
1647  *
1648  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1649  * backward compatibility.
1650  */
1651 static void
1652 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1653 {
1654   _clutter_actor_traverse (self,
1655                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1656                            unrealize_actor_before_children_cb,
1657                            unrealize_actor_after_children_cb,
1658                            NULL);
1659 }
1660
1661 /*
1662  * _clutter_actor_rerealize:
1663  * @self: A #ClutterActor
1664  * @callback: Function to call while unrealized
1665  * @data: data for callback
1666  *
1667  * If an actor is already unrealized, this just calls the callback.
1668  *
1669  * If it is realized, it unrealizes temporarily, calls the callback,
1670  * and then re-realizes the actor.
1671  *
1672  * As a side effect, leaves all children of the actor unrealized if
1673  * the actor was realized but not showing.  This is because when we
1674  * unrealize the actor temporarily we must unrealize its children
1675  * (e.g. children of a stage can't be realized if stage window is
1676  * gone). And we aren't clever enough to save the realization state of
1677  * all children. In most cases this should not matter, because
1678  * the children will automatically realize when they next become mapped.
1679  */
1680 void
1681 _clutter_actor_rerealize (ClutterActor    *self,
1682                           ClutterCallback  callback,
1683                           void            *data)
1684 {
1685   gboolean was_mapped;
1686   gboolean was_showing;
1687   gboolean was_realized;
1688
1689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1690
1691 #ifdef CLUTTER_ENABLE_DEBUG
1692   clutter_actor_verify_map_state (self);
1693 #endif
1694
1695   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1696   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1697   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1698
1699   /* Must be unmapped to unrealize. Note we only have to hide this
1700    * actor if it was mapped (if all parents were showing).  If actor
1701    * is merely visible (but not mapped), then that's fine, we can
1702    * leave it visible.
1703    */
1704   if (was_mapped)
1705     clutter_actor_hide (self);
1706
1707   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1708
1709   /* unrealize self and all children */
1710   clutter_actor_unrealize_not_hiding (self);
1711
1712   if (callback != NULL)
1713     {
1714       (* callback) (self, data);
1715     }
1716
1717   if (was_showing)
1718     clutter_actor_show (self); /* will realize only if mapping implies it */
1719   else if (was_realized)
1720     clutter_actor_realize (self); /* realize self and all parents */
1721 }
1722
1723 static void
1724 clutter_actor_real_pick (ClutterActor       *self,
1725                          const ClutterColor *color)
1726 {
1727   /* the default implementation is just to paint a rectangle
1728    * with the same size of the actor using the passed color
1729    */
1730   if (clutter_actor_should_pick_paint (self))
1731     {
1732       ClutterActorBox box = { 0, };
1733       float width, height;
1734
1735       clutter_actor_get_allocation_box (self, &box);
1736
1737       width = box.x2 - box.x1;
1738       height = box.y2 - box.y1;
1739
1740       cogl_set_source_color4ub (color->red,
1741                                 color->green,
1742                                 color->blue,
1743                                 color->alpha);
1744
1745       cogl_rectangle (0, 0, width, height);
1746     }
1747
1748   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1749    * with existing container classes that override the pick() virtual
1750    * and chain up to the default implementation - otherwise we'll end up
1751    * painting our children twice.
1752    *
1753    * this has to go away for 2.0; hopefully along the pick() itself.
1754    */
1755   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1756     {
1757       ClutterActor *iter;
1758
1759       for (iter = self->priv->first_child;
1760            iter != NULL;
1761            iter = iter->priv->next_sibling)
1762         clutter_actor_paint (iter);
1763     }
1764 }
1765
1766 /**
1767  * clutter_actor_should_pick_paint:
1768  * @self: A #ClutterActor
1769  *
1770  * Should be called inside the implementation of the
1771  * #ClutterActor::pick virtual function in order to check whether
1772  * the actor should paint itself in pick mode or not.
1773  *
1774  * This function should never be called directly by applications.
1775  *
1776  * Return value: %TRUE if the actor should paint its silhouette,
1777  *   %FALSE otherwise
1778  */
1779 gboolean
1780 clutter_actor_should_pick_paint (ClutterActor *self)
1781 {
1782   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1783
1784   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1785       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1786        CLUTTER_ACTOR_IS_REACTIVE (self)))
1787     return TRUE;
1788
1789   return FALSE;
1790 }
1791
1792 static void
1793 clutter_actor_real_get_preferred_width (ClutterActor *self,
1794                                         gfloat        for_height,
1795                                         gfloat       *min_width_p,
1796                                         gfloat       *natural_width_p)
1797 {
1798   ClutterActorPrivate *priv = self->priv;
1799
1800   if (priv->n_children != 0 &&
1801       priv->layout_manager != NULL)
1802     {
1803       ClutterContainer *container = CLUTTER_CONTAINER (self);
1804
1805       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1806                     "for the preferred width",
1807                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1808                     priv->layout_manager);
1809
1810       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1811                                                   container,
1812                                                   for_height,
1813                                                   min_width_p,
1814                                                   natural_width_p);
1815
1816       return;
1817     }
1818
1819   /* Default implementation is always 0x0, usually an actor
1820    * using this default is relying on someone to set the
1821    * request manually
1822    */
1823   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1824
1825   if (min_width_p)
1826     *min_width_p = 0;
1827
1828   if (natural_width_p)
1829     *natural_width_p = 0;
1830 }
1831
1832 static void
1833 clutter_actor_real_get_preferred_height (ClutterActor *self,
1834                                          gfloat        for_width,
1835                                          gfloat       *min_height_p,
1836                                          gfloat       *natural_height_p)
1837 {
1838   ClutterActorPrivate *priv = self->priv;
1839
1840   if (priv->n_children != 0 &&
1841       priv->layout_manager != NULL)
1842     {
1843       ClutterContainer *container = CLUTTER_CONTAINER (self);
1844
1845       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1846                     "for the preferred height",
1847                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1848                     priv->layout_manager);
1849
1850       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1851                                                    container,
1852                                                    for_width,
1853                                                    min_height_p,
1854                                                    natural_height_p);
1855
1856       return;
1857     }
1858   /* Default implementation is always 0x0, usually an actor
1859    * using this default is relying on someone to set the
1860    * request manually
1861    */
1862   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1863
1864   if (min_height_p)
1865     *min_height_p = 0;
1866
1867   if (natural_height_p)
1868     *natural_height_p = 0;
1869 }
1870
1871 static void
1872 clutter_actor_store_old_geometry (ClutterActor    *self,
1873                                   ClutterActorBox *box)
1874 {
1875   *box = self->priv->allocation;
1876 }
1877
1878 static inline void
1879 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1880                                           const ClutterActorBox *old)
1881 {
1882   ClutterActorPrivate *priv = self->priv;
1883   GObject *obj = G_OBJECT (self);
1884
1885   g_object_freeze_notify (obj);
1886
1887   /* to avoid excessive requisition or allocation cycles we
1888    * use the cached values.
1889    *
1890    * - if we don't have an allocation we assume that we need
1891    *   to notify anyway
1892    * - if we don't have a width or a height request we notify
1893    *   width and height
1894    * - if we have a valid allocation then we check the old
1895    *   bounding box with the current allocation and we notify
1896    *   the changes
1897    */
1898   if (priv->needs_allocation)
1899     {
1900       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1901       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1904     }
1905   else if (priv->needs_width_request || priv->needs_height_request)
1906     {
1907       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1908       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1909     }
1910   else
1911     {
1912       gfloat xu, yu;
1913       gfloat widthu, heightu;
1914
1915       xu = priv->allocation.x1;
1916       yu = priv->allocation.y1;
1917       widthu = priv->allocation.x2 - priv->allocation.x1;
1918       heightu = priv->allocation.y2 - priv->allocation.y1;
1919
1920       if (xu != old->x1)
1921         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1922
1923       if (yu != old->y1)
1924         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1925
1926       if (widthu != (old->x2 - old->x1))
1927         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1928
1929       if (heightu != (old->y2 - old->y1))
1930         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1931     }
1932
1933   g_object_thaw_notify (obj);
1934 }
1935
1936 /*< private >
1937  * clutter_actor_set_allocation_internal:
1938  * @self: a #ClutterActor
1939  * @box: a #ClutterActorBox
1940  * @flags: allocation flags
1941  *
1942  * Stores the allocation of @self.
1943  *
1944  * This function only performs basic storage and property notification.
1945  *
1946  * This function should be called by clutter_actor_set_allocation()
1947  * and by the default implementation of #ClutterActorClass.allocate().
1948  *
1949  * Return value: %TRUE if the allocation of the #ClutterActor has been
1950  *   changed, and %FALSE otherwise
1951  */
1952 static inline gboolean
1953 clutter_actor_set_allocation_internal (ClutterActor           *self,
1954                                        const ClutterActorBox  *box,
1955                                        ClutterAllocationFlags  flags)
1956 {
1957   ClutterActorPrivate *priv = self->priv;
1958   GObject *obj;
1959   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1960   gboolean flags_changed;
1961   gboolean retval;
1962   ClutterActorBox old_alloc = { 0, };
1963
1964   obj = G_OBJECT (self);
1965
1966   g_object_freeze_notify (obj);
1967
1968   clutter_actor_store_old_geometry (self, &old_alloc);
1969
1970   x1_changed = priv->allocation.x1 != box->x1;
1971   y1_changed = priv->allocation.y1 != box->y1;
1972   x2_changed = priv->allocation.x2 != box->x2;
1973   y2_changed = priv->allocation.y2 != box->y2;
1974
1975   flags_changed = priv->allocation_flags != flags;
1976
1977   priv->allocation = *box;
1978   priv->allocation_flags = flags;
1979
1980   /* allocation is authoritative */
1981   priv->needs_width_request = FALSE;
1982   priv->needs_height_request = FALSE;
1983   priv->needs_allocation = FALSE;
1984
1985   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1986     {
1987       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1988                     _clutter_actor_get_debug_name (self));
1989
1990       priv->transform_valid = FALSE;
1991
1992       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1993
1994       retval = TRUE;
1995     }
1996   else
1997     retval = FALSE;
1998
1999   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2000
2001   g_object_thaw_notify (obj);
2002
2003   return retval;
2004 }
2005
2006 static void clutter_actor_real_allocate (ClutterActor           *self,
2007                                          const ClutterActorBox  *box,
2008                                          ClutterAllocationFlags  flags);
2009
2010 static inline void
2011 clutter_actor_maybe_layout_children (ClutterActor           *self,
2012                                      const ClutterActorBox  *allocation,
2013                                      ClutterAllocationFlags  flags)
2014 {
2015   ClutterActorPrivate *priv = self->priv;
2016
2017   /* this is going to be a bit hard to follow, so let's put an explanation
2018    * here.
2019    *
2020    * we want ClutterActor to have a default layout manager if the actor was
2021    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2022    *
2023    * we also want any subclass of ClutterActor that does not override the
2024    * ::allocate() virtual function to delegate to a layout manager.
2025    *
2026    * finally, we want to allow people subclassing ClutterActor and overriding
2027    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2028    *
2029    * on the other hand, we want existing actor subclasses overriding the
2030    * ::allocate() virtual function and chaining up to the parent's
2031    * implementation to continue working without allocating their children
2032    * twice, or without entering an allocation loop.
2033    *
2034    * for the first two points, we check if the class of the actor is
2035    * overridding the ::allocate() virtual function; if it isn't, then we
2036    * follow through with checking whether we have children and a layout
2037    * manager, and eventually calling clutter_layout_manager_allocate().
2038    *
2039    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2040    * allocation flags that we got passed, and if it is present, we continue
2041    * with the check above.
2042    *
2043    * if neither of these two checks yields a positive result, we just
2044    * assume that the ::allocate() virtual function that resulted in this
2045    * function being called will also allocate the children of the actor.
2046    */
2047
2048   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2049     goto check_layout;
2050
2051   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2052     goto check_layout;
2053
2054   return;
2055
2056 check_layout:
2057   if (priv->n_children != 0 &&
2058       priv->layout_manager != NULL)
2059     {
2060       ClutterContainer *container = CLUTTER_CONTAINER (self);
2061       ClutterAllocationFlags children_flags;
2062       ClutterActorBox children_box;
2063
2064       /* normalize the box passed to the layout manager */
2065       children_box.x1 = children_box.y1 = 0.f;
2066       children_box.x2 = (allocation->x2 - allocation->x1);
2067       children_box.y2 = (allocation->y2 - allocation->y1);
2068
2069       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2070        * the actor's children, since it refers only to the current
2071        * actor's allocation.
2072        */
2073       children_flags = flags;
2074       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2075
2076       CLUTTER_NOTE (LAYOUT,
2077                     "Allocating %d children of %s "
2078                     "at { %.2f, %.2f - %.2f x %.2f } "
2079                     "using %s",
2080                     priv->n_children,
2081                     _clutter_actor_get_debug_name (self),
2082                     allocation->x1,
2083                     allocation->y1,
2084                     (allocation->x2 - allocation->x1),
2085                     (allocation->y2 - allocation->y1),
2086                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2087
2088       clutter_layout_manager_allocate (priv->layout_manager,
2089                                        container,
2090                                        &children_box,
2091                                        children_flags);
2092     }
2093 }
2094
2095 static void
2096 clutter_actor_real_allocate (ClutterActor           *self,
2097                              const ClutterActorBox  *box,
2098                              ClutterAllocationFlags  flags)
2099 {
2100   ClutterActorPrivate *priv = self->priv;
2101   gboolean changed;
2102
2103   g_object_freeze_notify (G_OBJECT (self));
2104
2105   changed = clutter_actor_set_allocation_internal (self, box, flags);
2106
2107   /* we allocate our children before we notify changes in our geometry,
2108    * so that people connecting to properties will be able to get valid
2109    * data out of the sub-tree of the scene graph that has this actor at
2110    * the root.
2111    */
2112   clutter_actor_maybe_layout_children (self, box, flags);
2113
2114   if (changed)
2115     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2116                    &priv->allocation,
2117                    priv->allocation_flags);
2118
2119   g_object_thaw_notify (G_OBJECT (self));
2120 }
2121
2122 static void
2123 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2124                                     ClutterActor *origin)
2125 {
2126   /* no point in queuing a redraw on a destroyed actor */
2127   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2128     return;
2129
2130   /* NB: We can't bail out early here if the actor is hidden in case
2131    * the actor bas been cloned. In this case the clone will need to
2132    * receive the signal so it can queue its own redraw.
2133    */
2134
2135   /* calls klass->queue_redraw in default handler */
2136   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2137 }
2138
2139 static void
2140 clutter_actor_real_queue_redraw (ClutterActor *self,
2141                                  ClutterActor *origin)
2142 {
2143   ClutterActor *parent;
2144
2145   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2146                 _clutter_actor_get_debug_name (self),
2147                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2148                                : "same actor");
2149
2150   /* no point in queuing a redraw on a destroyed actor */
2151   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2152     return;
2153
2154   /* If the queue redraw is coming from a child then the actor has
2155      become dirty and any queued effect is no longer valid */
2156   if (self != origin)
2157     {
2158       self->priv->is_dirty = TRUE;
2159       self->priv->effect_to_redraw = NULL;
2160     }
2161
2162   /* If the actor isn't visible, we still had to emit the signal
2163    * to allow for a ClutterClone, but the appearance of the parent
2164    * won't change so we don't have to propagate up the hierarchy.
2165    */
2166   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2167     return;
2168
2169   /* Although we could determine here that a full stage redraw
2170    * has already been queued and immediately bail out, we actually
2171    * guarantee that we will propagate a queue-redraw signal to our
2172    * parent at least once so that it's possible to implement a
2173    * container that tracks which of its children have queued a
2174    * redraw.
2175    */
2176   if (self->priv->propagated_one_redraw)
2177     {
2178       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2179       if (stage != NULL &&
2180           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2181         return;
2182     }
2183
2184   self->priv->propagated_one_redraw = TRUE;
2185
2186   /* notify parents, if they are all visible eventually we'll
2187    * queue redraw on the stage, which queues the redraw idle.
2188    */
2189   parent = clutter_actor_get_parent (self);
2190   if (parent != NULL)
2191     {
2192       /* this will go up recursively */
2193       _clutter_actor_signal_queue_redraw (parent, origin);
2194     }
2195 }
2196
2197 static void
2198 clutter_actor_real_queue_relayout (ClutterActor *self)
2199 {
2200   ClutterActorPrivate *priv = self->priv;
2201
2202   /* no point in queueing a redraw on a destroyed actor */
2203   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2204     return;
2205
2206   priv->needs_width_request  = TRUE;
2207   priv->needs_height_request = TRUE;
2208   priv->needs_allocation     = TRUE;
2209
2210   /* reset the cached size requests */
2211   memset (priv->width_requests, 0,
2212           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2213   memset (priv->height_requests, 0,
2214           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2215
2216   /* We need to go all the way up the hierarchy */
2217   if (priv->parent != NULL)
2218     _clutter_actor_queue_only_relayout (priv->parent);
2219 }
2220
2221 /**
2222  * clutter_actor_apply_relative_transform_to_point:
2223  * @self: A #ClutterActor
2224  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2225  *   default #ClutterStage
2226  * @point: A point as #ClutterVertex
2227  * @vertex: (out caller-allocates): The translated #ClutterVertex
2228  *
2229  * Transforms @point in coordinates relative to the actor into
2230  * ancestor-relative coordinates using the relevant transform
2231  * stack (i.e. scale, rotation, etc).
2232  *
2233  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2234  * this case, the coordinates returned will be the coordinates on
2235  * the stage before the projection is applied. This is different from
2236  * the behaviour of clutter_actor_apply_transform_to_point().
2237  *
2238  * Since: 0.6
2239  */
2240 void
2241 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2242                                                  ClutterActor        *ancestor,
2243                                                  const ClutterVertex *point,
2244                                                  ClutterVertex       *vertex)
2245 {
2246   gfloat w;
2247   CoglMatrix matrix;
2248
2249   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2250   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2251   g_return_if_fail (point != NULL);
2252   g_return_if_fail (vertex != NULL);
2253
2254   *vertex = *point;
2255   w = 1.0;
2256
2257   if (ancestor == NULL)
2258     ancestor = _clutter_actor_get_stage_internal (self);
2259
2260   if (ancestor == NULL)
2261     {
2262       *vertex = *point;
2263       return;
2264     }
2265
2266   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2267   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2268 }
2269
2270 static gboolean
2271 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2272                                          const ClutterVertex *vertices_in,
2273                                          ClutterVertex *vertices_out,
2274                                          int n_vertices)
2275 {
2276   ClutterActor *stage;
2277   CoglMatrix modelview;
2278   CoglMatrix projection;
2279   float viewport[4];
2280
2281   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2282
2283   stage = _clutter_actor_get_stage_internal (self);
2284
2285   /* We really can't do anything meaningful in this case so don't try
2286    * to do any transform */
2287   if (stage == NULL)
2288     return FALSE;
2289
2290   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2291    * that gets us to stage coordinates, we want to go all the way to eye
2292    * coordinates */
2293   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2294
2295   /* Fetch the projection and viewport */
2296   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2297   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2298                                &viewport[0],
2299                                &viewport[1],
2300                                &viewport[2],
2301                                &viewport[3]);
2302
2303   _clutter_util_fully_transform_vertices (&modelview,
2304                                           &projection,
2305                                           viewport,
2306                                           vertices_in,
2307                                           vertices_out,
2308                                           n_vertices);
2309
2310   return TRUE;
2311 }
2312
2313 /**
2314  * clutter_actor_apply_transform_to_point:
2315  * @self: A #ClutterActor
2316  * @point: A point as #ClutterVertex
2317  * @vertex: (out caller-allocates): The translated #ClutterVertex
2318  *
2319  * Transforms @point in coordinates relative to the actor
2320  * into screen-relative coordinates with the current actor
2321  * transformation (i.e. scale, rotation, etc)
2322  *
2323  * Since: 0.4
2324  **/
2325 void
2326 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2327                                         const ClutterVertex *point,
2328                                         ClutterVertex       *vertex)
2329 {
2330   g_return_if_fail (point != NULL);
2331   g_return_if_fail (vertex != NULL);
2332   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2333 }
2334
2335 /*
2336  * _clutter_actor_get_relative_transformation_matrix:
2337  * @self: The actor whose coordinate space you want to transform from.
2338  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2339  *            or %NULL if you want to transform all the way to eye coordinates.
2340  * @matrix: A #CoglMatrix to store the transformation
2341  *
2342  * This gets a transformation @matrix that will transform coordinates from the
2343  * coordinate space of @self into the coordinate space of @ancestor.
2344  *
2345  * For example if you need a matrix that can transform the local actor
2346  * coordinates of @self into stage coordinates you would pass the actor's stage
2347  * pointer as the @ancestor.
2348  *
2349  * If you pass %NULL then the transformation will take you all the way through
2350  * to eye coordinates. This can be useful if you want to extract the entire
2351  * modelview transform that Clutter applies before applying the projection
2352  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2353  * using cogl_set_modelview_matrix() for example then you would want a matrix
2354  * that transforms into eye coordinates.
2355  *
2356  * <note><para>This function explicitly initializes the given @matrix. If you just
2357  * want clutter to multiply a relative transformation with an existing matrix
2358  * you can use clutter_actor_apply_relative_transformation_matrix()
2359  * instead.</para></note>
2360  *
2361  */
2362 /* XXX: We should consider caching the stage relative modelview along with
2363  * the actor itself */
2364 static void
2365 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2366                                                    ClutterActor *ancestor,
2367                                                    CoglMatrix *matrix)
2368 {
2369   cogl_matrix_init_identity (matrix);
2370
2371   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2372 }
2373
2374 /* Project the given @box into stage window coordinates, writing the
2375  * transformed vertices to @verts[]. */
2376 static gboolean
2377 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2378                                           const ClutterActorBox *box,
2379                                           ClutterVertex          verts[])
2380 {
2381   ClutterVertex box_vertices[4];
2382
2383   box_vertices[0].x = box->x1;
2384   box_vertices[0].y = box->y1;
2385   box_vertices[0].z = 0;
2386   box_vertices[1].x = box->x2;
2387   box_vertices[1].y = box->y1;
2388   box_vertices[1].z = 0;
2389   box_vertices[2].x = box->x1;
2390   box_vertices[2].y = box->y2;
2391   box_vertices[2].z = 0;
2392   box_vertices[3].x = box->x2;
2393   box_vertices[3].y = box->y2;
2394   box_vertices[3].z = 0;
2395
2396   return
2397     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2398 }
2399
2400 /**
2401  * clutter_actor_get_allocation_vertices:
2402  * @self: A #ClutterActor
2403  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2404  *   against, or %NULL to use the #ClutterStage
2405  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2406  *   location for an array of 4 #ClutterVertex in which to store the result
2407  *
2408  * Calculates the transformed coordinates of the four corners of the
2409  * actor in the plane of @ancestor. The returned vertices relate to
2410  * the #ClutterActorBox coordinates as follows:
2411  * <itemizedlist>
2412  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2413  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2414  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2415  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2416  * </itemizedlist>
2417  *
2418  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2419  * this case, the coordinates returned will be the coordinates on
2420  * the stage before the projection is applied. This is different from
2421  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2422  *
2423  * Since: 0.6
2424  */
2425 void
2426 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2427                                        ClutterActor  *ancestor,
2428                                        ClutterVertex  verts[])
2429 {
2430   ClutterActorPrivate *priv;
2431   ClutterActorBox box;
2432   ClutterVertex vertices[4];
2433   CoglMatrix modelview;
2434
2435   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2436   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2437
2438   if (ancestor == NULL)
2439     ancestor = _clutter_actor_get_stage_internal (self);
2440
2441   /* Fallback to a NOP transform if the actor isn't parented under a
2442    * stage. */
2443   if (ancestor == NULL)
2444     ancestor = self;
2445
2446   priv = self->priv;
2447
2448   /* if the actor needs to be allocated we force a relayout, so that
2449    * we will have valid values to use in the transformations */
2450   if (priv->needs_allocation)
2451     {
2452       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2453       if (stage)
2454         _clutter_stage_maybe_relayout (stage);
2455       else
2456         {
2457           box.x1 = box.y1 = 0;
2458           /* The result isn't really meaningful in this case but at
2459            * least try to do something *vaguely* reasonable... */
2460           clutter_actor_get_size (self, &box.x2, &box.y2);
2461         }
2462     }
2463
2464   clutter_actor_get_allocation_box (self, &box);
2465
2466   vertices[0].x = box.x1;
2467   vertices[0].y = box.y1;
2468   vertices[0].z = 0;
2469   vertices[1].x = box.x2;
2470   vertices[1].y = box.y1;
2471   vertices[1].z = 0;
2472   vertices[2].x = box.x1;
2473   vertices[2].y = box.y2;
2474   vertices[2].z = 0;
2475   vertices[3].x = box.x2;
2476   vertices[3].y = box.y2;
2477   vertices[3].z = 0;
2478
2479   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2480                                                      &modelview);
2481
2482   cogl_matrix_transform_points (&modelview,
2483                                 3,
2484                                 sizeof (ClutterVertex),
2485                                 vertices,
2486                                 sizeof (ClutterVertex),
2487                                 vertices,
2488                                 4);
2489 }
2490
2491 /**
2492  * clutter_actor_get_abs_allocation_vertices:
2493  * @self: A #ClutterActor
2494  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2495  *   of 4 #ClutterVertex where to store the result.
2496  *
2497  * Calculates the transformed screen coordinates of the four corners of
2498  * the actor; the returned vertices relate to the #ClutterActorBox
2499  * coordinates  as follows:
2500  * <itemizedlist>
2501  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2502  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2503  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2504  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2505  * </itemizedlist>
2506  *
2507  * Since: 0.4
2508  */
2509 void
2510 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2511                                            ClutterVertex  verts[])
2512 {
2513   ClutterActorPrivate *priv;
2514   ClutterActorBox actor_space_allocation;
2515
2516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2517
2518   priv = self->priv;
2519
2520   /* if the actor needs to be allocated we force a relayout, so that
2521    * the actor allocation box will be valid for
2522    * _clutter_actor_transform_and_project_box()
2523    */
2524   if (priv->needs_allocation)
2525     {
2526       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2527       /* There's nothing meaningful we can do now */
2528       if (!stage)
2529         return;
2530
2531       _clutter_stage_maybe_relayout (stage);
2532     }
2533
2534   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2535    * own coordinate space... */
2536   actor_space_allocation.x1 = 0;
2537   actor_space_allocation.y1 = 0;
2538   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2539   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2540   _clutter_actor_transform_and_project_box (self,
2541                                             &actor_space_allocation,
2542                                             verts);
2543 }
2544
2545 static void
2546 clutter_actor_real_apply_transform (ClutterActor *self,
2547                                     CoglMatrix   *matrix)
2548 {
2549   ClutterActorPrivate *priv = self->priv;
2550
2551   if (!priv->transform_valid)
2552     {
2553       CoglMatrix *transform = &priv->transform;
2554       const ClutterTransformInfo *info;
2555
2556       info = _clutter_actor_get_transform_info_or_defaults (self);
2557
2558       cogl_matrix_init_identity (transform);
2559
2560       cogl_matrix_translate (transform,
2561                              priv->allocation.x1,
2562                              priv->allocation.y1,
2563                              0.0);
2564
2565       if (priv->z)
2566         cogl_matrix_translate (transform, 0, 0, priv->z);
2567
2568       /*
2569        * because the rotation involves translations, we must scale
2570        * before applying the rotations (if we apply the scale after
2571        * the rotations, the translations included in the rotation are
2572        * not scaled and so the entire object will move on the screen
2573        * as a result of rotating it).
2574        */
2575       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2576         {
2577           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2578                                         &info->scale_center,
2579                                         cogl_matrix_scale (transform,
2580                                                            info->scale_x,
2581                                                            info->scale_y,
2582                                                            1.0));
2583         }
2584
2585       if (info->rz_angle)
2586         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2587                                       &info->rz_center,
2588                                       cogl_matrix_rotate (transform,
2589                                                           info->rz_angle,
2590                                                           0, 0, 1.0));
2591
2592       if (info->ry_angle)
2593         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2594                                       &info->ry_center,
2595                                       cogl_matrix_rotate (transform,
2596                                                           info->ry_angle,
2597                                                           0, 1.0, 0));
2598
2599       if (info->rx_angle)
2600         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2601                                       &info->rx_center,
2602                                       cogl_matrix_rotate (transform,
2603                                                           info->rx_angle,
2604                                                           1.0, 0, 0));
2605
2606       if (!clutter_anchor_coord_is_zero (&info->anchor))
2607         {
2608           gfloat x, y, z;
2609
2610           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2611           cogl_matrix_translate (transform, -x, -y, -z);
2612         }
2613
2614       priv->transform_valid = TRUE;
2615     }
2616
2617   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2618 }
2619
2620 /* Applies the transforms associated with this actor to the given
2621  * matrix. */
2622 void
2623 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2624                                           CoglMatrix *matrix)
2625 {
2626   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2627 }
2628
2629 /*
2630  * clutter_actor_apply_relative_transformation_matrix:
2631  * @self: The actor whose coordinate space you want to transform from.
2632  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2633  *            or %NULL if you want to transform all the way to eye coordinates.
2634  * @matrix: A #CoglMatrix to apply the transformation too.
2635  *
2636  * This multiplies a transform with @matrix that will transform coordinates
2637  * from the coordinate space of @self into the coordinate space of @ancestor.
2638  *
2639  * For example if you need a matrix that can transform the local actor
2640  * coordinates of @self into stage coordinates you would pass the actor's stage
2641  * pointer as the @ancestor.
2642  *
2643  * If you pass %NULL then the transformation will take you all the way through
2644  * to eye coordinates. This can be useful if you want to extract the entire
2645  * modelview transform that Clutter applies before applying the projection
2646  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2647  * using cogl_set_modelview_matrix() for example then you would want a matrix
2648  * that transforms into eye coordinates.
2649  *
2650  * <note>This function doesn't initialize the given @matrix, it simply
2651  * multiplies the requested transformation matrix with the existing contents of
2652  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2653  * before calling this function, or you can use
2654  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2655  */
2656 void
2657 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2658                                                      ClutterActor *ancestor,
2659                                                      CoglMatrix *matrix)
2660 {
2661   ClutterActor *parent;
2662
2663   /* Note we terminate before ever calling stage->apply_transform()
2664    * since that would conceptually be relative to the underlying
2665    * window OpenGL coordinates so we'd need a special @ancestor
2666    * value to represent the fake parent of the stage. */
2667   if (self == ancestor)
2668     return;
2669
2670   parent = clutter_actor_get_parent (self);
2671
2672   if (parent != NULL)
2673     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2674                                                          matrix);
2675
2676   _clutter_actor_apply_modelview_transform (self, matrix);
2677 }
2678
2679 static void
2680 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2681                                        ClutterPaintVolume *pv,
2682                                        const char *label,
2683                                        const CoglColor *color)
2684 {
2685   static CoglPipeline *outline = NULL;
2686   CoglPrimitive *prim;
2687   ClutterVertex line_ends[12 * 2];
2688   int n_vertices;
2689   CoglContext *ctx =
2690     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2691   /* XXX: at some point we'll query this from the stage but we can't
2692    * do that until the osx backend uses Cogl natively. */
2693   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2694
2695   if (outline == NULL)
2696     outline = cogl_pipeline_new (ctx);
2697
2698   _clutter_paint_volume_complete (pv);
2699
2700   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2701
2702   /* Front face */
2703   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2704   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2705   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2706   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2707
2708   if (!pv->is_2d)
2709     {
2710       /* Back face */
2711       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2712       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2713       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2714       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2715
2716       /* Lines connecting front face to back face */
2717       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2718       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2719       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2720       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2721     }
2722
2723   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2724                                 n_vertices,
2725                                 (CoglVertexP3 *)line_ends);
2726
2727   cogl_pipeline_set_color (outline, color);
2728   cogl_framebuffer_draw_primitive (fb, outline, prim);
2729   cogl_object_unref (prim);
2730
2731   if (label)
2732     {
2733       PangoLayout *layout;
2734       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2735       pango_layout_set_text (layout, label, -1);
2736       cogl_pango_render_layout (layout,
2737                                 pv->vertices[0].x,
2738                                 pv->vertices[0].y,
2739                                 color,
2740                                 0);
2741       g_object_unref (layout);
2742     }
2743 }
2744
2745 static void
2746 _clutter_actor_draw_paint_volume (ClutterActor *self)
2747 {
2748   ClutterPaintVolume *pv;
2749   CoglColor color;
2750
2751   pv = _clutter_actor_get_paint_volume_mutable (self);
2752   if (!pv)
2753     {
2754       gfloat width, height;
2755       ClutterPaintVolume fake_pv;
2756
2757       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2758       _clutter_paint_volume_init_static (&fake_pv, stage);
2759
2760       clutter_actor_get_size (self, &width, &height);
2761       clutter_paint_volume_set_width (&fake_pv, width);
2762       clutter_paint_volume_set_height (&fake_pv, height);
2763
2764       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2765       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2766                                              _clutter_actor_get_debug_name (self),
2767                                              &color);
2768
2769       clutter_paint_volume_free (&fake_pv);
2770     }
2771   else
2772     {
2773       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2774       _clutter_actor_draw_paint_volume_full (self, pv,
2775                                              _clutter_actor_get_debug_name (self),
2776                                              &color);
2777     }
2778 }
2779
2780 static void
2781 _clutter_actor_paint_cull_result (ClutterActor *self,
2782                                   gboolean success,
2783                                   ClutterCullResult result)
2784 {
2785   ClutterPaintVolume *pv;
2786   CoglColor color;
2787
2788   if (success)
2789     {
2790       if (result == CLUTTER_CULL_RESULT_IN)
2791         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2792       else if (result == CLUTTER_CULL_RESULT_OUT)
2793         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2794       else
2795         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2796     }
2797   else
2798     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2799
2800   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2801     _clutter_actor_draw_paint_volume_full (self, pv,
2802                                            _clutter_actor_get_debug_name (self),
2803                                            &color);
2804   else
2805     {
2806       PangoLayout *layout;
2807       char *label =
2808         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2809       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2810       cogl_set_source_color (&color);
2811
2812       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2813       pango_layout_set_text (layout, label, -1);
2814       cogl_pango_render_layout (layout,
2815                                 0,
2816                                 0,
2817                                 &color,
2818                                 0);
2819       g_free (label);
2820       g_object_unref (layout);
2821     }
2822 }
2823
2824 static int clone_paint_level = 0;
2825
2826 void
2827 _clutter_actor_push_clone_paint (void)
2828 {
2829   clone_paint_level++;
2830 }
2831
2832 void
2833 _clutter_actor_pop_clone_paint (void)
2834 {
2835   clone_paint_level--;
2836 }
2837
2838 static gboolean
2839 in_clone_paint (void)
2840 {
2841   return clone_paint_level > 0;
2842 }
2843
2844 /* Returns TRUE if the actor can be ignored */
2845 /* FIXME: we should return a ClutterCullResult, and
2846  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2847  * means there's no point in trying to cull descendants of the current
2848  * node. */
2849 static gboolean
2850 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2851 {
2852   ClutterActorPrivate *priv = self->priv;
2853   ClutterActor *stage;
2854   const ClutterPlane *stage_clip;
2855
2856   if (!priv->last_paint_volume_valid)
2857     {
2858       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2859                     "->last_paint_volume_valid == FALSE",
2860                     _clutter_actor_get_debug_name (self));
2861       return FALSE;
2862     }
2863
2864   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2865     return FALSE;
2866
2867   stage = _clutter_actor_get_stage_internal (self);
2868   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2869   if (G_UNLIKELY (!stage_clip))
2870     {
2871       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2872                     "No stage clip set",
2873                     _clutter_actor_get_debug_name (self));
2874       return FALSE;
2875     }
2876
2877   if (cogl_get_draw_framebuffer () !=
2878       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2879     {
2880       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2881                     "Current framebuffer doesn't correspond to stage",
2882                     _clutter_actor_get_debug_name (self));
2883       return FALSE;
2884     }
2885
2886   *result_out =
2887     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2888   return TRUE;
2889 }
2890
2891 static void
2892 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2893 {
2894   ClutterActorPrivate *priv = self->priv;
2895   const ClutterPaintVolume *pv;
2896
2897   if (priv->last_paint_volume_valid)
2898     {
2899       clutter_paint_volume_free (&priv->last_paint_volume);
2900       priv->last_paint_volume_valid = FALSE;
2901     }
2902
2903   pv = clutter_actor_get_paint_volume (self);
2904   if (!pv)
2905     {
2906       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2907                     "Actor failed to report a paint volume",
2908                     _clutter_actor_get_debug_name (self));
2909       return;
2910     }
2911
2912   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2913
2914   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2915                                             NULL); /* eye coordinates */
2916
2917   priv->last_paint_volume_valid = TRUE;
2918 }
2919
2920 static inline gboolean
2921 actor_has_shader_data (ClutterActor *self)
2922 {
2923   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2924 }
2925
2926 guint32
2927 _clutter_actor_get_pick_id (ClutterActor *self)
2928 {
2929   if (self->priv->pick_id < 0)
2930     return 0;
2931
2932   return self->priv->pick_id;
2933 }
2934
2935 /* This is the same as clutter_actor_add_effect except that it doesn't
2936    queue a redraw and it doesn't notify on the effect property */
2937 static void
2938 _clutter_actor_add_effect_internal (ClutterActor  *self,
2939                                     ClutterEffect *effect)
2940 {
2941   ClutterActorPrivate *priv = self->priv;
2942
2943   if (priv->effects == NULL)
2944     {
2945       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2946       priv->effects->actor = self;
2947     }
2948
2949   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2950 }
2951
2952 /* This is the same as clutter_actor_remove_effect except that it doesn't
2953    queue a redraw and it doesn't notify on the effect property */
2954 static void
2955 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2956                                        ClutterEffect *effect)
2957 {
2958   ClutterActorPrivate *priv = self->priv;
2959
2960   if (priv->effects == NULL)
2961     return;
2962
2963   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2964 }
2965
2966 static gboolean
2967 needs_flatten_effect (ClutterActor *self)
2968 {
2969   ClutterActorPrivate *priv = self->priv;
2970
2971   if (G_UNLIKELY (clutter_paint_debug_flags &
2972                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2973     return FALSE;
2974
2975   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2976     return TRUE;
2977   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2978     {
2979       if (clutter_actor_get_paint_opacity (self) < 255 &&
2980           clutter_actor_has_overlaps (self))
2981         return TRUE;
2982     }
2983
2984   return FALSE;
2985 }
2986
2987 static void
2988 add_or_remove_flatten_effect (ClutterActor *self)
2989 {
2990   ClutterActorPrivate *priv = self->priv;
2991
2992   /* Add or remove the flatten effect depending on the
2993      offscreen-redirect property. */
2994   if (needs_flatten_effect (self))
2995     {
2996       if (priv->flatten_effect == NULL)
2997         {
2998           ClutterActorMeta *actor_meta;
2999           gint priority;
3000
3001           priv->flatten_effect = _clutter_flatten_effect_new ();
3002           /* Keep a reference to the effect so that we can queue
3003              redraws from it */
3004           g_object_ref_sink (priv->flatten_effect);
3005
3006           /* Set the priority of the effect to high so that it will
3007              always be applied to the actor first. It uses an internal
3008              priority so that it won't be visible to applications */
3009           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3010           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3011           _clutter_actor_meta_set_priority (actor_meta, priority);
3012
3013           /* This will add the effect without queueing a redraw */
3014           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3015         }
3016     }
3017   else
3018     {
3019       if (priv->flatten_effect != NULL)
3020         {
3021           /* Destroy the effect so that it will lose its fbo cache of
3022              the actor */
3023           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3024           g_object_unref (priv->flatten_effect);
3025           priv->flatten_effect = NULL;
3026         }
3027     }
3028 }
3029
3030 static void
3031 clutter_actor_real_paint (ClutterActor *actor)
3032 {
3033   ClutterActorPrivate *priv = actor->priv;
3034   ClutterActor *iter;
3035
3036   /* paint the background color, if set */
3037   if (priv->bg_color_set)
3038     {
3039       float width, height;
3040       guint8 real_alpha;
3041
3042       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3043
3044       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3045                  * priv->bg_color.alpha
3046                  / 255;
3047
3048       cogl_set_source_color4ub (priv->bg_color.red,
3049                                 priv->bg_color.green,
3050                                 priv->bg_color.blue,
3051                                 real_alpha);
3052
3053       cogl_rectangle (0, 0, width, height);
3054     }
3055
3056   for (iter = priv->first_child;
3057        iter != NULL;
3058        iter = iter->priv->next_sibling)
3059     {
3060       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3061                     _clutter_actor_get_debug_name (iter),
3062                     _clutter_actor_get_debug_name (actor),
3063                     iter->priv->allocation.x1,
3064                     iter->priv->allocation.y1,
3065                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3066                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3067
3068       clutter_actor_paint (iter);
3069     }
3070 }
3071
3072 /**
3073  * clutter_actor_paint:
3074  * @self: A #ClutterActor
3075  *
3076  * Renders the actor to display.
3077  *
3078  * This function should not be called directly by applications.
3079  * Call clutter_actor_queue_redraw() to queue paints, instead.
3080  *
3081  * This function is context-aware, and will either cause a
3082  * regular paint or a pick paint.
3083  *
3084  * This function will emit the #ClutterActor::paint signal or
3085  * the #ClutterActor::pick signal, depending on the context.
3086  *
3087  * This function does not paint the actor if the actor is set to 0,
3088  * unless it is performing a pick paint.
3089  */
3090 void
3091 clutter_actor_paint (ClutterActor *self)
3092 {
3093   ClutterActorPrivate *priv;
3094   ClutterPickMode pick_mode;
3095   gboolean clip_set = FALSE;
3096   gboolean shader_applied = FALSE;
3097
3098   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3099                           "Actor real-paint counter",
3100                           "Increments each time any actor is painted",
3101                           0 /* no application private data */);
3102   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3103                           "Actor pick-paint counter",
3104                           "Increments each time any actor is painted "
3105                           "for picking",
3106                           0 /* no application private data */);
3107
3108   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3109
3110   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3111     return;
3112
3113   priv = self->priv;
3114
3115   pick_mode = _clutter_context_get_pick_mode ();
3116
3117   if (pick_mode == CLUTTER_PICK_NONE)
3118     priv->propagated_one_redraw = FALSE;
3119
3120   /* It's an important optimization that we consider painting of
3121    * actors with 0 opacity to be a NOP... */
3122   if (pick_mode == CLUTTER_PICK_NONE &&
3123       /* ignore top-levels, since they might be transparent */
3124       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3125       /* Use the override opacity if its been set */
3126       ((priv->opacity_override >= 0) ?
3127        priv->opacity_override : priv->opacity) == 0)
3128     return;
3129
3130   /* if we aren't paintable (not in a toplevel with all
3131    * parents paintable) then do nothing.
3132    */
3133   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3134     return;
3135
3136   /* mark that we are in the paint process */
3137   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3138
3139   cogl_push_matrix();
3140
3141   if (priv->enable_model_view_transform)
3142     {
3143       CoglMatrix matrix;
3144
3145       /* XXX: It could be better to cache the modelview with the actor
3146        * instead of progressively building up the transformations on
3147        * the matrix stack every time we paint. */
3148       cogl_get_modelview_matrix (&matrix);
3149       _clutter_actor_apply_modelview_transform (self, &matrix);
3150
3151 #ifdef CLUTTER_ENABLE_DEBUG
3152       /* Catch when out-of-band transforms have been made by actors not as part
3153        * of an apply_transform vfunc... */
3154       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3155         {
3156           CoglMatrix expected_matrix;
3157
3158           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3159                                                              &expected_matrix);
3160
3161           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3162             {
3163               GString *buf = g_string_sized_new (1024);
3164               ClutterActor *parent;
3165
3166               parent = self;
3167               while (parent != NULL)
3168                 {
3169                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3170
3171                   if (parent->priv->parent != NULL)
3172                     g_string_append (buf, "->");
3173
3174                   parent = parent->priv->parent;
3175                 }
3176
3177               g_warning ("Unexpected transform found when painting actor "
3178                          "\"%s\". This will be caused by one of the actor's "
3179                          "ancestors (%s) using the Cogl API directly to transform "
3180                          "children instead of using ::apply_transform().",
3181                          _clutter_actor_get_debug_name (self),
3182                          buf->str);
3183
3184               g_string_free (buf, TRUE);
3185             }
3186         }
3187 #endif /* CLUTTER_ENABLE_DEBUG */
3188
3189       cogl_set_modelview_matrix (&matrix);
3190     }
3191
3192   if (priv->has_clip)
3193     {
3194       cogl_clip_push_rectangle (priv->clip.x,
3195                                 priv->clip.y,
3196                                 priv->clip.x + priv->clip.width,
3197                                 priv->clip.y + priv->clip.height);
3198       clip_set = TRUE;
3199     }
3200   else if (priv->clip_to_allocation)
3201     {
3202       gfloat width, height;
3203
3204       width  = priv->allocation.x2 - priv->allocation.x1;
3205       height = priv->allocation.y2 - priv->allocation.y1;
3206
3207       cogl_clip_push_rectangle (0, 0, width, height);
3208       clip_set = TRUE;
3209     }
3210
3211   if (pick_mode == CLUTTER_PICK_NONE)
3212     {
3213       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3214
3215       /* We check whether we need to add the flatten effect before
3216          each paint so that we can avoid having a mechanism for
3217          applications to notify when the value of the
3218          has_overlaps virtual changes. */
3219       add_or_remove_flatten_effect (self);
3220     }
3221   else
3222     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3223
3224   /* We save the current paint volume so that the next time the
3225    * actor queues a redraw we can constrain the redraw to just
3226    * cover the union of the new bounding box and the old.
3227    *
3228    * We also fetch the current paint volume to perform culling so
3229    * we can avoid painting actors outside the current clip region.
3230    *
3231    * If we are painting inside a clone, we should neither update
3232    * the paint volume or use it to cull painting, since the paint
3233    * box represents the location of the source actor on the
3234    * screen.
3235    *
3236    * XXX: We are starting to do a lot of vertex transforms on
3237    * the CPU in a typical paint, so at some point we should
3238    * audit these and consider caching some things.
3239    *
3240    * NB: We don't perform culling while picking at this point because
3241    * clutter-stage.c doesn't setup the clipping planes appropriately.
3242    *
3243    * NB: We don't want to update the last-paint-volume during picking
3244    * because the last-paint-volume is used to determine the old screen
3245    * space location of an actor that has moved so we can know the
3246    * minimal region to redraw to clear an old view of the actor. If we
3247    * update this during picking then by the time we come around to
3248    * paint then the last-paint-volume would likely represent the new
3249    * actor position not the old.
3250    */
3251   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3252     {
3253       gboolean success;
3254       /* annoyingly gcc warns if uninitialized even though
3255        * the initialization is redundant :-( */
3256       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3257
3258       if (G_LIKELY ((clutter_paint_debug_flags &
3259                      (CLUTTER_DEBUG_DISABLE_CULLING |
3260                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3261                     (CLUTTER_DEBUG_DISABLE_CULLING |
3262                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3263         _clutter_actor_update_last_paint_volume (self);
3264
3265       success = cull_actor (self, &result);
3266
3267       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3268         _clutter_actor_paint_cull_result (self, success, result);
3269       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3270         goto done;
3271     }
3272
3273   if (priv->effects == NULL)
3274     {
3275       if (pick_mode == CLUTTER_PICK_NONE &&
3276           actor_has_shader_data (self))
3277         {
3278           _clutter_actor_shader_pre_paint (self, FALSE);
3279           shader_applied = TRUE;
3280         }
3281
3282       priv->next_effect_to_paint = NULL;
3283     }
3284   else
3285     priv->next_effect_to_paint =
3286       _clutter_meta_group_peek_metas (priv->effects);
3287
3288   clutter_actor_continue_paint (self);
3289
3290   if (shader_applied)
3291     _clutter_actor_shader_post_paint (self);
3292
3293   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3294                   pick_mode == CLUTTER_PICK_NONE))
3295     _clutter_actor_draw_paint_volume (self);
3296
3297 done:
3298   /* If we make it here then the actor has run through a complete
3299      paint run including all the effects so it's no longer dirty */
3300   if (pick_mode == CLUTTER_PICK_NONE)
3301     priv->is_dirty = FALSE;
3302
3303   if (clip_set)
3304     cogl_clip_pop();
3305
3306   cogl_pop_matrix();
3307
3308   /* paint sequence complete */
3309   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3310 }
3311
3312 /**
3313  * clutter_actor_continue_paint:
3314  * @self: A #ClutterActor
3315  *
3316  * Run the next stage of the paint sequence. This function should only
3317  * be called within the implementation of the ‘run’ virtual of a
3318  * #ClutterEffect. It will cause the run method of the next effect to
3319  * be applied, or it will paint the actual actor if the current effect
3320  * is the last effect in the chain.
3321  *
3322  * Since: 1.8
3323  */
3324 void
3325 clutter_actor_continue_paint (ClutterActor *self)
3326 {
3327   ClutterActorPrivate *priv;
3328
3329   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3330   /* This should only be called from with in the ‘run’ implementation
3331      of a ClutterEffect */
3332   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3333
3334   priv = self->priv;
3335
3336   /* Skip any effects that are disabled */
3337   while (priv->next_effect_to_paint &&
3338          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3339     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3340
3341   /* If this has come from the last effect then we'll just paint the
3342      actual actor */
3343   if (priv->next_effect_to_paint == NULL)
3344     {
3345       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3346         {
3347           g_signal_emit (self, actor_signals[PAINT], 0);
3348         }
3349       else
3350         {
3351           ClutterColor col = { 0, };
3352
3353           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3354
3355           /* Actor will then paint silhouette of itself in supplied
3356            * color.  See clutter_stage_get_actor_at_pos() for where
3357            * picking is enabled.
3358            */
3359           g_signal_emit (self, actor_signals[PICK], 0, &col);
3360         }
3361     }
3362   else
3363     {
3364       ClutterEffect *old_current_effect;
3365       ClutterEffectPaintFlags run_flags = 0;
3366
3367       /* Cache the current effect so that we can put it back before
3368          returning */
3369       old_current_effect = priv->current_effect;
3370
3371       priv->current_effect = priv->next_effect_to_paint->data;
3372       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3373
3374       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3375         {
3376           if (priv->is_dirty)
3377             {
3378               /* If there's an effect queued with this redraw then all
3379                  effects up to that one will be considered dirty. It
3380                  is expected the queued effect will paint the cached
3381                  image and not call clutter_actor_continue_paint again
3382                  (although it should work ok if it does) */
3383               if (priv->effect_to_redraw == NULL ||
3384                   priv->current_effect != priv->effect_to_redraw)
3385                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3386             }
3387
3388           _clutter_effect_paint (priv->current_effect, run_flags);
3389         }
3390       else
3391         {
3392           /* We can't determine when an actor has been modified since
3393              its last pick so lets just assume it has always been
3394              modified */
3395           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3396
3397           _clutter_effect_pick (priv->current_effect, run_flags);
3398         }
3399
3400       priv->current_effect = old_current_effect;
3401     }
3402 }
3403
3404 static ClutterActorTraverseVisitFlags
3405 invalidate_queue_redraw_entry (ClutterActor *self,
3406                                int           depth,
3407                                gpointer      user_data)
3408 {
3409   ClutterActorPrivate *priv = self->priv;
3410
3411   if (priv->queue_redraw_entry != NULL)
3412     {
3413       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3414       priv->queue_redraw_entry = NULL;
3415     }
3416
3417   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3418 }
3419
3420 static inline void
3421 remove_child (ClutterActor *self,
3422               ClutterActor *child)
3423 {
3424   ClutterActor *prev_sibling, *next_sibling;
3425
3426   prev_sibling = child->priv->prev_sibling;
3427   next_sibling = child->priv->next_sibling;
3428
3429   if (prev_sibling != NULL)
3430     prev_sibling->priv->next_sibling = next_sibling;
3431
3432   if (next_sibling != NULL)
3433     next_sibling->priv->prev_sibling = prev_sibling;
3434
3435   if (self->priv->first_child == child)
3436     self->priv->first_child = next_sibling;
3437
3438   if (self->priv->last_child == child)
3439     self->priv->last_child = prev_sibling;
3440
3441   child->priv->parent = NULL;
3442   child->priv->prev_sibling = NULL;
3443   child->priv->next_sibling = NULL;
3444 }
3445
3446 typedef enum {
3447   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3448   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3449   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3450   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3451   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3452   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3453
3454   /* default flags for public API */
3455   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3456                                     REMOVE_CHILD_EMIT_PARENT_SET |
3457                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3458                                     REMOVE_CHILD_CHECK_STATE |
3459                                     REMOVE_CHILD_FLUSH_QUEUE |
3460                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3461
3462   /* flags for legacy/deprecated API */
3463   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3464                                     REMOVE_CHILD_FLUSH_QUEUE |
3465                                     REMOVE_CHILD_EMIT_PARENT_SET |
3466                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3467 } ClutterActorRemoveChildFlags;
3468
3469 /*< private >
3470  * clutter_actor_remove_child_internal:
3471  * @self: a #ClutterActor
3472  * @child: the child of @self that has to be removed
3473  * @flags: control the removal operations
3474  *
3475  * Removes @child from the list of children of @self.
3476  */
3477 static void
3478 clutter_actor_remove_child_internal (ClutterActor                 *self,
3479                                      ClutterActor                 *child,
3480                                      ClutterActorRemoveChildFlags  flags)
3481 {
3482   ClutterActor *old_first, *old_last;
3483   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3484   gboolean flush_queue;
3485   gboolean notify_first_last;
3486   gboolean was_mapped;
3487
3488   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3489   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3490   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3491   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3492   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3493   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3494
3495   g_object_freeze_notify (G_OBJECT (self));
3496
3497   if (destroy_meta)
3498     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3499
3500   if (check_state)
3501     {
3502       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3503
3504       /* we need to unrealize *before* we set parent_actor to NULL,
3505        * because in an unrealize method actors are dissociating from the
3506        * stage, which means they need to be able to
3507        * clutter_actor_get_stage().
3508        *
3509        * yhis should unmap and unrealize, unless we're reparenting.
3510        */
3511       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3512     }
3513   else
3514     was_mapped = FALSE;
3515
3516   if (flush_queue)
3517     {
3518       /* We take this opportunity to invalidate any queue redraw entry
3519        * associated with the actor and descendants since we won't be able to
3520        * determine the appropriate stage after this.
3521        *
3522        * we do this after we updated the mapped state because actors might
3523        * end up queueing redraws inside their mapped/unmapped virtual
3524        * functions, and if we invalidate the redraw entry we could end up
3525        * with an inconsistent state and weird memory corruption. see
3526        * bugs:
3527        *
3528        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3529        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3530        */
3531       _clutter_actor_traverse (child,
3532                                0,
3533                                invalidate_queue_redraw_entry,
3534                                NULL,
3535                                NULL);
3536     }
3537
3538   old_first = self->priv->first_child;
3539   old_last = self->priv->last_child;
3540
3541   remove_child (self, child);
3542
3543   self->priv->n_children -= 1;
3544
3545   self->priv->age += 1;
3546
3547   /* clutter_actor_reparent() will emit ::parent-set for us */
3548   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3549     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3550
3551   /* if the child was mapped then we need to relayout ourselves to account
3552    * for the removed child
3553    */
3554   if (was_mapped)
3555     clutter_actor_queue_relayout (self);
3556
3557   /* we need to emit the signal before dropping the reference */
3558   if (emit_actor_removed)
3559     g_signal_emit_by_name (self, "actor-removed", child);
3560
3561   if (notify_first_last)
3562     {
3563       if (old_first != self->priv->first_child)
3564         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3565
3566       if (old_last != self->priv->last_child)
3567         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3568     }
3569
3570   g_object_thaw_notify (G_OBJECT (self));
3571
3572   /* remove the reference we acquired in clutter_actor_add_child() */
3573   g_object_unref (child);
3574 }
3575
3576 static const ClutterTransformInfo default_transform_info = {
3577   0.0, { 0, },          /* rotation-x */
3578   0.0, { 0, },          /* rotation-y */
3579   0.0, { 0, },          /* rotation-z */
3580
3581   1.0, 1.0, { 0, },     /* scale */
3582
3583   { 0, },               /* anchor */
3584 };
3585
3586 /*< private >
3587  * _clutter_actor_get_transform_info_or_defaults:
3588  * @self: a #ClutterActor
3589  *
3590  * Retrieves the ClutterTransformInfo structure associated to an actor.
3591  *
3592  * If the actor does not have a ClutterTransformInfo structure associated
3593  * to it, then the default structure will be returned.
3594  *
3595  * This function should only be used for getters.
3596  *
3597  * Return value: a const pointer to the ClutterTransformInfo structure
3598  */
3599 const ClutterTransformInfo *
3600 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3601 {
3602   ClutterTransformInfo *info;
3603
3604   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3605   if (info != NULL)
3606     return info;
3607
3608   return &default_transform_info;
3609 }
3610
3611 static void
3612 clutter_transform_info_free (gpointer data)
3613 {
3614   if (data != NULL)
3615     g_slice_free (ClutterTransformInfo, data);
3616 }
3617
3618 /*< private >
3619  * _clutter_actor_get_transform_info:
3620  * @self: a #ClutterActor
3621  *
3622  * Retrieves a pointer to the ClutterTransformInfo structure.
3623  *
3624  * If the actor does not have a ClutterTransformInfo associated to it, one
3625  * will be created and initialized to the default values.
3626  *
3627  * This function should be used for setters.
3628  *
3629  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3630  * instead.
3631  *
3632  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3633  *   structure
3634  */
3635 ClutterTransformInfo *
3636 _clutter_actor_get_transform_info (ClutterActor *self)
3637 {
3638   ClutterTransformInfo *info;
3639
3640   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3641   if (info == NULL)
3642     {
3643       info = g_slice_new (ClutterTransformInfo);
3644
3645       *info = default_transform_info;
3646
3647       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3648                                info,
3649                                clutter_transform_info_free);
3650     }
3651
3652   return info;
3653 }
3654
3655 /*< private >
3656  * clutter_actor_set_rotation_angle_internal:
3657  * @self: a #ClutterActor
3658  * @axis: the axis of the angle to change
3659  * @angle: the angle of rotation
3660  *
3661  * Sets the rotation angle on the given axis without affecting the
3662  * rotation center point.
3663  */
3664 static inline void
3665 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3666                                            ClutterRotateAxis  axis,
3667                                            gdouble            angle)
3668 {
3669   GObject *obj = G_OBJECT (self);
3670   ClutterTransformInfo *info;
3671
3672   info = _clutter_actor_get_transform_info (self);
3673
3674   g_object_freeze_notify (obj);
3675
3676   switch (axis)
3677     {
3678     case CLUTTER_X_AXIS:
3679       info->rx_angle = angle;
3680       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3681       break;
3682
3683     case CLUTTER_Y_AXIS:
3684       info->ry_angle = angle;
3685       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3686       break;
3687
3688     case CLUTTER_Z_AXIS:
3689       info->rz_angle = angle;
3690       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3691       break;
3692     }
3693
3694   self->priv->transform_valid = FALSE;
3695
3696   g_object_thaw_notify (obj);
3697
3698   clutter_actor_queue_redraw (self);
3699 }
3700
3701 /*< private >
3702  * clutter_actor_set_rotation_center_internal:
3703  * @self: a #ClutterActor
3704  * @axis: the axis of the center to change
3705  * @center: the coordinates of the rotation center
3706  *
3707  * Sets the rotation center on the given axis without affecting the
3708  * rotation angle.
3709  */
3710 static inline void
3711 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3712                                             ClutterRotateAxis    axis,
3713                                             const ClutterVertex *center)
3714 {
3715   GObject *obj = G_OBJECT (self);
3716   ClutterTransformInfo *info;
3717   ClutterVertex v = { 0, 0, 0 };
3718
3719   info = _clutter_actor_get_transform_info (self);
3720
3721   if (center != NULL)
3722     v = *center;
3723
3724   g_object_freeze_notify (obj);
3725
3726   switch (axis)
3727     {
3728     case CLUTTER_X_AXIS:
3729       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3730       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3731       break;
3732
3733     case CLUTTER_Y_AXIS:
3734       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3735       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3736       break;
3737
3738     case CLUTTER_Z_AXIS:
3739       /* if the previously set rotation center was fractional, then
3740        * setting explicit coordinates will have to notify the
3741        * :rotation-center-z-gravity property as well
3742        */
3743       if (info->rz_center.is_fractional)
3744         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3745
3746       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3747       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3748       break;
3749     }
3750
3751   self->priv->transform_valid = FALSE;
3752
3753   g_object_thaw_notify (obj);
3754
3755   clutter_actor_queue_redraw (self);
3756 }
3757
3758 static inline void
3759 clutter_actor_set_scale_factor (ClutterActor      *self,
3760                                 ClutterRotateAxis  axis,
3761                                 gdouble            factor)
3762 {
3763   GObject *obj = G_OBJECT (self);
3764   ClutterTransformInfo *info;
3765
3766   info = _clutter_actor_get_transform_info (self);
3767
3768   g_object_freeze_notify (obj);
3769
3770   switch (axis)
3771     {
3772     case CLUTTER_X_AXIS:
3773       info->scale_x = factor;
3774       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3775       break;
3776
3777     case CLUTTER_Y_AXIS:
3778       info->scale_y = factor;
3779       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3780       break;
3781
3782     default:
3783       g_assert_not_reached ();
3784     }
3785
3786   self->priv->transform_valid = FALSE;
3787
3788   clutter_actor_queue_redraw (self);
3789
3790   g_object_thaw_notify (obj);
3791 }
3792
3793 static inline void
3794 clutter_actor_set_scale_center (ClutterActor      *self,
3795                                 ClutterRotateAxis  axis,
3796                                 gfloat             coord)
3797 {
3798   GObject *obj = G_OBJECT (self);
3799   ClutterTransformInfo *info;
3800   gfloat center_x, center_y;
3801
3802   info = _clutter_actor_get_transform_info (self);
3803
3804   g_object_freeze_notify (obj);
3805
3806   /* get the current scale center coordinates */
3807   clutter_anchor_coord_get_units (self, &info->scale_center,
3808                                   &center_x,
3809                                   &center_y,
3810                                   NULL);
3811
3812   /* we need to notify this too, because setting explicit coordinates will
3813    * change the gravity as a side effect
3814    */
3815   if (info->scale_center.is_fractional)
3816     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3817
3818   switch (axis)
3819     {
3820     case CLUTTER_X_AXIS:
3821       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3822       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3823       break;
3824
3825     case CLUTTER_Y_AXIS:
3826       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3827       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3828       break;
3829
3830     default:
3831       g_assert_not_reached ();
3832     }
3833
3834   self->priv->transform_valid = FALSE;
3835
3836   clutter_actor_queue_redraw (self);
3837
3838   g_object_thaw_notify (obj);
3839 }
3840
3841 static inline void
3842 clutter_actor_set_anchor_coord (ClutterActor      *self,
3843                                 ClutterRotateAxis  axis,
3844                                 gfloat             coord)
3845 {
3846   GObject *obj = G_OBJECT (self);
3847   ClutterTransformInfo *info;
3848   gfloat anchor_x, anchor_y;
3849
3850   info = _clutter_actor_get_transform_info (self);
3851
3852   g_object_freeze_notify (obj);
3853
3854   clutter_anchor_coord_get_units (self, &info->anchor,
3855                                   &anchor_x,
3856                                   &anchor_y,
3857                                   NULL);
3858
3859   if (info->anchor.is_fractional)
3860     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3861
3862   switch (axis)
3863     {
3864     case CLUTTER_X_AXIS:
3865       clutter_anchor_coord_set_units (&info->anchor,
3866                                       coord,
3867                                       anchor_y,
3868                                       0.0);
3869       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3870       break;
3871
3872     case CLUTTER_Y_AXIS:
3873       clutter_anchor_coord_set_units (&info->anchor,
3874                                       anchor_x,
3875                                       coord,
3876                                       0.0);
3877       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3878       break;
3879
3880     default:
3881       g_assert_not_reached ();
3882     }
3883
3884   self->priv->transform_valid = FALSE;
3885
3886   clutter_actor_queue_redraw (self);
3887
3888   g_object_thaw_notify (obj);
3889 }
3890
3891 static void
3892 clutter_actor_set_property (GObject      *object,
3893                             guint         prop_id,
3894                             const GValue *value,
3895                             GParamSpec   *pspec)
3896 {
3897   ClutterActor *actor = CLUTTER_ACTOR (object);
3898   ClutterActorPrivate *priv = actor->priv;
3899
3900   switch (prop_id)
3901     {
3902     case PROP_X:
3903       clutter_actor_set_x (actor, g_value_get_float (value));
3904       break;
3905
3906     case PROP_Y:
3907       clutter_actor_set_y (actor, g_value_get_float (value));
3908       break;
3909
3910     case PROP_WIDTH:
3911       clutter_actor_set_width (actor, g_value_get_float (value));
3912       break;
3913
3914     case PROP_HEIGHT:
3915       clutter_actor_set_height (actor, g_value_get_float (value));
3916       break;
3917
3918     case PROP_FIXED_X:
3919       clutter_actor_set_x (actor, g_value_get_float (value));
3920       break;
3921
3922     case PROP_FIXED_Y:
3923       clutter_actor_set_y (actor, g_value_get_float (value));
3924       break;
3925
3926     case PROP_FIXED_POSITION_SET:
3927       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3928       break;
3929
3930     case PROP_MIN_WIDTH:
3931       clutter_actor_set_min_width (actor, g_value_get_float (value));
3932       break;
3933
3934     case PROP_MIN_HEIGHT:
3935       clutter_actor_set_min_height (actor, g_value_get_float (value));
3936       break;
3937
3938     case PROP_NATURAL_WIDTH:
3939       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3940       break;
3941
3942     case PROP_NATURAL_HEIGHT:
3943       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3944       break;
3945
3946     case PROP_MIN_WIDTH_SET:
3947       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3948       break;
3949
3950     case PROP_MIN_HEIGHT_SET:
3951       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3952       break;
3953
3954     case PROP_NATURAL_WIDTH_SET:
3955       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3956       break;
3957
3958     case PROP_NATURAL_HEIGHT_SET:
3959       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3960       break;
3961
3962     case PROP_REQUEST_MODE:
3963       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3964       break;
3965
3966     case PROP_DEPTH:
3967       clutter_actor_set_depth (actor, g_value_get_float (value));
3968       break;
3969
3970     case PROP_OPACITY:
3971       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3972       break;
3973
3974     case PROP_OFFSCREEN_REDIRECT:
3975       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3976       break;
3977
3978     case PROP_NAME:
3979       clutter_actor_set_name (actor, g_value_get_string (value));
3980       break;
3981
3982     case PROP_VISIBLE:
3983       if (g_value_get_boolean (value) == TRUE)
3984         clutter_actor_show (actor);
3985       else
3986         clutter_actor_hide (actor);
3987       break;
3988
3989     case PROP_SCALE_X:
3990       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3991                                       g_value_get_double (value));
3992       break;
3993
3994     case PROP_SCALE_Y:
3995       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3996                                       g_value_get_double (value));
3997       break;
3998
3999     case PROP_SCALE_CENTER_X:
4000       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4001                                       g_value_get_float (value));
4002       break;
4003
4004     case PROP_SCALE_CENTER_Y:
4005       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4006                                       g_value_get_float (value));
4007       break;
4008
4009     case PROP_SCALE_GRAVITY:
4010       {
4011         const ClutterTransformInfo *info;
4012         ClutterGravity gravity;
4013
4014         info = _clutter_actor_get_transform_info_or_defaults (actor);
4015         gravity = g_value_get_enum (value);
4016
4017         clutter_actor_set_scale_with_gravity (actor,
4018                                               info->scale_x,
4019                                               info->scale_y,
4020                                               gravity);
4021       }
4022       break;
4023
4024     case PROP_CLIP:
4025       {
4026         const ClutterGeometry *geom = g_value_get_boxed (value);
4027
4028         clutter_actor_set_clip (actor,
4029                                 geom->x, geom->y,
4030                                 geom->width, geom->height);
4031       }
4032       break;
4033
4034     case PROP_CLIP_TO_ALLOCATION:
4035       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4036       break;
4037
4038     case PROP_REACTIVE:
4039       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4040       break;
4041
4042     case PROP_ROTATION_ANGLE_X:
4043       clutter_actor_set_rotation_angle_internal (actor,
4044                                                  CLUTTER_X_AXIS,
4045                                                  g_value_get_double (value));
4046       break;
4047
4048     case PROP_ROTATION_ANGLE_Y:
4049       clutter_actor_set_rotation_angle_internal (actor,
4050                                                  CLUTTER_Y_AXIS,
4051                                                  g_value_get_double (value));
4052       break;
4053
4054     case PROP_ROTATION_ANGLE_Z:
4055       clutter_actor_set_rotation_angle_internal (actor,
4056                                                  CLUTTER_Z_AXIS,
4057                                                  g_value_get_double (value));
4058       break;
4059
4060     case PROP_ROTATION_CENTER_X:
4061       clutter_actor_set_rotation_center_internal (actor,
4062                                                   CLUTTER_X_AXIS,
4063                                                   g_value_get_boxed (value));
4064       break;
4065
4066     case PROP_ROTATION_CENTER_Y:
4067       clutter_actor_set_rotation_center_internal (actor,
4068                                                   CLUTTER_Y_AXIS,
4069                                                   g_value_get_boxed (value));
4070       break;
4071
4072     case PROP_ROTATION_CENTER_Z:
4073       clutter_actor_set_rotation_center_internal (actor,
4074                                                   CLUTTER_Z_AXIS,
4075                                                   g_value_get_boxed (value));
4076       break;
4077
4078     case PROP_ROTATION_CENTER_Z_GRAVITY:
4079       {
4080         const ClutterTransformInfo *info;
4081
4082         info = _clutter_actor_get_transform_info_or_defaults (actor);
4083         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4084                                                    g_value_get_enum (value));
4085       }
4086       break;
4087
4088     case PROP_ANCHOR_X:
4089       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4090                                       g_value_get_float (value));
4091       break;
4092
4093     case PROP_ANCHOR_Y:
4094       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4095                                       g_value_get_float (value));
4096       break;
4097
4098     case PROP_ANCHOR_GRAVITY:
4099       clutter_actor_set_anchor_point_from_gravity (actor,
4100                                                    g_value_get_enum (value));
4101       break;
4102
4103     case PROP_SHOW_ON_SET_PARENT:
4104       priv->show_on_set_parent = g_value_get_boolean (value);
4105       break;
4106
4107     case PROP_TEXT_DIRECTION:
4108       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4109       break;
4110
4111     case PROP_ACTIONS:
4112       clutter_actor_add_action (actor, g_value_get_object (value));
4113       break;
4114
4115     case PROP_CONSTRAINTS:
4116       clutter_actor_add_constraint (actor, g_value_get_object (value));
4117       break;
4118
4119     case PROP_EFFECT:
4120       clutter_actor_add_effect (actor, g_value_get_object (value));
4121       break;
4122
4123     case PROP_LAYOUT_MANAGER:
4124       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4125       break;
4126
4127     case PROP_X_ALIGN:
4128       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4129       break;
4130
4131     case PROP_Y_ALIGN:
4132       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4133       break;
4134
4135     case PROP_MARGIN_TOP:
4136       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4137       break;
4138
4139     case PROP_MARGIN_BOTTOM:
4140       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4141       break;
4142
4143     case PROP_MARGIN_LEFT:
4144       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4145       break;
4146
4147     case PROP_MARGIN_RIGHT:
4148       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4149       break;
4150
4151     case PROP_BACKGROUND_COLOR:
4152       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4153       break;
4154
4155     default:
4156       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4157       break;
4158     }
4159 }
4160
4161 static void
4162 clutter_actor_get_property (GObject    *object,
4163                             guint       prop_id,
4164                             GValue     *value,
4165                             GParamSpec *pspec)
4166 {
4167   ClutterActor *actor = CLUTTER_ACTOR (object);
4168   ClutterActorPrivate *priv = actor->priv;
4169
4170   switch (prop_id)
4171     {
4172     case PROP_X:
4173       g_value_set_float (value, clutter_actor_get_x (actor));
4174       break;
4175
4176     case PROP_Y:
4177       g_value_set_float (value, clutter_actor_get_y (actor));
4178       break;
4179
4180     case PROP_WIDTH:
4181       g_value_set_float (value, clutter_actor_get_width (actor));
4182       break;
4183
4184     case PROP_HEIGHT:
4185       g_value_set_float (value, clutter_actor_get_height (actor));
4186       break;
4187
4188     case PROP_FIXED_X:
4189       {
4190         const ClutterLayoutInfo *info;
4191
4192         info = _clutter_actor_get_layout_info_or_defaults (actor);
4193         g_value_set_float (value, info->fixed_x);
4194       }
4195       break;
4196
4197     case PROP_FIXED_Y:
4198       {
4199         const ClutterLayoutInfo *info;
4200
4201         info = _clutter_actor_get_layout_info_or_defaults (actor);
4202         g_value_set_float (value, info->fixed_y);
4203       }
4204       break;
4205
4206     case PROP_FIXED_POSITION_SET:
4207       g_value_set_boolean (value, priv->position_set);
4208       break;
4209
4210     case PROP_MIN_WIDTH:
4211       {
4212         const ClutterLayoutInfo *info;
4213
4214         info = _clutter_actor_get_layout_info_or_defaults (actor);
4215         g_value_set_float (value, info->min_width);
4216       }
4217       break;
4218
4219     case PROP_MIN_HEIGHT:
4220       {
4221         const ClutterLayoutInfo *info;
4222
4223         info = _clutter_actor_get_layout_info_or_defaults (actor);
4224         g_value_set_float (value, info->min_height);
4225       }
4226       break;
4227
4228     case PROP_NATURAL_WIDTH:
4229       {
4230         const ClutterLayoutInfo *info;
4231
4232         info = _clutter_actor_get_layout_info_or_defaults (actor);
4233         g_value_set_float (value, info->natural_width);
4234       }
4235       break;
4236
4237     case PROP_NATURAL_HEIGHT:
4238       {
4239         const ClutterLayoutInfo *info;
4240
4241         info = _clutter_actor_get_layout_info_or_defaults (actor);
4242         g_value_set_float (value, info->natural_height);
4243       }
4244       break;
4245
4246     case PROP_MIN_WIDTH_SET:
4247       g_value_set_boolean (value, priv->min_width_set);
4248       break;
4249
4250     case PROP_MIN_HEIGHT_SET:
4251       g_value_set_boolean (value, priv->min_height_set);
4252       break;
4253
4254     case PROP_NATURAL_WIDTH_SET:
4255       g_value_set_boolean (value, priv->natural_width_set);
4256       break;
4257
4258     case PROP_NATURAL_HEIGHT_SET:
4259       g_value_set_boolean (value, priv->natural_height_set);
4260       break;
4261
4262     case PROP_REQUEST_MODE:
4263       g_value_set_enum (value, priv->request_mode);
4264       break;
4265
4266     case PROP_ALLOCATION:
4267       g_value_set_boxed (value, &priv->allocation);
4268       break;
4269
4270     case PROP_DEPTH:
4271       g_value_set_float (value, clutter_actor_get_depth (actor));
4272       break;
4273
4274     case PROP_OPACITY:
4275       g_value_set_uint (value, priv->opacity);
4276       break;
4277
4278     case PROP_OFFSCREEN_REDIRECT:
4279       g_value_set_enum (value, priv->offscreen_redirect);
4280       break;
4281
4282     case PROP_NAME:
4283       g_value_set_string (value, priv->name);
4284       break;
4285
4286     case PROP_VISIBLE:
4287       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4288       break;
4289
4290     case PROP_MAPPED:
4291       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4292       break;
4293
4294     case PROP_REALIZED:
4295       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4296       break;
4297
4298     case PROP_HAS_CLIP:
4299       g_value_set_boolean (value, priv->has_clip);
4300       break;
4301
4302     case PROP_CLIP:
4303       {
4304         ClutterGeometry clip;
4305
4306         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4307         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4308         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4309         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4310
4311         g_value_set_boxed (value, &clip);
4312       }
4313       break;
4314
4315     case PROP_CLIP_TO_ALLOCATION:
4316       g_value_set_boolean (value, priv->clip_to_allocation);
4317       break;
4318
4319     case PROP_SCALE_X:
4320       {
4321         const ClutterTransformInfo *info;
4322
4323         info = _clutter_actor_get_transform_info_or_defaults (actor);
4324         g_value_set_double (value, info->scale_x);
4325       }
4326       break;
4327
4328     case PROP_SCALE_Y:
4329       {
4330         const ClutterTransformInfo *info;
4331
4332         info = _clutter_actor_get_transform_info_or_defaults (actor);
4333         g_value_set_double (value, info->scale_y);
4334       }
4335       break;
4336
4337     case PROP_SCALE_CENTER_X:
4338       {
4339         gfloat center;
4340
4341         clutter_actor_get_scale_center (actor, &center, NULL);
4342
4343         g_value_set_float (value, center);
4344       }
4345       break;
4346
4347     case PROP_SCALE_CENTER_Y:
4348       {
4349         gfloat center;
4350
4351         clutter_actor_get_scale_center (actor, NULL, &center);
4352
4353         g_value_set_float (value, center);
4354       }
4355       break;
4356
4357     case PROP_SCALE_GRAVITY:
4358       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4359       break;
4360
4361     case PROP_REACTIVE:
4362       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4363       break;
4364
4365     case PROP_ROTATION_ANGLE_X:
4366       {
4367         const ClutterTransformInfo *info;
4368
4369         info = _clutter_actor_get_transform_info_or_defaults (actor);
4370         g_value_set_double (value, info->rx_angle);
4371       }
4372       break;
4373
4374     case PROP_ROTATION_ANGLE_Y:
4375       {
4376         const ClutterTransformInfo *info;
4377
4378         info = _clutter_actor_get_transform_info_or_defaults (actor);
4379         g_value_set_double (value, info->ry_angle);
4380       }
4381       break;
4382
4383     case PROP_ROTATION_ANGLE_Z:
4384       {
4385         const ClutterTransformInfo *info;
4386
4387         info = _clutter_actor_get_transform_info_or_defaults (actor);
4388         g_value_set_double (value, info->rz_angle);
4389       }
4390       break;
4391
4392     case PROP_ROTATION_CENTER_X:
4393       {
4394         ClutterVertex center;
4395
4396         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4397                                     &center.x,
4398                                     &center.y,
4399                                     &center.z);
4400
4401         g_value_set_boxed (value, &center);
4402       }
4403       break;
4404
4405     case PROP_ROTATION_CENTER_Y:
4406       {
4407         ClutterVertex center;
4408
4409         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4410                                     &center.x,
4411                                     &center.y,
4412                                     &center.z);
4413
4414         g_value_set_boxed (value, &center);
4415       }
4416       break;
4417
4418     case PROP_ROTATION_CENTER_Z:
4419       {
4420         ClutterVertex center;
4421
4422         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4423                                     &center.x,
4424                                     &center.y,
4425                                     &center.z);
4426
4427         g_value_set_boxed (value, &center);
4428       }
4429       break;
4430
4431     case PROP_ROTATION_CENTER_Z_GRAVITY:
4432       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4433       break;
4434
4435     case PROP_ANCHOR_X:
4436       {
4437         const ClutterTransformInfo *info;
4438         gfloat anchor_x;
4439
4440         info = _clutter_actor_get_transform_info_or_defaults (actor);
4441         clutter_anchor_coord_get_units (actor, &info->anchor,
4442                                         &anchor_x,
4443                                         NULL,
4444                                         NULL);
4445         g_value_set_float (value, anchor_x);
4446       }
4447       break;
4448
4449     case PROP_ANCHOR_Y:
4450       {
4451         const ClutterTransformInfo *info;
4452         gfloat anchor_y;
4453
4454         info = _clutter_actor_get_transform_info_or_defaults (actor);
4455         clutter_anchor_coord_get_units (actor, &info->anchor,
4456                                         NULL,
4457                                         &anchor_y,
4458                                         NULL);
4459         g_value_set_float (value, anchor_y);
4460       }
4461       break;
4462
4463     case PROP_ANCHOR_GRAVITY:
4464       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4465       break;
4466
4467     case PROP_SHOW_ON_SET_PARENT:
4468       g_value_set_boolean (value, priv->show_on_set_parent);
4469       break;
4470
4471     case PROP_TEXT_DIRECTION:
4472       g_value_set_enum (value, priv->text_direction);
4473       break;
4474
4475     case PROP_HAS_POINTER:
4476       g_value_set_boolean (value, priv->has_pointer);
4477       break;
4478
4479     case PROP_LAYOUT_MANAGER:
4480       g_value_set_object (value, priv->layout_manager);
4481       break;
4482
4483     case PROP_X_ALIGN:
4484       {
4485         const ClutterLayoutInfo *info;
4486
4487         info = _clutter_actor_get_layout_info_or_defaults (actor);
4488         g_value_set_enum (value, info->x_align);
4489       }
4490       break;
4491
4492     case PROP_Y_ALIGN:
4493       {
4494         const ClutterLayoutInfo *info;
4495
4496         info = _clutter_actor_get_layout_info_or_defaults (actor);
4497         g_value_set_enum (value, info->y_align);
4498       }
4499       break;
4500
4501     case PROP_MARGIN_TOP:
4502       {
4503         const ClutterLayoutInfo *info;
4504
4505         info = _clutter_actor_get_layout_info_or_defaults (actor);
4506         g_value_set_float (value, info->margin.top);
4507       }
4508       break;
4509
4510     case PROP_MARGIN_BOTTOM:
4511       {
4512         const ClutterLayoutInfo *info;
4513
4514         info = _clutter_actor_get_layout_info_or_defaults (actor);
4515         g_value_set_float (value, info->margin.bottom);
4516       }
4517       break;
4518
4519     case PROP_MARGIN_LEFT:
4520       {
4521         const ClutterLayoutInfo *info;
4522
4523         info = _clutter_actor_get_layout_info_or_defaults (actor);
4524         g_value_set_float (value, info->margin.left);
4525       }
4526       break;
4527
4528     case PROP_MARGIN_RIGHT:
4529       {
4530         const ClutterLayoutInfo *info;
4531
4532         info = _clutter_actor_get_layout_info_or_defaults (actor);
4533         g_value_set_float (value, info->margin.right);
4534       }
4535       break;
4536
4537     case PROP_BACKGROUND_COLOR_SET:
4538       g_value_set_boolean (value, priv->bg_color_set);
4539       break;
4540
4541     case PROP_BACKGROUND_COLOR:
4542       g_value_set_boxed (value, &priv->bg_color);
4543       break;
4544
4545     case PROP_FIRST_CHILD:
4546       g_value_set_object (value, priv->first_child);
4547       break;
4548
4549     case PROP_LAST_CHILD:
4550       g_value_set_object (value, priv->last_child);
4551       break;
4552
4553     default:
4554       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4555       break;
4556     }
4557 }
4558
4559 static void
4560 clutter_actor_dispose (GObject *object)
4561 {
4562   ClutterActor *self = CLUTTER_ACTOR (object);
4563   ClutterActorPrivate *priv = self->priv;
4564
4565   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4566                 priv->id,
4567                 g_type_name (G_OBJECT_TYPE (self)),
4568                 object->ref_count);
4569
4570   g_signal_emit (self, actor_signals[DESTROY], 0);
4571
4572   /* avoid recursing when called from clutter_actor_destroy() */
4573   if (priv->parent != NULL)
4574     {
4575       ClutterActor *parent = priv->parent;
4576
4577       /* go through the Container implementation unless this
4578        * is an internal child and has been marked as such.
4579        *
4580        * removing the actor from its parent will reset the
4581        * realized and mapped states.
4582        */
4583       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4584         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4585       else
4586         clutter_actor_remove_child_internal (parent, self,
4587                                              REMOVE_CHILD_LEGACY_FLAGS);
4588     }
4589
4590   /* parent must be gone at this point */
4591   g_assert (priv->parent == NULL);
4592
4593   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4594     {
4595       /* can't be mapped or realized with no parent */
4596       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4597       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4598     }
4599
4600   g_clear_object (&priv->pango_context);
4601   g_clear_object (&priv->actions);
4602   g_clear_object (&priv->constraints);
4603   g_clear_object (&priv->effects);
4604   g_clear_object (&priv->flatten_effect);
4605
4606   if (priv->layout_manager != NULL)
4607     {
4608       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4609       g_object_unref (priv->layout_manager);
4610       priv->layout_manager = NULL;
4611     }
4612
4613   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4614 }
4615
4616 static void
4617 clutter_actor_finalize (GObject *object)
4618 {
4619   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4620
4621   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4622                 priv->name != NULL ? priv->name : "<none>",
4623                 priv->id,
4624                 g_type_name (G_OBJECT_TYPE (object)));
4625
4626   _clutter_context_release_id (priv->id);
4627
4628   g_free (priv->name);
4629
4630   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4631 }
4632
4633
4634 /**
4635  * clutter_actor_get_accessible:
4636  * @self: a #ClutterActor
4637  *
4638  * Returns the accessible object that describes the actor to an
4639  * assistive technology.
4640  *
4641  * If no class-specific #AtkObject implementation is available for the
4642  * actor instance in question, it will inherit an #AtkObject
4643  * implementation from the first ancestor class for which such an
4644  * implementation is defined.
4645  *
4646  * The documentation of the <ulink
4647  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4648  * library contains more information about accessible objects and
4649  * their uses.
4650  *
4651  * Returns: (transfer none): the #AtkObject associated with @actor
4652  */
4653 AtkObject *
4654 clutter_actor_get_accessible (ClutterActor *self)
4655 {
4656   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4657
4658   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4659 }
4660
4661 static AtkObject *
4662 clutter_actor_real_get_accessible (ClutterActor *actor)
4663 {
4664   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4665 }
4666
4667 static AtkObject *
4668 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4669 {
4670   AtkObject *accessible;
4671
4672   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4673   if (accessible != NULL)
4674     g_object_ref (accessible);
4675
4676   return accessible;
4677 }
4678
4679 static void
4680 atk_implementor_iface_init (AtkImplementorIface *iface)
4681 {
4682   iface->ref_accessible = _clutter_actor_ref_accessible;
4683 }
4684
4685 static gboolean
4686 clutter_actor_update_default_paint_volume (ClutterActor       *self,
4687                                            ClutterPaintVolume *volume)
4688 {
4689   ClutterActorPrivate *priv = self->priv;
4690   gboolean res = FALSE;
4691
4692   /* we start from the allocation */
4693   clutter_paint_volume_set_width (volume,
4694                                   priv->allocation.x2 - priv->allocation.x1);
4695   clutter_paint_volume_set_height (volume,
4696                                    priv->allocation.y2 - priv->allocation.y1);
4697
4698   /* if the actor has a clip set then we have a pretty definite
4699    * size for the paint volume: the actor cannot possibly paint
4700    * outside the clip region.
4701    */
4702   if (priv->clip_to_allocation)
4703     {
4704       /* the allocation has already been set, so we just flip the
4705        * return value
4706        */
4707       res = TRUE;
4708     }
4709   else
4710     {
4711       ClutterActor *child;
4712
4713       if (priv->has_clip &&
4714           priv->clip.width >= 0 &&
4715           priv->clip.height >= 0)
4716         {
4717           ClutterVertex origin;
4718
4719           origin.x = priv->clip.x;
4720           origin.y = priv->clip.y;
4721           origin.z = 0;
4722
4723           clutter_paint_volume_set_origin (volume, &origin);
4724           clutter_paint_volume_set_width (volume, priv->clip.width);
4725           clutter_paint_volume_set_height (volume, priv->clip.height);
4726
4727           res = TRUE;
4728         }
4729
4730       /* if we don't have children we just bail out here... */
4731       if (priv->n_children == 0)
4732         return res;
4733
4734       /* ...but if we have children then we ask for their paint volume in
4735        * our coordinates. if any of our children replies that it doesn't
4736        * have a paint volume, we bail out
4737        */
4738       for (child = priv->first_child;
4739            child != NULL;
4740            child = child->priv->next_sibling)
4741         {
4742           const ClutterPaintVolume *child_volume;
4743
4744           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4745           if (child_volume == NULL)
4746             {
4747               res = FALSE;
4748               break;
4749             }
4750
4751           clutter_paint_volume_union (volume, child_volume);
4752           res = TRUE;
4753         }
4754     }
4755
4756   return res;
4757
4758 }
4759
4760 static gboolean
4761 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4762                                      ClutterPaintVolume *volume)
4763 {
4764   ClutterActorClass *klass;
4765   gboolean res;
4766
4767   klass = CLUTTER_ACTOR_GET_CLASS (self);
4768
4769   /* XXX - this thoroughly sucks, but we don't want to penalize users
4770    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4771    * redraw. This should go away in 2.0.
4772    */
4773   if (klass->paint == clutter_actor_real_paint &&
4774       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4775     {
4776       res = TRUE;
4777     }
4778   else
4779     {
4780       /* this is the default return value: we cannot know if a class
4781        * is going to paint outside its allocation, so we take the
4782        * conservative approach.
4783        */
4784       res = FALSE;
4785     }
4786
4787   if (clutter_actor_update_default_paint_volume (self, volume))
4788     return res;
4789
4790   return FALSE;
4791 }
4792
4793 /**
4794  * clutter_actor_get_default_paint_volume:
4795  * @self: a #ClutterActor
4796  *
4797  * Retrieves the default paint volume for @self.
4798  *
4799  * This function provides the same #ClutterPaintVolume that would be
4800  * computed by the default implementation inside #ClutterActor of the
4801  * #ClutterActorClass.get_paint_volume() virtual function.
4802  *
4803  * This function should only be used by #ClutterActor subclasses that
4804  * cannot chain up to the parent implementation when computing their
4805  * paint volume.
4806  *
4807  * Return value: (transfer none): a pointer to the default
4808  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
4809  *   the actor could not compute a valid paint volume. The returned value
4810  *   is not guaranteed to be stable across multiple frames, so if you
4811  *   want to retain it, you will need to copy it using
4812  *   clutter_paint_volume_copy().
4813  *
4814  * Since: 1.10
4815  */
4816 const ClutterPaintVolume *
4817 clutter_actor_get_default_paint_volume (ClutterActor *self)
4818 {
4819   ClutterPaintVolume volume;
4820   ClutterPaintVolume *res;
4821
4822   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4823
4824   res = NULL;
4825   _clutter_paint_volume_init_static (&volume, self);
4826   if (clutter_actor_update_default_paint_volume (self, &volume))
4827     {
4828       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
4829
4830       if (stage != NULL)
4831         {
4832           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
4833           _clutter_paint_volume_copy_static (&volume, res);
4834         }
4835     }
4836
4837   clutter_paint_volume_free (&volume);
4838
4839   return res;
4840 }
4841
4842 static gboolean
4843 clutter_actor_real_has_overlaps (ClutterActor *self)
4844 {
4845   /* By default we'll assume that all actors need an offscreen redirect to get
4846    * the correct opacity. Actors such as ClutterTexture that would never need
4847    * an offscreen redirect can override this to return FALSE. */
4848   return TRUE;
4849 }
4850
4851 static void
4852 clutter_actor_real_destroy (ClutterActor *actor)
4853 {
4854   ClutterActorIter iter;
4855
4856   clutter_actor_iter_init (&iter, actor);
4857   while (clutter_actor_iter_next (&iter, NULL))
4858     clutter_actor_iter_destroy (&iter);
4859 }
4860
4861 static GObject *
4862 clutter_actor_constructor (GType gtype,
4863                            guint n_props,
4864                            GObjectConstructParam *props)
4865 {
4866   GObjectClass *gobject_class;
4867   ClutterActor *self;
4868   GObject *retval;
4869
4870   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4871   retval = gobject_class->constructor (gtype, n_props, props);
4872   self = CLUTTER_ACTOR (retval);
4873
4874   if (self->priv->layout_manager == NULL)
4875     {
4876       ClutterLayoutManager *default_layout;
4877
4878       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4879
4880       default_layout = clutter_fixed_layout_new ();
4881       clutter_actor_set_layout_manager (self, default_layout);
4882     }
4883
4884   return retval;
4885 }
4886
4887 static void
4888 clutter_actor_class_init (ClutterActorClass *klass)
4889 {
4890   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4891
4892   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4893   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4894   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4895
4896   object_class->constructor = clutter_actor_constructor;
4897   object_class->set_property = clutter_actor_set_property;
4898   object_class->get_property = clutter_actor_get_property;
4899   object_class->dispose = clutter_actor_dispose;
4900   object_class->finalize = clutter_actor_finalize;
4901
4902   klass->show = clutter_actor_real_show;
4903   klass->show_all = clutter_actor_show;
4904   klass->hide = clutter_actor_real_hide;
4905   klass->hide_all = clutter_actor_hide;
4906   klass->map = clutter_actor_real_map;
4907   klass->unmap = clutter_actor_real_unmap;
4908   klass->unrealize = clutter_actor_real_unrealize;
4909   klass->pick = clutter_actor_real_pick;
4910   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4911   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4912   klass->allocate = clutter_actor_real_allocate;
4913   klass->queue_redraw = clutter_actor_real_queue_redraw;
4914   klass->queue_relayout = clutter_actor_real_queue_relayout;
4915   klass->apply_transform = clutter_actor_real_apply_transform;
4916   klass->get_accessible = clutter_actor_real_get_accessible;
4917   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4918   klass->has_overlaps = clutter_actor_real_has_overlaps;
4919   klass->paint = clutter_actor_real_paint;
4920   klass->destroy = clutter_actor_real_destroy;
4921
4922   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4923
4924   /**
4925    * ClutterActor:x:
4926    *
4927    * X coordinate of the actor in pixels. If written, forces a fixed
4928    * position for the actor. If read, returns the fixed position if any,
4929    * otherwise the allocation if available, otherwise 0.
4930    */
4931   obj_props[PROP_X] =
4932     g_param_spec_float ("x",
4933                         P_("X coordinate"),
4934                         P_("X coordinate of the actor"),
4935                         -G_MAXFLOAT, G_MAXFLOAT,
4936                         0.0,
4937                         CLUTTER_PARAM_READWRITE);
4938
4939   /**
4940    * ClutterActor:y:
4941    *
4942    * Y coordinate of the actor in pixels. If written, forces a fixed
4943    * position for the actor.  If read, returns the fixed position if
4944    * any, otherwise the allocation if available, otherwise 0.
4945    */
4946   obj_props[PROP_Y] =
4947     g_param_spec_float ("y",
4948                         P_("Y coordinate"),
4949                         P_("Y coordinate of the actor"),
4950                         -G_MAXFLOAT, G_MAXFLOAT,
4951                         0.0,
4952                         CLUTTER_PARAM_READWRITE);
4953
4954   /**
4955    * ClutterActor:width:
4956    *
4957    * Width of the actor (in pixels). If written, forces the minimum and
4958    * natural size request of the actor to the given width. If read, returns
4959    * the allocated width if available, otherwise the width request.
4960    */
4961   obj_props[PROP_WIDTH] =
4962     g_param_spec_float ("width",
4963                         P_("Width"),
4964                         P_("Width of the actor"),
4965                         0.0, G_MAXFLOAT,
4966                         0.0,
4967                         CLUTTER_PARAM_READWRITE);
4968
4969   /**
4970    * ClutterActor:height:
4971    *
4972    * Height of the actor (in pixels).  If written, forces the minimum and
4973    * natural size request of the actor to the given height. If read, returns
4974    * the allocated height if available, otherwise the height request.
4975    */
4976   obj_props[PROP_HEIGHT] =
4977     g_param_spec_float ("height",
4978                         P_("Height"),
4979                         P_("Height of the actor"),
4980                         0.0, G_MAXFLOAT,
4981                         0.0,
4982                         CLUTTER_PARAM_READWRITE);
4983
4984   /**
4985    * ClutterActor:fixed-x:
4986    *
4987    * The fixed X position of the actor in pixels.
4988    *
4989    * Writing this property sets #ClutterActor:fixed-position-set
4990    * property as well, as a side effect
4991    *
4992    * Since: 0.8
4993    */
4994   obj_props[PROP_FIXED_X] =
4995     g_param_spec_float ("fixed-x",
4996                         P_("Fixed X"),
4997                         P_("Forced X position of the actor"),
4998                         -G_MAXFLOAT, G_MAXFLOAT,
4999                         0.0,
5000                         CLUTTER_PARAM_READWRITE);
5001
5002   /**
5003    * ClutterActor:fixed-y:
5004    *
5005    * The fixed Y position of the actor in pixels.
5006    *
5007    * Writing this property sets the #ClutterActor:fixed-position-set
5008    * property as well, as a side effect
5009    *
5010    * Since: 0.8
5011    */
5012   obj_props[PROP_FIXED_Y] =
5013     g_param_spec_float ("fixed-y",
5014                         P_("Fixed Y"),
5015                         P_("Forced Y position of the actor"),
5016                         -G_MAXFLOAT, G_MAXFLOAT,
5017                         0,
5018                         CLUTTER_PARAM_READWRITE);
5019
5020   /**
5021    * ClutterActor:fixed-position-set:
5022    *
5023    * This flag controls whether the #ClutterActor:fixed-x and
5024    * #ClutterActor:fixed-y properties are used
5025    *
5026    * Since: 0.8
5027    */
5028   obj_props[PROP_FIXED_POSITION_SET] =
5029     g_param_spec_boolean ("fixed-position-set",
5030                           P_("Fixed position set"),
5031                           P_("Whether to use fixed positioning for the actor"),
5032                           FALSE,
5033                           CLUTTER_PARAM_READWRITE);
5034
5035   /**
5036    * ClutterActor:min-width:
5037    *
5038    * A forced minimum width request for the actor, in pixels
5039    *
5040    * Writing this property sets the #ClutterActor:min-width-set property
5041    * as well, as a side effect.
5042    *
5043    *This property overrides the usual width request of the actor.
5044    *
5045    * Since: 0.8
5046    */
5047   obj_props[PROP_MIN_WIDTH] =
5048     g_param_spec_float ("min-width",
5049                         P_("Min Width"),
5050                         P_("Forced minimum width request for the actor"),
5051                         0.0, G_MAXFLOAT,
5052                         0.0,
5053                         CLUTTER_PARAM_READWRITE);
5054
5055   /**
5056    * ClutterActor:min-height:
5057    *
5058    * A forced minimum height request for the actor, in pixels
5059    *
5060    * Writing this property sets the #ClutterActor:min-height-set property
5061    * as well, as a side effect. This property overrides the usual height
5062    * request of the actor.
5063    *
5064    * Since: 0.8
5065    */
5066   obj_props[PROP_MIN_HEIGHT] =
5067     g_param_spec_float ("min-height",
5068                         P_("Min Height"),
5069                         P_("Forced minimum height request for the actor"),
5070                         0.0, G_MAXFLOAT,
5071                         0.0,
5072                         CLUTTER_PARAM_READWRITE);
5073
5074   /**
5075    * ClutterActor:natural-width:
5076    *
5077    * A forced natural width request for the actor, in pixels
5078    *
5079    * Writing this property sets the #ClutterActor:natural-width-set
5080    * property as well, as a side effect. This property overrides the
5081    * usual width request of the actor
5082    *
5083    * Since: 0.8
5084    */
5085   obj_props[PROP_NATURAL_WIDTH] =
5086     g_param_spec_float ("natural-width",
5087                         P_("Natural Width"),
5088                         P_("Forced natural width request for the actor"),
5089                         0.0, G_MAXFLOAT,
5090                         0.0,
5091                         CLUTTER_PARAM_READWRITE);
5092
5093   /**
5094    * ClutterActor:natural-height:
5095    *
5096    * A forced natural height request for the actor, in pixels
5097    *
5098    * Writing this property sets the #ClutterActor:natural-height-set
5099    * property as well, as a side effect. This property overrides the
5100    * usual height request of the actor
5101    *
5102    * Since: 0.8
5103    */
5104   obj_props[PROP_NATURAL_HEIGHT] =
5105     g_param_spec_float ("natural-height",
5106                         P_("Natural Height"),
5107                         P_("Forced natural height request for the actor"),
5108                         0.0, G_MAXFLOAT,
5109                         0.0,
5110                         CLUTTER_PARAM_READWRITE);
5111
5112   /**
5113    * ClutterActor:min-width-set:
5114    *
5115    * This flag controls whether the #ClutterActor:min-width property
5116    * is used
5117    *
5118    * Since: 0.8
5119    */
5120   obj_props[PROP_MIN_WIDTH_SET] =
5121     g_param_spec_boolean ("min-width-set",
5122                           P_("Minimum width set"),
5123                           P_("Whether to use the min-width property"),
5124                           FALSE,
5125                           CLUTTER_PARAM_READWRITE);
5126
5127   /**
5128    * ClutterActor:min-height-set:
5129    *
5130    * This flag controls whether the #ClutterActor:min-height property
5131    * is used
5132    *
5133    * Since: 0.8
5134    */
5135   obj_props[PROP_MIN_HEIGHT_SET] =
5136     g_param_spec_boolean ("min-height-set",
5137                           P_("Minimum height set"),
5138                           P_("Whether to use the min-height property"),
5139                           FALSE,
5140                           CLUTTER_PARAM_READWRITE);
5141
5142   /**
5143    * ClutterActor:natural-width-set:
5144    *
5145    * This flag controls whether the #ClutterActor:natural-width property
5146    * is used
5147    *
5148    * Since: 0.8
5149    */
5150   obj_props[PROP_NATURAL_WIDTH_SET] =
5151     g_param_spec_boolean ("natural-width-set",
5152                           P_("Natural width set"),
5153                           P_("Whether to use the natural-width property"),
5154                           FALSE,
5155                           CLUTTER_PARAM_READWRITE);
5156
5157   /**
5158    * ClutterActor:natural-height-set:
5159    *
5160    * This flag controls whether the #ClutterActor:natural-height property
5161    * is used
5162    *
5163    * Since: 0.8
5164    */
5165   obj_props[PROP_NATURAL_HEIGHT_SET] =
5166     g_param_spec_boolean ("natural-height-set",
5167                           P_("Natural height set"),
5168                           P_("Whether to use the natural-height property"),
5169                           FALSE,
5170                           CLUTTER_PARAM_READWRITE);
5171
5172   /**
5173    * ClutterActor:allocation:
5174    *
5175    * The allocation for the actor, in pixels
5176    *
5177    * This is property is read-only, but you might monitor it to know when an
5178    * actor moves or resizes
5179    *
5180    * Since: 0.8
5181    */
5182   obj_props[PROP_ALLOCATION] =
5183     g_param_spec_boxed ("allocation",
5184                         P_("Allocation"),
5185                         P_("The actor's allocation"),
5186                         CLUTTER_TYPE_ACTOR_BOX,
5187                         CLUTTER_PARAM_READABLE);
5188
5189   /**
5190    * ClutterActor:request-mode:
5191    *
5192    * Request mode for the #ClutterActor. The request mode determines the
5193    * type of geometry management used by the actor, either height for width
5194    * (the default) or width for height.
5195    *
5196    * For actors implementing height for width, the parent container should get
5197    * the preferred width first, and then the preferred height for that width.
5198    *
5199    * For actors implementing width for height, the parent container should get
5200    * the preferred height first, and then the preferred width for that height.
5201    *
5202    * For instance:
5203    *
5204    * |[
5205    *   ClutterRequestMode mode;
5206    *   gfloat natural_width, min_width;
5207    *   gfloat natural_height, min_height;
5208    *
5209    *   mode = clutter_actor_get_request_mode (child);
5210    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5211    *     {
5212    *       clutter_actor_get_preferred_width (child, -1,
5213    *                                          &amp;min_width,
5214    *                                          &amp;natural_width);
5215    *       clutter_actor_get_preferred_height (child, natural_width,
5216    *                                           &amp;min_height,
5217    *                                           &amp;natural_height);
5218    *     }
5219    *   else
5220    *     {
5221    *       clutter_actor_get_preferred_height (child, -1,
5222    *                                           &amp;min_height,
5223    *                                           &amp;natural_height);
5224    *       clutter_actor_get_preferred_width (child, natural_height,
5225    *                                          &amp;min_width,
5226    *                                          &amp;natural_width);
5227    *     }
5228    * ]|
5229    *
5230    * will retrieve the minimum and natural width and height depending on the
5231    * preferred request mode of the #ClutterActor "child".
5232    *
5233    * The clutter_actor_get_preferred_size() function will implement this
5234    * check for you.
5235    *
5236    * Since: 0.8
5237    */
5238   obj_props[PROP_REQUEST_MODE] =
5239     g_param_spec_enum ("request-mode",
5240                        P_("Request Mode"),
5241                        P_("The actor's request mode"),
5242                        CLUTTER_TYPE_REQUEST_MODE,
5243                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5244                        CLUTTER_PARAM_READWRITE);
5245
5246   /**
5247    * ClutterActor:depth:
5248    *
5249    * The position of the actor on the Z axis
5250    *
5251    * Since: 0.6
5252    */
5253   obj_props[PROP_DEPTH] =
5254     g_param_spec_float ("depth",
5255                         P_("Depth"),
5256                         P_("Position on the Z axis"),
5257                         -G_MAXFLOAT, G_MAXFLOAT,
5258                         0.0,
5259                         CLUTTER_PARAM_READWRITE);
5260
5261   /**
5262    * ClutterActor:opacity:
5263    *
5264    * Opacity of an actor, between 0 (fully transparent) and
5265    * 255 (fully opaque)
5266    */
5267   obj_props[PROP_OPACITY] =
5268     g_param_spec_uint ("opacity",
5269                        P_("Opacity"),
5270                        P_("Opacity of an actor"),
5271                        0, 255,
5272                        255,
5273                        CLUTTER_PARAM_READWRITE);
5274
5275   /**
5276    * ClutterActor:offscreen-redirect:
5277    *
5278    * Determines the conditions in which the actor will be redirected
5279    * to an offscreen framebuffer while being painted. For example this
5280    * can be used to cache an actor in a framebuffer or for improved
5281    * handling of transparent actors. See
5282    * clutter_actor_set_offscreen_redirect() for details.
5283    *
5284    * Since: 1.8
5285    */
5286   obj_props[PROP_OFFSCREEN_REDIRECT] =
5287     g_param_spec_flags ("offscreen-redirect",
5288                         P_("Offscreen redirect"),
5289                         P_("Flags controlling when to flatten the actor into a single image"),
5290                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5291                         0,
5292                         CLUTTER_PARAM_READWRITE);
5293
5294   /**
5295    * ClutterActor:visible:
5296    *
5297    * Whether the actor is set to be visible or not
5298    *
5299    * See also #ClutterActor:mapped
5300    */
5301   obj_props[PROP_VISIBLE] =
5302     g_param_spec_boolean ("visible",
5303                           P_("Visible"),
5304                           P_("Whether the actor is visible or not"),
5305                           FALSE,
5306                           CLUTTER_PARAM_READWRITE);
5307
5308   /**
5309    * ClutterActor:mapped:
5310    *
5311    * Whether the actor is mapped (will be painted when the stage
5312    * to which it belongs is mapped)
5313    *
5314    * Since: 1.0
5315    */
5316   obj_props[PROP_MAPPED] =
5317     g_param_spec_boolean ("mapped",
5318                           P_("Mapped"),
5319                           P_("Whether the actor will be painted"),
5320                           FALSE,
5321                           CLUTTER_PARAM_READABLE);
5322
5323   /**
5324    * ClutterActor:realized:
5325    *
5326    * Whether the actor has been realized
5327    *
5328    * Since: 1.0
5329    */
5330   obj_props[PROP_REALIZED] =
5331     g_param_spec_boolean ("realized",
5332                           P_("Realized"),
5333                           P_("Whether the actor has been realized"),
5334                           FALSE,
5335                           CLUTTER_PARAM_READABLE);
5336
5337   /**
5338    * ClutterActor:reactive:
5339    *
5340    * Whether the actor is reactive to events or not
5341    *
5342    * Only reactive actors will emit event-related signals
5343    *
5344    * Since: 0.6
5345    */
5346   obj_props[PROP_REACTIVE] =
5347     g_param_spec_boolean ("reactive",
5348                           P_("Reactive"),
5349                           P_("Whether the actor is reactive to events"),
5350                           FALSE,
5351                           CLUTTER_PARAM_READWRITE);
5352
5353   /**
5354    * ClutterActor:has-clip:
5355    *
5356    * Whether the actor has the #ClutterActor:clip property set or not
5357    */
5358   obj_props[PROP_HAS_CLIP] =
5359     g_param_spec_boolean ("has-clip",
5360                           P_("Has Clip"),
5361                           P_("Whether the actor has a clip set"),
5362                           FALSE,
5363                           CLUTTER_PARAM_READABLE);
5364
5365   /**
5366    * ClutterActor:clip:
5367    *
5368    * The clip region for the actor, in actor-relative coordinates
5369    *
5370    * Every part of the actor outside the clip region will not be
5371    * painted
5372    */
5373   obj_props[PROP_CLIP] =
5374     g_param_spec_boxed ("clip",
5375                         P_("Clip"),
5376                         P_("The clip region for the actor"),
5377                         CLUTTER_TYPE_GEOMETRY,
5378                         CLUTTER_PARAM_READWRITE);
5379
5380   /**
5381    * ClutterActor:name:
5382    *
5383    * The name of the actor
5384    *
5385    * Since: 0.2
5386    */
5387   obj_props[PROP_NAME] =
5388     g_param_spec_string ("name",
5389                          P_("Name"),
5390                          P_("Name of the actor"),
5391                          NULL,
5392                          CLUTTER_PARAM_READWRITE);
5393
5394   /**
5395    * ClutterActor:scale-x:
5396    *
5397    * The horizontal scale of the actor
5398    *
5399    * Since: 0.6
5400    */
5401   obj_props[PROP_SCALE_X] =
5402     g_param_spec_double ("scale-x",
5403                          P_("Scale X"),
5404                          P_("Scale factor on the X axis"),
5405                          0.0, G_MAXDOUBLE,
5406                          1.0,
5407                          CLUTTER_PARAM_READWRITE);
5408
5409   /**
5410    * ClutterActor:scale-y:
5411    *
5412    * The vertical scale of the actor
5413    *
5414    * Since: 0.6
5415    */
5416   obj_props[PROP_SCALE_Y] =
5417     g_param_spec_double ("scale-y",
5418                          P_("Scale Y"),
5419                          P_("Scale factor on the Y axis"),
5420                          0.0, G_MAXDOUBLE,
5421                          1.0,
5422                          CLUTTER_PARAM_READWRITE);
5423
5424   /**
5425    * ClutterActor:scale-center-x:
5426    *
5427    * The horizontal center point for scaling
5428    *
5429    * Since: 1.0
5430    */
5431   obj_props[PROP_SCALE_CENTER_X] =
5432     g_param_spec_float ("scale-center-x",
5433                         P_("Scale Center X"),
5434                         P_("Horizontal scale center"),
5435                         -G_MAXFLOAT, G_MAXFLOAT,
5436                         0.0,
5437                         CLUTTER_PARAM_READWRITE);
5438
5439   /**
5440    * ClutterActor:scale-center-y:
5441    *
5442    * The vertical center point for scaling
5443    *
5444    * Since: 1.0
5445    */
5446   obj_props[PROP_SCALE_CENTER_Y] =
5447     g_param_spec_float ("scale-center-y",
5448                         P_("Scale Center Y"),
5449                         P_("Vertical scale center"),
5450                         -G_MAXFLOAT, G_MAXFLOAT,
5451                         0.0,
5452                         CLUTTER_PARAM_READWRITE);
5453
5454   /**
5455    * ClutterActor:scale-gravity:
5456    *
5457    * The center point for scaling expressed as a #ClutterGravity
5458    *
5459    * Since: 1.0
5460    */
5461   obj_props[PROP_SCALE_GRAVITY] =
5462     g_param_spec_enum ("scale-gravity",
5463                        P_("Scale Gravity"),
5464                        P_("The center of scaling"),
5465                        CLUTTER_TYPE_GRAVITY,
5466                        CLUTTER_GRAVITY_NONE,
5467                        CLUTTER_PARAM_READWRITE);
5468
5469   /**
5470    * ClutterActor:rotation-angle-x:
5471    *
5472    * The rotation angle on the X axis
5473    *
5474    * Since: 0.6
5475    */
5476   obj_props[PROP_ROTATION_ANGLE_X] =
5477     g_param_spec_double ("rotation-angle-x",
5478                          P_("Rotation Angle X"),
5479                          P_("The rotation angle on the X axis"),
5480                          -G_MAXDOUBLE, G_MAXDOUBLE,
5481                          0.0,
5482                          CLUTTER_PARAM_READWRITE);
5483
5484   /**
5485    * ClutterActor:rotation-angle-y:
5486    *
5487    * The rotation angle on the Y axis
5488    *
5489    * Since: 0.6
5490    */
5491   obj_props[PROP_ROTATION_ANGLE_Y] =
5492     g_param_spec_double ("rotation-angle-y",
5493                          P_("Rotation Angle Y"),
5494                          P_("The rotation angle on the Y axis"),
5495                          -G_MAXDOUBLE, G_MAXDOUBLE,
5496                          0.0,
5497                          CLUTTER_PARAM_READWRITE);
5498
5499   /**
5500    * ClutterActor:rotation-angle-z:
5501    *
5502    * The rotation angle on the Z axis
5503    *
5504    * Since: 0.6
5505    */
5506   obj_props[PROP_ROTATION_ANGLE_Z] =
5507     g_param_spec_double ("rotation-angle-z",
5508                          P_("Rotation Angle Z"),
5509                          P_("The rotation angle on the Z axis"),
5510                          -G_MAXDOUBLE, G_MAXDOUBLE,
5511                          0.0,
5512                          CLUTTER_PARAM_READWRITE);
5513
5514   /**
5515    * ClutterActor:rotation-center-x:
5516    *
5517    * The rotation center on the X axis.
5518    *
5519    * Since: 0.6
5520    */
5521   obj_props[PROP_ROTATION_CENTER_X] =
5522     g_param_spec_boxed ("rotation-center-x",
5523                         P_("Rotation Center X"),
5524                         P_("The rotation center on the X axis"),
5525                         CLUTTER_TYPE_VERTEX,
5526                         CLUTTER_PARAM_READWRITE);
5527
5528   /**
5529    * ClutterActor:rotation-center-y:
5530    *
5531    * The rotation center on the Y axis.
5532    *
5533    * Since: 0.6
5534    */
5535   obj_props[PROP_ROTATION_CENTER_Y] =
5536     g_param_spec_boxed ("rotation-center-y",
5537                         P_("Rotation Center Y"),
5538                         P_("The rotation center on the Y axis"),
5539                         CLUTTER_TYPE_VERTEX,
5540                         CLUTTER_PARAM_READWRITE);
5541
5542   /**
5543    * ClutterActor:rotation-center-z:
5544    *
5545    * The rotation center on the Z axis.
5546    *
5547    * Since: 0.6
5548    */
5549   obj_props[PROP_ROTATION_CENTER_Z] =
5550     g_param_spec_boxed ("rotation-center-z",
5551                         P_("Rotation Center Z"),
5552                         P_("The rotation center on the Z axis"),
5553                         CLUTTER_TYPE_VERTEX,
5554                         CLUTTER_PARAM_READWRITE);
5555
5556   /**
5557    * ClutterActor:rotation-center-z-gravity:
5558    *
5559    * The rotation center on the Z axis expressed as a #ClutterGravity.
5560    *
5561    * Since: 1.0
5562    */
5563   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5564     g_param_spec_enum ("rotation-center-z-gravity",
5565                        P_("Rotation Center Z Gravity"),
5566                        P_("Center point for rotation around the Z axis"),
5567                        CLUTTER_TYPE_GRAVITY,
5568                        CLUTTER_GRAVITY_NONE,
5569                        CLUTTER_PARAM_READWRITE);
5570
5571   /**
5572    * ClutterActor:anchor-x:
5573    *
5574    * The X coordinate of an actor's anchor point, relative to
5575    * the actor coordinate space, in pixels
5576    *
5577    * Since: 0.8
5578    */
5579   obj_props[PROP_ANCHOR_X] =
5580     g_param_spec_float ("anchor-x",
5581                         P_("Anchor X"),
5582                         P_("X coordinate of the anchor point"),
5583                         -G_MAXFLOAT, G_MAXFLOAT,
5584                         0,
5585                         CLUTTER_PARAM_READWRITE);
5586
5587   /**
5588    * ClutterActor:anchor-y:
5589    *
5590    * The Y coordinate of an actor's anchor point, relative to
5591    * the actor coordinate space, in pixels
5592    *
5593    * Since: 0.8
5594    */
5595   obj_props[PROP_ANCHOR_Y] =
5596     g_param_spec_float ("anchor-y",
5597                         P_("Anchor Y"),
5598                         P_("Y coordinate of the anchor point"),
5599                         -G_MAXFLOAT, G_MAXFLOAT,
5600                         0,
5601                         CLUTTER_PARAM_READWRITE);
5602
5603   /**
5604    * ClutterActor:anchor-gravity:
5605    *
5606    * The anchor point expressed as a #ClutterGravity
5607    *
5608    * Since: 1.0
5609    */
5610   obj_props[PROP_ANCHOR_GRAVITY] =
5611     g_param_spec_enum ("anchor-gravity",
5612                        P_("Anchor Gravity"),
5613                        P_("The anchor point as a ClutterGravity"),
5614                        CLUTTER_TYPE_GRAVITY,
5615                        CLUTTER_GRAVITY_NONE,
5616                        CLUTTER_PARAM_READWRITE);
5617
5618   /**
5619    * ClutterActor:show-on-set-parent:
5620    *
5621    * If %TRUE, the actor is automatically shown when parented.
5622    *
5623    * Calling clutter_actor_hide() on an actor which has not been
5624    * parented will set this property to %FALSE as a side effect.
5625    *
5626    * Since: 0.8
5627    */
5628   obj_props[PROP_SHOW_ON_SET_PARENT] =
5629     g_param_spec_boolean ("show-on-set-parent",
5630                           P_("Show on set parent"),
5631                           P_("Whether the actor is shown when parented"),
5632                           TRUE,
5633                           CLUTTER_PARAM_READWRITE);
5634
5635   /**
5636    * ClutterActor:clip-to-allocation:
5637    *
5638    * Whether the clip region should track the allocated area
5639    * of the actor.
5640    *
5641    * This property is ignored if a clip area has been explicitly
5642    * set using clutter_actor_set_clip().
5643    *
5644    * Since: 1.0
5645    */
5646   obj_props[PROP_CLIP_TO_ALLOCATION] =
5647     g_param_spec_boolean ("clip-to-allocation",
5648                           P_("Clip to Allocation"),
5649                           P_("Sets the clip region to track the actor's allocation"),
5650                           FALSE,
5651                           CLUTTER_PARAM_READWRITE);
5652
5653   /**
5654    * ClutterActor:text-direction:
5655    *
5656    * The direction of the text inside a #ClutterActor.
5657    *
5658    * Since: 1.0
5659    */
5660   obj_props[PROP_TEXT_DIRECTION] =
5661     g_param_spec_enum ("text-direction",
5662                        P_("Text Direction"),
5663                        P_("Direction of the text"),
5664                        CLUTTER_TYPE_TEXT_DIRECTION,
5665                        CLUTTER_TEXT_DIRECTION_LTR,
5666                        CLUTTER_PARAM_READWRITE);
5667
5668   /**
5669    * ClutterActor:has-pointer:
5670    *
5671    * Whether the actor contains the pointer of a #ClutterInputDevice
5672    * or not.
5673    *
5674    * Since: 1.2
5675    */
5676   obj_props[PROP_HAS_POINTER] =
5677     g_param_spec_boolean ("has-pointer",
5678                           P_("Has Pointer"),
5679                           P_("Whether the actor contains the pointer of an input device"),
5680                           FALSE,
5681                           CLUTTER_PARAM_READABLE);
5682
5683   /**
5684    * ClutterActor:actions:
5685    *
5686    * Adds a #ClutterAction to the actor
5687    *
5688    * Since: 1.4
5689    */
5690   obj_props[PROP_ACTIONS] =
5691     g_param_spec_object ("actions",
5692                          P_("Actions"),
5693                          P_("Adds an action to the actor"),
5694                          CLUTTER_TYPE_ACTION,
5695                          CLUTTER_PARAM_WRITABLE);
5696
5697   /**
5698    * ClutterActor:constraints:
5699    *
5700    * Adds a #ClutterConstraint to the actor
5701    *
5702    * Since: 1.4
5703    */
5704   obj_props[PROP_CONSTRAINTS] =
5705     g_param_spec_object ("constraints",
5706                          P_("Constraints"),
5707                          P_("Adds a constraint to the actor"),
5708                          CLUTTER_TYPE_CONSTRAINT,
5709                          CLUTTER_PARAM_WRITABLE);
5710
5711   /**
5712    * ClutterActor:effect:
5713    *
5714    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5715    *
5716    * Since: 1.4
5717    */
5718   obj_props[PROP_EFFECT] =
5719     g_param_spec_object ("effect",
5720                          P_("Effect"),
5721                          P_("Add an effect to be applied on the actor"),
5722                          CLUTTER_TYPE_EFFECT,
5723                          CLUTTER_PARAM_WRITABLE);
5724
5725   /**
5726    * ClutterActor:layout-manager:
5727    *
5728    * A delegate object for controlling the layout of the children of
5729    * an actor.
5730    *
5731    * Since: 1.10
5732    */
5733   obj_props[PROP_LAYOUT_MANAGER] =
5734     g_param_spec_object ("layout-manager",
5735                          P_("Layout Manager"),
5736                          P_("The object controlling the layout of an actor's children"),
5737                          CLUTTER_TYPE_LAYOUT_MANAGER,
5738                          CLUTTER_PARAM_READWRITE);
5739
5740
5741   /**
5742    * ClutterActor:x-align:
5743    *
5744    * The alignment of an actor on the X axis, if the actor has been given
5745    * extra space for its allocation.
5746    *
5747    * Since: 1.10
5748    */
5749   obj_props[PROP_X_ALIGN] =
5750     g_param_spec_enum ("x-align",
5751                        P_("X Alignment"),
5752                        P_("The alignment of the actor on the X axis within its allocation"),
5753                        CLUTTER_TYPE_ACTOR_ALIGN,
5754                        CLUTTER_ACTOR_ALIGN_FILL,
5755                        CLUTTER_PARAM_READWRITE);
5756
5757   /**
5758    * ClutterActor:y-align:
5759    *
5760    * The alignment of an actor on the Y axis, if the actor has been given
5761    * extra space for its allocation.
5762    *
5763    * Since: 1.10
5764    */
5765   obj_props[PROP_Y_ALIGN] =
5766     g_param_spec_enum ("y-align",
5767                        P_("Y Alignment"),
5768                        P_("The alignment of the actor on the Y axis within its allocation"),
5769                        CLUTTER_TYPE_ACTOR_ALIGN,
5770                        CLUTTER_ACTOR_ALIGN_FILL,
5771                        CLUTTER_PARAM_READWRITE);
5772
5773   /**
5774    * ClutterActor:margin-top:
5775    *
5776    * The margin (in pixels) from the top of the actor.
5777    *
5778    * This property adds a margin to the actor's preferred size; the margin
5779    * will be automatically taken into account when allocating the actor.
5780    *
5781    * Since: 1.10
5782    */
5783   obj_props[PROP_MARGIN_TOP] =
5784     g_param_spec_float ("margin-top",
5785                         P_("Margin Top"),
5786                         P_("Extra space at the top"),
5787                         0.0, G_MAXFLOAT,
5788                         0.0,
5789                         CLUTTER_PARAM_READWRITE);
5790
5791   /**
5792    * ClutterActor:margin-bottom:
5793    *
5794    * The margin (in pixels) from the bottom of the actor.
5795    *
5796    * This property adds a margin to the actor's preferred size; the margin
5797    * will be automatically taken into account when allocating the actor.
5798    *
5799    * Since: 1.10
5800    */
5801   obj_props[PROP_MARGIN_BOTTOM] =
5802     g_param_spec_float ("margin-bottom",
5803                         P_("Margin Bottom"),
5804                         P_("Extra space at the bottom"),
5805                         0.0, G_MAXFLOAT,
5806                         0.0,
5807                         CLUTTER_PARAM_READWRITE);
5808
5809   /**
5810    * ClutterActor:margin-left:
5811    *
5812    * The margin (in pixels) from the left of the actor.
5813    *
5814    * This property adds a margin to the actor's preferred size; the margin
5815    * will be automatically taken into account when allocating the actor.
5816    *
5817    * Since: 1.10
5818    */
5819   obj_props[PROP_MARGIN_LEFT] =
5820     g_param_spec_float ("margin-left",
5821                         P_("Margin Left"),
5822                         P_("Extra space at the left"),
5823                         0.0, G_MAXFLOAT,
5824                         0.0,
5825                         CLUTTER_PARAM_READWRITE);
5826
5827   /**
5828    * ClutterActor:margin-right:
5829    *
5830    * The margin (in pixels) from the right of the actor.
5831    *
5832    * This property adds a margin to the actor's preferred size; the margin
5833    * will be automatically taken into account when allocating the actor.
5834    *
5835    * Since: 1.10
5836    */
5837   obj_props[PROP_MARGIN_RIGHT] =
5838     g_param_spec_float ("margin-right",
5839                         P_("Margin Right"),
5840                         P_("Extra space at the right"),
5841                         0.0, G_MAXFLOAT,
5842                         0.0,
5843                         CLUTTER_PARAM_READWRITE);
5844
5845   /**
5846    * ClutterActor:background-color-set:
5847    *
5848    * Whether the #ClutterActor:background-color property has been set.
5849    *
5850    * Since: 1.10
5851    */
5852   obj_props[PROP_BACKGROUND_COLOR_SET] =
5853     g_param_spec_boolean ("background-color-set",
5854                           P_("Background Color Set"),
5855                           P_("Whether the background color is set"),
5856                           FALSE,
5857                           CLUTTER_PARAM_READABLE);
5858
5859   /**
5860    * ClutterActor:background-color:
5861    *
5862    * Paints a solid fill of the actor's allocation using the specified
5863    * color.
5864    *
5865    * Since: 1.10
5866    */
5867   obj_props[PROP_BACKGROUND_COLOR] =
5868     clutter_param_spec_color ("background-color",
5869                               P_("Background color"),
5870                               P_("The actor's background color"),
5871                               CLUTTER_COLOR_Transparent,
5872                               CLUTTER_PARAM_READWRITE);
5873
5874   /**
5875    * ClutterActor:first-child:
5876    *
5877    * The actor's first child.
5878    *
5879    * Since: 1.10
5880    */
5881   obj_props[PROP_FIRST_CHILD] =
5882     g_param_spec_object ("first-child",
5883                          P_("First Child"),
5884                          P_("The actor's first child"),
5885                          CLUTTER_TYPE_ACTOR,
5886                          CLUTTER_PARAM_READABLE);
5887
5888   /**
5889    * ClutterActor:last-child:
5890    *
5891    * The actor's last child.
5892    *
5893    * Since: 1.10
5894    */
5895   obj_props[PROP_LAST_CHILD] =
5896     g_param_spec_object ("last-child",
5897                          P_("Last Child"),
5898                          P_("The actor's last child"),
5899                          CLUTTER_TYPE_ACTOR,
5900                          CLUTTER_PARAM_READABLE);
5901
5902   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5903
5904   /**
5905    * ClutterActor::destroy:
5906    * @actor: the #ClutterActor which emitted the signal
5907    *
5908    * The ::destroy signal notifies that all references held on the
5909    * actor which emitted it should be released.
5910    *
5911    * The ::destroy signal should be used by all holders of a reference
5912    * on @actor.
5913    *
5914    * This signal might result in the finalization of the #ClutterActor
5915    * if all references are released.
5916    *
5917    * Composite actors and actors implementing the #ClutterContainer
5918    * interface should override the default implementation of the
5919    * class handler of this signal and call clutter_actor_destroy() on
5920    * their children. When overriding the default class handler, it is
5921    * required to chain up to the parent's implementation.
5922    *
5923    * Since: 0.2
5924    */
5925   actor_signals[DESTROY] =
5926     g_signal_new (I_("destroy"),
5927                   G_TYPE_FROM_CLASS (object_class),
5928                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5929                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5930                   NULL, NULL,
5931                   _clutter_marshal_VOID__VOID,
5932                   G_TYPE_NONE, 0);
5933   /**
5934    * ClutterActor::show:
5935    * @actor: the object which received the signal
5936    *
5937    * The ::show signal is emitted when an actor is visible and
5938    * rendered on the stage.
5939    *
5940    * Since: 0.2
5941    */
5942   actor_signals[SHOW] =
5943     g_signal_new (I_("show"),
5944                   G_TYPE_FROM_CLASS (object_class),
5945                   G_SIGNAL_RUN_FIRST,
5946                   G_STRUCT_OFFSET (ClutterActorClass, show),
5947                   NULL, NULL,
5948                   _clutter_marshal_VOID__VOID,
5949                   G_TYPE_NONE, 0);
5950   /**
5951    * ClutterActor::hide:
5952    * @actor: the object which received the signal
5953    *
5954    * The ::hide signal is emitted when an actor is no longer rendered
5955    * on the stage.
5956    *
5957    * Since: 0.2
5958    */
5959   actor_signals[HIDE] =
5960     g_signal_new (I_("hide"),
5961                   G_TYPE_FROM_CLASS (object_class),
5962                   G_SIGNAL_RUN_FIRST,
5963                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5964                   NULL, NULL,
5965                   _clutter_marshal_VOID__VOID,
5966                   G_TYPE_NONE, 0);
5967   /**
5968    * ClutterActor::parent-set:
5969    * @actor: the object which received the signal
5970    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5971    *
5972    * This signal is emitted when the parent of the actor changes.
5973    *
5974    * Since: 0.2
5975    */
5976   actor_signals[PARENT_SET] =
5977     g_signal_new (I_("parent-set"),
5978                   G_TYPE_FROM_CLASS (object_class),
5979                   G_SIGNAL_RUN_LAST,
5980                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5981                   NULL, NULL,
5982                   _clutter_marshal_VOID__OBJECT,
5983                   G_TYPE_NONE, 1,
5984                   CLUTTER_TYPE_ACTOR);
5985
5986   /**
5987    * ClutterActor::queue-redraw:
5988    * @actor: the actor we're bubbling the redraw request through
5989    * @origin: the actor which initiated the redraw request
5990    *
5991    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5992    * is called on @origin.
5993    *
5994    * The default implementation for #ClutterActor chains up to the
5995    * parent actor and queues a redraw on the parent, thus "bubbling"
5996    * the redraw queue up through the actor graph. The default
5997    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5998    * in a main loop idle handler.
5999    *
6000    * Note that the @origin actor may be the stage, or a container; it
6001    * does not have to be a leaf node in the actor graph.
6002    *
6003    * Toolkits embedding a #ClutterStage which require a redraw and
6004    * relayout cycle can stop the emission of this signal using the
6005    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6006    * themselves, like:
6007    *
6008    * |[
6009    *   static void
6010    *   on_redraw_complete (gpointer data)
6011    *   {
6012    *     ClutterStage *stage = data;
6013    *
6014    *     /&ast; execute the Clutter drawing pipeline &ast;/
6015    *     clutter_stage_ensure_redraw (stage);
6016    *   }
6017    *
6018    *   static void
6019    *   on_stage_queue_redraw (ClutterStage *stage)
6020    *   {
6021    *     /&ast; this prevents the default handler to run &ast;/
6022    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6023    *
6024    *     /&ast; queue a redraw with the host toolkit and call
6025    *      &ast; a function when the redraw has been completed
6026    *      &ast;/
6027    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6028    *   }
6029    * ]|
6030    *
6031    * <note><para>This signal is emitted before the Clutter paint
6032    * pipeline is executed. If you want to know when the pipeline has
6033    * been completed you should connect to the ::paint signal on the
6034    * Stage with g_signal_connect_after().</para></note>
6035    *
6036    * Since: 1.0
6037    */
6038   actor_signals[QUEUE_REDRAW] =
6039     g_signal_new (I_("queue-redraw"),
6040                   G_TYPE_FROM_CLASS (object_class),
6041                   G_SIGNAL_RUN_LAST,
6042                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6043                   NULL, NULL,
6044                   _clutter_marshal_VOID__OBJECT,
6045                   G_TYPE_NONE, 1,
6046                   CLUTTER_TYPE_ACTOR);
6047
6048   /**
6049    * ClutterActor::queue-relayout
6050    * @actor: the actor being queued for relayout
6051    *
6052    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6053    * is called on an actor.
6054    *
6055    * The default implementation for #ClutterActor chains up to the
6056    * parent actor and queues a relayout on the parent, thus "bubbling"
6057    * the relayout queue up through the actor graph.
6058    *
6059    * The main purpose of this signal is to allow relayout to be propagated
6060    * properly in the procense of #ClutterClone actors. Applications will
6061    * not normally need to connect to this signal.
6062    *
6063    * Since: 1.2
6064    */
6065   actor_signals[QUEUE_RELAYOUT] =
6066     g_signal_new (I_("queue-relayout"),
6067                   G_TYPE_FROM_CLASS (object_class),
6068                   G_SIGNAL_RUN_LAST,
6069                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6070                   NULL, NULL,
6071                   _clutter_marshal_VOID__VOID,
6072                   G_TYPE_NONE, 0);
6073
6074   /**
6075    * ClutterActor::event:
6076    * @actor: the actor which received the event
6077    * @event: a #ClutterEvent
6078    *
6079    * The ::event signal is emitted each time an event is received
6080    * by the @actor. This signal will be emitted on every actor,
6081    * following the hierarchy chain, until it reaches the top-level
6082    * container (the #ClutterStage).
6083    *
6084    * Return value: %TRUE if the event has been handled by the actor,
6085    *   or %FALSE to continue the emission.
6086    *
6087    * Since: 0.6
6088    */
6089   actor_signals[EVENT] =
6090     g_signal_new (I_("event"),
6091                   G_TYPE_FROM_CLASS (object_class),
6092                   G_SIGNAL_RUN_LAST,
6093                   G_STRUCT_OFFSET (ClutterActorClass, event),
6094                   _clutter_boolean_handled_accumulator, NULL,
6095                   _clutter_marshal_BOOLEAN__BOXED,
6096                   G_TYPE_BOOLEAN, 1,
6097                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6098   /**
6099    * ClutterActor::button-press-event:
6100    * @actor: the actor which received the event
6101    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6102    *
6103    * The ::button-press-event signal is emitted each time a mouse button
6104    * is pressed on @actor.
6105    *
6106    * Return value: %TRUE if the event has been handled by the actor,
6107    *   or %FALSE to continue the emission.
6108    *
6109    * Since: 0.6
6110    */
6111   actor_signals[BUTTON_PRESS_EVENT] =
6112     g_signal_new (I_("button-press-event"),
6113                   G_TYPE_FROM_CLASS (object_class),
6114                   G_SIGNAL_RUN_LAST,
6115                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6116                   _clutter_boolean_handled_accumulator, NULL,
6117                   _clutter_marshal_BOOLEAN__BOXED,
6118                   G_TYPE_BOOLEAN, 1,
6119                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6120   /**
6121    * ClutterActor::button-release-event:
6122    * @actor: the actor which received the event
6123    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6124    *
6125    * The ::button-release-event signal is emitted each time a mouse button
6126    * is released on @actor.
6127    *
6128    * Return value: %TRUE if the event has been handled by the actor,
6129    *   or %FALSE to continue the emission.
6130    *
6131    * Since: 0.6
6132    */
6133   actor_signals[BUTTON_RELEASE_EVENT] =
6134     g_signal_new (I_("button-release-event"),
6135                   G_TYPE_FROM_CLASS (object_class),
6136                   G_SIGNAL_RUN_LAST,
6137                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6138                   _clutter_boolean_handled_accumulator, NULL,
6139                   _clutter_marshal_BOOLEAN__BOXED,
6140                   G_TYPE_BOOLEAN, 1,
6141                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6142   /**
6143    * ClutterActor::scroll-event:
6144    * @actor: the actor which received the event
6145    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6146    *
6147    * The ::scroll-event signal is emitted each time the mouse is
6148    * scrolled on @actor
6149    *
6150    * Return value: %TRUE if the event has been handled by the actor,
6151    *   or %FALSE to continue the emission.
6152    *
6153    * Since: 0.6
6154    */
6155   actor_signals[SCROLL_EVENT] =
6156     g_signal_new (I_("scroll-event"),
6157                   G_TYPE_FROM_CLASS (object_class),
6158                   G_SIGNAL_RUN_LAST,
6159                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6160                   _clutter_boolean_handled_accumulator, NULL,
6161                   _clutter_marshal_BOOLEAN__BOXED,
6162                   G_TYPE_BOOLEAN, 1,
6163                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6164   /**
6165    * ClutterActor::key-press-event:
6166    * @actor: the actor which received the event
6167    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6168    *
6169    * The ::key-press-event signal is emitted each time a keyboard button
6170    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6171    *
6172    * Return value: %TRUE if the event has been handled by the actor,
6173    *   or %FALSE to continue the emission.
6174    *
6175    * Since: 0.6
6176    */
6177   actor_signals[KEY_PRESS_EVENT] =
6178     g_signal_new (I_("key-press-event"),
6179                   G_TYPE_FROM_CLASS (object_class),
6180                   G_SIGNAL_RUN_LAST,
6181                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6182                   _clutter_boolean_handled_accumulator, NULL,
6183                   _clutter_marshal_BOOLEAN__BOXED,
6184                   G_TYPE_BOOLEAN, 1,
6185                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6186   /**
6187    * ClutterActor::key-release-event:
6188    * @actor: the actor which received the event
6189    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6190    *
6191    * The ::key-release-event signal is emitted each time a keyboard button
6192    * is released while @actor has key focus (see
6193    * clutter_stage_set_key_focus()).
6194    *
6195    * Return value: %TRUE if the event has been handled by the actor,
6196    *   or %FALSE to continue the emission.
6197    *
6198    * Since: 0.6
6199    */
6200   actor_signals[KEY_RELEASE_EVENT] =
6201     g_signal_new (I_("key-release-event"),
6202                   G_TYPE_FROM_CLASS (object_class),
6203                   G_SIGNAL_RUN_LAST,
6204                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6205                   _clutter_boolean_handled_accumulator, NULL,
6206                   _clutter_marshal_BOOLEAN__BOXED,
6207                   G_TYPE_BOOLEAN, 1,
6208                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6209   /**
6210    * ClutterActor::motion-event:
6211    * @actor: the actor which received the event
6212    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6213    *
6214    * The ::motion-event signal is emitted each time the mouse pointer is
6215    * moved over @actor.
6216    *
6217    * Return value: %TRUE if the event has been handled by the actor,
6218    *   or %FALSE to continue the emission.
6219    *
6220    * Since: 0.6
6221    */
6222   actor_signals[MOTION_EVENT] =
6223     g_signal_new (I_("motion-event"),
6224                   G_TYPE_FROM_CLASS (object_class),
6225                   G_SIGNAL_RUN_LAST,
6226                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6227                   _clutter_boolean_handled_accumulator, NULL,
6228                   _clutter_marshal_BOOLEAN__BOXED,
6229                   G_TYPE_BOOLEAN, 1,
6230                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6231
6232   /**
6233    * ClutterActor::key-focus-in:
6234    * @actor: the actor which now has key focus
6235    *
6236    * The ::key-focus-in signal is emitted when @actor receives key focus.
6237    *
6238    * Since: 0.6
6239    */
6240   actor_signals[KEY_FOCUS_IN] =
6241     g_signal_new (I_("key-focus-in"),
6242                   G_TYPE_FROM_CLASS (object_class),
6243                   G_SIGNAL_RUN_LAST,
6244                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6245                   NULL, NULL,
6246                   _clutter_marshal_VOID__VOID,
6247                   G_TYPE_NONE, 0);
6248
6249   /**
6250    * ClutterActor::key-focus-out:
6251    * @actor: the actor which now has key focus
6252    *
6253    * The ::key-focus-out signal is emitted when @actor loses key focus.
6254    *
6255    * Since: 0.6
6256    */
6257   actor_signals[KEY_FOCUS_OUT] =
6258     g_signal_new (I_("key-focus-out"),
6259                   G_TYPE_FROM_CLASS (object_class),
6260                   G_SIGNAL_RUN_LAST,
6261                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6262                   NULL, NULL,
6263                   _clutter_marshal_VOID__VOID,
6264                   G_TYPE_NONE, 0);
6265
6266   /**
6267    * ClutterActor::enter-event:
6268    * @actor: the actor which the pointer has entered.
6269    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6270    *
6271    * The ::enter-event signal is emitted when the pointer enters the @actor
6272    *
6273    * Return value: %TRUE if the event has been handled by the actor,
6274    *   or %FALSE to continue the emission.
6275    *
6276    * Since: 0.6
6277    */
6278   actor_signals[ENTER_EVENT] =
6279     g_signal_new (I_("enter-event"),
6280                   G_TYPE_FROM_CLASS (object_class),
6281                   G_SIGNAL_RUN_LAST,
6282                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6283                   _clutter_boolean_handled_accumulator, NULL,
6284                   _clutter_marshal_BOOLEAN__BOXED,
6285                   G_TYPE_BOOLEAN, 1,
6286                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6287
6288   /**
6289    * ClutterActor::leave-event:
6290    * @actor: the actor which the pointer has left
6291    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6292    *
6293    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6294    *
6295    * Return value: %TRUE if the event has been handled by the actor,
6296    *   or %FALSE to continue the emission.
6297    *
6298    * Since: 0.6
6299    */
6300   actor_signals[LEAVE_EVENT] =
6301     g_signal_new (I_("leave-event"),
6302                   G_TYPE_FROM_CLASS (object_class),
6303                   G_SIGNAL_RUN_LAST,
6304                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6305                   _clutter_boolean_handled_accumulator, NULL,
6306                   _clutter_marshal_BOOLEAN__BOXED,
6307                   G_TYPE_BOOLEAN, 1,
6308                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6309
6310   /**
6311    * ClutterActor::captured-event:
6312    * @actor: the actor which received the signal
6313    * @event: a #ClutterEvent
6314    *
6315    * The ::captured-event signal is emitted when an event is captured
6316    * by Clutter. This signal will be emitted starting from the top-level
6317    * container (the #ClutterStage) to the actor which received the event
6318    * going down the hierarchy. This signal can be used to intercept every
6319    * event before the specialized events (like
6320    * ClutterActor::button-press-event or ::key-released-event) are
6321    * emitted.
6322    *
6323    * Return value: %TRUE if the event has been handled by the actor,
6324    *   or %FALSE to continue the emission.
6325    *
6326    * Since: 0.6
6327    */
6328   actor_signals[CAPTURED_EVENT] =
6329     g_signal_new (I_("captured-event"),
6330                   G_TYPE_FROM_CLASS (object_class),
6331                   G_SIGNAL_RUN_LAST,
6332                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6333                   _clutter_boolean_handled_accumulator, NULL,
6334                   _clutter_marshal_BOOLEAN__BOXED,
6335                   G_TYPE_BOOLEAN, 1,
6336                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6337
6338   /**
6339    * ClutterActor::paint:
6340    * @actor: the #ClutterActor that received the signal
6341    *
6342    * The ::paint signal is emitted each time an actor is being painted.
6343    *
6344    * Subclasses of #ClutterActor should override the class signal handler
6345    * and paint themselves in that function.
6346    *
6347    * It is possible to connect a handler to the ::paint signal in order
6348    * to set up some custom aspect of a paint.
6349    *
6350    * Since: 0.8
6351    */
6352   actor_signals[PAINT] =
6353     g_signal_new (I_("paint"),
6354                   G_TYPE_FROM_CLASS (object_class),
6355                   G_SIGNAL_RUN_LAST,
6356                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6357                   NULL, NULL,
6358                   _clutter_marshal_VOID__VOID,
6359                   G_TYPE_NONE, 0);
6360   /**
6361    * ClutterActor::realize:
6362    * @actor: the #ClutterActor that received the signal
6363    *
6364    * The ::realize signal is emitted each time an actor is being
6365    * realized.
6366    *
6367    * Since: 0.8
6368    */
6369   actor_signals[REALIZE] =
6370     g_signal_new (I_("realize"),
6371                   G_TYPE_FROM_CLASS (object_class),
6372                   G_SIGNAL_RUN_LAST,
6373                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6374                   NULL, NULL,
6375                   _clutter_marshal_VOID__VOID,
6376                   G_TYPE_NONE, 0);
6377   /**
6378    * ClutterActor::unrealize:
6379    * @actor: the #ClutterActor that received the signal
6380    *
6381    * The ::unrealize signal is emitted each time an actor is being
6382    * unrealized.
6383    *
6384    * Since: 0.8
6385    */
6386   actor_signals[UNREALIZE] =
6387     g_signal_new (I_("unrealize"),
6388                   G_TYPE_FROM_CLASS (object_class),
6389                   G_SIGNAL_RUN_LAST,
6390                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6391                   NULL, NULL,
6392                   _clutter_marshal_VOID__VOID,
6393                   G_TYPE_NONE, 0);
6394
6395   /**
6396    * ClutterActor::pick:
6397    * @actor: the #ClutterActor that received the signal
6398    * @color: the #ClutterColor to be used when picking
6399    *
6400    * The ::pick signal is emitted each time an actor is being painted
6401    * in "pick mode". The pick mode is used to identify the actor during
6402    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6403    * The actor should paint its shape using the passed @pick_color.
6404    *
6405    * Subclasses of #ClutterActor should override the class signal handler
6406    * and paint themselves in that function.
6407    *
6408    * It is possible to connect a handler to the ::pick signal in order
6409    * to set up some custom aspect of a paint in pick mode.
6410    *
6411    * Since: 1.0
6412    */
6413   actor_signals[PICK] =
6414     g_signal_new (I_("pick"),
6415                   G_TYPE_FROM_CLASS (object_class),
6416                   G_SIGNAL_RUN_LAST,
6417                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6418                   NULL, NULL,
6419                   _clutter_marshal_VOID__BOXED,
6420                   G_TYPE_NONE, 1,
6421                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6422
6423   /**
6424    * ClutterActor::allocation-changed:
6425    * @actor: the #ClutterActor that emitted the signal
6426    * @box: a #ClutterActorBox with the new allocation
6427    * @flags: #ClutterAllocationFlags for the allocation
6428    *
6429    * The ::allocation-changed signal is emitted when the
6430    * #ClutterActor:allocation property changes. Usually, application
6431    * code should just use the notifications for the :allocation property
6432    * but if you want to track the allocation flags as well, for instance
6433    * to know whether the absolute origin of @actor changed, then you might
6434    * want use this signal instead.
6435    *
6436    * Since: 1.0
6437    */
6438   actor_signals[ALLOCATION_CHANGED] =
6439     g_signal_new (I_("allocation-changed"),
6440                   G_TYPE_FROM_CLASS (object_class),
6441                   G_SIGNAL_RUN_LAST,
6442                   0,
6443                   NULL, NULL,
6444                   _clutter_marshal_VOID__BOXED_FLAGS,
6445                   G_TYPE_NONE, 2,
6446                   CLUTTER_TYPE_ACTOR_BOX,
6447                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6448 }
6449
6450 static void
6451 clutter_actor_init (ClutterActor *self)
6452 {
6453   ClutterActorPrivate *priv;
6454
6455   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6456
6457   priv->id = _clutter_context_acquire_id (self);
6458   priv->pick_id = -1;
6459
6460   priv->opacity = 0xff;
6461   priv->show_on_set_parent = TRUE;
6462
6463   priv->needs_width_request = TRUE;
6464   priv->needs_height_request = TRUE;
6465   priv->needs_allocation = TRUE;
6466
6467   priv->cached_width_age = 1;
6468   priv->cached_height_age = 1;
6469
6470   priv->opacity_override = -1;
6471   priv->enable_model_view_transform = TRUE;
6472
6473   /* Initialize an empty paint volume to start with */
6474   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6475   priv->last_paint_volume_valid = TRUE;
6476
6477   priv->transform_valid = FALSE;
6478 }
6479
6480 /**
6481  * clutter_actor_new:
6482  *
6483  * Creates a new #ClutterActor.
6484  *
6485  * A newly created actor has a floating reference, which will be sunk
6486  * when it is added to another actor.
6487  *
6488  * Return value: (transfer full): the newly created #ClutterActor
6489  *
6490  * Since: 1.10
6491  */
6492 ClutterActor *
6493 clutter_actor_new (void)
6494 {
6495   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6496 }
6497
6498 /**
6499  * clutter_actor_destroy:
6500  * @self: a #ClutterActor
6501  *
6502  * Destroys an actor.  When an actor is destroyed, it will break any
6503  * references it holds to other objects.  If the actor is inside a
6504  * container, the actor will be removed.
6505  *
6506  * When you destroy a container, its children will be destroyed as well.
6507  *
6508  * Note: you cannot destroy the #ClutterStage returned by
6509  * clutter_stage_get_default().
6510  */
6511 void
6512 clutter_actor_destroy (ClutterActor *self)
6513 {
6514   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6515
6516   g_object_ref (self);
6517
6518   /* avoid recursion while destroying */
6519   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6520     {
6521       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6522
6523       g_object_run_dispose (G_OBJECT (self));
6524
6525       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6526     }
6527
6528   g_object_unref (self);
6529 }
6530
6531 void
6532 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6533                                     ClutterPaintVolume *clip)
6534 {
6535   ClutterActorPrivate *priv = self->priv;
6536   ClutterPaintVolume *pv;
6537   gboolean clipped;
6538
6539   /* If we've been explicitly passed a clip volume then there's
6540    * nothing more to calculate, but otherwise the only thing we know
6541    * is that the change is constrained to the given actor.
6542    *
6543    * The idea is that if we know the paint volume for where the actor
6544    * was last drawn (in eye coordinates) and we also have the paint
6545    * volume for where it will be drawn next (in actor coordinates)
6546    * then if we queue a redraw for both these volumes that will cover
6547    * everything that needs to be redrawn to clear the old view and
6548    * show the latest view of the actor.
6549    *
6550    * Don't clip this redraw if we don't know what position we had for
6551    * the previous redraw since we don't know where to set the clip so
6552    * it will clear the actor as it is currently.
6553    */
6554   if (clip)
6555     {
6556       _clutter_actor_set_queue_redraw_clip (self, clip);
6557       clipped = TRUE;
6558     }
6559   else if (G_LIKELY (priv->last_paint_volume_valid))
6560     {
6561       pv = _clutter_actor_get_paint_volume_mutable (self);
6562       if (pv)
6563         {
6564           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6565
6566           /* make sure we redraw the actors old position... */
6567           _clutter_actor_set_queue_redraw_clip (stage,
6568                                                 &priv->last_paint_volume);
6569           _clutter_actor_signal_queue_redraw (stage, stage);
6570           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6571
6572           /* XXX: Ideally the redraw signal would take a clip volume
6573            * argument, but that would be an ABI break. Until we can
6574            * break the ABI we pass the argument out-of-band
6575            */
6576
6577           /* setup the clip for the actors new position... */
6578           _clutter_actor_set_queue_redraw_clip (self, pv);
6579           clipped = TRUE;
6580         }
6581       else
6582         clipped = FALSE;
6583     }
6584   else
6585     clipped = FALSE;
6586
6587   _clutter_actor_signal_queue_redraw (self, self);
6588
6589   /* Just in case anyone is manually firing redraw signals without
6590    * using the public queue_redraw() API we are careful to ensure that
6591    * our out-of-band clip member is cleared before returning...
6592    *
6593    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6594    */
6595   if (G_LIKELY (clipped))
6596     _clutter_actor_set_queue_redraw_clip (self, NULL);
6597
6598   priv->queue_redraw_entry = NULL;
6599 }
6600
6601 static void
6602 _clutter_actor_get_allocation_clip (ClutterActor *self,
6603                                     ClutterActorBox *clip)
6604 {
6605   ClutterActorBox allocation;
6606
6607   /* XXX: we don't care if we get an out of date allocation here
6608    * because clutter_actor_queue_redraw_with_clip knows to ignore
6609    * the clip if the actor's allocation is invalid.
6610    *
6611    * This is noted because clutter_actor_get_allocation_box does some
6612    * unnecessary work to support buggy code with a comment suggesting
6613    * that it could be changed later which would be good for this use
6614    * case!
6615    */
6616   clutter_actor_get_allocation_box (self, &allocation);
6617
6618   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6619    * actor's own coordinate space but the allocation is in parent
6620    * coordinates */
6621   clip->x1 = 0;
6622   clip->y1 = 0;
6623   clip->x2 = allocation.x2 - allocation.x1;
6624   clip->y2 = allocation.y2 - allocation.y1;
6625 }
6626
6627 void
6628 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6629                                   ClutterRedrawFlags  flags,
6630                                   ClutterPaintVolume *volume,
6631                                   ClutterEffect      *effect)
6632 {
6633   ClutterActorPrivate *priv = self->priv;
6634   ClutterPaintVolume allocation_pv;
6635   ClutterPaintVolume *pv;
6636   gboolean should_free_pv;
6637   ClutterActor *stage;
6638
6639   /* Here's an outline of the actor queue redraw mechanism:
6640    *
6641    * The process starts in one of the following two functions which
6642    * are wrappers for this function:
6643    * clutter_actor_queue_redraw
6644    * _clutter_actor_queue_redraw_with_clip
6645    *
6646    * additionally, an effect can queue a redraw by wrapping this
6647    * function in clutter_effect_queue_rerun
6648    *
6649    * This functions queues an entry in a list associated with the
6650    * stage which is a list of actors that queued a redraw while
6651    * updating the timelines, performing layouting and processing other
6652    * mainloop sources before the next paint starts.
6653    *
6654    * We aim to minimize the processing done at this point because
6655    * there is a good chance other events will happen while updating
6656    * the scenegraph that would invalidate any expensive work we might
6657    * otherwise try to do here. For example we don't try and resolve
6658    * the screen space bounding box of an actor at this stage so as to
6659    * minimize how much of the screen redraw because it's possible
6660    * something else will happen which will force a full redraw anyway.
6661    *
6662    * When all updates are complete and we come to paint the stage then
6663    * we iterate this list and actually emit the "queue-redraw" signals
6664    * for each of the listed actors which will bubble up to the stage
6665    * for each actor and at that point we will transform the actors
6666    * paint volume into screen coordinates to determine the clip region
6667    * for what needs to be redrawn in the next paint.
6668    *
6669    * Besides minimizing redundant work another reason for this
6670    * deferred design is that it's more likely we will be able to
6671    * determine the paint volume of an actor once we've finished
6672    * updating the scenegraph because its allocation should be up to
6673    * date. NB: If we can't determine an actors paint volume then we
6674    * can't automatically queue a clipped redraw which can make a big
6675    * difference to performance.
6676    *
6677    * So the control flow goes like this:
6678    * One of clutter_actor_queue_redraw,
6679    *        _clutter_actor_queue_redraw_with_clip
6680    *     or clutter_effect_queue_rerun
6681    *
6682    * then control moves to:
6683    *   _clutter_stage_queue_actor_redraw
6684    *
6685    * later during _clutter_stage_do_update, once relayouting is done
6686    * and the scenegraph has been updated we will call:
6687    * _clutter_stage_finish_queue_redraws
6688    *
6689    * _clutter_stage_finish_queue_redraws will call
6690    * _clutter_actor_finish_queue_redraw for each listed actor.
6691    * Note: actors *are* allowed to queue further redraws during this
6692    * process (considering clone actors or texture_new_from_actor which
6693    * respond to their source queueing a redraw by queuing a redraw
6694    * themselves). We repeat the process until the list is empty.
6695    *
6696    * This will result in the "queue-redraw" signal being fired for
6697    * each actor which will pass control to the default signal handler:
6698    * clutter_actor_real_queue_redraw
6699    *
6700    * This will bubble up to the stages handler:
6701    * clutter_stage_real_queue_redraw
6702    *
6703    * clutter_stage_real_queue_redraw will transform the actors paint
6704    * volume into screen space and add it as a clip region for the next
6705    * paint.
6706    */
6707
6708   /* ignore queueing a redraw for actors being destroyed */
6709   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6710     return;
6711
6712   stage = _clutter_actor_get_stage_internal (self);
6713
6714   /* Ignore queueing a redraw for actors not descended from a stage */
6715   if (stage == NULL)
6716     return;
6717
6718   /* ignore queueing a redraw on stages that are being destroyed */
6719   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6720     return;
6721
6722   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6723     {
6724       ClutterActorBox allocation_clip;
6725       ClutterVertex origin;
6726
6727       /* If the actor doesn't have a valid allocation then we will
6728        * queue a full stage redraw. */
6729       if (priv->needs_allocation)
6730         {
6731           /* NB: NULL denotes an undefined clip which will result in a
6732            * full redraw... */
6733           _clutter_actor_set_queue_redraw_clip (self, NULL);
6734           _clutter_actor_signal_queue_redraw (self, self);
6735           return;
6736         }
6737
6738       _clutter_paint_volume_init_static (&allocation_pv, self);
6739       pv = &allocation_pv;
6740
6741       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6742
6743       origin.x = allocation_clip.x1;
6744       origin.y = allocation_clip.y1;
6745       origin.z = 0;
6746       clutter_paint_volume_set_origin (pv, &origin);
6747       clutter_paint_volume_set_width (pv,
6748                                       allocation_clip.x2 - allocation_clip.x1);
6749       clutter_paint_volume_set_height (pv,
6750                                        allocation_clip.y2 -
6751                                        allocation_clip.y1);
6752       should_free_pv = TRUE;
6753     }
6754   else
6755     {
6756       pv = volume;
6757       should_free_pv = FALSE;
6758     }
6759
6760   self->priv->queue_redraw_entry =
6761     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6762                                        priv->queue_redraw_entry,
6763                                        self,
6764                                        pv);
6765
6766   if (should_free_pv)
6767     clutter_paint_volume_free (pv);
6768
6769   /* If this is the first redraw queued then we can directly use the
6770      effect parameter */
6771   if (!priv->is_dirty)
6772     priv->effect_to_redraw = effect;
6773   /* Otherwise we need to merge it with the existing effect parameter */
6774   else if (effect != NULL)
6775     {
6776       /* If there's already an effect then we need to use whichever is
6777          later in the chain of actors. Otherwise a full redraw has
6778          already been queued on the actor so we need to ignore the
6779          effect parameter */
6780       if (priv->effect_to_redraw != NULL)
6781         {
6782           if (priv->effects == NULL)
6783             g_warning ("Redraw queued with an effect that is "
6784                        "not applied to the actor");
6785           else
6786             {
6787               const GList *l;
6788
6789               for (l = _clutter_meta_group_peek_metas (priv->effects);
6790                    l != NULL;
6791                    l = l->next)
6792                 {
6793                   if (l->data == priv->effect_to_redraw ||
6794                       l->data == effect)
6795                     priv->effect_to_redraw = l->data;
6796                 }
6797             }
6798         }
6799     }
6800   else
6801     {
6802       /* If no effect is specified then we need to redraw the whole
6803          actor */
6804       priv->effect_to_redraw = NULL;
6805     }
6806
6807   priv->is_dirty = TRUE;
6808 }
6809
6810 /**
6811  * clutter_actor_queue_redraw:
6812  * @self: A #ClutterActor
6813  *
6814  * Queues up a redraw of an actor and any children. The redraw occurs
6815  * once the main loop becomes idle (after the current batch of events
6816  * has been processed, roughly).
6817  *
6818  * Applications rarely need to call this, as redraws are handled
6819  * automatically by modification functions.
6820  *
6821  * This function will not do anything if @self is not visible, or
6822  * if the actor is inside an invisible part of the scenegraph.
6823  *
6824  * Also be aware that painting is a NOP for actors with an opacity of
6825  * 0
6826  *
6827  * When you are implementing a custom actor you must queue a redraw
6828  * whenever some private state changes that will affect painting or
6829  * picking of your actor.
6830  */
6831 void
6832 clutter_actor_queue_redraw (ClutterActor *self)
6833 {
6834   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6835
6836   _clutter_actor_queue_redraw_full (self,
6837                                     0, /* flags */
6838                                     NULL, /* clip volume */
6839                                     NULL /* effect */);
6840 }
6841
6842 /*< private >
6843  * _clutter_actor_queue_redraw_with_clip:
6844  * @self: A #ClutterActor
6845  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6846  *   this queue redraw.
6847  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6848  *   redrawn or %NULL if you are just using a @flag to state your
6849  *   desired clipping.
6850  *
6851  * Queues up a clipped redraw of an actor and any children. The redraw
6852  * occurs once the main loop becomes idle (after the current batch of
6853  * events has been processed, roughly).
6854  *
6855  * If no flags are given the clip volume is defined by @volume
6856  * specified in actor coordinates and tells Clutter that only content
6857  * within this volume has been changed so Clutter can optionally
6858  * optimize the redraw.
6859  *
6860  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6861  * should be %NULL and this tells Clutter to use the actor's current
6862  * allocation as a clip box. This flag can only be used for 2D actors,
6863  * because any actor with depth may be projected outside its
6864  * allocation.
6865  *
6866  * Applications rarely need to call this, as redraws are handled
6867  * automatically by modification functions.
6868  *
6869  * This function will not do anything if @self is not visible, or if
6870  * the actor is inside an invisible part of the scenegraph.
6871  *
6872  * Also be aware that painting is a NOP for actors with an opacity of
6873  * 0
6874  *
6875  * When you are implementing a custom actor you must queue a redraw
6876  * whenever some private state changes that will affect painting or
6877  * picking of your actor.
6878  */
6879 void
6880 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6881                                        ClutterRedrawFlags  flags,
6882                                        ClutterPaintVolume *volume)
6883 {
6884   _clutter_actor_queue_redraw_full (self,
6885                                     flags, /* flags */
6886                                     volume, /* clip volume */
6887                                     NULL /* effect */);
6888 }
6889
6890 static void
6891 _clutter_actor_queue_only_relayout (ClutterActor *self)
6892 {
6893   ClutterActorPrivate *priv = self->priv;
6894
6895   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6896     return;
6897
6898   if (priv->needs_width_request &&
6899       priv->needs_height_request &&
6900       priv->needs_allocation)
6901     return; /* save some cpu cycles */
6902
6903 #if CLUTTER_ENABLE_DEBUG
6904   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6905     {
6906       g_warning ("The actor '%s' is currently inside an allocation "
6907                  "cycle; calling clutter_actor_queue_relayout() is "
6908                  "not recommended",
6909                  _clutter_actor_get_debug_name (self));
6910     }
6911 #endif /* CLUTTER_ENABLE_DEBUG */
6912
6913   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6914 }
6915
6916 /**
6917  * clutter_actor_queue_redraw_with_clip:
6918  * @self: a #ClutterActor
6919  * @clip: (allow-none): a rectangular clip region, or %NULL
6920  *
6921  * Queues a redraw on @self limited to a specific, actor-relative
6922  * rectangular area.
6923  *
6924  * If @clip is %NULL this function is equivalent to
6925  * clutter_actor_queue_redraw().
6926  *
6927  * Since: 1.10
6928  */
6929 void
6930 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6931                                       const cairo_rectangle_int_t *clip)
6932 {
6933   ClutterPaintVolume volume;
6934   ClutterVertex origin;
6935
6936   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6937
6938   if (clip == NULL)
6939     {
6940       clutter_actor_queue_redraw (self);
6941       return;
6942     }
6943
6944   _clutter_paint_volume_init_static (&volume, self);
6945
6946   origin.x = clip->x;
6947   origin.y = clip->y;
6948   origin.z = 0.0f;
6949
6950   clutter_paint_volume_set_origin (&volume, &origin);
6951   clutter_paint_volume_set_width (&volume, clip->width);
6952   clutter_paint_volume_set_height (&volume, clip->height);
6953
6954   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6955
6956   clutter_paint_volume_free (&volume);
6957 }
6958
6959 /**
6960  * clutter_actor_queue_relayout:
6961  * @self: A #ClutterActor
6962  *
6963  * Indicates that the actor's size request or other layout-affecting
6964  * properties may have changed. This function is used inside #ClutterActor
6965  * subclass implementations, not by applications directly.
6966  *
6967  * Queueing a new layout automatically queues a redraw as well.
6968  *
6969  * Since: 0.8
6970  */
6971 void
6972 clutter_actor_queue_relayout (ClutterActor *self)
6973 {
6974   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6975
6976   _clutter_actor_queue_only_relayout (self);
6977   clutter_actor_queue_redraw (self);
6978 }
6979
6980 /**
6981  * clutter_actor_get_preferred_size:
6982  * @self: a #ClutterActor
6983  * @min_width_p: (out) (allow-none): return location for the minimum
6984  *   width, or %NULL
6985  * @min_height_p: (out) (allow-none): return location for the minimum
6986  *   height, or %NULL
6987  * @natural_width_p: (out) (allow-none): return location for the natural
6988  *   width, or %NULL
6989  * @natural_height_p: (out) (allow-none): return location for the natural
6990  *   height, or %NULL
6991  *
6992  * Computes the preferred minimum and natural size of an actor, taking into
6993  * account the actor's geometry management (either height-for-width
6994  * or width-for-height).
6995  *
6996  * The width and height used to compute the preferred height and preferred
6997  * width are the actor's natural ones.
6998  *
6999  * If you need to control the height for the preferred width, or the width for
7000  * the preferred height, you should use clutter_actor_get_preferred_width()
7001  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7002  * geometry management using the #ClutterActor:request-mode property.
7003  *
7004  * Since: 0.8
7005  */
7006 void
7007 clutter_actor_get_preferred_size (ClutterActor *self,
7008                                   gfloat       *min_width_p,
7009                                   gfloat       *min_height_p,
7010                                   gfloat       *natural_width_p,
7011                                   gfloat       *natural_height_p)
7012 {
7013   ClutterActorPrivate *priv;
7014   gfloat min_width, min_height;
7015   gfloat natural_width, natural_height;
7016
7017   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7018
7019   priv = self->priv;
7020
7021   min_width = min_height = 0;
7022   natural_width = natural_height = 0;
7023
7024   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7025     {
7026       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7027       clutter_actor_get_preferred_width (self, -1,
7028                                          &min_width,
7029                                          &natural_width);
7030       clutter_actor_get_preferred_height (self, natural_width,
7031                                           &min_height,
7032                                           &natural_height);
7033     }
7034   else
7035     {
7036       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7037       clutter_actor_get_preferred_height (self, -1,
7038                                           &min_height,
7039                                           &natural_height);
7040       clutter_actor_get_preferred_width (self, natural_height,
7041                                          &min_width,
7042                                          &natural_width);
7043     }
7044
7045   if (min_width_p)
7046     *min_width_p = min_width;
7047
7048   if (min_height_p)
7049     *min_height_p = min_height;
7050
7051   if (natural_width_p)
7052     *natural_width_p = natural_width;
7053
7054   if (natural_height_p)
7055     *natural_height_p = natural_height;
7056 }
7057
7058 /*< private >
7059  * effective_align:
7060  * @align: a #ClutterActorAlign
7061  * @direction: a #ClutterTextDirection
7062  *
7063  * Retrieves the correct alignment depending on the text direction
7064  *
7065  * Return value: the effective alignment
7066  */
7067 static ClutterActorAlign
7068 effective_align (ClutterActorAlign    align,
7069                  ClutterTextDirection direction)
7070 {
7071   ClutterActorAlign res;
7072
7073   switch (align)
7074     {
7075     case CLUTTER_ACTOR_ALIGN_START:
7076       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7077           ? CLUTTER_ACTOR_ALIGN_END
7078           : CLUTTER_ACTOR_ALIGN_START;
7079       break;
7080
7081     case CLUTTER_ACTOR_ALIGN_END:
7082       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7083           ? CLUTTER_ACTOR_ALIGN_START
7084           : CLUTTER_ACTOR_ALIGN_END;
7085       break;
7086
7087     default:
7088       res = align;
7089       break;
7090     }
7091
7092   return res;
7093 }
7094
7095 static inline void
7096 adjust_for_margin (float  margin_start,
7097                    float  margin_end,
7098                    float *minimum_size,
7099                    float *natural_size,
7100                    float *allocated_start,
7101                    float *allocated_end)
7102 {
7103   *minimum_size -= (margin_start + margin_end);
7104   *natural_size -= (margin_start + margin_end);
7105   *allocated_start += margin_start;
7106   *allocated_end -= margin_end;
7107 }
7108
7109 static inline void
7110 adjust_for_alignment (ClutterActorAlign  alignment,
7111                       float              natural_size,
7112                       float             *allocated_start,
7113                       float             *allocated_end)
7114 {
7115   float allocated_size = *allocated_end - *allocated_start;
7116
7117   switch (alignment)
7118     {
7119     case CLUTTER_ACTOR_ALIGN_FILL:
7120       /* do nothing */
7121       break;
7122
7123     case CLUTTER_ACTOR_ALIGN_START:
7124       /* keep start */
7125       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7126       break;
7127
7128     case CLUTTER_ACTOR_ALIGN_END:
7129       if (allocated_size > natural_size)
7130         {
7131           *allocated_start += (allocated_size - natural_size);
7132           *allocated_end = *allocated_start + natural_size;
7133         }
7134       break;
7135
7136     case CLUTTER_ACTOR_ALIGN_CENTER:
7137       if (allocated_size > natural_size)
7138         {
7139           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7140           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7141         }
7142       break;
7143     }
7144 }
7145
7146 /*< private >
7147  * clutter_actor_adjust_width:
7148  * @self: a #ClutterActor
7149  * @minimum_width: (inout): the actor's preferred minimum width, which
7150  *   will be adjusted depending on the margin
7151  * @natural_width: (inout): the actor's preferred natural width, which
7152  *   will be adjusted depending on the margin
7153  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7154  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7155  *
7156  * Adjusts the preferred and allocated position and size of an actor,
7157  * depending on the margin and alignment properties.
7158  */
7159 static void
7160 clutter_actor_adjust_width (ClutterActor *self,
7161                             gfloat       *minimum_width,
7162                             gfloat       *natural_width,
7163                             gfloat       *adjusted_x1,
7164                             gfloat       *adjusted_x2)
7165 {
7166   ClutterTextDirection text_dir;
7167   const ClutterLayoutInfo *info;
7168
7169   info = _clutter_actor_get_layout_info_or_defaults (self);
7170   text_dir = clutter_actor_get_text_direction (self);
7171
7172   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7173
7174   /* this will tweak natural_width to remove the margin, so that
7175    * adjust_for_alignment() will use the correct size
7176    */
7177   adjust_for_margin (info->margin.left, info->margin.right,
7178                      minimum_width, natural_width,
7179                      adjusted_x1, adjusted_x2);
7180
7181   adjust_for_alignment (effective_align (info->x_align, text_dir),
7182                         *natural_width,
7183                         adjusted_x1, adjusted_x2);
7184 }
7185
7186 /*< private >
7187  * clutter_actor_adjust_height:
7188  * @self: a #ClutterActor
7189  * @minimum_height: (inout): the actor's preferred minimum height, which
7190  *   will be adjusted depending on the margin
7191  * @natural_height: (inout): the actor's preferred natural height, which
7192  *   will be adjusted depending on the margin
7193  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7194  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7195  *
7196  * Adjusts the preferred and allocated position and size of an actor,
7197  * depending on the margin and alignment properties.
7198  */
7199 static void
7200 clutter_actor_adjust_height (ClutterActor *self,
7201                              gfloat       *minimum_height,
7202                              gfloat       *natural_height,
7203                              gfloat       *adjusted_y1,
7204                              gfloat       *adjusted_y2)
7205 {
7206   const ClutterLayoutInfo *info;
7207
7208   info = _clutter_actor_get_layout_info_or_defaults (self);
7209
7210   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7211
7212   /* this will tweak natural_height to remove the margin, so that
7213    * adjust_for_alignment() will use the correct size
7214    */
7215   adjust_for_margin (info->margin.top, info->margin.bottom,
7216                      minimum_height, natural_height,
7217                      adjusted_y1,
7218                      adjusted_y2);
7219
7220   /* we don't use effective_align() here, because text direction
7221    * only affects the horizontal axis
7222    */
7223   adjust_for_alignment (info->y_align,
7224                         *natural_height,
7225                         adjusted_y1,
7226                         adjusted_y2);
7227
7228 }
7229
7230 /* looks for a cached size request for this for_size. If not
7231  * found, returns the oldest entry so it can be overwritten */
7232 static gboolean
7233 _clutter_actor_get_cached_size_request (gfloat         for_size,
7234                                         SizeRequest   *cached_size_requests,
7235                                         SizeRequest  **result)
7236 {
7237   guint i;
7238
7239   *result = &cached_size_requests[0];
7240
7241   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7242     {
7243       SizeRequest *sr;
7244
7245       sr = &cached_size_requests[i];
7246
7247       if (sr->age > 0 &&
7248           sr->for_size == for_size)
7249         {
7250           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7251           *result = sr;
7252           return TRUE;
7253         }
7254       else if (sr->age < (*result)->age)
7255         {
7256           *result = sr;
7257         }
7258     }
7259
7260   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7261
7262   return FALSE;
7263 }
7264
7265 /**
7266  * clutter_actor_get_preferred_width:
7267  * @self: A #ClutterActor
7268  * @for_height: available height when computing the preferred width,
7269  *   or a negative value to indicate that no height is defined
7270  * @min_width_p: (out) (allow-none): return location for minimum width,
7271  *   or %NULL
7272  * @natural_width_p: (out) (allow-none): return location for the natural
7273  *   width, or %NULL
7274  *
7275  * Computes the requested minimum and natural widths for an actor,
7276  * optionally depending on the specified height, or if they are
7277  * already computed, returns the cached values.
7278  *
7279  * An actor may not get its request - depending on the layout
7280  * manager that's in effect.
7281  *
7282  * A request should not incorporate the actor's scale or anchor point;
7283  * those transformations do not affect layout, only rendering.
7284  *
7285  * Since: 0.8
7286  */
7287 void
7288 clutter_actor_get_preferred_width (ClutterActor *self,
7289                                    gfloat        for_height,
7290                                    gfloat       *min_width_p,
7291                                    gfloat       *natural_width_p)
7292 {
7293   float request_min_width, request_natural_width;
7294   SizeRequest *cached_size_request;
7295   const ClutterLayoutInfo *info;
7296   ClutterActorPrivate *priv;
7297   gboolean found_in_cache;
7298
7299   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7300
7301   priv = self->priv;
7302
7303   info = _clutter_actor_get_layout_info_or_defaults (self);
7304
7305   /* we shortcircuit the case of a fixed size set using set_width() */
7306   if (priv->min_width_set && priv->natural_width_set)
7307     {
7308       if (min_width_p != NULL)
7309         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7310
7311       if (natural_width_p != NULL)
7312         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7313
7314       return;
7315     }
7316
7317   /* the remaining cases are:
7318    *
7319    *   - either min_width or natural_width have been set
7320    *   - neither min_width or natural_width have been set
7321    *
7322    * in both cases, we go through the cache (and through the actor in case
7323    * of cache misses) and determine the authoritative value depending on
7324    * the *_set flags.
7325    */
7326
7327   if (!priv->needs_width_request)
7328     {
7329       found_in_cache =
7330         _clutter_actor_get_cached_size_request (for_height,
7331                                                 priv->width_requests,
7332                                                 &cached_size_request);
7333     }
7334   else
7335     {
7336       /* if the actor needs a width request we use the first slot */
7337       found_in_cache = FALSE;
7338       cached_size_request = &priv->width_requests[0];
7339     }
7340
7341   if (!found_in_cache)
7342     {
7343       gfloat minimum_width, natural_width;
7344       ClutterActorClass *klass;
7345
7346       minimum_width = natural_width = 0;
7347
7348       /* adjust for the margin */
7349       if (for_height >= 0)
7350         {
7351           for_height -= (info->margin.top + info->margin.bottom);
7352           if (for_height < 0)
7353             for_height = 0;
7354         }
7355
7356       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7357
7358       klass = CLUTTER_ACTOR_GET_CLASS (self);
7359       klass->get_preferred_width (self, for_height,
7360                                   &minimum_width,
7361                                   &natural_width);
7362
7363       /* adjust for the margin */
7364       minimum_width += (info->margin.left + info->margin.right);
7365       natural_width += (info->margin.left + info->margin.right);
7366
7367       /* Due to accumulated float errors, it's better not to warn
7368        * on this, but just fix it.
7369        */
7370       if (natural_width < minimum_width)
7371         natural_width = minimum_width;
7372
7373       cached_size_request->min_size = minimum_width;
7374       cached_size_request->natural_size = natural_width;
7375       cached_size_request->for_size = for_height;
7376       cached_size_request->age = priv->cached_width_age;
7377
7378       priv->cached_width_age += 1;
7379       priv->needs_width_request = FALSE;
7380     }
7381
7382   if (!priv->min_width_set)
7383     request_min_width = cached_size_request->min_size;
7384   else
7385     request_min_width = info->min_width;
7386
7387   if (!priv->natural_width_set)
7388     request_natural_width = cached_size_request->natural_size;
7389   else
7390     request_natural_width = info->natural_width;
7391
7392   if (min_width_p)
7393     *min_width_p = request_min_width;
7394
7395   if (natural_width_p)
7396     *natural_width_p = request_natural_width;
7397 }
7398
7399 /**
7400  * clutter_actor_get_preferred_height:
7401  * @self: A #ClutterActor
7402  * @for_width: available width to assume in computing desired height,
7403  *   or a negative value to indicate that no width is defined
7404  * @min_height_p: (out) (allow-none): return location for minimum height,
7405  *   or %NULL
7406  * @natural_height_p: (out) (allow-none): return location for natural
7407  *   height, or %NULL
7408  *
7409  * Computes the requested minimum and natural heights for an actor,
7410  * or if they are already computed, returns the cached values.
7411  *
7412  * An actor may not get its request - depending on the layout
7413  * manager that's in effect.
7414  *
7415  * A request should not incorporate the actor's scale or anchor point;
7416  * those transformations do not affect layout, only rendering.
7417  *
7418  * Since: 0.8
7419  */
7420 void
7421 clutter_actor_get_preferred_height (ClutterActor *self,
7422                                     gfloat        for_width,
7423                                     gfloat       *min_height_p,
7424                                     gfloat       *natural_height_p)
7425 {
7426   float request_min_height, request_natural_height;
7427   SizeRequest *cached_size_request;
7428   const ClutterLayoutInfo *info;
7429   ClutterActorPrivate *priv;
7430   gboolean found_in_cache;
7431
7432   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7433
7434   priv = self->priv;
7435
7436   info = _clutter_actor_get_layout_info_or_defaults (self);
7437
7438   /* we shortcircuit the case of a fixed size set using set_height() */
7439   if (priv->min_height_set && priv->natural_height_set)
7440     {
7441       if (min_height_p != NULL)
7442         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7443
7444       if (natural_height_p != NULL)
7445         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7446
7447       return;
7448     }
7449
7450   /* the remaining cases are:
7451    *
7452    *   - either min_height or natural_height have been set
7453    *   - neither min_height or natural_height have been set
7454    *
7455    * in both cases, we go through the cache (and through the actor in case
7456    * of cache misses) and determine the authoritative value depending on
7457    * the *_set flags.
7458    */
7459
7460   if (!priv->needs_height_request)
7461     {
7462       found_in_cache =
7463         _clutter_actor_get_cached_size_request (for_width,
7464                                                 priv->height_requests,
7465                                                 &cached_size_request);
7466     }
7467   else
7468     {
7469       found_in_cache = FALSE;
7470       cached_size_request = &priv->height_requests[0];
7471     }
7472
7473   if (!found_in_cache)
7474     {
7475       gfloat minimum_height, natural_height;
7476       ClutterActorClass *klass;
7477
7478       minimum_height = natural_height = 0;
7479
7480       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7481
7482       /* adjust for margin */
7483       if (for_width >= 0)
7484         {
7485           for_width -= (info->margin.left + info->margin.right);
7486           if (for_width < 0)
7487             for_width = 0;
7488         }
7489
7490       klass = CLUTTER_ACTOR_GET_CLASS (self);
7491       klass->get_preferred_height (self, for_width,
7492                                    &minimum_height,
7493                                    &natural_height);
7494
7495       /* adjust for margin */
7496       minimum_height += (info->margin.top + info->margin.bottom);
7497       natural_height += (info->margin.top + info->margin.bottom);
7498
7499       /* Due to accumulated float errors, it's better not to warn
7500        * on this, but just fix it.
7501        */
7502       if (natural_height < minimum_height)
7503         natural_height = minimum_height;
7504
7505       cached_size_request->min_size = minimum_height;
7506       cached_size_request->natural_size = natural_height;
7507       cached_size_request->for_size = for_width;
7508       cached_size_request->age = priv->cached_height_age;
7509
7510       priv->cached_height_age += 1;
7511       priv->needs_height_request = FALSE;
7512     }
7513
7514   if (!priv->min_height_set)
7515     request_min_height = cached_size_request->min_size;
7516   else
7517     request_min_height = info->min_height;
7518
7519   if (!priv->natural_height_set)
7520     request_natural_height = cached_size_request->natural_size;
7521   else
7522     request_natural_height = info->natural_height;
7523
7524   if (min_height_p)
7525     *min_height_p = request_min_height;
7526
7527   if (natural_height_p)
7528     *natural_height_p = request_natural_height;
7529 }
7530
7531 /**
7532  * clutter_actor_get_allocation_box:
7533  * @self: A #ClutterActor
7534  * @box: (out): the function fills this in with the actor's allocation
7535  *
7536  * Gets the layout box an actor has been assigned. The allocation can
7537  * only be assumed valid inside a paint() method; anywhere else, it
7538  * may be out-of-date.
7539  *
7540  * An allocation does not incorporate the actor's scale or anchor point;
7541  * those transformations do not affect layout, only rendering.
7542  *
7543  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7544  * of functions inside the implementation of the get_preferred_width()
7545  * or get_preferred_height() virtual functions.</note>
7546  *
7547  * Since: 0.8
7548  */
7549 void
7550 clutter_actor_get_allocation_box (ClutterActor    *self,
7551                                   ClutterActorBox *box)
7552 {
7553   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7554
7555   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7556    * which limits calling get_allocation to inside paint() basically; or
7557    * we can 2) force a layout, which could be expensive if someone calls
7558    * get_allocation somewhere silly; or we can 3) just return the latest
7559    * value, allowing it to be out-of-date, and assume people know what
7560    * they are doing.
7561    *
7562    * The least-surprises approach that keeps existing code working is
7563    * likely to be 2). People can end up doing some inefficient things,
7564    * though, and in general code that requires 2) is probably broken.
7565    */
7566
7567   /* this implements 2) */
7568   if (G_UNLIKELY (self->priv->needs_allocation))
7569     {
7570       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7571
7572       /* do not queue a relayout on an unparented actor */
7573       if (stage)
7574         _clutter_stage_maybe_relayout (stage);
7575     }
7576
7577   /* commenting out the code above and just keeping this assigment
7578    * implements 3)
7579    */
7580   *box = self->priv->allocation;
7581 }
7582
7583 /**
7584  * clutter_actor_get_allocation_geometry:
7585  * @self: A #ClutterActor
7586  * @geom: (out): allocation geometry in pixels
7587  *
7588  * Gets the layout box an actor has been assigned.  The allocation can
7589  * only be assumed valid inside a paint() method; anywhere else, it
7590  * may be out-of-date.
7591  *
7592  * An allocation does not incorporate the actor's scale or anchor point;
7593  * those transformations do not affect layout, only rendering.
7594  *
7595  * The returned rectangle is in pixels.
7596  *
7597  * Since: 0.8
7598  */
7599 void
7600 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7601                                        ClutterGeometry *geom)
7602 {
7603   ClutterActorBox box;
7604
7605   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7606   g_return_if_fail (geom != NULL);
7607
7608   clutter_actor_get_allocation_box (self, &box);
7609
7610   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7611   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7612   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7613   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7614 }
7615
7616 static void
7617 clutter_actor_update_constraints (ClutterActor    *self,
7618                                   ClutterActorBox *allocation)
7619 {
7620   ClutterActorPrivate *priv = self->priv;
7621   const GList *constraints, *l;
7622
7623   if (priv->constraints == NULL)
7624     return;
7625
7626   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7627   for (l = constraints; l != NULL; l = l->next)
7628     {
7629       ClutterConstraint *constraint = l->data;
7630       ClutterActorMeta *meta = l->data;
7631
7632       if (clutter_actor_meta_get_enabled (meta))
7633         {
7634           _clutter_constraint_update_allocation (constraint,
7635                                                  self,
7636                                                  allocation);
7637         }
7638     }
7639 }
7640
7641 /*< private >
7642  * clutter_actor_adjust_allocation:
7643  * @self: a #ClutterActor
7644  * @allocation: (inout): the allocation to adjust
7645  *
7646  * Adjusts the passed allocation box taking into account the actor's
7647  * layout information, like alignment, expansion, and margin.
7648  */
7649 static void
7650 clutter_actor_adjust_allocation (ClutterActor    *self,
7651                                  ClutterActorBox *allocation)
7652 {
7653   ClutterActorBox adj_allocation;
7654   float alloc_width, alloc_height;
7655   float min_width, min_height;
7656   float nat_width, nat_height;
7657   ClutterRequestMode req_mode;
7658
7659   adj_allocation = *allocation;
7660
7661   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7662
7663   /* we want to hit the cache, so we use the public API */
7664   req_mode = clutter_actor_get_request_mode (self);
7665
7666   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7667     {
7668       clutter_actor_get_preferred_width (self, -1,
7669                                          &min_width,
7670                                          &nat_width);
7671       clutter_actor_get_preferred_height (self, alloc_width,
7672                                           &min_height,
7673                                           &nat_height);
7674     }
7675   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7676     {
7677       clutter_actor_get_preferred_height (self, -1,
7678                                           &min_height,
7679                                           &nat_height);
7680       clutter_actor_get_preferred_height (self, alloc_height,
7681                                           &min_width,
7682                                           &nat_width);
7683     }
7684
7685 #ifdef CLUTTER_ENABLE_DEBUG
7686   /* warn about underallocations */
7687   if (_clutter_diagnostic_enabled () &&
7688       (floorf (min_width - alloc_width) > 0 ||
7689        floorf (min_height - alloc_height) > 0))
7690     {
7691       ClutterActor *parent = clutter_actor_get_parent (self);
7692
7693       /* the only actors that are allowed to be underallocated are the Stage,
7694        * as it doesn't have an implicit size, and Actors that specifically
7695        * told us that they want to opt-out from layout control mechanisms
7696        * through the NO_LAYOUT escape hatch.
7697        */
7698       if (parent != NULL &&
7699           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7700         {
7701           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7702                      "of %.2f x %.2f from its parent actor '%s', but its "
7703                      "requested minimum size is of %.2f x %.2f",
7704                      _clutter_actor_get_debug_name (self),
7705                      alloc_width, alloc_height,
7706                      _clutter_actor_get_debug_name (parent),
7707                      min_width, min_height);
7708         }
7709     }
7710 #endif
7711
7712   clutter_actor_adjust_width (self,
7713                               &min_width,
7714                               &nat_width,
7715                               &adj_allocation.x1,
7716                               &adj_allocation.x2);
7717
7718   clutter_actor_adjust_height (self,
7719                                &min_height,
7720                                &nat_height,
7721                                &adj_allocation.y1,
7722                                &adj_allocation.y2);
7723
7724   /* we maintain the invariant that an allocation cannot be adjusted
7725    * to be outside the parent-given box
7726    */
7727   if (adj_allocation.x1 < allocation->x1 ||
7728       adj_allocation.y1 < allocation->y1 ||
7729       adj_allocation.x2 > allocation->x2 ||
7730       adj_allocation.y2 > allocation->y2)
7731     {
7732       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7733                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7734                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7735                  _clutter_actor_get_debug_name (self),
7736                  adj_allocation.x1, adj_allocation.y1,
7737                  adj_allocation.x2 - adj_allocation.x1,
7738                  adj_allocation.y2 - adj_allocation.y1,
7739                  allocation->x1, allocation->y1,
7740                  allocation->x2 - allocation->x1,
7741                  allocation->y2 - allocation->y1);
7742       return;
7743     }
7744
7745   *allocation = adj_allocation;
7746 }
7747
7748 /**
7749  * clutter_actor_allocate:
7750  * @self: A #ClutterActor
7751  * @box: new allocation of the actor, in parent-relative coordinates
7752  * @flags: flags that control the allocation
7753  *
7754  * Called by the parent of an actor to assign the actor its size.
7755  * Should never be called by applications (except when implementing
7756  * a container or layout manager).
7757  *
7758  * Actors can know from their allocation box whether they have moved
7759  * with respect to their parent actor. The @flags parameter describes
7760  * additional information about the allocation, for instance whether
7761  * the parent has moved with respect to the stage, for example because
7762  * a grandparent's origin has moved.
7763  *
7764  * Since: 0.8
7765  */
7766 void
7767 clutter_actor_allocate (ClutterActor           *self,
7768                         const ClutterActorBox  *box,
7769                         ClutterAllocationFlags  flags)
7770 {
7771   ClutterActorPrivate *priv;
7772   ClutterActorClass *klass;
7773   ClutterActorBox old_allocation, real_allocation;
7774   gboolean origin_changed, child_moved, size_changed;
7775   gboolean stage_allocation_changed;
7776
7777   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7778   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7779     {
7780       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7781                  "which isn't a descendent of the stage!\n",
7782                  self, _clutter_actor_get_debug_name (self));
7783       return;
7784     }
7785
7786   priv = self->priv;
7787
7788   old_allocation = priv->allocation;
7789   real_allocation = *box;
7790
7791   /* constraints are allowed to modify the allocation only here; we do
7792    * this prior to all the other checks so that we can bail out if the
7793    * allocation did not change
7794    */
7795   clutter_actor_update_constraints (self, &real_allocation);
7796
7797   /* adjust the allocation depending on the align/margin properties */
7798   clutter_actor_adjust_allocation (self, &real_allocation);
7799
7800   if (real_allocation.x2 < real_allocation.x1 ||
7801       real_allocation.y2 < real_allocation.y1)
7802     {
7803       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7804                  _clutter_actor_get_debug_name (self),
7805                  real_allocation.x2 - real_allocation.x1,
7806                  real_allocation.y2 - real_allocation.y1);
7807     }
7808
7809   /* we allow 0-sized actors, but not negative-sized ones */
7810   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7811   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7812
7813   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7814
7815   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7816                  real_allocation.y1 != old_allocation.y1);
7817
7818   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7819                   real_allocation.y2 != old_allocation.y2);
7820
7821   if (origin_changed || child_moved || size_changed)
7822     stage_allocation_changed = TRUE;
7823   else
7824     stage_allocation_changed = FALSE;
7825
7826   /* If we get an allocation "out of the blue"
7827    * (we did not queue relayout), then we want to
7828    * ignore it. But if we have needs_allocation set,
7829    * we want to guarantee that allocate() virtual
7830    * method is always called, i.e. that queue_relayout()
7831    * always results in an allocate() invocation on
7832    * an actor.
7833    *
7834    * The optimization here is to avoid re-allocating
7835    * actors that did not queue relayout and were
7836    * not moved.
7837    */
7838   if (!priv->needs_allocation && !stage_allocation_changed)
7839     {
7840       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7841       return;
7842     }
7843
7844   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7845    * clutter_actor_allocate(), it indicates whether the parent has its
7846    * absolute origin moved; when passed in to ClutterActor::allocate()
7847    * virtual method though, it indicates whether the child has its
7848    * absolute origin moved.  So we set it when child_moved is TRUE
7849    */
7850   if (child_moved)
7851     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7852
7853   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7854
7855   klass = CLUTTER_ACTOR_GET_CLASS (self);
7856   klass->allocate (self, &real_allocation, flags);
7857
7858   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7859
7860   if (stage_allocation_changed)
7861     clutter_actor_queue_redraw (self);
7862 }
7863
7864 /**
7865  * clutter_actor_set_allocation:
7866  * @self: a #ClutterActor
7867  * @box: a #ClutterActorBox
7868  * @flags: allocation flags
7869  *
7870  * Stores the allocation of @self as defined by @box.
7871  *
7872  * This function can only be called from within the implementation of
7873  * the #ClutterActorClass.allocate() virtual function.
7874  *
7875  * The allocation should have been adjusted to take into account constraints,
7876  * alignment, and margin properties. If you are implementing a #ClutterActor
7877  * subclass that provides its own layout management policy for its children
7878  * instead of using a #ClutterLayoutManager delegate, you should not call
7879  * this function on the children of @self; instead, you should call
7880  * clutter_actor_allocate(), which will adjust the allocation box for
7881  * you.
7882  *
7883  * This function should only be used by subclasses of #ClutterActor
7884  * that wish to store their allocation but cannot chain up to the
7885  * parent's implementation; the default implementation of the
7886  * #ClutterActorClass.allocate() virtual function will call this
7887  * function.
7888  *
7889  * It is important to note that, while chaining up was the recommended
7890  * behaviour for #ClutterActor subclasses prior to the introduction of
7891  * this function, it is recommended to call clutter_actor_set_allocation()
7892  * instead.
7893  *
7894  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7895  * to handle the allocation of its children, this function will call
7896  * the clutter_layout_manager_allocate() function only if the
7897  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7898  * expected that the subclass will call clutter_layout_manager_allocate()
7899  * by itself. For instance, the following code:
7900  *
7901  * |[
7902  * static void
7903  * my_actor_allocate (ClutterActor *actor,
7904  *                    const ClutterActorBox *allocation,
7905  *                    ClutterAllocationFlags flags)
7906  * {
7907  *   ClutterActorBox new_alloc;
7908  *   ClutterAllocationFlags new_flags;
7909  *
7910  *   adjust_allocation (allocation, &amp;new_alloc);
7911  *
7912  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7913  *
7914  *   /&ast; this will use the layout manager set on the actor &ast;/
7915  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7916  * }
7917  * ]|
7918  *
7919  * is equivalent to this:
7920  *
7921  * |[
7922  * static void
7923  * my_actor_allocate (ClutterActor *actor,
7924  *                    const ClutterActorBox *allocation,
7925  *                    ClutterAllocationFlags flags)
7926  * {
7927  *   ClutterLayoutManager *layout;
7928  *   ClutterActorBox new_alloc;
7929  *
7930  *   adjust_allocation (allocation, &amp;new_alloc);
7931  *
7932  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7933  *
7934  *   layout = clutter_actor_get_layout_manager (actor);
7935  *   clutter_layout_manager_allocate (layout,
7936  *                                    CLUTTER_CONTAINER (actor),
7937  *                                    &amp;new_alloc,
7938  *                                    flags);
7939  * }
7940  * ]|
7941  *
7942  * Since: 1.10
7943  */
7944 void
7945 clutter_actor_set_allocation (ClutterActor           *self,
7946                               const ClutterActorBox  *box,
7947                               ClutterAllocationFlags  flags)
7948 {
7949   ClutterActorPrivate *priv;
7950   gboolean changed;
7951
7952   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7953   g_return_if_fail (box != NULL);
7954
7955   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7956     {
7957       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7958                   "can only be called from within the implementation of "
7959                   "the ClutterActor::allocate() virtual function.");
7960       return;
7961     }
7962
7963   priv = self->priv;
7964
7965   g_object_freeze_notify (G_OBJECT (self));
7966
7967   changed = clutter_actor_set_allocation_internal (self, box, flags);
7968
7969   /* we allocate our children before we notify changes in our geometry,
7970    * so that people connecting to properties will be able to get valid
7971    * data out of the sub-tree of the scene graph that has this actor at
7972    * the root.
7973    */
7974   clutter_actor_maybe_layout_children (self, box, flags);
7975
7976   if (changed)
7977     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7978                    &priv->allocation,
7979                    priv->allocation_flags);
7980
7981   g_object_thaw_notify (G_OBJECT (self));
7982 }
7983
7984 /**
7985  * clutter_actor_set_geometry:
7986  * @self: A #ClutterActor
7987  * @geometry: A #ClutterGeometry
7988  *
7989  * Sets the actor's fixed position and forces its minimum and natural
7990  * size, in pixels. This means the untransformed actor will have the
7991  * given geometry. This is the same as calling clutter_actor_set_position()
7992  * and clutter_actor_set_size().
7993  *
7994  * Deprecated: 1.10: Use clutter_actor_set_position() and
7995  *   clutter_actor_set_size() instead.
7996  */
7997 void
7998 clutter_actor_set_geometry (ClutterActor          *self,
7999                             const ClutterGeometry *geometry)
8000 {
8001   g_object_freeze_notify (G_OBJECT (self));
8002
8003   clutter_actor_set_position (self, geometry->x, geometry->y);
8004   clutter_actor_set_size (self, geometry->width, geometry->height);
8005
8006   g_object_thaw_notify (G_OBJECT (self));
8007 }
8008
8009 /**
8010  * clutter_actor_get_geometry:
8011  * @self: A #ClutterActor
8012  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8013  *
8014  * Gets the size and position of an actor relative to its parent
8015  * actor. This is the same as calling clutter_actor_get_position() and
8016  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8017  * requested size and position if the actor's allocation is invalid.
8018  *
8019  * Deprecated: 1.10: Use clutter_actor_get_position() and
8020  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8021  *   instead.
8022  */
8023 void
8024 clutter_actor_get_geometry (ClutterActor    *self,
8025                             ClutterGeometry *geometry)
8026 {
8027   gfloat x, y, width, height;
8028
8029   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8030   g_return_if_fail (geometry != NULL);
8031
8032   clutter_actor_get_position (self, &x, &y);
8033   clutter_actor_get_size (self, &width, &height);
8034
8035   geometry->x = (int) x;
8036   geometry->y = (int) y;
8037   geometry->width = (int) width;
8038   geometry->height = (int) height;
8039 }
8040
8041 /**
8042  * clutter_actor_set_position:
8043  * @self: A #ClutterActor
8044  * @x: New left position of actor in pixels.
8045  * @y: New top position of actor in pixels.
8046  *
8047  * Sets the actor's fixed position in pixels relative to any parent
8048  * actor.
8049  *
8050  * If a layout manager is in use, this position will override the
8051  * layout manager and force a fixed position.
8052  */
8053 void
8054 clutter_actor_set_position (ClutterActor *self,
8055                             gfloat        x,
8056                             gfloat        y)
8057 {
8058   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8059
8060   g_object_freeze_notify (G_OBJECT (self));
8061
8062   clutter_actor_set_x (self, x);
8063   clutter_actor_set_y (self, y);
8064
8065   g_object_thaw_notify (G_OBJECT (self));
8066 }
8067
8068 /**
8069  * clutter_actor_get_fixed_position_set:
8070  * @self: A #ClutterActor
8071  *
8072  * Checks whether an actor has a fixed position set (and will thus be
8073  * unaffected by any layout manager).
8074  *
8075  * Return value: %TRUE if the fixed position is set on the actor
8076  *
8077  * Since: 0.8
8078  */
8079 gboolean
8080 clutter_actor_get_fixed_position_set (ClutterActor *self)
8081 {
8082   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8083
8084   return self->priv->position_set;
8085 }
8086
8087 /**
8088  * clutter_actor_set_fixed_position_set:
8089  * @self: A #ClutterActor
8090  * @is_set: whether to use fixed position
8091  *
8092  * Sets whether an actor has a fixed position set (and will thus be
8093  * unaffected by any layout manager).
8094  *
8095  * Since: 0.8
8096  */
8097 void
8098 clutter_actor_set_fixed_position_set (ClutterActor *self,
8099                                       gboolean      is_set)
8100 {
8101   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8102
8103   if (self->priv->position_set == (is_set != FALSE))
8104     return;
8105
8106   self->priv->position_set = is_set != FALSE;
8107   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8108
8109   clutter_actor_queue_relayout (self);
8110 }
8111
8112 /**
8113  * clutter_actor_move_by:
8114  * @self: A #ClutterActor
8115  * @dx: Distance to move Actor on X axis.
8116  * @dy: Distance to move Actor on Y axis.
8117  *
8118  * Moves an actor by the specified distance relative to its current
8119  * position in pixels.
8120  *
8121  * This function modifies the fixed position of an actor and thus removes
8122  * it from any layout management. Another way to move an actor is with an
8123  * anchor point, see clutter_actor_set_anchor_point().
8124  *
8125  * Since: 0.2
8126  */
8127 void
8128 clutter_actor_move_by (ClutterActor *self,
8129                        gfloat        dx,
8130                        gfloat        dy)
8131 {
8132   const ClutterLayoutInfo *info;
8133   gfloat x, y;
8134
8135   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8136
8137   info = _clutter_actor_get_layout_info_or_defaults (self);
8138   x = info->fixed_x;
8139   y = info->fixed_y;
8140
8141   clutter_actor_set_position (self, x + dx, y + dy);
8142 }
8143
8144 static void
8145 clutter_actor_set_min_width (ClutterActor *self,
8146                              gfloat        min_width)
8147 {
8148   ClutterActorPrivate *priv = self->priv;
8149   ClutterActorBox old = { 0, };
8150   ClutterLayoutInfo *info;
8151
8152   /* if we are setting the size on a top-level actor and the
8153    * backend only supports static top-levels (e.g. framebuffers)
8154    * then we ignore the passed value and we override it with
8155    * the stage implementation's preferred size.
8156    */
8157   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8158       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8159     return;
8160
8161   info = _clutter_actor_get_layout_info (self);
8162
8163   if (priv->min_width_set && min_width == info->min_width)
8164     return;
8165
8166   g_object_freeze_notify (G_OBJECT (self));
8167
8168   clutter_actor_store_old_geometry (self, &old);
8169
8170   info->min_width = min_width;
8171   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8172   clutter_actor_set_min_width_set (self, TRUE);
8173
8174   clutter_actor_notify_if_geometry_changed (self, &old);
8175
8176   g_object_thaw_notify (G_OBJECT (self));
8177
8178   clutter_actor_queue_relayout (self);
8179 }
8180
8181 static void
8182 clutter_actor_set_min_height (ClutterActor *self,
8183                               gfloat        min_height)
8184
8185 {
8186   ClutterActorPrivate *priv = self->priv;
8187   ClutterActorBox old = { 0, };
8188   ClutterLayoutInfo *info;
8189
8190   /* if we are setting the size on a top-level actor and the
8191    * backend only supports static top-levels (e.g. framebuffers)
8192    * then we ignore the passed value and we override it with
8193    * the stage implementation's preferred size.
8194    */
8195   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8196       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8197     return;
8198
8199   info = _clutter_actor_get_layout_info (self);
8200
8201   if (priv->min_height_set && min_height == info->min_height)
8202     return;
8203
8204   g_object_freeze_notify (G_OBJECT (self));
8205
8206   clutter_actor_store_old_geometry (self, &old);
8207
8208   info->min_height = min_height;
8209   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8210   clutter_actor_set_min_height_set (self, TRUE);
8211
8212   clutter_actor_notify_if_geometry_changed (self, &old);
8213
8214   g_object_thaw_notify (G_OBJECT (self));
8215
8216   clutter_actor_queue_relayout (self);
8217 }
8218
8219 static void
8220 clutter_actor_set_natural_width (ClutterActor *self,
8221                                  gfloat        natural_width)
8222 {
8223   ClutterActorPrivate *priv = self->priv;
8224   ClutterActorBox old = { 0, };
8225   ClutterLayoutInfo *info;
8226
8227   /* if we are setting the size on a top-level actor and the
8228    * backend only supports static top-levels (e.g. framebuffers)
8229    * then we ignore the passed value and we override it with
8230    * the stage implementation's preferred size.
8231    */
8232   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8233       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8234     return;
8235
8236   info = _clutter_actor_get_layout_info (self);
8237
8238   if (priv->natural_width_set && natural_width == info->natural_width)
8239     return;
8240
8241   g_object_freeze_notify (G_OBJECT (self));
8242
8243   clutter_actor_store_old_geometry (self, &old);
8244
8245   info->natural_width = natural_width;
8246   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8247   clutter_actor_set_natural_width_set (self, TRUE);
8248
8249   clutter_actor_notify_if_geometry_changed (self, &old);
8250
8251   g_object_thaw_notify (G_OBJECT (self));
8252
8253   clutter_actor_queue_relayout (self);
8254 }
8255
8256 static void
8257 clutter_actor_set_natural_height (ClutterActor *self,
8258                                   gfloat        natural_height)
8259 {
8260   ClutterActorPrivate *priv = self->priv;
8261   ClutterActorBox old = { 0, };
8262   ClutterLayoutInfo *info;
8263
8264   /* if we are setting the size on a top-level actor and the
8265    * backend only supports static top-levels (e.g. framebuffers)
8266    * then we ignore the passed value and we override it with
8267    * the stage implementation's preferred size.
8268    */
8269   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8270       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8271     return;
8272
8273   info = _clutter_actor_get_layout_info (self);
8274
8275   if (priv->natural_height_set && natural_height == info->natural_height)
8276     return;
8277
8278   g_object_freeze_notify (G_OBJECT (self));
8279
8280   clutter_actor_store_old_geometry (self, &old);
8281
8282   info->natural_height = natural_height;
8283   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8284   clutter_actor_set_natural_height_set (self, TRUE);
8285
8286   clutter_actor_notify_if_geometry_changed (self, &old);
8287
8288   g_object_thaw_notify (G_OBJECT (self));
8289
8290   clutter_actor_queue_relayout (self);
8291 }
8292
8293 static void
8294 clutter_actor_set_min_width_set (ClutterActor *self,
8295                                  gboolean      use_min_width)
8296 {
8297   ClutterActorPrivate *priv = self->priv;
8298   ClutterActorBox old = { 0, };
8299
8300   if (priv->min_width_set == (use_min_width != FALSE))
8301     return;
8302
8303   clutter_actor_store_old_geometry (self, &old);
8304
8305   priv->min_width_set = use_min_width != FALSE;
8306   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8307
8308   clutter_actor_notify_if_geometry_changed (self, &old);
8309
8310   clutter_actor_queue_relayout (self);
8311 }
8312
8313 static void
8314 clutter_actor_set_min_height_set (ClutterActor *self,
8315                                   gboolean      use_min_height)
8316 {
8317   ClutterActorPrivate *priv = self->priv;
8318   ClutterActorBox old = { 0, };
8319
8320   if (priv->min_height_set == (use_min_height != FALSE))
8321     return;
8322
8323   clutter_actor_store_old_geometry (self, &old);
8324
8325   priv->min_height_set = use_min_height != FALSE;
8326   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8327
8328   clutter_actor_notify_if_geometry_changed (self, &old);
8329
8330   clutter_actor_queue_relayout (self);
8331 }
8332
8333 static void
8334 clutter_actor_set_natural_width_set (ClutterActor *self,
8335                                      gboolean      use_natural_width)
8336 {
8337   ClutterActorPrivate *priv = self->priv;
8338   ClutterActorBox old = { 0, };
8339
8340   if (priv->natural_width_set == (use_natural_width != FALSE))
8341     return;
8342
8343   clutter_actor_store_old_geometry (self, &old);
8344
8345   priv->natural_width_set = use_natural_width != FALSE;
8346   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8347
8348   clutter_actor_notify_if_geometry_changed (self, &old);
8349
8350   clutter_actor_queue_relayout (self);
8351 }
8352
8353 static void
8354 clutter_actor_set_natural_height_set (ClutterActor *self,
8355                                       gboolean      use_natural_height)
8356 {
8357   ClutterActorPrivate *priv = self->priv;
8358   ClutterActorBox old = { 0, };
8359
8360   if (priv->natural_height_set == (use_natural_height != FALSE))
8361     return;
8362
8363   clutter_actor_store_old_geometry (self, &old);
8364
8365   priv->natural_height_set = use_natural_height != FALSE;
8366   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8367
8368   clutter_actor_notify_if_geometry_changed (self, &old);
8369
8370   clutter_actor_queue_relayout (self);
8371 }
8372
8373 /**
8374  * clutter_actor_set_request_mode:
8375  * @self: a #ClutterActor
8376  * @mode: the request mode
8377  *
8378  * Sets the geometry request mode of @self.
8379  *
8380  * The @mode determines the order for invoking
8381  * clutter_actor_get_preferred_width() and
8382  * clutter_actor_get_preferred_height()
8383  *
8384  * Since: 1.2
8385  */
8386 void
8387 clutter_actor_set_request_mode (ClutterActor       *self,
8388                                 ClutterRequestMode  mode)
8389 {
8390   ClutterActorPrivate *priv;
8391
8392   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8393
8394   priv = self->priv;
8395
8396   if (priv->request_mode == mode)
8397     return;
8398
8399   priv->request_mode = mode;
8400
8401   priv->needs_width_request = TRUE;
8402   priv->needs_height_request = TRUE;
8403
8404   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8405
8406   clutter_actor_queue_relayout (self);
8407 }
8408
8409 /**
8410  * clutter_actor_get_request_mode:
8411  * @self: a #ClutterActor
8412  *
8413  * Retrieves the geometry request mode of @self
8414  *
8415  * Return value: the request mode for the actor
8416  *
8417  * Since: 1.2
8418  */
8419 ClutterRequestMode
8420 clutter_actor_get_request_mode (ClutterActor *self)
8421 {
8422   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8423                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8424
8425   return self->priv->request_mode;
8426 }
8427
8428 /* variant of set_width() without checks and without notification
8429  * freeze+thaw, for internal usage only
8430  */
8431 static inline void
8432 clutter_actor_set_width_internal (ClutterActor *self,
8433                                   gfloat        width)
8434 {
8435   if (width >= 0)
8436     {
8437       /* the Stage will use the :min-width to control the minimum
8438        * width to be resized to, so we should not be setting it
8439        * along with the :natural-width
8440        */
8441       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8442         clutter_actor_set_min_width (self, width);
8443
8444       clutter_actor_set_natural_width (self, width);
8445     }
8446   else
8447     {
8448       /* we only unset the :natural-width for the Stage */
8449       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8450         clutter_actor_set_min_width_set (self, FALSE);
8451
8452       clutter_actor_set_natural_width_set (self, FALSE);
8453     }
8454 }
8455
8456 /* variant of set_height() without checks and without notification
8457  * freeze+thaw, for internal usage only
8458  */
8459 static inline void
8460 clutter_actor_set_height_internal (ClutterActor *self,
8461                                    gfloat        height)
8462 {
8463   if (height >= 0)
8464     {
8465       /* see the comment above in set_width_internal() */
8466       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8467         clutter_actor_set_min_height (self, height);
8468
8469       clutter_actor_set_natural_height (self, height);
8470     }
8471   else
8472     {
8473       /* see the comment above in set_width_internal() */
8474       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8475         clutter_actor_set_min_height_set (self, FALSE);
8476
8477       clutter_actor_set_natural_height_set (self, FALSE);
8478     }
8479 }
8480
8481 /**
8482  * clutter_actor_set_size:
8483  * @self: A #ClutterActor
8484  * @width: New width of actor in pixels, or -1
8485  * @height: New height of actor in pixels, or -1
8486  *
8487  * Sets the actor's size request in pixels. This overrides any
8488  * "normal" size request the actor would have. For example
8489  * a text actor might normally request the size of the text;
8490  * this function would force a specific size instead.
8491  *
8492  * If @width and/or @height are -1 the actor will use its
8493  * "normal" size request instead of overriding it, i.e.
8494  * you can "unset" the size with -1.
8495  *
8496  * This function sets or unsets both the minimum and natural size.
8497  */
8498 void
8499 clutter_actor_set_size (ClutterActor *self,
8500                         gfloat        width,
8501                         gfloat        height)
8502 {
8503   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8504
8505   g_object_freeze_notify (G_OBJECT (self));
8506
8507   clutter_actor_set_width_internal (self, width);
8508   clutter_actor_set_height_internal (self, height);
8509
8510   g_object_thaw_notify (G_OBJECT (self));
8511 }
8512
8513 /**
8514  * clutter_actor_get_size:
8515  * @self: A #ClutterActor
8516  * @width: (out) (allow-none): return location for the width, or %NULL.
8517  * @height: (out) (allow-none): return location for the height, or %NULL.
8518  *
8519  * This function tries to "do what you mean" and return
8520  * the size an actor will have. If the actor has a valid
8521  * allocation, the allocation will be returned; otherwise,
8522  * the actors natural size request will be returned.
8523  *
8524  * If you care whether you get the request vs. the allocation, you
8525  * should probably call a different function like
8526  * clutter_actor_get_allocation_box() or
8527  * clutter_actor_get_preferred_width().
8528  *
8529  * Since: 0.2
8530  */
8531 void
8532 clutter_actor_get_size (ClutterActor *self,
8533                         gfloat       *width,
8534                         gfloat       *height)
8535 {
8536   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8537
8538   if (width)
8539     *width = clutter_actor_get_width (self);
8540
8541   if (height)
8542     *height = clutter_actor_get_height (self);
8543 }
8544
8545 /**
8546  * clutter_actor_get_position:
8547  * @self: a #ClutterActor
8548  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8549  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8550  *
8551  * This function tries to "do what you mean" and tell you where the
8552  * actor is, prior to any transformations. Retrieves the fixed
8553  * position of an actor in pixels, if one has been set; otherwise, if
8554  * the allocation is valid, returns the actor's allocated position;
8555  * otherwise, returns 0,0.
8556  *
8557  * The returned position is in pixels.
8558  *
8559  * Since: 0.6
8560  */
8561 void
8562 clutter_actor_get_position (ClutterActor *self,
8563                             gfloat       *x,
8564                             gfloat       *y)
8565 {
8566   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8567
8568   if (x)
8569     *x = clutter_actor_get_x (self);
8570
8571   if (y)
8572     *y = clutter_actor_get_y (self);
8573 }
8574
8575 /**
8576  * clutter_actor_get_transformed_position:
8577  * @self: A #ClutterActor
8578  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8579  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8580  *
8581  * Gets the absolute position of an actor, in pixels relative to the stage.
8582  *
8583  * Since: 0.8
8584  */
8585 void
8586 clutter_actor_get_transformed_position (ClutterActor *self,
8587                                         gfloat       *x,
8588                                         gfloat       *y)
8589 {
8590   ClutterVertex v1;
8591   ClutterVertex v2;
8592
8593   v1.x = v1.y = v1.z = 0;
8594   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8595
8596   if (x)
8597     *x = v2.x;
8598
8599   if (y)
8600     *y = v2.y;
8601 }
8602
8603 /**
8604  * clutter_actor_get_transformed_size:
8605  * @self: A #ClutterActor
8606  * @width: (out) (allow-none): return location for the width, or %NULL
8607  * @height: (out) (allow-none): return location for the height, or %NULL
8608  *
8609  * Gets the absolute size of an actor in pixels, taking into account the
8610  * scaling factors.
8611  *
8612  * If the actor has a valid allocation, the allocated size will be used.
8613  * If the actor has not a valid allocation then the preferred size will
8614  * be transformed and returned.
8615  *
8616  * If you want the transformed allocation, see
8617  * clutter_actor_get_abs_allocation_vertices() instead.
8618  *
8619  * <note>When the actor (or one of its ancestors) is rotated around the
8620  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8621  * as a generic quadrangle; in that case this function returns the size
8622  * of the smallest rectangle that encapsulates the entire quad. Please
8623  * note that in this case no assumptions can be made about the relative
8624  * position of this envelope to the absolute position of the actor, as
8625  * returned by clutter_actor_get_transformed_position(); if you need this
8626  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8627  * to get the coords of the actual quadrangle.</note>
8628  *
8629  * Since: 0.8
8630  */
8631 void
8632 clutter_actor_get_transformed_size (ClutterActor *self,
8633                                     gfloat       *width,
8634                                     gfloat       *height)
8635 {
8636   ClutterActorPrivate *priv;
8637   ClutterVertex v[4];
8638   gfloat x_min, x_max, y_min, y_max;
8639   gint i;
8640
8641   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8642
8643   priv = self->priv;
8644
8645   /* if the actor hasn't been allocated yet, get the preferred
8646    * size and transform that
8647    */
8648   if (priv->needs_allocation)
8649     {
8650       gfloat natural_width, natural_height;
8651       ClutterActorBox box;
8652
8653       /* Make a fake allocation to transform.
8654        *
8655        * NB: _clutter_actor_transform_and_project_box expects a box in
8656        * the actor's coordinate space... */
8657
8658       box.x1 = 0;
8659       box.y1 = 0;
8660
8661       natural_width = natural_height = 0;
8662       clutter_actor_get_preferred_size (self, NULL, NULL,
8663                                         &natural_width,
8664                                         &natural_height);
8665
8666       box.x2 = natural_width;
8667       box.y2 = natural_height;
8668
8669       _clutter_actor_transform_and_project_box (self, &box, v);
8670     }
8671   else
8672     clutter_actor_get_abs_allocation_vertices (self, v);
8673
8674   x_min = x_max = v[0].x;
8675   y_min = y_max = v[0].y;
8676
8677   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8678     {
8679       if (v[i].x < x_min)
8680         x_min = v[i].x;
8681
8682       if (v[i].x > x_max)
8683         x_max = v[i].x;
8684
8685       if (v[i].y < y_min)
8686         y_min = v[i].y;
8687
8688       if (v[i].y > y_max)
8689         y_max = v[i].y;
8690     }
8691
8692   if (width)
8693     *width  = x_max - x_min;
8694
8695   if (height)
8696     *height = y_max - y_min;
8697 }
8698
8699 /**
8700  * clutter_actor_get_width:
8701  * @self: A #ClutterActor
8702  *
8703  * Retrieves the width of a #ClutterActor.
8704  *
8705  * If the actor has a valid allocation, this function will return the
8706  * width of the allocated area given to the actor.
8707  *
8708  * If the actor does not have a valid allocation, this function will
8709  * return the actor's natural width, that is the preferred width of
8710  * the actor.
8711  *
8712  * If you care whether you get the preferred width or the width that
8713  * has been assigned to the actor, you should probably call a different
8714  * function like clutter_actor_get_allocation_box() to retrieve the
8715  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8716  * preferred width.
8717  *
8718  * If an actor has a fixed width, for instance a width that has been
8719  * assigned using clutter_actor_set_width(), the width returned will
8720  * be the same value.
8721  *
8722  * Return value: the width of the actor, in pixels
8723  */
8724 gfloat
8725 clutter_actor_get_width (ClutterActor *self)
8726 {
8727   ClutterActorPrivate *priv;
8728
8729   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8730
8731   priv = self->priv;
8732
8733   if (priv->needs_allocation)
8734     {
8735       gfloat natural_width = 0;
8736
8737       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8738         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8739       else
8740         {
8741           gfloat natural_height = 0;
8742
8743           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8744           clutter_actor_get_preferred_width (self, natural_height,
8745                                              NULL,
8746                                              &natural_width);
8747         }
8748
8749       return natural_width;
8750     }
8751   else
8752     return priv->allocation.x2 - priv->allocation.x1;
8753 }
8754
8755 /**
8756  * clutter_actor_get_height:
8757  * @self: A #ClutterActor
8758  *
8759  * Retrieves the height of a #ClutterActor.
8760  *
8761  * If the actor has a valid allocation, this function will return the
8762  * height of the allocated area given to the actor.
8763  *
8764  * If the actor does not have a valid allocation, this function will
8765  * return the actor's natural height, that is the preferred height of
8766  * the actor.
8767  *
8768  * If you care whether you get the preferred height or the height that
8769  * has been assigned to the actor, you should probably call a different
8770  * function like clutter_actor_get_allocation_box() to retrieve the
8771  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8772  * preferred height.
8773  *
8774  * If an actor has a fixed height, for instance a height that has been
8775  * assigned using clutter_actor_set_height(), the height returned will
8776  * be the same value.
8777  *
8778  * Return value: the height of the actor, in pixels
8779  */
8780 gfloat
8781 clutter_actor_get_height (ClutterActor *self)
8782 {
8783   ClutterActorPrivate *priv;
8784
8785   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8786
8787   priv = self->priv;
8788
8789   if (priv->needs_allocation)
8790     {
8791       gfloat natural_height = 0;
8792
8793       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8794         {
8795           gfloat natural_width = 0;
8796
8797           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8798           clutter_actor_get_preferred_height (self, natural_width,
8799                                               NULL, &natural_height);
8800         }
8801       else
8802         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8803
8804       return natural_height;
8805     }
8806   else
8807     return priv->allocation.y2 - priv->allocation.y1;
8808 }
8809
8810 /**
8811  * clutter_actor_set_width:
8812  * @self: A #ClutterActor
8813  * @width: Requested new width for the actor, in pixels, or -1
8814  *
8815  * Forces a width on an actor, causing the actor's preferred width
8816  * and height (if any) to be ignored.
8817  *
8818  * If @width is -1 the actor will use its preferred width request
8819  * instead of overriding it, i.e. you can "unset" the width with -1.
8820  *
8821  * This function sets both the minimum and natural size of the actor.
8822  *
8823  * since: 0.2
8824  */
8825 void
8826 clutter_actor_set_width (ClutterActor *self,
8827                          gfloat        width)
8828 {
8829   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8830
8831   g_object_freeze_notify (G_OBJECT (self));
8832
8833   clutter_actor_set_width_internal (self, width);
8834
8835   g_object_thaw_notify (G_OBJECT (self));
8836 }
8837
8838 /**
8839  * clutter_actor_set_height:
8840  * @self: A #ClutterActor
8841  * @height: Requested new height for the actor, in pixels, or -1
8842  *
8843  * Forces a height on an actor, causing the actor's preferred width
8844  * and height (if any) to be ignored.
8845  *
8846  * If @height is -1 the actor will use its preferred height instead of
8847  * overriding it, i.e. you can "unset" the height with -1.
8848  *
8849  * This function sets both the minimum and natural size of the actor.
8850  *
8851  * since: 0.2
8852  */
8853 void
8854 clutter_actor_set_height (ClutterActor *self,
8855                           gfloat        height)
8856 {
8857   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8858
8859   g_object_freeze_notify (G_OBJECT (self));
8860
8861   clutter_actor_set_height_internal (self, height);
8862
8863   g_object_thaw_notify (G_OBJECT (self));
8864 }
8865
8866 /**
8867  * clutter_actor_set_x:
8868  * @self: a #ClutterActor
8869  * @x: the actor's position on the X axis
8870  *
8871  * Sets the actor's X coordinate, relative to its parent, in pixels.
8872  *
8873  * Overrides any layout manager and forces a fixed position for
8874  * the actor.
8875  *
8876  * Since: 0.6
8877  */
8878 void
8879 clutter_actor_set_x (ClutterActor *self,
8880                      gfloat        x)
8881 {
8882   ClutterActorBox old = { 0, };
8883   ClutterActorPrivate *priv;
8884   ClutterLayoutInfo *info;
8885
8886   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8887
8888   priv = self->priv;
8889
8890   info = _clutter_actor_get_layout_info (self);
8891
8892   if (priv->position_set && info->fixed_x == x)
8893     return;
8894
8895   clutter_actor_store_old_geometry (self, &old);
8896
8897   info->fixed_x = x;
8898   clutter_actor_set_fixed_position_set (self, TRUE);
8899
8900   clutter_actor_notify_if_geometry_changed (self, &old);
8901
8902   clutter_actor_queue_relayout (self);
8903 }
8904
8905 /**
8906  * clutter_actor_set_y:
8907  * @self: a #ClutterActor
8908  * @y: the actor's position on the Y axis
8909  *
8910  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8911  *
8912  * Overrides any layout manager and forces a fixed position for
8913  * the actor.
8914  *
8915  * Since: 0.6
8916  */
8917 void
8918 clutter_actor_set_y (ClutterActor *self,
8919                      gfloat        y)
8920 {
8921   ClutterActorBox old = { 0, };
8922   ClutterActorPrivate *priv;
8923   ClutterLayoutInfo *info;
8924
8925   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8926
8927   priv = self->priv;
8928
8929   info = _clutter_actor_get_layout_info (self);
8930
8931   if (priv->position_set && info->fixed_y == y)
8932     return;
8933
8934   clutter_actor_store_old_geometry (self, &old);
8935
8936   info->fixed_y = y;
8937   clutter_actor_set_fixed_position_set (self, TRUE);
8938
8939   clutter_actor_notify_if_geometry_changed (self, &old);
8940
8941   clutter_actor_queue_relayout (self);
8942 }
8943
8944 /**
8945  * clutter_actor_get_x:
8946  * @self: A #ClutterActor
8947  *
8948  * Retrieves the X coordinate of a #ClutterActor.
8949  *
8950  * This function tries to "do what you mean", by returning the
8951  * correct value depending on the actor's state.
8952  *
8953  * If the actor has a valid allocation, this function will return
8954  * the X coordinate of the origin of the allocation box.
8955  *
8956  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8957  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8958  * function will return that coordinate.
8959  *
8960  * If both the allocation and a fixed position are missing, this function
8961  * will return 0.
8962  *
8963  * Return value: the X coordinate, in pixels, ignoring any
8964  *   transformation (i.e. scaling, rotation)
8965  */
8966 gfloat
8967 clutter_actor_get_x (ClutterActor *self)
8968 {
8969   ClutterActorPrivate *priv;
8970
8971   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8972
8973   priv = self->priv;
8974
8975   if (priv->needs_allocation)
8976     {
8977       if (priv->position_set)
8978         {
8979           const ClutterLayoutInfo *info;
8980
8981           info = _clutter_actor_get_layout_info_or_defaults (self);
8982
8983           return info->fixed_x;
8984         }
8985       else
8986         return 0;
8987     }
8988   else
8989     return priv->allocation.x1;
8990 }
8991
8992 /**
8993  * clutter_actor_get_y:
8994  * @self: A #ClutterActor
8995  *
8996  * Retrieves the Y coordinate of a #ClutterActor.
8997  *
8998  * This function tries to "do what you mean", by returning the
8999  * correct value depending on the actor's state.
9000  *
9001  * If the actor has a valid allocation, this function will return
9002  * the Y coordinate of the origin of the allocation box.
9003  *
9004  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9005  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9006  * function will return that coordinate.
9007  *
9008  * If both the allocation and a fixed position are missing, this function
9009  * will return 0.
9010  *
9011  * Return value: the Y coordinate, in pixels, ignoring any
9012  *   transformation (i.e. scaling, rotation)
9013  */
9014 gfloat
9015 clutter_actor_get_y (ClutterActor *self)
9016 {
9017   ClutterActorPrivate *priv;
9018
9019   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9020
9021   priv = self->priv;
9022
9023   if (priv->needs_allocation)
9024     {
9025       if (priv->position_set)
9026         {
9027           const ClutterLayoutInfo *info;
9028
9029           info = _clutter_actor_get_layout_info_or_defaults (self);
9030
9031           return info->fixed_y;
9032         }
9033       else
9034         return 0;
9035     }
9036   else
9037     return priv->allocation.y1;
9038 }
9039
9040 /**
9041  * clutter_actor_set_scale:
9042  * @self: A #ClutterActor
9043  * @scale_x: double factor to scale actor by horizontally.
9044  * @scale_y: double factor to scale actor by vertically.
9045  *
9046  * Scales an actor with the given factors. The scaling is relative to
9047  * the scale center and the anchor point. The scale center is
9048  * unchanged by this function and defaults to 0,0.
9049  *
9050  * Since: 0.2
9051  */
9052 void
9053 clutter_actor_set_scale (ClutterActor *self,
9054                          gdouble       scale_x,
9055                          gdouble       scale_y)
9056 {
9057   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9058
9059   g_object_freeze_notify (G_OBJECT (self));
9060
9061   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9062   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9063
9064   g_object_thaw_notify (G_OBJECT (self));
9065 }
9066
9067 /**
9068  * clutter_actor_set_scale_full:
9069  * @self: A #ClutterActor
9070  * @scale_x: double factor to scale actor by horizontally.
9071  * @scale_y: double factor to scale actor by vertically.
9072  * @center_x: X coordinate of the center of the scale.
9073  * @center_y: Y coordinate of the center of the scale
9074  *
9075  * Scales an actor with the given factors around the given center
9076  * point. The center point is specified in pixels relative to the
9077  * anchor point (usually the top left corner of the actor).
9078  *
9079  * Since: 1.0
9080  */
9081 void
9082 clutter_actor_set_scale_full (ClutterActor *self,
9083                               gdouble       scale_x,
9084                               gdouble       scale_y,
9085                               gfloat        center_x,
9086                               gfloat        center_y)
9087 {
9088   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9089
9090   g_object_freeze_notify (G_OBJECT (self));
9091
9092   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9093   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9094   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9095   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9096
9097   g_object_thaw_notify (G_OBJECT (self));
9098 }
9099
9100 /**
9101  * clutter_actor_set_scale_with_gravity:
9102  * @self: A #ClutterActor
9103  * @scale_x: double factor to scale actor by horizontally.
9104  * @scale_y: double factor to scale actor by vertically.
9105  * @gravity: the location of the scale center expressed as a compass
9106  * direction.
9107  *
9108  * Scales an actor with the given factors around the given
9109  * center point. The center point is specified as one of the compass
9110  * directions in #ClutterGravity. For example, setting it to north
9111  * will cause the top of the actor to remain unchanged and the rest of
9112  * the actor to expand left, right and downwards.
9113  *
9114  * Since: 1.0
9115  */
9116 void
9117 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9118                                       gdouble         scale_x,
9119                                       gdouble         scale_y,
9120                                       ClutterGravity  gravity)
9121 {
9122   ClutterTransformInfo *info;
9123   GObject *obj;
9124
9125   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9126
9127   obj = G_OBJECT (self);
9128
9129   g_object_freeze_notify (obj);
9130
9131   info = _clutter_actor_get_transform_info (self);
9132   info->scale_x = scale_x;
9133   info->scale_y = scale_y;
9134
9135   if (gravity == CLUTTER_GRAVITY_NONE)
9136     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9137   else
9138     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9139
9140   self->priv->transform_valid = FALSE;
9141
9142   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9143   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9144   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9145   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9146   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9147
9148   clutter_actor_queue_redraw (self);
9149
9150   g_object_thaw_notify (obj);
9151 }
9152
9153 /**
9154  * clutter_actor_get_scale:
9155  * @self: A #ClutterActor
9156  * @scale_x: (out) (allow-none): Location to store horizonal
9157  *   scale factor, or %NULL.
9158  * @scale_y: (out) (allow-none): Location to store vertical
9159  *   scale factor, or %NULL.
9160  *
9161  * Retrieves an actors scale factors.
9162  *
9163  * Since: 0.2
9164  */
9165 void
9166 clutter_actor_get_scale (ClutterActor *self,
9167                          gdouble      *scale_x,
9168                          gdouble      *scale_y)
9169 {
9170   const ClutterTransformInfo *info;
9171
9172   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9173
9174   info = _clutter_actor_get_transform_info_or_defaults (self);
9175
9176   if (scale_x)
9177     *scale_x = info->scale_x;
9178
9179   if (scale_y)
9180     *scale_y = info->scale_y;
9181 }
9182
9183 /**
9184  * clutter_actor_get_scale_center:
9185  * @self: A #ClutterActor
9186  * @center_x: (out) (allow-none): Location to store the X position
9187  *   of the scale center, or %NULL.
9188  * @center_y: (out) (allow-none): Location to store the Y position
9189  *   of the scale center, or %NULL.
9190  *
9191  * Retrieves the scale center coordinate in pixels relative to the top
9192  * left corner of the actor. If the scale center was specified using a
9193  * #ClutterGravity this will calculate the pixel offset using the
9194  * current size of the actor.
9195  *
9196  * Since: 1.0
9197  */
9198 void
9199 clutter_actor_get_scale_center (ClutterActor *self,
9200                                 gfloat       *center_x,
9201                                 gfloat       *center_y)
9202 {
9203   const ClutterTransformInfo *info;
9204
9205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9206
9207   info = _clutter_actor_get_transform_info_or_defaults (self);
9208
9209   clutter_anchor_coord_get_units (self, &info->scale_center,
9210                                   center_x,
9211                                   center_y,
9212                                   NULL);
9213 }
9214
9215 /**
9216  * clutter_actor_get_scale_gravity:
9217  * @self: A #ClutterActor
9218  *
9219  * Retrieves the scale center as a compass direction. If the scale
9220  * center was specified in pixels or units this will return
9221  * %CLUTTER_GRAVITY_NONE.
9222  *
9223  * Return value: the scale gravity
9224  *
9225  * Since: 1.0
9226  */
9227 ClutterGravity
9228 clutter_actor_get_scale_gravity (ClutterActor *self)
9229 {
9230   const ClutterTransformInfo *info;
9231
9232   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9233
9234   info = _clutter_actor_get_transform_info_or_defaults (self);
9235
9236   return clutter_anchor_coord_get_gravity (&info->scale_center);
9237 }
9238
9239 /**
9240  * clutter_actor_set_opacity:
9241  * @self: A #ClutterActor
9242  * @opacity: New opacity value for the actor.
9243  *
9244  * Sets the actor's opacity, with zero being completely transparent and
9245  * 255 (0xff) being fully opaque.
9246  */
9247 void
9248 clutter_actor_set_opacity (ClutterActor *self,
9249                            guint8        opacity)
9250 {
9251   ClutterActorPrivate *priv;
9252
9253   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9254
9255   priv = self->priv;
9256
9257   if (priv->opacity != opacity)
9258     {
9259       priv->opacity = opacity;
9260
9261       /* Queue a redraw from the flatten effect so that it can use
9262          its cached image if available instead of having to redraw the
9263          actual actor. If it doesn't end up using the FBO then the
9264          effect is still able to continue the paint anyway. If there
9265          is no flatten effect yet then this is equivalent to queueing
9266          a full redraw */
9267       _clutter_actor_queue_redraw_full (self,
9268                                         0, /* flags */
9269                                         NULL, /* clip */
9270                                         priv->flatten_effect);
9271
9272       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9273     }
9274 }
9275
9276 /*
9277  * clutter_actor_get_paint_opacity_internal:
9278  * @self: a #ClutterActor
9279  *
9280  * Retrieves the absolute opacity of the actor, as it appears on the stage
9281  *
9282  * This function does not do type checks
9283  *
9284  * Return value: the absolute opacity of the actor
9285  */
9286 static guint8
9287 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9288 {
9289   ClutterActorPrivate *priv = self->priv;
9290   ClutterActor *parent;
9291
9292   /* override the top-level opacity to always be 255; even in
9293    * case of ClutterStage:use-alpha being TRUE we want the rest
9294    * of the scene to be painted
9295    */
9296   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9297     return 255;
9298
9299   if (priv->opacity_override >= 0)
9300     return priv->opacity_override;
9301
9302   parent = priv->parent;
9303
9304   /* Factor in the actual actors opacity with parents */
9305   if (parent != NULL)
9306     {
9307       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9308
9309       if (opacity != 0xff)
9310         return (opacity * priv->opacity) / 0xff;
9311     }
9312
9313   return priv->opacity;
9314
9315 }
9316
9317 /**
9318  * clutter_actor_get_paint_opacity:
9319  * @self: A #ClutterActor
9320  *
9321  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9322  *
9323  * This function traverses the hierarchy chain and composites the opacity of
9324  * the actor with that of its parents.
9325  *
9326  * This function is intended for subclasses to use in the paint virtual
9327  * function, to paint themselves with the correct opacity.
9328  *
9329  * Return value: The actor opacity value.
9330  *
9331  * Since: 0.8
9332  */
9333 guint8
9334 clutter_actor_get_paint_opacity (ClutterActor *self)
9335 {
9336   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9337
9338   return clutter_actor_get_paint_opacity_internal (self);
9339 }
9340
9341 /**
9342  * clutter_actor_get_opacity:
9343  * @self: a #ClutterActor
9344  *
9345  * Retrieves the opacity value of an actor, as set by
9346  * clutter_actor_set_opacity().
9347  *
9348  * For retrieving the absolute opacity of the actor inside a paint
9349  * virtual function, see clutter_actor_get_paint_opacity().
9350  *
9351  * Return value: the opacity of the actor
9352  */
9353 guint8
9354 clutter_actor_get_opacity (ClutterActor *self)
9355 {
9356   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9357
9358   return self->priv->opacity;
9359 }
9360
9361 /**
9362  * clutter_actor_set_offscreen_redirect:
9363  * @self: A #ClutterActor
9364  * @redirect: New offscreen redirect flags for the actor.
9365  *
9366  * Defines the circumstances where the actor should be redirected into
9367  * an offscreen image. The offscreen image is used to flatten the
9368  * actor into a single image while painting for two main reasons.
9369  * Firstly, when the actor is painted a second time without any of its
9370  * contents changing it can simply repaint the cached image without
9371  * descending further down the actor hierarchy. Secondly, it will make
9372  * the opacity look correct even if there are overlapping primitives
9373  * in the actor.
9374  *
9375  * Caching the actor could in some cases be a performance win and in
9376  * some cases be a performance lose so it is important to determine
9377  * which value is right for an actor before modifying this value. For
9378  * example, there is never any reason to flatten an actor that is just
9379  * a single texture (such as a #ClutterTexture) because it is
9380  * effectively already cached in an image so the offscreen would be
9381  * redundant. Also if the actor contains primitives that are far apart
9382  * with a large transparent area in the middle (such as a large
9383  * CluterGroup with a small actor in the top left and a small actor in
9384  * the bottom right) then the cached image will contain the entire
9385  * image of the large area and the paint will waste time blending all
9386  * of the transparent pixels in the middle.
9387  *
9388  * The default method of implementing opacity on a container simply
9389  * forwards on the opacity to all of the children. If the children are
9390  * overlapping then it will appear as if they are two separate glassy
9391  * objects and there will be a break in the color where they
9392  * overlap. By redirecting to an offscreen buffer it will be as if the
9393  * two opaque objects are combined into one and then made transparent
9394  * which is usually what is expected.
9395  *
9396  * The image below demonstrates the difference between redirecting and
9397  * not. The image shows two Clutter groups, each containing a red and
9398  * a green rectangle which overlap. The opacity on the group is set to
9399  * 128 (which is 50%). When the offscreen redirect is not used, the
9400  * red rectangle can be seen through the blue rectangle as if the two
9401  * rectangles were separately transparent. When the redirect is used
9402  * the group as a whole is transparent instead so the red rectangle is
9403  * not visible where they overlap.
9404  *
9405  * <figure id="offscreen-redirect">
9406  *   <title>Sample of using an offscreen redirect for transparency</title>
9407  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9408  * </figure>
9409  *
9410  * The default value for this property is 0, so we effectively will
9411  * never redirect an actor offscreen by default. This means that there
9412  * are times that transparent actors may look glassy as described
9413  * above. The reason this is the default is because there is a
9414  * performance trade off between quality and performance here. In many
9415  * cases the default form of glassy opacity looks good enough, but if
9416  * it's not you will need to set the
9417  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9418  * redirection for opacity.
9419  *
9420  * Custom actors that don't contain any overlapping primitives are
9421  * recommended to override the has_overlaps() virtual to return %FALSE
9422  * for maximum efficiency.
9423  *
9424  * Since: 1.8
9425  */
9426 void
9427 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9428                                       ClutterOffscreenRedirect redirect)
9429 {
9430   ClutterActorPrivate *priv;
9431
9432   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9433
9434   priv = self->priv;
9435
9436   if (priv->offscreen_redirect != redirect)
9437     {
9438       priv->offscreen_redirect = redirect;
9439
9440       /* Queue a redraw from the effect so that it can use its cached
9441          image if available instead of having to redraw the actual
9442          actor. If it doesn't end up using the FBO then the effect is
9443          still able to continue the paint anyway. If there is no
9444          effect then this is equivalent to queuing a full redraw */
9445       _clutter_actor_queue_redraw_full (self,
9446                                         0, /* flags */
9447                                         NULL, /* clip */
9448                                         priv->flatten_effect);
9449
9450       g_object_notify_by_pspec (G_OBJECT (self),
9451                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9452     }
9453 }
9454
9455 /**
9456  * clutter_actor_get_offscreen_redirect:
9457  * @self: a #ClutterActor
9458  *
9459  * Retrieves whether to redirect the actor to an offscreen buffer, as
9460  * set by clutter_actor_set_offscreen_redirect().
9461  *
9462  * Return value: the value of the offscreen-redirect property of the actor
9463  *
9464  * Since: 1.8
9465  */
9466 ClutterOffscreenRedirect
9467 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9468 {
9469   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9470
9471   return self->priv->offscreen_redirect;
9472 }
9473
9474 /**
9475  * clutter_actor_set_name:
9476  * @self: A #ClutterActor
9477  * @name: Textual tag to apply to actor
9478  *
9479  * Sets the given name to @self. The name can be used to identify
9480  * a #ClutterActor.
9481  */
9482 void
9483 clutter_actor_set_name (ClutterActor *self,
9484                         const gchar  *name)
9485 {
9486   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9487
9488   g_free (self->priv->name);
9489   self->priv->name = g_strdup (name);
9490
9491   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9492 }
9493
9494 /**
9495  * clutter_actor_get_name:
9496  * @self: A #ClutterActor
9497  *
9498  * Retrieves the name of @self.
9499  *
9500  * Return value: the name of the actor, or %NULL. The returned string is
9501  *   owned by the actor and should not be modified or freed.
9502  */
9503 const gchar *
9504 clutter_actor_get_name (ClutterActor *self)
9505 {
9506   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9507
9508   return self->priv->name;
9509 }
9510
9511 /**
9512  * clutter_actor_get_gid:
9513  * @self: A #ClutterActor
9514  *
9515  * Retrieves the unique id for @self.
9516  *
9517  * Return value: Globally unique value for this object instance.
9518  *
9519  * Since: 0.6
9520  *
9521  * Deprecated: 1.8: The id is not used any longer.
9522  */
9523 guint32
9524 clutter_actor_get_gid (ClutterActor *self)
9525 {
9526   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9527
9528   return self->priv->id;
9529 }
9530
9531 /**
9532  * clutter_actor_set_depth:
9533  * @self: a #ClutterActor
9534  * @depth: Z co-ord
9535  *
9536  * Sets the Z coordinate of @self to @depth.
9537  *
9538  * The unit used by @depth is dependant on the perspective setup. See
9539  * also clutter_stage_set_perspective().
9540  */
9541 void
9542 clutter_actor_set_depth (ClutterActor *self,
9543                          gfloat        depth)
9544 {
9545   ClutterActorPrivate *priv;
9546
9547   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9548
9549   priv = self->priv;
9550
9551   if (priv->z != depth)
9552     {
9553       /* Sets Z value - XXX 2.0: should we invert? */
9554       priv->z = depth;
9555
9556       priv->transform_valid = FALSE;
9557
9558       /* FIXME - remove this crap; sadly, there are still containers
9559        * in Clutter that depend on this utter brain damage
9560        */
9561       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9562
9563       clutter_actor_queue_redraw (self);
9564
9565       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9566     }
9567 }
9568
9569 /**
9570  * clutter_actor_get_depth:
9571  * @self: a #ClutterActor
9572  *
9573  * Retrieves the depth of @self.
9574  *
9575  * Return value: the depth of the actor
9576  */
9577 gfloat
9578 clutter_actor_get_depth (ClutterActor *self)
9579 {
9580   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9581
9582   return self->priv->z;
9583 }
9584
9585 /**
9586  * clutter_actor_set_rotation:
9587  * @self: a #ClutterActor
9588  * @axis: the axis of rotation
9589  * @angle: the angle of rotation
9590  * @x: X coordinate of the rotation center
9591  * @y: Y coordinate of the rotation center
9592  * @z: Z coordinate of the rotation center
9593  *
9594  * Sets the rotation angle of @self around the given axis.
9595  *
9596  * The rotation center coordinates used depend on the value of @axis:
9597  * <itemizedlist>
9598  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9599  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9600  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9601  * </itemizedlist>
9602  *
9603  * The rotation coordinates are relative to the anchor point of the
9604  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9605  * point is set, the upper left corner is assumed as the origin.
9606  *
9607  * Since: 0.8
9608  */
9609 void
9610 clutter_actor_set_rotation (ClutterActor      *self,
9611                             ClutterRotateAxis  axis,
9612                             gdouble            angle,
9613                             gfloat             x,
9614                             gfloat             y,
9615                             gfloat             z)
9616 {
9617   ClutterVertex v;
9618
9619   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9620
9621   v.x = x;
9622   v.y = y;
9623   v.z = z;
9624
9625   g_object_freeze_notify (G_OBJECT (self));
9626
9627   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9628   clutter_actor_set_rotation_center_internal (self, axis, &v);
9629
9630   g_object_thaw_notify (G_OBJECT (self));
9631 }
9632
9633 /**
9634  * clutter_actor_set_z_rotation_from_gravity:
9635  * @self: a #ClutterActor
9636  * @angle: the angle of rotation
9637  * @gravity: the center point of the rotation
9638  *
9639  * Sets the rotation angle of @self around the Z axis using the center
9640  * point specified as a compass point. For example to rotate such that
9641  * the center of the actor remains static you can use
9642  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9643  * will move accordingly.
9644  *
9645  * Since: 1.0
9646  */
9647 void
9648 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9649                                            gdouble         angle,
9650                                            ClutterGravity  gravity)
9651 {
9652   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9653
9654   if (gravity == CLUTTER_GRAVITY_NONE)
9655     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9656   else
9657     {
9658       GObject *obj = G_OBJECT (self);
9659       ClutterTransformInfo *info;
9660
9661       info = _clutter_actor_get_transform_info (self);
9662
9663       g_object_freeze_notify (obj);
9664
9665       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9666
9667       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9668       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9669       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9670
9671       g_object_thaw_notify (obj);
9672     }
9673 }
9674
9675 /**
9676  * clutter_actor_get_rotation:
9677  * @self: a #ClutterActor
9678  * @axis: the axis of rotation
9679  * @x: (out): return value for the X coordinate of the center of rotation
9680  * @y: (out): return value for the Y coordinate of the center of rotation
9681  * @z: (out): return value for the Z coordinate of the center of rotation
9682  *
9683  * Retrieves the angle and center of rotation on the given axis,
9684  * set using clutter_actor_set_rotation().
9685  *
9686  * Return value: the angle of rotation
9687  *
9688  * Since: 0.8
9689  */
9690 gdouble
9691 clutter_actor_get_rotation (ClutterActor      *self,
9692                             ClutterRotateAxis  axis,
9693                             gfloat            *x,
9694                             gfloat            *y,
9695                             gfloat            *z)
9696 {
9697   const ClutterTransformInfo *info;
9698   const AnchorCoord *anchor_coord;
9699   gdouble retval = 0;
9700
9701   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9702
9703   info = _clutter_actor_get_transform_info_or_defaults (self);
9704
9705   switch (axis)
9706     {
9707     case CLUTTER_X_AXIS:
9708       anchor_coord = &info->rx_center;
9709       retval = info->rx_angle;
9710       break;
9711
9712     case CLUTTER_Y_AXIS:
9713       anchor_coord = &info->ry_center;
9714       retval = info->ry_angle;
9715       break;
9716
9717     case CLUTTER_Z_AXIS:
9718       anchor_coord = &info->rz_center;
9719       retval = info->rz_angle;
9720       break;
9721
9722     default:
9723       anchor_coord = NULL;
9724       retval = 0.0;
9725       break;
9726     }
9727
9728   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9729
9730   return retval;
9731 }
9732
9733 /**
9734  * clutter_actor_get_z_rotation_gravity:
9735  * @self: A #ClutterActor
9736  *
9737  * Retrieves the center for the rotation around the Z axis as a
9738  * compass direction. If the center was specified in pixels or units
9739  * this will return %CLUTTER_GRAVITY_NONE.
9740  *
9741  * Return value: the Z rotation center
9742  *
9743  * Since: 1.0
9744  */
9745 ClutterGravity
9746 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9747 {
9748   const ClutterTransformInfo *info;
9749
9750   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9751
9752   info = _clutter_actor_get_transform_info_or_defaults (self);
9753
9754   return clutter_anchor_coord_get_gravity (&info->rz_center);
9755 }
9756
9757 /**
9758  * clutter_actor_set_clip:
9759  * @self: A #ClutterActor
9760  * @xoff: X offset of the clip rectangle
9761  * @yoff: Y offset of the clip rectangle
9762  * @width: Width of the clip rectangle
9763  * @height: Height of the clip rectangle
9764  *
9765  * Sets clip area for @self. The clip area is always computed from the
9766  * upper left corner of the actor, even if the anchor point is set
9767  * otherwise.
9768  *
9769  * Since: 0.6
9770  */
9771 void
9772 clutter_actor_set_clip (ClutterActor *self,
9773                         gfloat        xoff,
9774                         gfloat        yoff,
9775                         gfloat        width,
9776                         gfloat        height)
9777 {
9778   ClutterActorPrivate *priv;
9779
9780   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9781
9782   priv = self->priv;
9783
9784   if (priv->has_clip &&
9785       priv->clip.x == xoff &&
9786       priv->clip.y == yoff &&
9787       priv->clip.width == width &&
9788       priv->clip.height == height)
9789     return;
9790
9791   priv->clip.x = xoff;
9792   priv->clip.y = yoff;
9793   priv->clip.width = width;
9794   priv->clip.height = height;
9795
9796   priv->has_clip = TRUE;
9797
9798   clutter_actor_queue_redraw (self);
9799
9800   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9801   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9802 }
9803
9804 /**
9805  * clutter_actor_remove_clip:
9806  * @self: A #ClutterActor
9807  *
9808  * Removes clip area from @self.
9809  */
9810 void
9811 clutter_actor_remove_clip (ClutterActor *self)
9812 {
9813   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9814
9815   if (!self->priv->has_clip)
9816     return;
9817
9818   self->priv->has_clip = FALSE;
9819
9820   clutter_actor_queue_redraw (self);
9821
9822   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9823 }
9824
9825 /**
9826  * clutter_actor_has_clip:
9827  * @self: a #ClutterActor
9828  *
9829  * Determines whether the actor has a clip area set or not.
9830  *
9831  * Return value: %TRUE if the actor has a clip area set.
9832  *
9833  * Since: 0.1.1
9834  */
9835 gboolean
9836 clutter_actor_has_clip (ClutterActor *self)
9837 {
9838   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9839
9840   return self->priv->has_clip;
9841 }
9842
9843 /**
9844  * clutter_actor_get_clip:
9845  * @self: a #ClutterActor
9846  * @xoff: (out) (allow-none): return location for the X offset of
9847  *   the clip rectangle, or %NULL
9848  * @yoff: (out) (allow-none): return location for the Y offset of
9849  *   the clip rectangle, or %NULL
9850  * @width: (out) (allow-none): return location for the width of
9851  *   the clip rectangle, or %NULL
9852  * @height: (out) (allow-none): return location for the height of
9853  *   the clip rectangle, or %NULL
9854  *
9855  * Gets the clip area for @self, if any is set
9856  *
9857  * Since: 0.6
9858  */
9859 void
9860 clutter_actor_get_clip (ClutterActor *self,
9861                         gfloat       *xoff,
9862                         gfloat       *yoff,
9863                         gfloat       *width,
9864                         gfloat       *height)
9865 {
9866   ClutterActorPrivate *priv;
9867
9868   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9869
9870   priv = self->priv;
9871
9872   if (!priv->has_clip)
9873     return;
9874
9875   if (xoff != NULL)
9876     *xoff = priv->clip.x;
9877
9878   if (yoff != NULL)
9879     *yoff = priv->clip.y;
9880
9881   if (width != NULL)
9882     *width = priv->clip.width;
9883
9884   if (height != NULL)
9885     *height = priv->clip.height;
9886 }
9887
9888 /**
9889  * clutter_actor_get_children:
9890  * @self: a #ClutterActor
9891  *
9892  * Retrieves the list of children of @self.
9893  *
9894  * Return value: (transfer container) (element-type ClutterActor): A newly
9895  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9896  *   done.
9897  *
9898  * Since: 1.10
9899  */
9900 GList *
9901 clutter_actor_get_children (ClutterActor *self)
9902 {
9903   ClutterActor *iter;
9904   GList *res;
9905
9906   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9907
9908   /* we walk the list backward so that we can use prepend(),
9909    * which is O(1)
9910    */
9911   for (iter = self->priv->last_child, res = NULL;
9912        iter != NULL;
9913        iter = iter->priv->prev_sibling)
9914     {
9915       res = g_list_prepend (res, iter);
9916     }
9917
9918   return res;
9919 }
9920
9921 /*< private >
9922  * insert_child_at_depth:
9923  * @self: a #ClutterActor
9924  * @child: a #ClutterActor
9925  *
9926  * Inserts @child inside the list of children held by @self, using
9927  * the depth as the insertion criteria.
9928  *
9929  * This sadly makes the insertion not O(1), but we can keep the
9930  * list sorted so that the painters algorithm we use for painting
9931  * the children will work correctly.
9932  */
9933 static void
9934 insert_child_at_depth (ClutterActor *self,
9935                        ClutterActor *child,
9936                        gpointer      dummy G_GNUC_UNUSED)
9937 {
9938   ClutterActor *iter;
9939
9940   child->priv->parent = self;
9941
9942   /* special-case the first child */
9943   if (self->priv->n_children == 0)
9944     {
9945       self->priv->first_child = child;
9946       self->priv->last_child = child;
9947
9948       child->priv->next_sibling = NULL;
9949       child->priv->prev_sibling = NULL;
9950
9951       return;
9952     }
9953
9954   /* Find the right place to insert the child so that it will still be
9955      sorted and the child will be after all of the actors at the same
9956      dept */
9957   for (iter = self->priv->first_child;
9958        iter != NULL;
9959        iter = iter->priv->next_sibling)
9960     {
9961       if (iter->priv->z > child->priv->z)
9962         break;
9963     }
9964
9965   if (iter != NULL)
9966     {
9967       ClutterActor *tmp = iter->priv->prev_sibling;
9968
9969       if (tmp != NULL)
9970         tmp->priv->next_sibling = child;
9971
9972       /* Insert the node before the found one */
9973       child->priv->prev_sibling = iter->priv->prev_sibling;
9974       child->priv->next_sibling = iter;
9975       iter->priv->prev_sibling = child;
9976     }
9977   else
9978     {
9979       ClutterActor *tmp = self->priv->last_child;
9980
9981       if (tmp != NULL)
9982         tmp->priv->next_sibling = child;
9983
9984       /* insert the node at the end of the list */
9985       child->priv->prev_sibling = self->priv->last_child;
9986       child->priv->next_sibling = NULL;
9987     }
9988
9989   if (child->priv->prev_sibling == NULL)
9990     self->priv->first_child = child;
9991
9992   if (child->priv->next_sibling == NULL)
9993     self->priv->last_child = child;
9994 }
9995
9996 static void
9997 insert_child_at_index (ClutterActor *self,
9998                        ClutterActor *child,
9999                        gpointer      data_)
10000 {
10001   gint index_ = GPOINTER_TO_INT (data_);
10002
10003   child->priv->parent = self;
10004
10005   if (index_ == 0)
10006     {
10007       ClutterActor *tmp = self->priv->first_child;
10008
10009       if (tmp != NULL)
10010         tmp->priv->prev_sibling = child;
10011
10012       child->priv->prev_sibling = NULL;
10013       child->priv->next_sibling = tmp;
10014     }
10015   else if (index_ < 0 || index_ >= self->priv->n_children)
10016     {
10017       ClutterActor *tmp = self->priv->last_child;
10018
10019       if (tmp != NULL)
10020         tmp->priv->next_sibling = child;
10021
10022       child->priv->prev_sibling = tmp;
10023       child->priv->next_sibling = NULL;
10024     }
10025   else
10026     {
10027       ClutterActor *iter;
10028       int i;
10029
10030       for (iter = self->priv->first_child, i = 0;
10031            iter != NULL;
10032            iter = iter->priv->next_sibling, i += 1)
10033         {
10034           if (index_ == i)
10035             {
10036               ClutterActor *tmp = iter->priv->prev_sibling;
10037
10038               child->priv->prev_sibling = tmp;
10039               child->priv->next_sibling = iter;
10040
10041               iter->priv->prev_sibling = child;
10042
10043               if (tmp != NULL)
10044                 tmp->priv->next_sibling = child;
10045
10046               break;
10047             }
10048         }
10049     }
10050
10051   if (child->priv->prev_sibling == NULL)
10052     self->priv->first_child = child;
10053
10054   if (child->priv->next_sibling == NULL)
10055     self->priv->last_child = child;
10056 }
10057
10058 static void
10059 insert_child_above (ClutterActor *self,
10060                     ClutterActor *child,
10061                     gpointer      data)
10062 {
10063   ClutterActor *sibling = data;
10064
10065   child->priv->parent = self;
10066
10067   if (sibling == NULL)
10068     sibling = self->priv->last_child;
10069
10070   child->priv->prev_sibling = sibling;
10071
10072   if (sibling != NULL)
10073     {
10074       ClutterActor *tmp = sibling->priv->next_sibling;
10075
10076       child->priv->next_sibling = tmp;
10077
10078       if (tmp != NULL)
10079         tmp->priv->prev_sibling = child;
10080
10081       sibling->priv->next_sibling = child;
10082     }
10083   else
10084     child->priv->next_sibling = NULL;
10085
10086   if (child->priv->prev_sibling == NULL)
10087     self->priv->first_child = child;
10088
10089   if (child->priv->next_sibling == NULL)
10090     self->priv->last_child = child;
10091 }
10092
10093 static void
10094 insert_child_below (ClutterActor *self,
10095                     ClutterActor *child,
10096                     gpointer      data)
10097 {
10098   ClutterActor *sibling = data;
10099
10100   child->priv->parent = self;
10101
10102   if (sibling == NULL)
10103     sibling = self->priv->first_child;
10104
10105   child->priv->next_sibling = sibling;
10106
10107   if (sibling != NULL)
10108     {
10109       ClutterActor *tmp = sibling->priv->prev_sibling;
10110
10111       child->priv->prev_sibling = tmp;
10112
10113       if (tmp != NULL)
10114         tmp->priv->next_sibling = child;
10115
10116       sibling->priv->prev_sibling = child;
10117     }
10118   else
10119     child->priv->prev_sibling = NULL;
10120
10121   if (child->priv->prev_sibling == NULL)
10122     self->priv->first_child = child;
10123
10124   if (child->priv->next_sibling == NULL)
10125     self->priv->last_child = child;
10126 }
10127
10128 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10129                                            ClutterActor *child,
10130                                            gpointer      data);
10131
10132 typedef enum {
10133   ADD_CHILD_CREATE_META       = 1 << 0,
10134   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10135   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10136   ADD_CHILD_CHECK_STATE       = 1 << 3,
10137   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10138
10139   /* default flags for public API */
10140   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10141                                ADD_CHILD_EMIT_PARENT_SET |
10142                                ADD_CHILD_EMIT_ACTOR_ADDED |
10143                                ADD_CHILD_CHECK_STATE |
10144                                ADD_CHILD_NOTIFY_FIRST_LAST,
10145
10146   /* flags for legacy/deprecated API */
10147   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10148                                ADD_CHILD_CHECK_STATE |
10149                                ADD_CHILD_NOTIFY_FIRST_LAST
10150 } ClutterActorAddChildFlags;
10151
10152 /*< private >
10153  * clutter_actor_add_child_internal:
10154  * @self: a #ClutterActor
10155  * @child: a #ClutterActor
10156  * @flags: control flags for actions
10157  * @add_func: delegate function
10158  * @data: (closure): data to pass to @add_func
10159  *
10160  * Adds @child to the list of children of @self.
10161  *
10162  * The actual insertion inside the list is delegated to @add_func: this
10163  * function will just set up the state, perform basic checks, and emit
10164  * signals.
10165  *
10166  * The @flags argument is used to perform additional operations.
10167  */
10168 static inline void
10169 clutter_actor_add_child_internal (ClutterActor              *self,
10170                                   ClutterActor              *child,
10171                                   ClutterActorAddChildFlags  flags,
10172                                   ClutterActorAddChildFunc   add_func,
10173                                   gpointer                   data)
10174 {
10175   ClutterTextDirection text_dir;
10176   gboolean create_meta;
10177   gboolean emit_parent_set, emit_actor_added;
10178   gboolean check_state;
10179   gboolean notify_first_last;
10180   ClutterActor *old_first_child, *old_last_child;
10181
10182   if (child->priv->parent != NULL)
10183     {
10184       g_warning ("Cannot set a parent on an actor which has a parent. "
10185                  "You must use clutter_actor_remove_child() first.");
10186       return;
10187     }
10188
10189   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10190     {
10191       g_warning ("Cannot set a parent on a toplevel actor\n");
10192       return;
10193     }
10194
10195   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10196     {
10197       g_warning ("Cannot set a parent currently being destroyed");
10198       return;
10199     }
10200
10201   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10202   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10203   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10204   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10205   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10206
10207   old_first_child = self->priv->first_child;
10208   old_last_child = self->priv->last_child;
10209
10210   g_object_freeze_notify (G_OBJECT (self));
10211
10212   if (create_meta)
10213     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10214
10215   g_object_ref_sink (child);
10216   child->priv->parent = NULL;
10217   child->priv->next_sibling = NULL;
10218   child->priv->prev_sibling = NULL;
10219
10220   /* delegate the actual insertion */
10221   add_func (self, child, data);
10222
10223   g_assert (child->priv->parent == self);
10224
10225   self->priv->n_children += 1;
10226
10227   self->priv->age += 1;
10228
10229   /* if push_internal() has been called then we automatically set
10230    * the flag on the actor
10231    */
10232   if (self->priv->internal_child)
10233     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10234
10235   /* clutter_actor_reparent() will emit ::parent-set for us */
10236   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10237     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10238
10239   if (check_state)
10240     {
10241       /* If parent is mapped or realized, we need to also be mapped or
10242        * realized once we're inside the parent.
10243        */
10244       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10245
10246       /* propagate the parent's text direction to the child */
10247       text_dir = clutter_actor_get_text_direction (self);
10248       clutter_actor_set_text_direction (child, text_dir);
10249     }
10250
10251   if (child->priv->show_on_set_parent)
10252     clutter_actor_show (child);
10253
10254   if (CLUTTER_ACTOR_IS_MAPPED (child))
10255     clutter_actor_queue_redraw (child);
10256
10257   /* maintain the invariant that if an actor needs layout,
10258    * its parents do as well
10259    */
10260   if (child->priv->needs_width_request ||
10261       child->priv->needs_height_request ||
10262       child->priv->needs_allocation)
10263     {
10264       /* we work around the short-circuiting we do
10265        * in clutter_actor_queue_relayout() since we
10266        * want to force a relayout
10267        */
10268       child->priv->needs_width_request = TRUE;
10269       child->priv->needs_height_request = TRUE;
10270       child->priv->needs_allocation = TRUE;
10271
10272       clutter_actor_queue_relayout (child->priv->parent);
10273     }
10274
10275   if (emit_actor_added)
10276     g_signal_emit_by_name (self, "actor-added", child);
10277
10278   if (notify_first_last)
10279     {
10280       if (old_first_child != self->priv->first_child)
10281         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10282
10283       if (old_last_child != self->priv->last_child)
10284         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10285     }
10286
10287   g_object_thaw_notify (G_OBJECT (self));
10288 }
10289
10290 /**
10291  * clutter_actor_add_child:
10292  * @self: a #ClutterActor
10293  * @child: a #ClutterActor
10294  *
10295  * Adds @child to the children of @self.
10296  *
10297  * This function will acquire a reference on @child that will only
10298  * be released when calling clutter_actor_remove_child().
10299  *
10300  * This function will take into consideration the #ClutterActor:depth
10301  * of @child, and will keep the list of children sorted.
10302  *
10303  * This function will emit the #ClutterContainer::actor-added signal
10304  * on @self.
10305  *
10306  * Since: 1.10
10307  */
10308 void
10309 clutter_actor_add_child (ClutterActor *self,
10310                          ClutterActor *child)
10311 {
10312   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10313   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10314   g_return_if_fail (self != child);
10315   g_return_if_fail (child->priv->parent == NULL);
10316
10317   clutter_actor_add_child_internal (self, child,
10318                                     ADD_CHILD_DEFAULT_FLAGS,
10319                                     insert_child_at_depth,
10320                                     NULL);
10321 }
10322
10323 /**
10324  * clutter_actor_insert_child_at_index:
10325  * @self: a #ClutterActor
10326  * @child: a #ClutterActor
10327  * @index_: the index
10328  *
10329  * Inserts @child into the list of children of @self, using the
10330  * given @index_. If @index_ is greater than the number of children
10331  * in @self, or is less than 0, then the new child is added at the end.
10332  *
10333  * This function will acquire a reference on @child that will only
10334  * be released when calling clutter_actor_remove_child().
10335  *
10336  * This function will not take into consideration the #ClutterActor:depth
10337  * of @child.
10338  *
10339  * This function will emit the #ClutterContainer::actor-added signal
10340  * on @self.
10341  *
10342  * Since: 1.10
10343  */
10344 void
10345 clutter_actor_insert_child_at_index (ClutterActor *self,
10346                                      ClutterActor *child,
10347                                      gint          index_)
10348 {
10349   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10350   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10351   g_return_if_fail (self != child);
10352   g_return_if_fail (child->priv->parent == NULL);
10353
10354   clutter_actor_add_child_internal (self, child,
10355                                     ADD_CHILD_DEFAULT_FLAGS,
10356                                     insert_child_at_index,
10357                                     GINT_TO_POINTER (index_));
10358 }
10359
10360 /**
10361  * clutter_actor_insert_child_above:
10362  * @self: a #ClutterActor
10363  * @child: a #ClutterActor
10364  * @sibling: (allow-none): a child of @self, or %NULL
10365  *
10366  * Inserts @child into the list of children of @self, above another
10367  * child of @self or, if @sibling is %NULL, above all the children
10368  * of @self.
10369  *
10370  * This function will acquire a reference on @child that will only
10371  * be released when calling clutter_actor_remove_child().
10372  *
10373  * This function will not take into consideration the #ClutterActor:depth
10374  * of @child.
10375  *
10376  * This function will emit the #ClutterContainer::actor-added signal
10377  * on @self.
10378  *
10379  * Since: 1.10
10380  */
10381 void
10382 clutter_actor_insert_child_above (ClutterActor *self,
10383                                   ClutterActor *child,
10384                                   ClutterActor *sibling)
10385 {
10386   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10387   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10388   g_return_if_fail (self != child);
10389   g_return_if_fail (child != sibling);
10390   g_return_if_fail (child->priv->parent == NULL);
10391   g_return_if_fail (sibling == NULL ||
10392                     (CLUTTER_IS_ACTOR (sibling) &&
10393                      sibling->priv->parent == self));
10394
10395   clutter_actor_add_child_internal (self, child,
10396                                     ADD_CHILD_DEFAULT_FLAGS,
10397                                     insert_child_above,
10398                                     sibling);
10399 }
10400
10401 /**
10402  * clutter_actor_insert_child_below:
10403  * @self: a #ClutterActor
10404  * @child: a #ClutterActor
10405  * @sibling: (allow-none): a child of @self, or %NULL
10406  *
10407  * Inserts @child into the list of children of @self, below another
10408  * child of @self or, if @sibling is %NULL, below all the children
10409  * of @self.
10410  *
10411  * This function will acquire a reference on @child that will only
10412  * be released when calling clutter_actor_remove_child().
10413  *
10414  * This function will not take into consideration the #ClutterActor:depth
10415  * of @child.
10416  *
10417  * This function will emit the #ClutterContainer::actor-added signal
10418  * on @self.
10419  *
10420  * Since: 1.10
10421  */
10422 void
10423 clutter_actor_insert_child_below (ClutterActor *self,
10424                                   ClutterActor *child,
10425                                   ClutterActor *sibling)
10426 {
10427   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10428   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10429   g_return_if_fail (self != child);
10430   g_return_if_fail (child != sibling);
10431   g_return_if_fail (child->priv->parent == NULL);
10432   g_return_if_fail (sibling == NULL ||
10433                     (CLUTTER_IS_ACTOR (sibling) &&
10434                      sibling->priv->parent == self));
10435
10436   clutter_actor_add_child_internal (self, child,
10437                                     ADD_CHILD_DEFAULT_FLAGS,
10438                                     insert_child_below,
10439                                     sibling);
10440 }
10441
10442 /**
10443  * clutter_actor_set_parent:
10444  * @self: A #ClutterActor
10445  * @parent: A new #ClutterActor parent
10446  *
10447  * Sets the parent of @self to @parent.
10448  *
10449  * This function will result in @parent acquiring a reference on @self,
10450  * eventually by sinking its floating reference first. The reference
10451  * will be released by clutter_actor_unparent().
10452  *
10453  * This function should only be called by legacy #ClutterActor<!-- -->s
10454  * implementing the #ClutterContainer interface.
10455  *
10456  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10457  */
10458 void
10459 clutter_actor_set_parent (ClutterActor *self,
10460                           ClutterActor *parent)
10461 {
10462   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10463   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10464   g_return_if_fail (self != parent);
10465   g_return_if_fail (self->priv->parent == NULL);
10466
10467   /* as this function will be called inside ClutterContainer::add
10468    * implementations or when building up a composite actor, we have
10469    * to preserve the old behaviour, and not create child meta or
10470    * emit the ::actor-added signal, to avoid recursion or double
10471    * emissions
10472    */
10473   clutter_actor_add_child_internal (parent, self,
10474                                     ADD_CHILD_LEGACY_FLAGS,
10475                                     insert_child_at_depth,
10476                                     NULL);
10477 }
10478
10479 /**
10480  * clutter_actor_get_parent:
10481  * @self: A #ClutterActor
10482  *
10483  * Retrieves the parent of @self.
10484  *
10485  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10486  *  if no parent is set
10487  */
10488 ClutterActor *
10489 clutter_actor_get_parent (ClutterActor *self)
10490 {
10491   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10492
10493   return self->priv->parent;
10494 }
10495
10496 /**
10497  * clutter_actor_get_paint_visibility:
10498  * @self: A #ClutterActor
10499  *
10500  * Retrieves the 'paint' visibility of an actor recursively checking for non
10501  * visible parents.
10502  *
10503  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10504  *
10505  * Return Value: %TRUE if the actor is visibile and will be painted.
10506  *
10507  * Since: 0.8.4
10508  */
10509 gboolean
10510 clutter_actor_get_paint_visibility (ClutterActor *actor)
10511 {
10512   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10513
10514   return CLUTTER_ACTOR_IS_MAPPED (actor);
10515 }
10516
10517 /**
10518  * clutter_actor_remove_child:
10519  * @self: a #ClutterActor
10520  * @child: a #ClutterActor
10521  *
10522  * Removes @child from the children of @self.
10523  *
10524  * This function will release the reference added by
10525  * clutter_actor_add_child(), so if you want to keep using @child
10526  * you will have to acquire a referenced on it before calling this
10527  * function.
10528  *
10529  * This function will emit the #ClutterContainer::actor-removed
10530  * signal on @self.
10531  *
10532  * Since: 1.10
10533  */
10534 void
10535 clutter_actor_remove_child (ClutterActor *self,
10536                             ClutterActor *child)
10537 {
10538   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10539   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10540   g_return_if_fail (self != child);
10541   g_return_if_fail (child->priv->parent != NULL);
10542   g_return_if_fail (child->priv->parent == self);
10543
10544   clutter_actor_remove_child_internal (self, child,
10545                                        REMOVE_CHILD_DEFAULT_FLAGS);
10546 }
10547
10548 /**
10549  * clutter_actor_remove_all_children:
10550  * @self: a #ClutterActor
10551  *
10552  * Removes all children of @self.
10553  *
10554  * This function releases the reference added by inserting a child actor
10555  * in the list of children of @self.
10556  *
10557  * If the reference count of a child drops to zero, the child will be
10558  * destroyed. If you want to ensure the destruction of all the children
10559  * of @self, use clutter_actor_destroy_all_children().
10560  *
10561  * Since: 1.10
10562  */
10563 void
10564 clutter_actor_remove_all_children (ClutterActor *self)
10565 {
10566   ClutterActorIter iter;
10567
10568   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10569
10570   if (self->priv->n_children == 0)
10571     return;
10572
10573   g_object_freeze_notify (G_OBJECT (self));
10574
10575   clutter_actor_iter_init (&iter, self);
10576   while (clutter_actor_iter_next (&iter, NULL))
10577     clutter_actor_iter_remove (&iter);
10578
10579   g_object_thaw_notify (G_OBJECT (self));
10580
10581   /* sanity check */
10582   g_assert (self->priv->first_child == NULL);
10583   g_assert (self->priv->last_child == NULL);
10584   g_assert (self->priv->n_children == 0);
10585 }
10586
10587 /**
10588  * clutter_actor_destroy_all_children:
10589  * @self: a #ClutterActor
10590  *
10591  * Destroys all children of @self.
10592  *
10593  * This function releases the reference added by inserting a child
10594  * actor in the list of children of @self, and ensures that the
10595  * #ClutterActor::destroy signal is emitted on each child of the
10596  * actor.
10597  *
10598  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10599  * when its reference count drops to 0; the default handler of the
10600  * #ClutterActor::destroy signal will destroy all the children of an
10601  * actor. This function ensures that all children are destroyed, instead
10602  * of just removed from @self, unlike clutter_actor_remove_all_children()
10603  * which will merely release the reference and remove each child.
10604  *
10605  * Unless you acquired an additional reference on each child of @self
10606  * prior to calling clutter_actor_remove_all_children() and want to reuse
10607  * the actors, you should use clutter_actor_destroy_all_children() in
10608  * order to make sure that children are destroyed and signal handlers
10609  * are disconnected even in cases where circular references prevent this
10610  * from automatically happening through reference counting alone.
10611  *
10612  * Since: 1.10
10613  */
10614 void
10615 clutter_actor_destroy_all_children (ClutterActor *self)
10616 {
10617   ClutterActorIter iter;
10618
10619   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10620
10621   if (self->priv->n_children == 0)
10622     return;
10623
10624   g_object_freeze_notify (G_OBJECT (self));
10625
10626   clutter_actor_iter_init (&iter, self);
10627   while (clutter_actor_iter_next (&iter, NULL))
10628     clutter_actor_iter_destroy (&iter);
10629
10630   g_object_thaw_notify (G_OBJECT (self));
10631
10632   /* sanity check */
10633   g_assert (self->priv->first_child == NULL);
10634   g_assert (self->priv->last_child == NULL);
10635   g_assert (self->priv->n_children == 0);
10636 }
10637
10638 typedef struct _InsertBetweenData {
10639   ClutterActor *prev_sibling;
10640   ClutterActor *next_sibling;
10641 } InsertBetweenData;
10642
10643 static void
10644 insert_child_between (ClutterActor *self,
10645                       ClutterActor *child,
10646                       gpointer      data_)
10647 {
10648   InsertBetweenData *data = data_;
10649   ClutterActor *prev_sibling = data->prev_sibling;
10650   ClutterActor *next_sibling = data->next_sibling;
10651
10652   child->priv->parent = self;
10653   child->priv->prev_sibling = prev_sibling;
10654   child->priv->next_sibling = next_sibling;
10655
10656   if (prev_sibling != NULL)
10657     prev_sibling->priv->next_sibling = child;
10658
10659   if (next_sibling != NULL)
10660     next_sibling->priv->prev_sibling = child;
10661
10662   if (child->priv->prev_sibling == NULL)
10663     self->priv->first_child = child;
10664
10665   if (child->priv->next_sibling == NULL)
10666     self->priv->last_child = child;
10667 }
10668
10669 /**
10670  * clutter_actor_replace_child:
10671  * @self: a #ClutterActor
10672  * @old_child: the child of @self to replace
10673  * @new_child: the #ClutterActor to replace @old_child
10674  *
10675  * Replaces @old_child with @new_child in the list of children of @self.
10676  *
10677  * Since: 1.10
10678  */
10679 void
10680 clutter_actor_replace_child (ClutterActor *self,
10681                              ClutterActor *old_child,
10682                              ClutterActor *new_child)
10683 {
10684   ClutterActor *prev_sibling, *next_sibling;
10685   InsertBetweenData clos;
10686
10687   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10688   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10689   g_return_if_fail (old_child->priv->parent == self);
10690   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10691   g_return_if_fail (old_child != new_child);
10692   g_return_if_fail (new_child != self);
10693   g_return_if_fail (new_child->priv->parent == NULL);
10694
10695   prev_sibling = old_child->priv->prev_sibling;
10696   next_sibling = old_child->priv->next_sibling;
10697   clutter_actor_remove_child_internal (self, old_child,
10698                                        REMOVE_CHILD_DEFAULT_FLAGS);
10699
10700   clos.prev_sibling = prev_sibling;
10701   clos.next_sibling = next_sibling;
10702   clutter_actor_add_child_internal (self, new_child,
10703                                     ADD_CHILD_DEFAULT_FLAGS,
10704                                     insert_child_between,
10705                                     &clos);
10706 }
10707
10708 /**
10709  * clutter_actor_unparent:
10710  * @self: a #ClutterActor
10711  *
10712  * Removes the parent of @self.
10713  *
10714  * This will cause the parent of @self to release the reference
10715  * acquired when calling clutter_actor_set_parent(), so if you
10716  * want to keep @self you will have to acquire a reference of
10717  * your own, through g_object_ref().
10718  *
10719  * This function should only be called by legacy #ClutterActor<!-- -->s
10720  * implementing the #ClutterContainer interface.
10721  *
10722  * Since: 0.1.1
10723  *
10724  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10725  */
10726 void
10727 clutter_actor_unparent (ClutterActor *self)
10728 {
10729   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10730
10731   if (self->priv->parent == NULL)
10732     return;
10733
10734   clutter_actor_remove_child_internal (self->priv->parent, self,
10735                                        REMOVE_CHILD_LEGACY_FLAGS);
10736 }
10737
10738 /**
10739  * clutter_actor_reparent:
10740  * @self: a #ClutterActor
10741  * @new_parent: the new #ClutterActor parent
10742  *
10743  * Resets the parent actor of @self.
10744  *
10745  * This function is logically equivalent to calling clutter_actor_unparent()
10746  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10747  * ensures the child is not finalized when unparented, and emits the
10748  * #ClutterActor::parent-set signal only once.
10749  *
10750  * In reality, calling this function is less useful than it sounds, as some
10751  * application code may rely on changes in the intermediate state between
10752  * removal and addition of the actor from its old parent to the @new_parent.
10753  * Thus, it is strongly encouraged to avoid using this function in application
10754  * code.
10755  *
10756  * Since: 0.2
10757  *
10758  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10759  *   clutter_actor_add_child() instead; remember to take a reference on
10760  *   the actor being removed before calling clutter_actor_remove_child()
10761  *   to avoid the reference count dropping to zero and the actor being
10762  *   destroyed.
10763  */
10764 void
10765 clutter_actor_reparent (ClutterActor *self,
10766                         ClutterActor *new_parent)
10767 {
10768   ClutterActorPrivate *priv;
10769
10770   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10771   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10772   g_return_if_fail (self != new_parent);
10773
10774   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10775     {
10776       g_warning ("Cannot set a parent on a toplevel actor");
10777       return;
10778     }
10779
10780   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10781     {
10782       g_warning ("Cannot set a parent currently being destroyed");
10783       return;
10784     }
10785
10786   priv = self->priv;
10787
10788   if (priv->parent != new_parent)
10789     {
10790       ClutterActor *old_parent;
10791
10792       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10793
10794       old_parent = priv->parent;
10795
10796       g_object_ref (self);
10797
10798       if (old_parent != NULL)
10799         {
10800          /* go through the Container implementation if this is a regular
10801           * child and not an internal one
10802           */
10803          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10804            {
10805              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10806
10807              /* this will have to call unparent() */
10808              clutter_container_remove_actor (parent, self);
10809            }
10810          else
10811            clutter_actor_remove_child_internal (old_parent, self,
10812                                                 REMOVE_CHILD_LEGACY_FLAGS);
10813         }
10814
10815       /* Note, will call set_parent() */
10816       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10817         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10818       else
10819         clutter_actor_add_child_internal (new_parent, self,
10820                                           ADD_CHILD_LEGACY_FLAGS,
10821                                           insert_child_at_depth,
10822                                           NULL);
10823
10824       /* we emit the ::parent-set signal once */
10825       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10826
10827       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10828
10829       /* the IN_REPARENT flag suspends state updates */
10830       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10831
10832       g_object_unref (self);
10833    }
10834 }
10835
10836 /**
10837  * clutter_actor_contains:
10838  * @self: A #ClutterActor
10839  * @descendant: A #ClutterActor, possibly contained in @self
10840  *
10841  * Determines if @descendant is contained inside @self (either as an
10842  * immediate child, or as a deeper descendant). If @self and
10843  * @descendant point to the same actor then it will also return %TRUE.
10844  *
10845  * Return value: whether @descendent is contained within @self
10846  *
10847  * Since: 1.4
10848  */
10849 gboolean
10850 clutter_actor_contains (ClutterActor *self,
10851                         ClutterActor *descendant)
10852 {
10853   ClutterActor *actor;
10854
10855   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10856   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10857
10858   for (actor = descendant; actor; actor = actor->priv->parent)
10859     if (actor == self)
10860       return TRUE;
10861
10862   return FALSE;
10863 }
10864
10865 /**
10866  * clutter_actor_set_child_above_sibling:
10867  * @self: a #ClutterActor
10868  * @child: a #ClutterActor child of @self
10869  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10870  *
10871  * Sets @child to be above @sibling in the list of children of @self.
10872  *
10873  * If @sibling is %NULL, @child will be the new last child of @self.
10874  *
10875  * This function is logically equivalent to removing @child and using
10876  * clutter_actor_insert_child_above(), but it will not emit signals
10877  * or change state on @child.
10878  *
10879  * Since: 1.10
10880  */
10881 void
10882 clutter_actor_set_child_above_sibling (ClutterActor *self,
10883                                        ClutterActor *child,
10884                                        ClutterActor *sibling)
10885 {
10886   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10887   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10888   g_return_if_fail (child->priv->parent == self);
10889   g_return_if_fail (child != sibling);
10890   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10891
10892   if (sibling != NULL)
10893     g_return_if_fail (sibling->priv->parent == self);
10894
10895   /* we don't want to change the state of child, or emit signals, or
10896    * regenerate ChildMeta instances here, but we still want to follow
10897    * the correct sequence of steps encoded in remove_child() and
10898    * add_child(), so that correctness is ensured, and we only go
10899    * through one known code path.
10900    */
10901   g_object_ref (child);
10902   clutter_actor_remove_child_internal (self, child, 0);
10903   clutter_actor_add_child_internal (self, child,
10904                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10905                                     insert_child_above,
10906                                     sibling);
10907
10908   clutter_actor_queue_relayout (self);
10909 }
10910
10911 /**
10912  * clutter_actor_set_child_below_sibling:
10913  * @self: a #ClutterActor
10914  * @child: a #ClutterActor child of @self
10915  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10916  *
10917  * Sets @child to be below @sibling in the list of children of @self.
10918  *
10919  * If @sibling is %NULL, @child will be the new first child of @self.
10920  *
10921  * This function is logically equivalent to removing @self and using
10922  * clutter_actor_insert_child_below(), but it will not emit signals
10923  * or change state on @child.
10924  *
10925  * Since: 1.10
10926  */
10927 void
10928 clutter_actor_set_child_below_sibling (ClutterActor *self,
10929                                        ClutterActor *child,
10930                                        ClutterActor *sibling)
10931 {
10932   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10933   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10934   g_return_if_fail (child->priv->parent == self);
10935   g_return_if_fail (child != sibling);
10936   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10937
10938   if (sibling != NULL)
10939     g_return_if_fail (sibling->priv->parent == self);
10940
10941   /* see the comment in set_child_above_sibling() */
10942   g_object_ref (child);
10943   clutter_actor_remove_child_internal (self, child, 0);
10944   clutter_actor_add_child_internal (self, child,
10945                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10946                                     insert_child_below,
10947                                     sibling);
10948
10949   clutter_actor_queue_relayout (self);
10950 }
10951
10952 /**
10953  * clutter_actor_set_child_at_index:
10954  * @self: a #ClutterActor
10955  * @child: a #ClutterActor child of @self
10956  * @index_: the new index for @child
10957  *
10958  * Changes the index of @child in the list of children of @self.
10959  *
10960  * This function is logically equivalent to removing @child and
10961  * calling clutter_actor_insert_child_at_index(), but it will not
10962  * emit signals or change state on @child.
10963  *
10964  * Since: 1.10
10965  */
10966 void
10967 clutter_actor_set_child_at_index (ClutterActor *self,
10968                                   ClutterActor *child,
10969                                   gint          index_)
10970 {
10971   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10972   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10973   g_return_if_fail (child->priv->parent == self);
10974   g_return_if_fail (index_ <= self->priv->n_children);
10975
10976   g_object_ref (child);
10977   clutter_actor_remove_child_internal (self, child, 0);
10978   clutter_actor_add_child_internal (self, child,
10979                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10980                                     insert_child_at_index,
10981                                     GINT_TO_POINTER (index_));
10982
10983   clutter_actor_queue_relayout (self);
10984 }
10985
10986 /**
10987  * clutter_actor_raise:
10988  * @self: A #ClutterActor
10989  * @below: (allow-none): A #ClutterActor to raise above.
10990  *
10991  * Puts @self above @below.
10992  *
10993  * Both actors must have the same parent, and the parent must implement
10994  * the #ClutterContainer interface
10995  *
10996  * This function calls clutter_container_raise_child() internally.
10997  *
10998  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
10999  */
11000 void
11001 clutter_actor_raise (ClutterActor *self,
11002                      ClutterActor *below)
11003 {
11004   ClutterActor *parent;
11005
11006   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11007
11008   parent = clutter_actor_get_parent (self);
11009   if (parent == NULL)
11010     {
11011       g_warning ("%s: Actor '%s' is not inside a container",
11012                  G_STRFUNC,
11013                  _clutter_actor_get_debug_name (self));
11014       return;
11015     }
11016
11017   if (below != NULL)
11018     {
11019       if (parent != clutter_actor_get_parent (below))
11020         {
11021           g_warning ("%s Actor '%s' is not in the same container as "
11022                      "actor '%s'",
11023                      G_STRFUNC,
11024                      _clutter_actor_get_debug_name (self),
11025                      _clutter_actor_get_debug_name (below));
11026           return;
11027         }
11028     }
11029
11030   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11031 }
11032
11033 /**
11034  * clutter_actor_lower:
11035  * @self: A #ClutterActor
11036  * @above: (allow-none): A #ClutterActor to lower below
11037  *
11038  * Puts @self below @above.
11039  *
11040  * Both actors must have the same parent, and the parent must implement
11041  * the #ClutterContainer interface.
11042  *
11043  * This function calls clutter_container_lower_child() internally.
11044  *
11045  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11046  */
11047 void
11048 clutter_actor_lower (ClutterActor *self,
11049                      ClutterActor *above)
11050 {
11051   ClutterActor *parent;
11052
11053   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11054
11055   parent = clutter_actor_get_parent (self);
11056   if (parent == NULL)
11057     {
11058       g_warning ("%s: Actor of type %s is not inside a container",
11059                  G_STRFUNC,
11060                  _clutter_actor_get_debug_name (self));
11061       return;
11062     }
11063
11064   if (above)
11065     {
11066       if (parent != clutter_actor_get_parent (above))
11067         {
11068           g_warning ("%s: Actor '%s' is not in the same container as "
11069                      "actor '%s'",
11070                      G_STRFUNC,
11071                      _clutter_actor_get_debug_name (self),
11072                      _clutter_actor_get_debug_name (above));
11073           return;
11074         }
11075     }
11076
11077   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11078 }
11079
11080 /**
11081  * clutter_actor_raise_top:
11082  * @self: A #ClutterActor
11083  *
11084  * Raises @self to the top.
11085  *
11086  * This function calls clutter_actor_raise() internally.
11087  *
11088  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11089  *   a %NULL sibling, instead.
11090  */
11091 void
11092 clutter_actor_raise_top (ClutterActor *self)
11093 {
11094   clutter_actor_raise (self, NULL);
11095 }
11096
11097 /**
11098  * clutter_actor_lower_bottom:
11099  * @self: A #ClutterActor
11100  *
11101  * Lowers @self to the bottom.
11102  *
11103  * This function calls clutter_actor_lower() internally.
11104  *
11105  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11106  *   a %NULL sibling, instead.
11107  */
11108 void
11109 clutter_actor_lower_bottom (ClutterActor *self)
11110 {
11111   clutter_actor_lower (self, NULL);
11112 }
11113
11114 /*
11115  * Event handling
11116  */
11117
11118 /**
11119  * clutter_actor_event:
11120  * @actor: a #ClutterActor
11121  * @event: a #ClutterEvent
11122  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11123  *
11124  * This function is used to emit an event on the main stage.
11125  * You should rarely need to use this function, except for
11126  * synthetising events.
11127  *
11128  * Return value: the return value from the signal emission: %TRUE
11129  *   if the actor handled the event, or %FALSE if the event was
11130  *   not handled
11131  *
11132  * Since: 0.6
11133  */
11134 gboolean
11135 clutter_actor_event (ClutterActor *actor,
11136                      ClutterEvent *event,
11137                      gboolean      capture)
11138 {
11139   gboolean retval = FALSE;
11140   gint signal_num = -1;
11141
11142   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11143   g_return_val_if_fail (event != NULL, FALSE);
11144
11145   g_object_ref (actor);
11146
11147   if (capture)
11148     {
11149       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11150                      event,
11151                      &retval);
11152       goto out;
11153     }
11154
11155   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11156
11157   if (!retval)
11158     {
11159       switch (event->type)
11160         {
11161         case CLUTTER_NOTHING:
11162           break;
11163         case CLUTTER_BUTTON_PRESS:
11164           signal_num = BUTTON_PRESS_EVENT;
11165           break;
11166         case CLUTTER_BUTTON_RELEASE:
11167           signal_num = BUTTON_RELEASE_EVENT;
11168           break;
11169         case CLUTTER_SCROLL:
11170           signal_num = SCROLL_EVENT;
11171           break;
11172         case CLUTTER_KEY_PRESS:
11173           signal_num = KEY_PRESS_EVENT;
11174           break;
11175         case CLUTTER_KEY_RELEASE:
11176           signal_num = KEY_RELEASE_EVENT;
11177           break;
11178         case CLUTTER_MOTION:
11179           signal_num = MOTION_EVENT;
11180           break;
11181         case CLUTTER_ENTER:
11182           signal_num = ENTER_EVENT;
11183           break;
11184         case CLUTTER_LEAVE:
11185           signal_num = LEAVE_EVENT;
11186           break;
11187         case CLUTTER_DELETE:
11188         case CLUTTER_DESTROY_NOTIFY:
11189         case CLUTTER_CLIENT_MESSAGE:
11190         default:
11191           signal_num = -1;
11192           break;
11193         }
11194
11195       if (signal_num != -1)
11196         g_signal_emit (actor, actor_signals[signal_num], 0,
11197                        event, &retval);
11198     }
11199
11200 out:
11201   g_object_unref (actor);
11202
11203   return retval;
11204 }
11205
11206 /**
11207  * clutter_actor_set_reactive:
11208  * @actor: a #ClutterActor
11209  * @reactive: whether the actor should be reactive to events
11210  *
11211  * Sets @actor as reactive. Reactive actors will receive events.
11212  *
11213  * Since: 0.6
11214  */
11215 void
11216 clutter_actor_set_reactive (ClutterActor *actor,
11217                             gboolean      reactive)
11218 {
11219   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11220
11221   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11222     return;
11223
11224   if (reactive)
11225     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11226   else
11227     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11228
11229   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11230 }
11231
11232 /**
11233  * clutter_actor_get_reactive:
11234  * @actor: a #ClutterActor
11235  *
11236  * Checks whether @actor is marked as reactive.
11237  *
11238  * Return value: %TRUE if the actor is reactive
11239  *
11240  * Since: 0.6
11241  */
11242 gboolean
11243 clutter_actor_get_reactive (ClutterActor *actor)
11244 {
11245   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11246
11247   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11248 }
11249
11250 /**
11251  * clutter_actor_get_anchor_point:
11252  * @self: a #ClutterActor
11253  * @anchor_x: (out): return location for the X coordinate of the anchor point
11254  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11255  *
11256  * Gets the current anchor point of the @actor in pixels.
11257  *
11258  * Since: 0.6
11259  */
11260 void
11261 clutter_actor_get_anchor_point (ClutterActor *self,
11262                                 gfloat       *anchor_x,
11263                                 gfloat       *anchor_y)
11264 {
11265   const ClutterTransformInfo *info;
11266
11267   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11268
11269   info = _clutter_actor_get_transform_info_or_defaults (self);
11270   clutter_anchor_coord_get_units (self, &info->anchor,
11271                                   anchor_x,
11272                                   anchor_y,
11273                                   NULL);
11274 }
11275
11276 /**
11277  * clutter_actor_set_anchor_point:
11278  * @self: a #ClutterActor
11279  * @anchor_x: X coordinate of the anchor point
11280  * @anchor_y: Y coordinate of the anchor point
11281  *
11282  * Sets an anchor point for @self. The anchor point is a point in the
11283  * coordinate space of an actor to which the actor position within its
11284  * parent is relative; the default is (0, 0), i.e. the top-left corner
11285  * of the actor.
11286  *
11287  * Since: 0.6
11288  */
11289 void
11290 clutter_actor_set_anchor_point (ClutterActor *self,
11291                                 gfloat        anchor_x,
11292                                 gfloat        anchor_y)
11293 {
11294   ClutterTransformInfo *info;
11295   ClutterActorPrivate *priv;
11296   gboolean changed = FALSE;
11297   gfloat old_anchor_x, old_anchor_y;
11298   GObject *obj;
11299
11300   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11301
11302   obj = G_OBJECT (self);
11303   priv = self->priv;
11304   info = _clutter_actor_get_transform_info (self);
11305
11306   g_object_freeze_notify (obj);
11307
11308   clutter_anchor_coord_get_units (self, &info->anchor,
11309                                   &old_anchor_x,
11310                                   &old_anchor_y,
11311                                   NULL);
11312
11313   if (info->anchor.is_fractional)
11314     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11315
11316   if (old_anchor_x != anchor_x)
11317     {
11318       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11319       changed = TRUE;
11320     }
11321
11322   if (old_anchor_y != anchor_y)
11323     {
11324       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11325       changed = TRUE;
11326     }
11327
11328   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11329
11330   if (changed)
11331     {
11332       priv->transform_valid = FALSE;
11333       clutter_actor_queue_redraw (self);
11334     }
11335
11336   g_object_thaw_notify (obj);
11337 }
11338
11339 /**
11340  * clutter_actor_get_anchor_point_gravity:
11341  * @self: a #ClutterActor
11342  *
11343  * Retrieves the anchor position expressed as a #ClutterGravity. If
11344  * the anchor point was specified using pixels or units this will
11345  * return %CLUTTER_GRAVITY_NONE.
11346  *
11347  * Return value: the #ClutterGravity used by the anchor point
11348  *
11349  * Since: 1.0
11350  */
11351 ClutterGravity
11352 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11353 {
11354   const ClutterTransformInfo *info;
11355
11356   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11357
11358   info = _clutter_actor_get_transform_info_or_defaults (self);
11359
11360   return clutter_anchor_coord_get_gravity (&info->anchor);
11361 }
11362
11363 /**
11364  * clutter_actor_move_anchor_point:
11365  * @self: a #ClutterActor
11366  * @anchor_x: X coordinate of the anchor point
11367  * @anchor_y: Y coordinate of the anchor point
11368  *
11369  * Sets an anchor point for the actor, and adjusts the actor postion so that
11370  * the relative position of the actor toward its parent remains the same.
11371  *
11372  * Since: 0.6
11373  */
11374 void
11375 clutter_actor_move_anchor_point (ClutterActor *self,
11376                                  gfloat        anchor_x,
11377                                  gfloat        anchor_y)
11378 {
11379   gfloat old_anchor_x, old_anchor_y;
11380   const ClutterTransformInfo *info;
11381
11382   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11383
11384   info = _clutter_actor_get_transform_info (self);
11385   clutter_anchor_coord_get_units (self, &info->anchor,
11386                                   &old_anchor_x,
11387                                   &old_anchor_y,
11388                                   NULL);
11389
11390   g_object_freeze_notify (G_OBJECT (self));
11391
11392   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11393
11394   if (self->priv->position_set)
11395     clutter_actor_move_by (self,
11396                            anchor_x - old_anchor_x,
11397                            anchor_y - old_anchor_y);
11398
11399   g_object_thaw_notify (G_OBJECT (self));
11400 }
11401
11402 /**
11403  * clutter_actor_move_anchor_point_from_gravity:
11404  * @self: a #ClutterActor
11405  * @gravity: #ClutterGravity.
11406  *
11407  * Sets an anchor point on the actor based on the given gravity, adjusting the
11408  * actor postion so that its relative position within its parent remains
11409  * unchanged.
11410  *
11411  * Since version 1.0 the anchor point will be stored as a gravity so
11412  * that if the actor changes size then the anchor point will move. For
11413  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11414  * and later double the size of the actor, the anchor point will move
11415  * to the bottom right.
11416  *
11417  * Since: 0.6
11418  */
11419 void
11420 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11421                                               ClutterGravity  gravity)
11422 {
11423   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11424   const ClutterTransformInfo *info;
11425   ClutterActorPrivate *priv;
11426
11427   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11428
11429   priv = self->priv;
11430   info = _clutter_actor_get_transform_info (self);
11431
11432   g_object_freeze_notify (G_OBJECT (self));
11433
11434   clutter_anchor_coord_get_units (self, &info->anchor,
11435                                   &old_anchor_x,
11436                                   &old_anchor_y,
11437                                   NULL);
11438   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11439   clutter_anchor_coord_get_units (self, &info->anchor,
11440                                   &new_anchor_x,
11441                                   &new_anchor_y,
11442                                   NULL);
11443
11444   if (priv->position_set)
11445     clutter_actor_move_by (self,
11446                            new_anchor_x - old_anchor_x,
11447                            new_anchor_y - old_anchor_y);
11448
11449   g_object_thaw_notify (G_OBJECT (self));
11450 }
11451
11452 /**
11453  * clutter_actor_set_anchor_point_from_gravity:
11454  * @self: a #ClutterActor
11455  * @gravity: #ClutterGravity.
11456  *
11457  * Sets an anchor point on the actor, based on the given gravity (this is a
11458  * convenience function wrapping clutter_actor_set_anchor_point()).
11459  *
11460  * Since version 1.0 the anchor point will be stored as a gravity so
11461  * that if the actor changes size then the anchor point will move. For
11462  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11463  * and later double the size of the actor, the anchor point will move
11464  * to the bottom right.
11465  *
11466  * Since: 0.6
11467  */
11468 void
11469 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11470                                              ClutterGravity  gravity)
11471 {
11472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11473
11474   if (gravity == CLUTTER_GRAVITY_NONE)
11475     clutter_actor_set_anchor_point (self, 0, 0);
11476   else
11477     {
11478       GObject *obj = G_OBJECT (self);
11479       ClutterTransformInfo *info;
11480
11481       g_object_freeze_notify (obj);
11482
11483       info = _clutter_actor_get_transform_info (self);
11484       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11485
11486       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11487       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11488       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11489
11490       self->priv->transform_valid = FALSE;
11491
11492       clutter_actor_queue_redraw (self);
11493
11494       g_object_thaw_notify (obj);
11495     }
11496 }
11497
11498 static void
11499 clutter_container_iface_init (ClutterContainerIface *iface)
11500 {
11501   /* we don't override anything, as ClutterContainer already has a default
11502    * implementation that we can use, and which calls into our own API.
11503    */
11504 }
11505
11506 typedef enum
11507 {
11508   PARSE_X,
11509   PARSE_Y,
11510   PARSE_WIDTH,
11511   PARSE_HEIGHT,
11512   PARSE_ANCHOR_X,
11513   PARSE_ANCHOR_Y
11514 } ParseDimension;
11515
11516 static gfloat
11517 parse_units (ClutterActor   *self,
11518              ParseDimension  dimension,
11519              JsonNode       *node)
11520 {
11521   GValue value = { 0, };
11522   gfloat retval = 0;
11523
11524   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11525     return 0;
11526
11527   json_node_get_value (node, &value);
11528
11529   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11530     {
11531       retval = (gfloat) g_value_get_int64 (&value);
11532     }
11533   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11534     {
11535       retval = g_value_get_double (&value);
11536     }
11537   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11538     {
11539       ClutterUnits units;
11540       gboolean res;
11541
11542       res = clutter_units_from_string (&units, g_value_get_string (&value));
11543       if (res)
11544         retval = clutter_units_to_pixels (&units);
11545       else
11546         {
11547           g_warning ("Invalid value '%s': integers, strings or floating point "
11548                      "values can be used for the x, y, width and height "
11549                      "properties. Valid modifiers for strings are 'px', 'mm', "
11550                      "'pt' and 'em'.",
11551                      g_value_get_string (&value));
11552           retval = 0;
11553         }
11554     }
11555   else
11556     {
11557       g_warning ("Invalid value of type '%s': integers, strings of floating "
11558                  "point values can be used for the x, y, width, height "
11559                  "anchor-x and anchor-y properties.",
11560                  g_type_name (G_VALUE_TYPE (&value)));
11561     }
11562
11563   g_value_unset (&value);
11564
11565   return retval;
11566 }
11567
11568 typedef struct {
11569   ClutterRotateAxis axis;
11570
11571   gdouble angle;
11572
11573   gfloat center_x;
11574   gfloat center_y;
11575   gfloat center_z;
11576 } RotationInfo;
11577
11578 static inline gboolean
11579 parse_rotation_array (ClutterActor *actor,
11580                       JsonArray    *array,
11581                       RotationInfo *info)
11582 {
11583   JsonNode *element;
11584
11585   if (json_array_get_length (array) != 2)
11586     return FALSE;
11587
11588   /* angle */
11589   element = json_array_get_element (array, 0);
11590   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11591     info->angle = json_node_get_double (element);
11592   else
11593     return FALSE;
11594
11595   /* center */
11596   element = json_array_get_element (array, 1);
11597   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11598     {
11599       JsonArray *center = json_node_get_array (element);
11600
11601       if (json_array_get_length (center) != 2)
11602         return FALSE;
11603
11604       switch (info->axis)
11605         {
11606         case CLUTTER_X_AXIS:
11607           info->center_y = parse_units (actor, PARSE_Y,
11608                                         json_array_get_element (center, 0));
11609           info->center_z = parse_units (actor, PARSE_Y,
11610                                         json_array_get_element (center, 1));
11611           return TRUE;
11612
11613         case CLUTTER_Y_AXIS:
11614           info->center_x = parse_units (actor, PARSE_X,
11615                                         json_array_get_element (center, 0));
11616           info->center_z = parse_units (actor, PARSE_X,
11617                                         json_array_get_element (center, 1));
11618           return TRUE;
11619
11620         case CLUTTER_Z_AXIS:
11621           info->center_x = parse_units (actor, PARSE_X,
11622                                         json_array_get_element (center, 0));
11623           info->center_y = parse_units (actor, PARSE_Y,
11624                                         json_array_get_element (center, 1));
11625           return TRUE;
11626         }
11627     }
11628
11629   return FALSE;
11630 }
11631
11632 static gboolean
11633 parse_rotation (ClutterActor *actor,
11634                 JsonNode     *node,
11635                 RotationInfo *info)
11636 {
11637   JsonArray *array;
11638   guint len, i;
11639   gboolean retval = FALSE;
11640
11641   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11642     {
11643       g_warning ("Invalid node of type '%s' found, expecting an array",
11644                  json_node_type_name (node));
11645       return FALSE;
11646     }
11647
11648   array = json_node_get_array (node);
11649   len = json_array_get_length (array);
11650
11651   for (i = 0; i < len; i++)
11652     {
11653       JsonNode *element = json_array_get_element (array, i);
11654       JsonObject *object;
11655       JsonNode *member;
11656
11657       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11658         {
11659           g_warning ("Invalid node of type '%s' found, expecting an object",
11660                      json_node_type_name (element));
11661           return FALSE;
11662         }
11663
11664       object = json_node_get_object (element);
11665
11666       if (json_object_has_member (object, "x-axis"))
11667         {
11668           member = json_object_get_member (object, "x-axis");
11669
11670           info->axis = CLUTTER_X_AXIS;
11671
11672           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11673             {
11674               info->angle = json_node_get_double (member);
11675               retval = TRUE;
11676             }
11677           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11678             retval = parse_rotation_array (actor,
11679                                            json_node_get_array (member),
11680                                            info);
11681           else
11682             retval = FALSE;
11683         }
11684       else if (json_object_has_member (object, "y-axis"))
11685         {
11686           member = json_object_get_member (object, "y-axis");
11687
11688           info->axis = CLUTTER_Y_AXIS;
11689
11690           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11691             {
11692               info->angle = json_node_get_double (member);
11693               retval = TRUE;
11694             }
11695           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11696             retval = parse_rotation_array (actor,
11697                                            json_node_get_array (member),
11698                                            info);
11699           else
11700             retval = FALSE;
11701         }
11702       else if (json_object_has_member (object, "z-axis"))
11703         {
11704           member = json_object_get_member (object, "z-axis");
11705
11706           info->axis = CLUTTER_Z_AXIS;
11707
11708           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11709             {
11710               info->angle = json_node_get_double (member);
11711               retval = TRUE;
11712             }
11713           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11714             retval = parse_rotation_array (actor,
11715                                            json_node_get_array (member),
11716                                            info);
11717           else
11718             retval = FALSE;
11719         }
11720     }
11721
11722   return retval;
11723 }
11724
11725 static GSList *
11726 parse_actor_metas (ClutterScript *script,
11727                    ClutterActor  *actor,
11728                    JsonNode      *node)
11729 {
11730   GList *elements, *l;
11731   GSList *retval = NULL;
11732
11733   if (!JSON_NODE_HOLDS_ARRAY (node))
11734     return NULL;
11735
11736   elements = json_array_get_elements (json_node_get_array (node));
11737
11738   for (l = elements; l != NULL; l = l->next)
11739     {
11740       JsonNode *element = l->data;
11741       const gchar *id_ = _clutter_script_get_id_from_node (element);
11742       GObject *meta;
11743
11744       if (id_ == NULL || *id_ == '\0')
11745         continue;
11746
11747       meta = clutter_script_get_object (script, id_);
11748       if (meta == NULL)
11749         continue;
11750
11751       retval = g_slist_prepend (retval, meta);
11752     }
11753
11754   g_list_free (elements);
11755
11756   return g_slist_reverse (retval);
11757 }
11758
11759 static GSList *
11760 parse_behaviours (ClutterScript *script,
11761                   ClutterActor  *actor,
11762                   JsonNode      *node)
11763 {
11764   GList *elements, *l;
11765   GSList *retval = NULL;
11766
11767   if (!JSON_NODE_HOLDS_ARRAY (node))
11768     return NULL;
11769
11770   elements = json_array_get_elements (json_node_get_array (node));
11771
11772   for (l = elements; l != NULL; l = l->next)
11773     {
11774       JsonNode *element = l->data;
11775       const gchar *id_ = _clutter_script_get_id_from_node (element);
11776       GObject *behaviour;
11777
11778       if (id_ == NULL || *id_ == '\0')
11779         continue;
11780
11781       behaviour = clutter_script_get_object (script, id_);
11782       if (behaviour == NULL)
11783         continue;
11784
11785       retval = g_slist_prepend (retval, behaviour);
11786     }
11787
11788   g_list_free (elements);
11789
11790   return g_slist_reverse (retval);
11791 }
11792
11793 static gboolean
11794 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11795                                  ClutterScript     *script,
11796                                  GValue            *value,
11797                                  const gchar       *name,
11798                                  JsonNode          *node)
11799 {
11800   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11801   gboolean retval = FALSE;
11802
11803   if ((name[0] == 'x' && name[1] == '\0') ||
11804       (name[0] == 'y' && name[1] == '\0') ||
11805       (strcmp (name, "width") == 0) ||
11806       (strcmp (name, "height") == 0) ||
11807       (strcmp (name, "anchor_x") == 0) ||
11808       (strcmp (name, "anchor_y") == 0))
11809     {
11810       ParseDimension dimension;
11811       gfloat units;
11812
11813       if (name[0] == 'x')
11814         dimension = PARSE_X;
11815       else if (name[0] == 'y')
11816         dimension = PARSE_Y;
11817       else if (name[0] == 'w')
11818         dimension = PARSE_WIDTH;
11819       else if (name[0] == 'h')
11820         dimension = PARSE_HEIGHT;
11821       else if (name[0] == 'a' && name[7] == 'x')
11822         dimension = PARSE_ANCHOR_X;
11823       else if (name[0] == 'a' && name[7] == 'y')
11824         dimension = PARSE_ANCHOR_Y;
11825       else
11826         return FALSE;
11827
11828       units = parse_units (actor, dimension, node);
11829
11830       /* convert back to pixels: all properties are pixel-based */
11831       g_value_init (value, G_TYPE_FLOAT);
11832       g_value_set_float (value, units);
11833
11834       retval = TRUE;
11835     }
11836   else if (strcmp (name, "rotation") == 0)
11837     {
11838       RotationInfo *info;
11839
11840       info = g_slice_new0 (RotationInfo);
11841       retval = parse_rotation (actor, node, info);
11842
11843       if (retval)
11844         {
11845           g_value_init (value, G_TYPE_POINTER);
11846           g_value_set_pointer (value, info);
11847         }
11848       else
11849         g_slice_free (RotationInfo, info);
11850     }
11851   else if (strcmp (name, "behaviours") == 0)
11852     {
11853       GSList *l;
11854
11855 #ifdef CLUTTER_ENABLE_DEBUG
11856       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11857         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11858                                      "and it should not be used in newly "
11859                                      "written ClutterScript definitions.");
11860 #endif
11861
11862       l = parse_behaviours (script, actor, node);
11863
11864       g_value_init (value, G_TYPE_POINTER);
11865       g_value_set_pointer (value, l);
11866
11867       retval = TRUE;
11868     }
11869   else if (strcmp (name, "actions") == 0 ||
11870            strcmp (name, "constraints") == 0 ||
11871            strcmp (name, "effects") == 0)
11872     {
11873       GSList *l;
11874
11875       l = parse_actor_metas (script, actor, node);
11876
11877       g_value_init (value, G_TYPE_POINTER);
11878       g_value_set_pointer (value, l);
11879
11880       retval = TRUE;
11881     }
11882
11883   return retval;
11884 }
11885
11886 static void
11887 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11888                                    ClutterScript     *script,
11889                                    const gchar       *name,
11890                                    const GValue      *value)
11891 {
11892   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11893
11894 #ifdef CLUTTER_ENABLE_DEBUG
11895   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11896     {
11897       gchar *tmp = g_strdup_value_contents (value);
11898
11899       CLUTTER_NOTE (SCRIPT,
11900                     "in ClutterActor::set_custom_property('%s') = %s",
11901                     name,
11902                     tmp);
11903
11904       g_free (tmp);
11905     }
11906 #endif /* CLUTTER_ENABLE_DEBUG */
11907
11908   if (strcmp (name, "rotation") == 0)
11909     {
11910       RotationInfo *info;
11911
11912       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11913         return;
11914
11915       info = g_value_get_pointer (value);
11916
11917       clutter_actor_set_rotation (actor,
11918                                   info->axis, info->angle,
11919                                   info->center_x,
11920                                   info->center_y,
11921                                   info->center_z);
11922
11923       g_slice_free (RotationInfo, info);
11924
11925       return;
11926     }
11927
11928   if (strcmp (name, "behaviours") == 0)
11929     {
11930       GSList *behaviours, *l;
11931
11932       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11933         return;
11934
11935       behaviours = g_value_get_pointer (value);
11936       for (l = behaviours; l != NULL; l = l->next)
11937         {
11938           ClutterBehaviour *behaviour = l->data;
11939
11940           clutter_behaviour_apply (behaviour, actor);
11941         }
11942
11943       g_slist_free (behaviours);
11944
11945       return;
11946     }
11947
11948   if (strcmp (name, "actions") == 0 ||
11949       strcmp (name, "constraints") == 0 ||
11950       strcmp (name, "effects") == 0)
11951     {
11952       GSList *metas, *l;
11953
11954       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11955         return;
11956
11957       metas = g_value_get_pointer (value);
11958       for (l = metas; l != NULL; l = l->next)
11959         {
11960           if (name[0] == 'a')
11961             clutter_actor_add_action (actor, l->data);
11962
11963           if (name[0] == 'c')
11964             clutter_actor_add_constraint (actor, l->data);
11965
11966           if (name[0] == 'e')
11967             clutter_actor_add_effect (actor, l->data);
11968         }
11969
11970       g_slist_free (metas);
11971
11972       return;
11973     }
11974
11975   g_object_set_property (G_OBJECT (scriptable), name, value);
11976 }
11977
11978 static void
11979 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
11980 {
11981   iface->parse_custom_node = clutter_actor_parse_custom_node;
11982   iface->set_custom_property = clutter_actor_set_custom_property;
11983 }
11984
11985 static ClutterActorMeta *
11986 get_meta_from_animation_property (ClutterActor  *actor,
11987                                   const gchar   *name,
11988                                   gchar        **name_p)
11989 {
11990   ClutterActorPrivate *priv = actor->priv;
11991   ClutterActorMeta *meta = NULL;
11992   gchar **tokens;
11993
11994   /* if this is not a special property, fall through */
11995   if (name[0] != '@')
11996     return NULL;
11997
11998   /* detect the properties named using the following spec:
11999    *
12000    *   @<section>.<meta-name>.<property-name>
12001    *
12002    * where <section> can be one of the following:
12003    *
12004    *   - actions
12005    *   - constraints
12006    *   - effects
12007    *
12008    * and <meta-name> is the name set on a specific ActorMeta
12009    */
12010
12011   tokens = g_strsplit (name + 1, ".", -1);
12012   if (tokens == NULL || g_strv_length (tokens) != 3)
12013     {
12014       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12015                     name + 1);
12016       g_strfreev (tokens);
12017       return NULL;
12018     }
12019
12020   if (strcmp (tokens[0], "actions") == 0)
12021     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12022
12023   if (strcmp (tokens[0], "constraints") == 0)
12024     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12025
12026   if (strcmp (tokens[0], "effects") == 0)
12027     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12028
12029   if (name_p != NULL)
12030     *name_p = g_strdup (tokens[2]);
12031
12032   CLUTTER_NOTE (ANIMATION,
12033                 "Looking for property '%s' of object '%s' in section '%s'",
12034                 tokens[2],
12035                 tokens[1],
12036                 tokens[0]);
12037
12038   g_strfreev (tokens);
12039
12040   return meta;
12041 }
12042
12043 static GParamSpec *
12044 clutter_actor_find_property (ClutterAnimatable *animatable,
12045                              const gchar       *property_name)
12046 {
12047   ClutterActorMeta *meta = NULL;
12048   GObjectClass *klass = NULL;
12049   GParamSpec *pspec = NULL;
12050   gchar *p_name = NULL;
12051
12052   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12053                                            property_name,
12054                                            &p_name);
12055
12056   if (meta != NULL)
12057     {
12058       klass = G_OBJECT_GET_CLASS (meta);
12059
12060       pspec = g_object_class_find_property (klass, p_name);
12061     }
12062   else
12063     {
12064       klass = G_OBJECT_GET_CLASS (animatable);
12065
12066       pspec = g_object_class_find_property (klass, property_name);
12067     }
12068
12069   g_free (p_name);
12070
12071   return pspec;
12072 }
12073
12074 static void
12075 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12076                                  const gchar       *property_name,
12077                                  GValue            *initial)
12078 {
12079   ClutterActorMeta *meta = NULL;
12080   gchar *p_name = NULL;
12081
12082   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12083                                            property_name,
12084                                            &p_name);
12085
12086   if (meta != NULL)
12087     g_object_get_property (G_OBJECT (meta), p_name, initial);
12088   else
12089     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12090
12091   g_free (p_name);
12092 }
12093
12094 static void
12095 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12096                                const gchar       *property_name,
12097                                const GValue      *final)
12098 {
12099   ClutterActorMeta *meta = NULL;
12100   gchar *p_name = NULL;
12101
12102   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12103                                            property_name,
12104                                            &p_name);
12105   if (meta != NULL)
12106     g_object_set_property (G_OBJECT (meta), p_name, final);
12107   else
12108     g_object_set_property (G_OBJECT (animatable), property_name, final);
12109
12110   g_free (p_name);
12111 }
12112
12113 static void
12114 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12115 {
12116   iface->find_property = clutter_actor_find_property;
12117   iface->get_initial_state = clutter_actor_get_initial_state;
12118   iface->set_final_state = clutter_actor_set_final_state;
12119 }
12120
12121 /**
12122  * clutter_actor_transform_stage_point:
12123  * @self: A #ClutterActor
12124  * @x: (in): x screen coordinate of the point to unproject
12125  * @y: (in): y screen coordinate of the point to unproject
12126  * @x_out: (out): return location for the unprojected x coordinance
12127  * @y_out: (out): return location for the unprojected y coordinance
12128  *
12129  * This function translates screen coordinates (@x, @y) to
12130  * coordinates relative to the actor. For example, it can be used to translate
12131  * screen events from global screen coordinates into actor-local coordinates.
12132  *
12133  * The conversion can fail, notably if the transform stack results in the
12134  * actor being projected on the screen as a mere line.
12135  *
12136  * The conversion should not be expected to be pixel-perfect due to the
12137  * nature of the operation. In general the error grows when the skewing
12138  * of the actor rectangle on screen increases.
12139  *
12140  * <note><para>This function can be computationally intensive.</para></note>
12141  *
12142  * <note><para>This function only works when the allocation is up-to-date,
12143  * i.e. inside of paint().</para></note>
12144  *
12145  * Return value: %TRUE if conversion was successful.
12146  *
12147  * Since: 0.6
12148  */
12149 gboolean
12150 clutter_actor_transform_stage_point (ClutterActor *self,
12151                                      gfloat        x,
12152                                      gfloat        y,
12153                                      gfloat       *x_out,
12154                                      gfloat       *y_out)
12155 {
12156   ClutterVertex v[4];
12157   float ST[3][3];
12158   float RQ[3][3];
12159   int du, dv, xi, yi;
12160   float px, py;
12161   float xf, yf, wf, det;
12162   ClutterActorPrivate *priv;
12163
12164   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12165
12166   priv = self->priv;
12167
12168   /* This implementation is based on the quad -> quad projection algorithm
12169    * described by Paul Heckbert in:
12170    *
12171    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12172    *
12173    * and the sample implementation at:
12174    *
12175    *   http://www.cs.cmu.edu/~ph/src/texfund/
12176    *
12177    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12178    * quad to rectangle only, which significantly simplifies things; the
12179    * function calls have been unrolled, and most of the math is done in fixed
12180    * point.
12181    */
12182
12183   clutter_actor_get_abs_allocation_vertices (self, v);
12184
12185   /* Keeping these as ints simplifies the multiplication (no significant
12186    * loss of precision here).
12187    */
12188   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12189   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12190
12191   if (!du || !dv)
12192     return FALSE;
12193
12194 #define UX2FP(x)        (x)
12195 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12196
12197   /* First, find mapping from unit uv square to xy quadrilateral; this
12198    * equivalent to the pmap_square_quad() functions in the sample
12199    * implementation, which we can simplify, since our target is always
12200    * a rectangle.
12201    */
12202   px = v[0].x - v[1].x + v[3].x - v[2].x;
12203   py = v[0].y - v[1].y + v[3].y - v[2].y;
12204
12205   if (!px && !py)
12206     {
12207       /* affine transform */
12208       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12209       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12210       RQ[2][0] = UX2FP (v[0].x);
12211       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12212       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12213       RQ[2][1] = UX2FP (v[0].y);
12214       RQ[0][2] = 0;
12215       RQ[1][2] = 0;
12216       RQ[2][2] = 1.0;
12217     }
12218   else
12219     {
12220       /* projective transform */
12221       double dx1, dx2, dy1, dy2, del;
12222
12223       dx1 = UX2FP (v[1].x - v[3].x);
12224       dx2 = UX2FP (v[2].x - v[3].x);
12225       dy1 = UX2FP (v[1].y - v[3].y);
12226       dy2 = UX2FP (v[2].y - v[3].y);
12227
12228       del = DET2FP (dx1, dx2, dy1, dy2);
12229       if (!del)
12230         return FALSE;
12231
12232       /*
12233        * The division here needs to be done in floating point for
12234        * precisions reasons.
12235        */
12236       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12237       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12238       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12239       RQ[2][2] = 1.0;
12240       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12241       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12242       RQ[2][0] = UX2FP (v[0].x);
12243       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12244       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12245       RQ[2][1] = UX2FP (v[0].y);
12246     }
12247
12248   /*
12249    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12250    * square. Since our rectangle is based at 0,0 we only need to scale.
12251    */
12252   RQ[0][0] /= du;
12253   RQ[1][0] /= dv;
12254   RQ[0][1] /= du;
12255   RQ[1][1] /= dv;
12256   RQ[0][2] /= du;
12257   RQ[1][2] /= dv;
12258
12259   /*
12260    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12261    * inverse of that.
12262    */
12263   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12264   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12265   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12266   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12267   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12268   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12269   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12270   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12271   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12272
12273   /*
12274    * Check the resulting matrix is OK.
12275    */
12276   det = (RQ[0][0] * ST[0][0])
12277       + (RQ[0][1] * ST[0][1])
12278       + (RQ[0][2] * ST[0][2]);
12279   if (!det)
12280     return FALSE;
12281
12282   /*
12283    * Now transform our point with the ST matrix; the notional w
12284    * coordinate is 1, hence the last part is simply added.
12285    */
12286   xi = (int) x;
12287   yi = (int) y;
12288
12289   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12290   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12291   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12292
12293   if (x_out)
12294     *x_out = xf / wf;
12295
12296   if (y_out)
12297     *y_out = yf / wf;
12298
12299 #undef UX2FP
12300 #undef DET2FP
12301
12302   return TRUE;
12303 }
12304
12305 /*
12306  * ClutterGeometry
12307  */
12308
12309 static ClutterGeometry*
12310 clutter_geometry_copy (const ClutterGeometry *geometry)
12311 {
12312   return g_slice_dup (ClutterGeometry, geometry);
12313 }
12314
12315 static void
12316 clutter_geometry_free (ClutterGeometry *geometry)
12317 {
12318   if (G_LIKELY (geometry != NULL))
12319     g_slice_free (ClutterGeometry, geometry);
12320 }
12321
12322 /**
12323  * clutter_geometry_union:
12324  * @geometry_a: a #ClutterGeometry
12325  * @geometry_b: another #ClutterGeometry
12326  * @result: (out): location to store the result
12327  *
12328  * Find the union of two rectangles represented as #ClutterGeometry.
12329  *
12330  * Since: 1.4
12331  */
12332 void
12333 clutter_geometry_union (const ClutterGeometry *geometry_a,
12334                         const ClutterGeometry *geometry_b,
12335                         ClutterGeometry       *result)
12336 {
12337   /* We don't try to handle rectangles that can't be represented
12338    * as a signed integer box */
12339   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12340   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12341   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12342                   geometry_b->x + (gint)geometry_b->width);
12343   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12344                   geometry_b->y + (gint)geometry_b->height);
12345   result->x = x_1;
12346   result->y = y_1;
12347   result->width = x_2 - x_1;
12348   result->height = y_2 - y_1;
12349 }
12350
12351 /**
12352  * clutter_geometry_intersects:
12353  * @geometry0: The first geometry to test
12354  * @geometry1: The second geometry to test
12355  *
12356  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12357  * they do else %FALSE.
12358  *
12359  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12360  * %FALSE.
12361  *
12362  * Since: 1.4
12363  */
12364 gboolean
12365 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12366                              const ClutterGeometry *geometry1)
12367 {
12368   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12369       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12370       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12371       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12372     return FALSE;
12373   else
12374     return TRUE;
12375 }
12376
12377 static gboolean
12378 clutter_geometry_progress (const GValue *a,
12379                            const GValue *b,
12380                            gdouble       progress,
12381                            GValue       *retval)
12382 {
12383   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12384   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12385   ClutterGeometry res = { 0, };
12386   gint a_width = a_geom->width;
12387   gint b_width = b_geom->width;
12388   gint a_height = a_geom->height;
12389   gint b_height = b_geom->height;
12390
12391   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12392   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12393
12394   res.width = a_width + (b_width - a_width) * progress;
12395   res.height = a_height + (b_height - a_height) * progress;
12396
12397   g_value_set_boxed (retval, &res);
12398
12399   return TRUE;
12400 }
12401
12402 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12403                                clutter_geometry_copy,
12404                                clutter_geometry_free,
12405                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12406
12407 /*
12408  * ClutterVertices
12409  */
12410
12411 /**
12412  * clutter_vertex_new:
12413  * @x: X coordinate
12414  * @y: Y coordinate
12415  * @z: Z coordinate
12416  *
12417  * Creates a new #ClutterVertex for the point in 3D space
12418  * identified by the 3 coordinates @x, @y, @z
12419  *
12420  * Return value: the newly allocate #ClutterVertex. Use
12421  *   clutter_vertex_free() to free the resources
12422  *
12423  * Since: 1.0
12424  */
12425 ClutterVertex *
12426 clutter_vertex_new (gfloat x,
12427                     gfloat y,
12428                     gfloat z)
12429 {
12430   ClutterVertex *vertex;
12431
12432   vertex = g_slice_new (ClutterVertex);
12433   vertex->x = x;
12434   vertex->y = y;
12435   vertex->z = z;
12436
12437   return vertex;
12438 }
12439
12440 /**
12441  * clutter_vertex_copy:
12442  * @vertex: a #ClutterVertex
12443  *
12444  * Copies @vertex
12445  *
12446  * Return value: a newly allocated copy of #ClutterVertex. Use
12447  *   clutter_vertex_free() to free the allocated resources
12448  *
12449  * Since: 1.0
12450  */
12451 ClutterVertex *
12452 clutter_vertex_copy (const ClutterVertex *vertex)
12453 {
12454   if (G_LIKELY (vertex != NULL))
12455     return g_slice_dup (ClutterVertex, vertex);
12456
12457   return NULL;
12458 }
12459
12460 /**
12461  * clutter_vertex_free:
12462  * @vertex: a #ClutterVertex
12463  *
12464  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12465  *
12466  * Since: 1.0
12467  */
12468 void
12469 clutter_vertex_free (ClutterVertex *vertex)
12470 {
12471   if (G_UNLIKELY (vertex != NULL))
12472     g_slice_free (ClutterVertex, vertex);
12473 }
12474
12475 /**
12476  * clutter_vertex_equal:
12477  * @vertex_a: a #ClutterVertex
12478  * @vertex_b: a #ClutterVertex
12479  *
12480  * Compares @vertex_a and @vertex_b for equality
12481  *
12482  * Return value: %TRUE if the passed #ClutterVertex are equal
12483  *
12484  * Since: 1.0
12485  */
12486 gboolean
12487 clutter_vertex_equal (const ClutterVertex *vertex_a,
12488                       const ClutterVertex *vertex_b)
12489 {
12490   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12491
12492   if (vertex_a == vertex_b)
12493     return TRUE;
12494
12495   return vertex_a->x == vertex_b->x &&
12496          vertex_a->y == vertex_b->y &&
12497          vertex_a->z == vertex_b->z;
12498 }
12499
12500 static gboolean
12501 clutter_vertex_progress (const GValue *a,
12502                          const GValue *b,
12503                          gdouble       progress,
12504                          GValue       *retval)
12505 {
12506   const ClutterVertex *av = g_value_get_boxed (a);
12507   const ClutterVertex *bv = g_value_get_boxed (b);
12508   ClutterVertex res = { 0, };
12509
12510   res.x = av->x + (bv->x - av->x) * progress;
12511   res.y = av->y + (bv->y - av->y) * progress;
12512   res.z = av->z + (bv->z - av->z) * progress;
12513
12514   g_value_set_boxed (retval, &res);
12515
12516   return TRUE;
12517 }
12518
12519 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12520                                clutter_vertex_copy,
12521                                clutter_vertex_free,
12522                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12523
12524 /**
12525  * clutter_actor_is_rotated:
12526  * @self: a #ClutterActor
12527  *
12528  * Checks whether any rotation is applied to the actor.
12529  *
12530  * Return value: %TRUE if the actor is rotated.
12531  *
12532  * Since: 0.6
12533  */
12534 gboolean
12535 clutter_actor_is_rotated (ClutterActor *self)
12536 {
12537   const ClutterTransformInfo *info;
12538
12539   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12540
12541   info = _clutter_actor_get_transform_info_or_defaults (self);
12542
12543   if (info->rx_angle || info->ry_angle || info->rz_angle)
12544     return TRUE;
12545
12546   return FALSE;
12547 }
12548
12549 /**
12550  * clutter_actor_is_scaled:
12551  * @self: a #ClutterActor
12552  *
12553  * Checks whether the actor is scaled in either dimension.
12554  *
12555  * Return value: %TRUE if the actor is scaled.
12556  *
12557  * Since: 0.6
12558  */
12559 gboolean
12560 clutter_actor_is_scaled (ClutterActor *self)
12561 {
12562   const ClutterTransformInfo *info;
12563
12564   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12565
12566   info = _clutter_actor_get_transform_info_or_defaults (self);
12567
12568   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12569     return TRUE;
12570
12571   return FALSE;
12572 }
12573
12574 ClutterActor *
12575 _clutter_actor_get_stage_internal (ClutterActor *actor)
12576 {
12577   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12578     actor = actor->priv->parent;
12579
12580   return actor;
12581 }
12582
12583 /**
12584  * clutter_actor_get_stage:
12585  * @actor: a #ClutterActor
12586  *
12587  * Retrieves the #ClutterStage where @actor is contained.
12588  *
12589  * Return value: (transfer none) (type Clutter.Stage): the stage
12590  *   containing the actor, or %NULL
12591  *
12592  * Since: 0.8
12593  */
12594 ClutterActor *
12595 clutter_actor_get_stage (ClutterActor *actor)
12596 {
12597   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12598
12599   return _clutter_actor_get_stage_internal (actor);
12600 }
12601
12602 /**
12603  * clutter_actor_allocate_available_size:
12604  * @self: a #ClutterActor
12605  * @x: the actor's X coordinate
12606  * @y: the actor's Y coordinate
12607  * @available_width: the maximum available width, or -1 to use the
12608  *   actor's natural width
12609  * @available_height: the maximum available height, or -1 to use the
12610  *   actor's natural height
12611  * @flags: flags controlling the allocation
12612  *
12613  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12614  * preferred size, but limiting it to the maximum available width
12615  * and height provided.
12616  *
12617  * This function will do the right thing when dealing with the
12618  * actor's request mode.
12619  *
12620  * The implementation of this function is equivalent to:
12621  *
12622  * |[
12623  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12624  *     {
12625  *       clutter_actor_get_preferred_width (self, available_height,
12626  *                                          &amp;min_width,
12627  *                                          &amp;natural_width);
12628  *       width = CLAMP (natural_width, min_width, available_width);
12629  *
12630  *       clutter_actor_get_preferred_height (self, width,
12631  *                                           &amp;min_height,
12632  *                                           &amp;natural_height);
12633  *       height = CLAMP (natural_height, min_height, available_height);
12634  *     }
12635  *   else
12636  *     {
12637  *       clutter_actor_get_preferred_height (self, available_width,
12638  *                                           &amp;min_height,
12639  *                                           &amp;natural_height);
12640  *       height = CLAMP (natural_height, min_height, available_height);
12641  *
12642  *       clutter_actor_get_preferred_width (self, height,
12643  *                                          &amp;min_width,
12644  *                                          &amp;natural_width);
12645  *       width = CLAMP (natural_width, min_width, available_width);
12646  *     }
12647  *
12648  *   box.x1 = x; box.y1 = y;
12649  *   box.x2 = box.x1 + available_width;
12650  *   box.y2 = box.y1 + available_height;
12651  *   clutter_actor_allocate (self, &amp;box, flags);
12652  * ]|
12653  *
12654  * This function can be used by fluid layout managers to allocate
12655  * an actor's preferred size without making it bigger than the area
12656  * available for the container.
12657  *
12658  * Since: 1.0
12659  */
12660 void
12661 clutter_actor_allocate_available_size (ClutterActor           *self,
12662                                        gfloat                  x,
12663                                        gfloat                  y,
12664                                        gfloat                  available_width,
12665                                        gfloat                  available_height,
12666                                        ClutterAllocationFlags  flags)
12667 {
12668   ClutterActorPrivate *priv;
12669   gfloat width, height;
12670   gfloat min_width, min_height;
12671   gfloat natural_width, natural_height;
12672   ClutterActorBox box;
12673
12674   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12675
12676   priv = self->priv;
12677
12678   width = height = 0.0;
12679
12680   switch (priv->request_mode)
12681     {
12682     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12683       clutter_actor_get_preferred_width (self, available_height,
12684                                          &min_width,
12685                                          &natural_width);
12686       width  = CLAMP (natural_width, min_width, available_width);
12687
12688       clutter_actor_get_preferred_height (self, width,
12689                                           &min_height,
12690                                           &natural_height);
12691       height = CLAMP (natural_height, min_height, available_height);
12692       break;
12693
12694     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12695       clutter_actor_get_preferred_height (self, available_width,
12696                                           &min_height,
12697                                           &natural_height);
12698       height = CLAMP (natural_height, min_height, available_height);
12699
12700       clutter_actor_get_preferred_width (self, height,
12701                                          &min_width,
12702                                          &natural_width);
12703       width  = CLAMP (natural_width, min_width, available_width);
12704       break;
12705     }
12706
12707
12708   box.x1 = x;
12709   box.y1 = y;
12710   box.x2 = box.x1 + width;
12711   box.y2 = box.y1 + height;
12712   clutter_actor_allocate (self, &box, flags);
12713 }
12714
12715 /**
12716  * clutter_actor_allocate_preferred_size:
12717  * @self: a #ClutterActor
12718  * @flags: flags controlling the allocation
12719  *
12720  * Allocates the natural size of @self.
12721  *
12722  * This function is a utility call for #ClutterActor implementations
12723  * that allocates the actor's preferred natural size. It can be used
12724  * by fixed layout managers (like #ClutterGroup or so called
12725  * 'composite actors') inside the ClutterActor::allocate
12726  * implementation to give each child exactly how much space it
12727  * requires.
12728  *
12729  * This function is not meant to be used by applications. It is also
12730  * not meant to be used outside the implementation of the
12731  * ClutterActor::allocate virtual function.
12732  *
12733  * Since: 0.8
12734  */
12735 void
12736 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12737                                        ClutterAllocationFlags  flags)
12738 {
12739   gfloat actor_x, actor_y;
12740   gfloat natural_width, natural_height;
12741   ClutterActorBox actor_box;
12742
12743   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12744
12745   actor_x = clutter_actor_get_x (self);
12746   actor_y = clutter_actor_get_y (self);
12747
12748   clutter_actor_get_preferred_size (self,
12749                                     NULL, NULL,
12750                                     &natural_width,
12751                                     &natural_height);
12752
12753   actor_box.x1 = actor_x;
12754   actor_box.y1 = actor_y;
12755   actor_box.x2 = actor_box.x1 + natural_width;
12756   actor_box.y2 = actor_box.y1 + natural_height;
12757
12758   clutter_actor_allocate (self, &actor_box, flags);
12759 }
12760
12761 /**
12762  * clutter_actor_allocate_align_fill:
12763  * @self: a #ClutterActor
12764  * @box: a #ClutterActorBox, containing the available width and height
12765  * @x_align: the horizontal alignment, between 0 and 1
12766  * @y_align: the vertical alignment, between 0 and 1
12767  * @x_fill: whether the actor should fill horizontally
12768  * @y_fill: whether the actor should fill vertically
12769  * @flags: allocation flags to be passed to clutter_actor_allocate()
12770  *
12771  * Allocates @self by taking into consideration the available allocation
12772  * area; an alignment factor on either axis; and whether the actor should
12773  * fill the allocation on either axis.
12774  *
12775  * The @box should contain the available allocation width and height;
12776  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12777  * allocation will be offset by their value.
12778  *
12779  * This function takes into consideration the geometry request specified by
12780  * the #ClutterActor:request-mode property, and the text direction.
12781  *
12782  * This function is useful for fluid layout managers, like #ClutterBinLayout
12783  * or #ClutterTableLayout
12784  *
12785  * Since: 1.4
12786  */
12787 void
12788 clutter_actor_allocate_align_fill (ClutterActor           *self,
12789                                    const ClutterActorBox  *box,
12790                                    gdouble                 x_align,
12791                                    gdouble                 y_align,
12792                                    gboolean                x_fill,
12793                                    gboolean                y_fill,
12794                                    ClutterAllocationFlags  flags)
12795 {
12796   ClutterActorPrivate *priv;
12797   ClutterActorBox allocation = { 0, };
12798   gfloat x_offset, y_offset;
12799   gfloat available_width, available_height;
12800   gfloat child_width, child_height;
12801
12802   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12803   g_return_if_fail (box != NULL);
12804   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12805   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12806
12807   priv = self->priv;
12808
12809   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12810   clutter_actor_box_get_size (box, &available_width, &available_height);
12811
12812   if (available_width < 0)
12813     available_width = 0;
12814
12815   if (available_height < 0)
12816     available_height = 0;
12817
12818   if (x_fill)
12819     {
12820       allocation.x1 = x_offset;
12821       allocation.x2 = allocation.x1 + available_width;
12822     }
12823
12824   if (y_fill)
12825     {
12826       allocation.y1 = y_offset;
12827       allocation.y2 = allocation.y1 + available_height;
12828     }
12829
12830   /* if we are filling horizontally and vertically then we're done */
12831   if (x_fill && y_fill)
12832     goto out;
12833
12834   child_width = child_height = 0.0f;
12835
12836   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12837     {
12838       gfloat min_width, natural_width;
12839       gfloat min_height, natural_height;
12840
12841       clutter_actor_get_preferred_width (self, available_height,
12842                                          &min_width,
12843                                          &natural_width);
12844
12845       child_width = CLAMP (natural_width, min_width, available_width);
12846
12847       if (!y_fill)
12848         {
12849           clutter_actor_get_preferred_height (self, child_width,
12850                                               &min_height,
12851                                               &natural_height);
12852
12853           child_height = CLAMP (natural_height, min_height, available_height);
12854         }
12855     }
12856   else
12857     {
12858       gfloat min_width, natural_width;
12859       gfloat min_height, natural_height;
12860
12861       clutter_actor_get_preferred_height (self, available_width,
12862                                           &min_height,
12863                                           &natural_height);
12864
12865       child_height = CLAMP (natural_height, min_height, available_height);
12866
12867       if (!x_fill)
12868         {
12869           clutter_actor_get_preferred_width (self, child_height,
12870                                              &min_width,
12871                                              &natural_width);
12872
12873           child_width = CLAMP (natural_width, min_width, available_width);
12874         }
12875     }
12876
12877   /* invert the horizontal alignment for RTL languages */
12878   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12879     x_align = 1.0 - x_align;
12880
12881   if (!x_fill)
12882     {
12883       allocation.x1 = x_offset
12884                     + ((available_width - child_width) * x_align);
12885       allocation.x2 = allocation.x1 + child_width;
12886     }
12887
12888   if (!y_fill)
12889     {
12890       allocation.y1 = y_offset
12891                     + ((available_height - child_height) * y_align);
12892       allocation.y2 = allocation.y1 + child_height;
12893     }
12894
12895 out:
12896   clutter_actor_box_clamp_to_pixel (&allocation);
12897   clutter_actor_allocate (self, &allocation, flags);
12898 }
12899
12900 /**
12901  * clutter_actor_grab_key_focus:
12902  * @self: a #ClutterActor
12903  *
12904  * Sets the key focus of the #ClutterStage including @self
12905  * to this #ClutterActor.
12906  *
12907  * Since: 1.0
12908  */
12909 void
12910 clutter_actor_grab_key_focus (ClutterActor *self)
12911 {
12912   ClutterActor *stage;
12913
12914   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12915
12916   stage = _clutter_actor_get_stage_internal (self);
12917   if (stage != NULL)
12918     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12919 }
12920
12921 /**
12922  * clutter_actor_get_pango_context:
12923  * @self: a #ClutterActor
12924  *
12925  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12926  * is already configured using the appropriate font map, resolution
12927  * and font options.
12928  *
12929  * Unlike clutter_actor_create_pango_context(), this context is owend
12930  * by the #ClutterActor and it will be updated each time the options
12931  * stored by the #ClutterBackend change.
12932  *
12933  * You can use the returned #PangoContext to create a #PangoLayout
12934  * and render text using cogl_pango_render_layout() to reuse the
12935  * glyphs cache also used by Clutter.
12936  *
12937  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12938  *   The returned #PangoContext is owned by the actor and should not be
12939  *   unreferenced by the application code
12940  *
12941  * Since: 1.0
12942  */
12943 PangoContext *
12944 clutter_actor_get_pango_context (ClutterActor *self)
12945 {
12946   ClutterActorPrivate *priv;
12947
12948   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12949
12950   priv = self->priv;
12951
12952   if (priv->pango_context != NULL)
12953     return priv->pango_context;
12954
12955   priv->pango_context = _clutter_context_get_pango_context ();
12956   g_object_ref (priv->pango_context);
12957
12958   return priv->pango_context;
12959 }
12960
12961 /**
12962  * clutter_actor_create_pango_context:
12963  * @self: a #ClutterActor
12964  *
12965  * Creates a #PangoContext for the given actor. The #PangoContext
12966  * is already configured using the appropriate font map, resolution
12967  * and font options.
12968  *
12969  * See also clutter_actor_get_pango_context().
12970  *
12971  * Return value: (transfer full): the newly created #PangoContext.
12972  *   Use g_object_unref() on the returned value to deallocate its
12973  *   resources
12974  *
12975  * Since: 1.0
12976  */
12977 PangoContext *
12978 clutter_actor_create_pango_context (ClutterActor *self)
12979 {
12980   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12981
12982   return _clutter_context_create_pango_context ();
12983 }
12984
12985 /**
12986  * clutter_actor_create_pango_layout:
12987  * @self: a #ClutterActor
12988  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
12989  *
12990  * Creates a new #PangoLayout from the same #PangoContext used
12991  * by the #ClutterActor. The #PangoLayout is already configured
12992  * with the font map, resolution and font options, and the
12993  * given @text.
12994  *
12995  * If you want to keep around a #PangoLayout created by this
12996  * function you will have to connect to the #ClutterBackend::font-changed
12997  * and #ClutterBackend::resolution-changed signals, and call
12998  * pango_layout_context_changed() in response to them.
12999  *
13000  * Return value: (transfer full): the newly created #PangoLayout.
13001  *   Use g_object_unref() when done
13002  *
13003  * Since: 1.0
13004  */
13005 PangoLayout *
13006 clutter_actor_create_pango_layout (ClutterActor *self,
13007                                    const gchar  *text)
13008 {
13009   PangoContext *context;
13010   PangoLayout *layout;
13011
13012   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13013
13014   context = clutter_actor_get_pango_context (self);
13015   layout = pango_layout_new (context);
13016
13017   if (text)
13018     pango_layout_set_text (layout, text, -1);
13019
13020   return layout;
13021 }
13022
13023 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13024  * ClutterOffscreenEffect.
13025  */
13026 void
13027 _clutter_actor_set_opacity_override (ClutterActor *self,
13028                                      gint          opacity)
13029 {
13030   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13031
13032   self->priv->opacity_override = opacity;
13033 }
13034
13035 gint
13036 _clutter_actor_get_opacity_override (ClutterActor *self)
13037 {
13038   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13039
13040   return self->priv->opacity_override;
13041 }
13042
13043 /* Allows you to disable applying the actors model view transform during
13044  * a paint. Used by ClutterClone. */
13045 void
13046 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13047                                                 gboolean      enable)
13048 {
13049   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13050
13051   self->priv->enable_model_view_transform = enable;
13052 }
13053
13054 void
13055 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13056                                           gboolean      enable)
13057 {
13058   ClutterActorPrivate *priv;
13059
13060   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13061
13062   priv = self->priv;
13063
13064   priv->enable_paint_unmapped = enable;
13065
13066   if (priv->enable_paint_unmapped)
13067     {
13068       /* Make sure that the parents of the widget are realized first;
13069        * otherwise checks in clutter_actor_update_map_state() will
13070        * fail.
13071        */
13072       clutter_actor_realize (self);
13073
13074       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13075     }
13076   else
13077     {
13078       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13079     }
13080 }
13081
13082 static void
13083 clutter_anchor_coord_get_units (ClutterActor      *self,
13084                                 const AnchorCoord *coord,
13085                                 gfloat            *x,
13086                                 gfloat            *y,
13087                                 gfloat            *z)
13088 {
13089   if (coord->is_fractional)
13090     {
13091       gfloat actor_width, actor_height;
13092
13093       clutter_actor_get_size (self, &actor_width, &actor_height);
13094
13095       if (x)
13096         *x = actor_width * coord->v.fraction.x;
13097
13098       if (y)
13099         *y = actor_height * coord->v.fraction.y;
13100
13101       if (z)
13102         *z = 0;
13103     }
13104   else
13105     {
13106       if (x)
13107         *x = coord->v.units.x;
13108
13109       if (y)
13110         *y = coord->v.units.y;
13111
13112       if (z)
13113         *z = coord->v.units.z;
13114     }
13115 }
13116
13117 static void
13118 clutter_anchor_coord_set_units (AnchorCoord *coord,
13119                                 gfloat       x,
13120                                 gfloat       y,
13121                                 gfloat       z)
13122 {
13123   coord->is_fractional = FALSE;
13124   coord->v.units.x = x;
13125   coord->v.units.y = y;
13126   coord->v.units.z = z;
13127 }
13128
13129 static ClutterGravity
13130 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13131 {
13132   if (coord->is_fractional)
13133     {
13134       if (coord->v.fraction.x == 0.0)
13135         {
13136           if (coord->v.fraction.y == 0.0)
13137             return CLUTTER_GRAVITY_NORTH_WEST;
13138           else if (coord->v.fraction.y == 0.5)
13139             return CLUTTER_GRAVITY_WEST;
13140           else if (coord->v.fraction.y == 1.0)
13141             return CLUTTER_GRAVITY_SOUTH_WEST;
13142           else
13143             return CLUTTER_GRAVITY_NONE;
13144         }
13145       else if (coord->v.fraction.x == 0.5)
13146         {
13147           if (coord->v.fraction.y == 0.0)
13148             return CLUTTER_GRAVITY_NORTH;
13149           else if (coord->v.fraction.y == 0.5)
13150             return CLUTTER_GRAVITY_CENTER;
13151           else if (coord->v.fraction.y == 1.0)
13152             return CLUTTER_GRAVITY_SOUTH;
13153           else
13154             return CLUTTER_GRAVITY_NONE;
13155         }
13156       else if (coord->v.fraction.x == 1.0)
13157         {
13158           if (coord->v.fraction.y == 0.0)
13159             return CLUTTER_GRAVITY_NORTH_EAST;
13160           else if (coord->v.fraction.y == 0.5)
13161             return CLUTTER_GRAVITY_EAST;
13162           else if (coord->v.fraction.y == 1.0)
13163             return CLUTTER_GRAVITY_SOUTH_EAST;
13164           else
13165             return CLUTTER_GRAVITY_NONE;
13166         }
13167       else
13168         return CLUTTER_GRAVITY_NONE;
13169     }
13170   else
13171     return CLUTTER_GRAVITY_NONE;
13172 }
13173
13174 static void
13175 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13176                                   ClutterGravity  gravity)
13177 {
13178   switch (gravity)
13179     {
13180     case CLUTTER_GRAVITY_NORTH:
13181       coord->v.fraction.x = 0.5;
13182       coord->v.fraction.y = 0.0;
13183       break;
13184
13185     case CLUTTER_GRAVITY_NORTH_EAST:
13186       coord->v.fraction.x = 1.0;
13187       coord->v.fraction.y = 0.0;
13188       break;
13189
13190     case CLUTTER_GRAVITY_EAST:
13191       coord->v.fraction.x = 1.0;
13192       coord->v.fraction.y = 0.5;
13193       break;
13194
13195     case CLUTTER_GRAVITY_SOUTH_EAST:
13196       coord->v.fraction.x = 1.0;
13197       coord->v.fraction.y = 1.0;
13198       break;
13199
13200     case CLUTTER_GRAVITY_SOUTH:
13201       coord->v.fraction.x = 0.5;
13202       coord->v.fraction.y = 1.0;
13203       break;
13204
13205     case CLUTTER_GRAVITY_SOUTH_WEST:
13206       coord->v.fraction.x = 0.0;
13207       coord->v.fraction.y = 1.0;
13208       break;
13209
13210     case CLUTTER_GRAVITY_WEST:
13211       coord->v.fraction.x = 0.0;
13212       coord->v.fraction.y = 0.5;
13213       break;
13214
13215     case CLUTTER_GRAVITY_NORTH_WEST:
13216       coord->v.fraction.x = 0.0;
13217       coord->v.fraction.y = 0.0;
13218       break;
13219
13220     case CLUTTER_GRAVITY_CENTER:
13221       coord->v.fraction.x = 0.5;
13222       coord->v.fraction.y = 0.5;
13223       break;
13224
13225     default:
13226       coord->v.fraction.x = 0.0;
13227       coord->v.fraction.y = 0.0;
13228       break;
13229     }
13230
13231   coord->is_fractional = TRUE;
13232 }
13233
13234 static gboolean
13235 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13236 {
13237   if (coord->is_fractional)
13238     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13239   else
13240     return (coord->v.units.x == 0.0
13241             && coord->v.units.y == 0.0
13242             && coord->v.units.z == 0.0);
13243 }
13244
13245 /**
13246  * clutter_actor_get_flags:
13247  * @self: a #ClutterActor
13248  *
13249  * Retrieves the flags set on @self
13250  *
13251  * Return value: a bitwise or of #ClutterActorFlags or 0
13252  *
13253  * Since: 1.0
13254  */
13255 ClutterActorFlags
13256 clutter_actor_get_flags (ClutterActor *self)
13257 {
13258   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13259
13260   return self->flags;
13261 }
13262
13263 /**
13264  * clutter_actor_set_flags:
13265  * @self: a #ClutterActor
13266  * @flags: the flags to set
13267  *
13268  * Sets @flags on @self
13269  *
13270  * This function will emit notifications for the changed properties
13271  *
13272  * Since: 1.0
13273  */
13274 void
13275 clutter_actor_set_flags (ClutterActor      *self,
13276                          ClutterActorFlags  flags)
13277 {
13278   ClutterActorFlags old_flags;
13279   GObject *obj;
13280   gboolean was_reactive_set, reactive_set;
13281   gboolean was_realized_set, realized_set;
13282   gboolean was_mapped_set, mapped_set;
13283   gboolean was_visible_set, visible_set;
13284
13285   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13286
13287   if (self->flags == flags)
13288     return;
13289
13290   obj = G_OBJECT (self);
13291   g_object_ref (obj);
13292   g_object_freeze_notify (obj);
13293
13294   old_flags = self->flags;
13295
13296   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13297   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13298   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13299   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13300
13301   self->flags |= flags;
13302
13303   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13304   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13305   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13306   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13307
13308   if (reactive_set != was_reactive_set)
13309     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13310
13311   if (realized_set != was_realized_set)
13312     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13313
13314   if (mapped_set != was_mapped_set)
13315     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13316
13317   if (visible_set != was_visible_set)
13318     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13319
13320   g_object_thaw_notify (obj);
13321   g_object_unref (obj);
13322 }
13323
13324 /**
13325  * clutter_actor_unset_flags:
13326  * @self: a #ClutterActor
13327  * @flags: the flags to unset
13328  *
13329  * Unsets @flags on @self
13330  *
13331  * This function will emit notifications for the changed properties
13332  *
13333  * Since: 1.0
13334  */
13335 void
13336 clutter_actor_unset_flags (ClutterActor      *self,
13337                            ClutterActorFlags  flags)
13338 {
13339   ClutterActorFlags old_flags;
13340   GObject *obj;
13341   gboolean was_reactive_set, reactive_set;
13342   gboolean was_realized_set, realized_set;
13343   gboolean was_mapped_set, mapped_set;
13344   gboolean was_visible_set, visible_set;
13345
13346   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13347
13348   obj = G_OBJECT (self);
13349   g_object_freeze_notify (obj);
13350
13351   old_flags = self->flags;
13352
13353   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13354   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13355   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13356   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13357
13358   self->flags &= ~flags;
13359
13360   if (self->flags == old_flags)
13361     return;
13362
13363   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13364   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13365   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13366   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13367
13368   if (reactive_set != was_reactive_set)
13369     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13370
13371   if (realized_set != was_realized_set)
13372     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13373
13374   if (mapped_set != was_mapped_set)
13375     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13376
13377   if (visible_set != was_visible_set)
13378     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13379
13380   g_object_thaw_notify (obj);
13381 }
13382
13383 /**
13384  * clutter_actor_get_transformation_matrix:
13385  * @self: a #ClutterActor
13386  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13387  *
13388  * Retrieves the transformations applied to @self relative to its
13389  * parent.
13390  *
13391  * Since: 1.0
13392  */
13393 void
13394 clutter_actor_get_transformation_matrix (ClutterActor *self,
13395                                          CoglMatrix   *matrix)
13396 {
13397   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13398
13399   cogl_matrix_init_identity (matrix);
13400
13401   _clutter_actor_apply_modelview_transform (self, matrix);
13402 }
13403
13404 void
13405 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13406                                    gboolean      is_in_clone_paint)
13407 {
13408   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13409   self->priv->in_clone_paint = is_in_clone_paint;
13410 }
13411
13412 /**
13413  * clutter_actor_is_in_clone_paint:
13414  * @self: a #ClutterActor
13415  *
13416  * Checks whether @self is being currently painted by a #ClutterClone
13417  *
13418  * This function is useful only inside the ::paint virtual function
13419  * implementations or within handlers for the #ClutterActor::paint
13420  * signal
13421  *
13422  * This function should not be used by applications
13423  *
13424  * Return value: %TRUE if the #ClutterActor is currently being painted
13425  *   by a #ClutterClone, and %FALSE otherwise
13426  *
13427  * Since: 1.0
13428  */
13429 gboolean
13430 clutter_actor_is_in_clone_paint (ClutterActor *self)
13431 {
13432   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13433
13434   return self->priv->in_clone_paint;
13435 }
13436
13437 static gboolean
13438 set_direction_recursive (ClutterActor *actor,
13439                          gpointer      user_data)
13440 {
13441   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13442
13443   clutter_actor_set_text_direction (actor, text_dir);
13444
13445   return TRUE;
13446 }
13447
13448 /**
13449  * clutter_actor_set_text_direction:
13450  * @self: a #ClutterActor
13451  * @text_dir: the text direction for @self
13452  *
13453  * Sets the #ClutterTextDirection for an actor
13454  *
13455  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13456  *
13457  * If @self implements #ClutterContainer then this function will recurse
13458  * inside all the children of @self (including the internal ones).
13459  *
13460  * Composite actors not implementing #ClutterContainer, or actors requiring
13461  * special handling when the text direction changes, should connect to
13462  * the #GObject::notify signal for the #ClutterActor:text-direction property
13463  *
13464  * Since: 1.2
13465  */
13466 void
13467 clutter_actor_set_text_direction (ClutterActor         *self,
13468                                   ClutterTextDirection  text_dir)
13469 {
13470   ClutterActorPrivate *priv;
13471
13472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13473   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13474
13475   priv = self->priv;
13476
13477   if (priv->text_direction != text_dir)
13478     {
13479       priv->text_direction = text_dir;
13480
13481       /* we need to emit the notify::text-direction first, so that
13482        * the sub-classes can catch that and do specific handling of
13483        * the text direction; see clutter_text_direction_changed_cb()
13484        * inside clutter-text.c
13485        */
13486       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13487
13488       _clutter_actor_foreach_child (self, set_direction_recursive,
13489                                     GINT_TO_POINTER (text_dir));
13490
13491       clutter_actor_queue_relayout (self);
13492     }
13493 }
13494
13495 void
13496 _clutter_actor_set_has_pointer (ClutterActor *self,
13497                                 gboolean      has_pointer)
13498 {
13499   ClutterActorPrivate *priv = self->priv;
13500
13501   if (priv->has_pointer != has_pointer)
13502     {
13503       priv->has_pointer = has_pointer;
13504
13505       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13506     }
13507 }
13508
13509 /**
13510  * clutter_actor_get_text_direction:
13511  * @self: a #ClutterActor
13512  *
13513  * Retrieves the value set using clutter_actor_set_text_direction()
13514  *
13515  * If no text direction has been previously set, the default text
13516  * direction, as returned by clutter_get_default_text_direction(), will
13517  * be returned instead
13518  *
13519  * Return value: the #ClutterTextDirection for the actor
13520  *
13521  * Since: 1.2
13522  */
13523 ClutterTextDirection
13524 clutter_actor_get_text_direction (ClutterActor *self)
13525 {
13526   ClutterActorPrivate *priv;
13527
13528   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13529                         CLUTTER_TEXT_DIRECTION_LTR);
13530
13531   priv = self->priv;
13532
13533   /* if no direction has been set yet use the default */
13534   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13535     priv->text_direction = clutter_get_default_text_direction ();
13536
13537   return priv->text_direction;
13538 }
13539
13540 /**
13541  * clutter_actor_push_internal:
13542  * @self: a #ClutterActor
13543  *
13544  * Should be used by actors implementing the #ClutterContainer and with
13545  * internal children added through clutter_actor_set_parent(), for instance:
13546  *
13547  * |[
13548  *   static void
13549  *   my_actor_init (MyActor *self)
13550  *   {
13551  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13552  *
13553  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13554  *
13555  *     /&ast; calling clutter_actor_set_parent() now will result in
13556  *      &ast; the internal flag being set on a child of MyActor
13557  *      &ast;/
13558  *
13559  *     /&ast; internal child - a background texture &ast;/
13560  *     self->priv->background_tex = clutter_texture_new ();
13561  *     clutter_actor_set_parent (self->priv->background_tex,
13562  *                               CLUTTER_ACTOR (self));
13563  *
13564  *     /&ast; internal child - a label &ast;/
13565  *     self->priv->label = clutter_text_new ();
13566  *     clutter_actor_set_parent (self->priv->label,
13567  *                               CLUTTER_ACTOR (self));
13568  *
13569  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13570  *
13571  *     /&ast; calling clutter_actor_set_parent() now will not result in
13572  *      &ast; the internal flag being set on a child of MyActor
13573  *      &ast;/
13574  *   }
13575  * ]|
13576  *
13577  * This function will be used by Clutter to toggle an "internal child"
13578  * flag whenever clutter_actor_set_parent() is called; internal children
13579  * are handled differently by Clutter, specifically when destroying their
13580  * parent.
13581  *
13582  * Call clutter_actor_pop_internal() when you finished adding internal
13583  * children.
13584  *
13585  * Nested calls to clutter_actor_push_internal() are allowed, but each
13586  * one must by followed by a clutter_actor_pop_internal() call.
13587  *
13588  * Since: 1.2
13589  *
13590  * Deprecated: 1.10: All children of an actor are accessible through
13591  *   the #ClutterActor API, and #ClutterActor implements the
13592  *   #ClutterContainer interface, so this function is only useful
13593  *   for legacy containers overriding the default implementation.
13594  */
13595 void
13596 clutter_actor_push_internal (ClutterActor *self)
13597 {
13598   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13599
13600   self->priv->internal_child += 1;
13601 }
13602
13603 /**
13604  * clutter_actor_pop_internal:
13605  * @self: a #ClutterActor
13606  *
13607  * Disables the effects of clutter_actor_push_internal().
13608  *
13609  * Since: 1.2
13610  *
13611  * Deprecated: 1.10: All children of an actor are accessible through
13612  *   the #ClutterActor API. This function is only useful for legacy
13613  *   containers overriding the default implementation of the
13614  *   #ClutterContainer interface.
13615  */
13616 void
13617 clutter_actor_pop_internal (ClutterActor *self)
13618 {
13619   ClutterActorPrivate *priv;
13620
13621   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13622
13623   priv = self->priv;
13624
13625   if (priv->internal_child == 0)
13626     {
13627       g_warning ("Mismatched %s: you need to call "
13628                  "clutter_actor_push_composite() at least once before "
13629                  "calling this function", G_STRFUNC);
13630       return;
13631     }
13632
13633   priv->internal_child -= 1;
13634 }
13635
13636 /**
13637  * clutter_actor_has_pointer:
13638  * @self: a #ClutterActor
13639  *
13640  * Checks whether an actor contains the pointer of a
13641  * #ClutterInputDevice
13642  *
13643  * Return value: %TRUE if the actor contains the pointer, and
13644  *   %FALSE otherwise
13645  *
13646  * Since: 1.2
13647  */
13648 gboolean
13649 clutter_actor_has_pointer (ClutterActor *self)
13650 {
13651   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13652
13653   return self->priv->has_pointer;
13654 }
13655
13656 /* XXX: This is a workaround for not being able to break the ABI of
13657  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13658  * clutter_actor_queue_clipped_redraw() for details.
13659  */
13660 ClutterPaintVolume *
13661 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13662 {
13663   return g_object_get_data (G_OBJECT (self),
13664                             "-clutter-actor-queue-redraw-clip");
13665 }
13666
13667 void
13668 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13669                                       ClutterPaintVolume *clip)
13670 {
13671   g_object_set_data (G_OBJECT (self),
13672                      "-clutter-actor-queue-redraw-clip",
13673                      clip);
13674 }
13675
13676 /**
13677  * clutter_actor_has_allocation:
13678  * @self: a #ClutterActor
13679  *
13680  * Checks if the actor has an up-to-date allocation assigned to
13681  * it. This means that the actor should have an allocation: it's
13682  * visible and has a parent. It also means that there is no
13683  * outstanding relayout request in progress for the actor or its
13684  * children (There might be other outstanding layout requests in
13685  * progress that will cause the actor to get a new allocation
13686  * when the stage is laid out, however).
13687  *
13688  * If this function returns %FALSE, then the actor will normally
13689  * be allocated before it is next drawn on the screen.
13690  *
13691  * Return value: %TRUE if the actor has an up-to-date allocation
13692  *
13693  * Since: 1.4
13694  */
13695 gboolean
13696 clutter_actor_has_allocation (ClutterActor *self)
13697 {
13698   ClutterActorPrivate *priv;
13699
13700   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13701
13702   priv = self->priv;
13703
13704   return priv->parent != NULL &&
13705          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13706          !priv->needs_allocation;
13707 }
13708
13709 /**
13710  * clutter_actor_add_action:
13711  * @self: a #ClutterActor
13712  * @action: a #ClutterAction
13713  *
13714  * Adds @action to the list of actions applied to @self
13715  *
13716  * A #ClutterAction can only belong to one actor at a time
13717  *
13718  * The #ClutterActor will hold a reference on @action until either
13719  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13720  * is called
13721  *
13722  * Since: 1.4
13723  */
13724 void
13725 clutter_actor_add_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     {
13737       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13738       priv->actions->actor = self;
13739     }
13740
13741   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13742
13743   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13744 }
13745
13746 /**
13747  * clutter_actor_add_action_with_name:
13748  * @self: a #ClutterActor
13749  * @name: the name to set on the action
13750  * @action: a #ClutterAction
13751  *
13752  * A convenience function for setting the name of a #ClutterAction
13753  * while adding it to the list of actions applied to @self
13754  *
13755  * This function is the logical equivalent of:
13756  *
13757  * |[
13758  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13759  *   clutter_actor_add_action (self, action);
13760  * ]|
13761  *
13762  * Since: 1.4
13763  */
13764 void
13765 clutter_actor_add_action_with_name (ClutterActor  *self,
13766                                     const gchar   *name,
13767                                     ClutterAction *action)
13768 {
13769   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13770   g_return_if_fail (name != NULL);
13771   g_return_if_fail (CLUTTER_IS_ACTION (action));
13772
13773   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13774   clutter_actor_add_action (self, action);
13775 }
13776
13777 /**
13778  * clutter_actor_remove_action:
13779  * @self: a #ClutterActor
13780  * @action: a #ClutterAction
13781  *
13782  * Removes @action from the list of actions applied to @self
13783  *
13784  * The reference held by @self on the #ClutterAction will be released
13785  *
13786  * Since: 1.4
13787  */
13788 void
13789 clutter_actor_remove_action (ClutterActor  *self,
13790                              ClutterAction *action)
13791 {
13792   ClutterActorPrivate *priv;
13793
13794   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13795   g_return_if_fail (CLUTTER_IS_ACTION (action));
13796
13797   priv = self->priv;
13798
13799   if (priv->actions == NULL)
13800     return;
13801
13802   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13803
13804   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13805 }
13806
13807 /**
13808  * clutter_actor_remove_action_by_name:
13809  * @self: a #ClutterActor
13810  * @name: the name of the action to remove
13811  *
13812  * Removes the #ClutterAction with the given name from the list
13813  * of actions applied to @self
13814  *
13815  * Since: 1.4
13816  */
13817 void
13818 clutter_actor_remove_action_by_name (ClutterActor *self,
13819                                      const gchar  *name)
13820 {
13821   ClutterActorPrivate *priv;
13822   ClutterActorMeta *meta;
13823
13824   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13825   g_return_if_fail (name != NULL);
13826
13827   priv = self->priv;
13828
13829   if (priv->actions == NULL)
13830     return;
13831
13832   meta = _clutter_meta_group_get_meta (priv->actions, name);
13833   if (meta == NULL)
13834     return;
13835
13836   _clutter_meta_group_remove_meta (priv->actions, meta);
13837
13838   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13839 }
13840
13841 /**
13842  * clutter_actor_get_actions:
13843  * @self: a #ClutterActor
13844  *
13845  * Retrieves the list of actions applied to @self
13846  *
13847  * Return value: (transfer container) (element-type Clutter.Action): a copy
13848  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13849  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13850  *   allocated by the returned #GList
13851  *
13852  * Since: 1.4
13853  */
13854 GList *
13855 clutter_actor_get_actions (ClutterActor *self)
13856 {
13857   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13858
13859   if (self->priv->actions == NULL)
13860     return NULL;
13861
13862   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13863 }
13864
13865 /**
13866  * clutter_actor_get_action:
13867  * @self: a #ClutterActor
13868  * @name: the name of the action to retrieve
13869  *
13870  * Retrieves the #ClutterAction with the given name in the list
13871  * of actions applied to @self
13872  *
13873  * Return value: (transfer none): a #ClutterAction for the given
13874  *   name, or %NULL. The returned #ClutterAction is owned by the
13875  *   actor and it should not be unreferenced directly
13876  *
13877  * Since: 1.4
13878  */
13879 ClutterAction *
13880 clutter_actor_get_action (ClutterActor *self,
13881                           const gchar  *name)
13882 {
13883   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13884   g_return_val_if_fail (name != NULL, NULL);
13885
13886   if (self->priv->actions == NULL)
13887     return NULL;
13888
13889   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13890 }
13891
13892 /**
13893  * clutter_actor_clear_actions:
13894  * @self: a #ClutterActor
13895  *
13896  * Clears the list of actions applied to @self
13897  *
13898  * Since: 1.4
13899  */
13900 void
13901 clutter_actor_clear_actions (ClutterActor *self)
13902 {
13903   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13904
13905   if (self->priv->actions == NULL)
13906     return;
13907
13908   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13909 }
13910
13911 /**
13912  * clutter_actor_add_constraint:
13913  * @self: a #ClutterActor
13914  * @constraint: a #ClutterConstraint
13915  *
13916  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13917  * to @self
13918  *
13919  * The #ClutterActor will hold a reference on the @constraint until
13920  * either clutter_actor_remove_constraint() or
13921  * clutter_actor_clear_constraints() is called.
13922  *
13923  * Since: 1.4
13924  */
13925 void
13926 clutter_actor_add_constraint (ClutterActor      *self,
13927                               ClutterConstraint *constraint)
13928 {
13929   ClutterActorPrivate *priv;
13930
13931   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13932   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13933
13934   priv = self->priv;
13935
13936   if (priv->constraints == NULL)
13937     {
13938       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13939       priv->constraints->actor = self;
13940     }
13941
13942   _clutter_meta_group_add_meta (priv->constraints,
13943                                 CLUTTER_ACTOR_META (constraint));
13944   clutter_actor_queue_relayout (self);
13945
13946   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13947 }
13948
13949 /**
13950  * clutter_actor_add_constraint_with_name:
13951  * @self: a #ClutterActor
13952  * @name: the name to set on the constraint
13953  * @constraint: a #ClutterConstraint
13954  *
13955  * A convenience function for setting the name of a #ClutterConstraint
13956  * while adding it to the list of constraints applied to @self
13957  *
13958  * This function is the logical equivalent of:
13959  *
13960  * |[
13961  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13962  *   clutter_actor_add_constraint (self, constraint);
13963  * ]|
13964  *
13965  * Since: 1.4
13966  */
13967 void
13968 clutter_actor_add_constraint_with_name (ClutterActor      *self,
13969                                         const gchar       *name,
13970                                         ClutterConstraint *constraint)
13971 {
13972   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13973   g_return_if_fail (name != NULL);
13974   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13975
13976   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13977   clutter_actor_add_constraint (self, constraint);
13978 }
13979
13980 /**
13981  * clutter_actor_remove_constraint:
13982  * @self: a #ClutterActor
13983  * @constraint: a #ClutterConstraint
13984  *
13985  * Removes @constraint from the list of constraints applied to @self
13986  *
13987  * The reference held by @self on the #ClutterConstraint will be released
13988  *
13989  * Since: 1.4
13990  */
13991 void
13992 clutter_actor_remove_constraint (ClutterActor      *self,
13993                                  ClutterConstraint *constraint)
13994 {
13995   ClutterActorPrivate *priv;
13996
13997   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13998   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13999
14000   priv = self->priv;
14001
14002   if (priv->constraints == NULL)
14003     return;
14004
14005   _clutter_meta_group_remove_meta (priv->constraints,
14006                                    CLUTTER_ACTOR_META (constraint));
14007   clutter_actor_queue_relayout (self);
14008
14009   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14010 }
14011
14012 /**
14013  * clutter_actor_remove_constraint_by_name:
14014  * @self: a #ClutterActor
14015  * @name: the name of the constraint to remove
14016  *
14017  * Removes the #ClutterConstraint with the given name from the list
14018  * of constraints applied to @self
14019  *
14020  * Since: 1.4
14021  */
14022 void
14023 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14024                                          const gchar  *name)
14025 {
14026   ClutterActorPrivate *priv;
14027   ClutterActorMeta *meta;
14028
14029   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14030   g_return_if_fail (name != NULL);
14031
14032   priv = self->priv;
14033
14034   if (priv->constraints == NULL)
14035     return;
14036
14037   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14038   if (meta == NULL)
14039     return;
14040
14041   _clutter_meta_group_remove_meta (priv->constraints, meta);
14042   clutter_actor_queue_relayout (self);
14043 }
14044
14045 /**
14046  * clutter_actor_get_constraints:
14047  * @self: a #ClutterActor
14048  *
14049  * Retrieves the list of constraints applied to @self
14050  *
14051  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14052  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14053  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14054  *   allocated by the returned #GList
14055  *
14056  * Since: 1.4
14057  */
14058 GList *
14059 clutter_actor_get_constraints (ClutterActor *self)
14060 {
14061   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14062
14063   if (self->priv->constraints == NULL)
14064     return NULL;
14065
14066   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14067 }
14068
14069 /**
14070  * clutter_actor_get_constraint:
14071  * @self: a #ClutterActor
14072  * @name: the name of the constraint to retrieve
14073  *
14074  * Retrieves the #ClutterConstraint with the given name in the list
14075  * of constraints applied to @self
14076  *
14077  * Return value: (transfer none): a #ClutterConstraint for the given
14078  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14079  *   actor and it should not be unreferenced directly
14080  *
14081  * Since: 1.4
14082  */
14083 ClutterConstraint *
14084 clutter_actor_get_constraint (ClutterActor *self,
14085                               const gchar  *name)
14086 {
14087   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14088   g_return_val_if_fail (name != NULL, NULL);
14089
14090   if (self->priv->constraints == NULL)
14091     return NULL;
14092
14093   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14094 }
14095
14096 /**
14097  * clutter_actor_clear_constraints:
14098  * @self: a #ClutterActor
14099  *
14100  * Clears the list of constraints applied to @self
14101  *
14102  * Since: 1.4
14103  */
14104 void
14105 clutter_actor_clear_constraints (ClutterActor *self)
14106 {
14107   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14108
14109   if (self->priv->constraints == NULL)
14110     return;
14111
14112   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14113
14114   clutter_actor_queue_relayout (self);
14115 }
14116
14117 /**
14118  * clutter_actor_set_clip_to_allocation:
14119  * @self: a #ClutterActor
14120  * @clip_set: %TRUE to apply a clip tracking the allocation
14121  *
14122  * Sets whether @self should be clipped to the same size as its
14123  * allocation
14124  *
14125  * Since: 1.4
14126  */
14127 void
14128 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14129                                       gboolean      clip_set)
14130 {
14131   ClutterActorPrivate *priv;
14132
14133   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14134
14135   clip_set = !!clip_set;
14136
14137   priv = self->priv;
14138
14139   if (priv->clip_to_allocation != clip_set)
14140     {
14141       priv->clip_to_allocation = clip_set;
14142
14143       clutter_actor_queue_redraw (self);
14144
14145       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14146     }
14147 }
14148
14149 /**
14150  * clutter_actor_get_clip_to_allocation:
14151  * @self: a #ClutterActor
14152  *
14153  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14154  *
14155  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14156  *
14157  * Since: 1.4
14158  */
14159 gboolean
14160 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14161 {
14162   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14163
14164   return self->priv->clip_to_allocation;
14165 }
14166
14167 /**
14168  * clutter_actor_add_effect:
14169  * @self: a #ClutterActor
14170  * @effect: a #ClutterEffect
14171  *
14172  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14173  *
14174  * The #ClutterActor will hold a reference on the @effect until either
14175  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14176  * called.
14177  *
14178  * Since: 1.4
14179  */
14180 void
14181 clutter_actor_add_effect (ClutterActor  *self,
14182                           ClutterEffect *effect)
14183 {
14184   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14185   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14186
14187   _clutter_actor_add_effect_internal (self, effect);
14188
14189   clutter_actor_queue_redraw (self);
14190
14191   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14192 }
14193
14194 /**
14195  * clutter_actor_add_effect_with_name:
14196  * @self: a #ClutterActor
14197  * @name: the name to set on the effect
14198  * @effect: a #ClutterEffect
14199  *
14200  * A convenience function for setting the name of a #ClutterEffect
14201  * while adding it to the list of effectss applied to @self
14202  *
14203  * This function is the logical equivalent of:
14204  *
14205  * |[
14206  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14207  *   clutter_actor_add_effect (self, effect);
14208  * ]|
14209  *
14210  * Since: 1.4
14211  */
14212 void
14213 clutter_actor_add_effect_with_name (ClutterActor  *self,
14214                                     const gchar   *name,
14215                                     ClutterEffect *effect)
14216 {
14217   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14218   g_return_if_fail (name != NULL);
14219   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14220
14221   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14222   clutter_actor_add_effect (self, effect);
14223 }
14224
14225 /**
14226  * clutter_actor_remove_effect:
14227  * @self: a #ClutterActor
14228  * @effect: a #ClutterEffect
14229  *
14230  * Removes @effect from the list of effects applied to @self
14231  *
14232  * The reference held by @self on the #ClutterEffect will be released
14233  *
14234  * Since: 1.4
14235  */
14236 void
14237 clutter_actor_remove_effect (ClutterActor  *self,
14238                              ClutterEffect *effect)
14239 {
14240   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14241   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14242
14243   _clutter_actor_remove_effect_internal (self, effect);
14244
14245   clutter_actor_queue_redraw (self);
14246
14247   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14248 }
14249
14250 /**
14251  * clutter_actor_remove_effect_by_name:
14252  * @self: a #ClutterActor
14253  * @name: the name of the effect to remove
14254  *
14255  * Removes the #ClutterEffect with the given name from the list
14256  * of effects applied to @self
14257  *
14258  * Since: 1.4
14259  */
14260 void
14261 clutter_actor_remove_effect_by_name (ClutterActor *self,
14262                                      const gchar  *name)
14263 {
14264   ClutterActorPrivate *priv;
14265   ClutterActorMeta *meta;
14266
14267   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14268   g_return_if_fail (name != NULL);
14269
14270   priv = self->priv;
14271
14272   if (priv->effects == NULL)
14273     return;
14274
14275   meta = _clutter_meta_group_get_meta (priv->effects, name);
14276   if (meta == NULL)
14277     return;
14278
14279   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14280 }
14281
14282 /**
14283  * clutter_actor_get_effects:
14284  * @self: a #ClutterActor
14285  *
14286  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14287  *
14288  * Return value: (transfer container) (element-type Clutter.Effect): a list
14289  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14290  *   list are owned by Clutter and they should not be freed. You should
14291  *   free the returned list using g_list_free() when done
14292  *
14293  * Since: 1.4
14294  */
14295 GList *
14296 clutter_actor_get_effects (ClutterActor *self)
14297 {
14298   ClutterActorPrivate *priv;
14299
14300   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14301
14302   priv = self->priv;
14303
14304   if (priv->effects == NULL)
14305     return NULL;
14306
14307   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14308 }
14309
14310 /**
14311  * clutter_actor_get_effect:
14312  * @self: a #ClutterActor
14313  * @name: the name of the effect to retrieve
14314  *
14315  * Retrieves the #ClutterEffect with the given name in the list
14316  * of effects applied to @self
14317  *
14318  * Return value: (transfer none): a #ClutterEffect for the given
14319  *   name, or %NULL. The returned #ClutterEffect is owned by the
14320  *   actor and it should not be unreferenced directly
14321  *
14322  * Since: 1.4
14323  */
14324 ClutterEffect *
14325 clutter_actor_get_effect (ClutterActor *self,
14326                           const gchar  *name)
14327 {
14328   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14329   g_return_val_if_fail (name != NULL, NULL);
14330
14331   if (self->priv->effects == NULL)
14332     return NULL;
14333
14334   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14335 }
14336
14337 /**
14338  * clutter_actor_clear_effects:
14339  * @self: a #ClutterActor
14340  *
14341  * Clears the list of effects applied to @self
14342  *
14343  * Since: 1.4
14344  */
14345 void
14346 clutter_actor_clear_effects (ClutterActor *self)
14347 {
14348   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14349
14350   if (self->priv->effects == NULL)
14351     return;
14352
14353   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14354
14355   clutter_actor_queue_redraw (self);
14356 }
14357
14358 /**
14359  * clutter_actor_has_key_focus:
14360  * @self: a #ClutterActor
14361  *
14362  * Checks whether @self is the #ClutterActor that has key focus
14363  *
14364  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14365  *
14366  * Since: 1.4
14367  */
14368 gboolean
14369 clutter_actor_has_key_focus (ClutterActor *self)
14370 {
14371   ClutterActor *stage;
14372
14373   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14374
14375   stage = _clutter_actor_get_stage_internal (self);
14376   if (stage == NULL)
14377     return FALSE;
14378
14379   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14380 }
14381
14382 static gboolean
14383 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14384                                       ClutterPaintVolume *pv)
14385 {
14386   ClutterActorPrivate *priv = self->priv;
14387
14388   /* Actors are only expected to report a valid paint volume
14389    * while they have a valid allocation. */
14390   if (G_UNLIKELY (priv->needs_allocation))
14391     {
14392       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14393                     "Actor needs allocation",
14394                     _clutter_actor_get_debug_name (self));
14395       return FALSE;
14396     }
14397
14398   /* Check if there are any handlers connected to the paint
14399    * signal. If there are then all bets are off for what the paint
14400    * volume for this actor might possibly be!
14401    *
14402    * XXX: It's expected that this is going to end up being quite a
14403    * costly check to have to do here, but we haven't come up with
14404    * another solution that can reliably catch paint signal handlers at
14405    * the right time to either avoid artefacts due to invalid stage
14406    * clipping or due to incorrect culling.
14407    *
14408    * Previously we checked in clutter_actor_paint(), but at that time
14409    * we may already be using a stage clip that could be derived from
14410    * an invalid paint-volume. We used to try and handle that by
14411    * queuing a follow up, unclipped, redraw but still the previous
14412    * checking wasn't enough to catch invalid volumes involved in
14413    * culling (considering that containers may derive their volume from
14414    * children that haven't yet been painted)
14415    *
14416    * Longer term, improved solutions could be:
14417    * - Disallow painting in the paint signal, only allow using it
14418    *   for tracking when paints happen. We can add another API that
14419    *   allows monkey patching the paint of arbitrary actors but in a
14420    *   more controlled way and that also supports modifying the
14421    *   paint-volume.
14422    * - If we could be notified somehow when signal handlers are
14423    *   connected we wouldn't have to poll for handlers like this.
14424    */
14425   if (g_signal_has_handler_pending (self,
14426                                     actor_signals[PAINT],
14427                                     0,
14428                                     TRUE))
14429     {
14430       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14431                     "Actor has \"paint\" signal handlers",
14432                     _clutter_actor_get_debug_name (self));
14433       return FALSE;
14434     }
14435
14436   _clutter_paint_volume_init_static (pv, self);
14437
14438   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14439     {
14440       clutter_paint_volume_free (pv);
14441       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14442                     "Actor failed to report a volume",
14443                     _clutter_actor_get_debug_name (self));
14444       return FALSE;
14445     }
14446
14447   /* since effects can modify the paint volume, we allow them to actually
14448    * do this by making get_paint_volume() "context sensitive"
14449    */
14450   if (priv->effects != NULL)
14451     {
14452       if (priv->current_effect != NULL)
14453         {
14454           const GList *effects, *l;
14455
14456           /* if we are being called from within the paint sequence of
14457            * an actor, get the paint volume up to the current effect
14458            */
14459           effects = _clutter_meta_group_peek_metas (priv->effects);
14460           for (l = effects;
14461                l != NULL || (l != NULL && l->data != priv->current_effect);
14462                l = l->next)
14463             {
14464               if (!_clutter_effect_get_paint_volume (l->data, pv))
14465                 {
14466                   clutter_paint_volume_free (pv);
14467                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14468                                 "Effect (%s) failed to report a volume",
14469                                 _clutter_actor_get_debug_name (self),
14470                                 _clutter_actor_meta_get_debug_name (l->data));
14471                   return FALSE;
14472                 }
14473             }
14474         }
14475       else
14476         {
14477           const GList *effects, *l;
14478
14479           /* otherwise, get the cumulative volume */
14480           effects = _clutter_meta_group_peek_metas (priv->effects);
14481           for (l = effects; l != NULL; l = l->next)
14482             if (!_clutter_effect_get_paint_volume (l->data, pv))
14483               {
14484                 clutter_paint_volume_free (pv);
14485                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14486                               "Effect (%s) failed to report a volume",
14487                               _clutter_actor_get_debug_name (self),
14488                               _clutter_actor_meta_get_debug_name (l->data));
14489                 return FALSE;
14490               }
14491         }
14492     }
14493
14494   return TRUE;
14495 }
14496
14497 /* The public clutter_actor_get_paint_volume API returns a const
14498  * pointer since we return a pointer directly to the cached
14499  * PaintVolume associated with the actor and don't want the user to
14500  * inadvertently modify it, but for internal uses we sometimes need
14501  * access to the same PaintVolume but need to apply some book-keeping
14502  * modifications to it so we don't want a const pointer.
14503  */
14504 static ClutterPaintVolume *
14505 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14506 {
14507   ClutterActorPrivate *priv;
14508
14509   priv = self->priv;
14510
14511   if (priv->paint_volume_valid)
14512     clutter_paint_volume_free (&priv->paint_volume);
14513
14514   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14515     {
14516       priv->paint_volume_valid = TRUE;
14517       return &priv->paint_volume;
14518     }
14519   else
14520     {
14521       priv->paint_volume_valid = FALSE;
14522       return NULL;
14523     }
14524 }
14525
14526 /**
14527  * clutter_actor_get_paint_volume:
14528  * @self: a #ClutterActor
14529  *
14530  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14531  * when a paint volume can't be determined.
14532  *
14533  * The paint volume is defined as the 3D space occupied by an actor
14534  * when being painted.
14535  *
14536  * This function will call the <function>get_paint_volume()</function>
14537  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14538  * should not usually care about overriding the default implementation,
14539  * unless they are, for instance: painting outside their allocation, or
14540  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14541  * 3D depth).
14542  *
14543  * <note>2D actors overriding <function>get_paint_volume()</function>
14544  * ensure their volume has a depth of 0. (This will be true so long as
14545  * you don't call clutter_paint_volume_set_depth().)</note>
14546  *
14547  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14548  *   or %NULL if no volume could be determined. The returned pointer
14549  *   is not guaranteed to be valid across multiple frames; if you want
14550  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
14551  *
14552  * Since: 1.6
14553  */
14554 const ClutterPaintVolume *
14555 clutter_actor_get_paint_volume (ClutterActor *self)
14556 {
14557   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14558
14559   return _clutter_actor_get_paint_volume_mutable (self);
14560 }
14561
14562 /**
14563  * clutter_actor_get_transformed_paint_volume:
14564  * @self: a #ClutterActor
14565  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14566  *    (or %NULL for the stage)
14567  *
14568  * Retrieves the 3D paint volume of an actor like
14569  * clutter_actor_get_paint_volume() does (Please refer to the
14570  * documentation of clutter_actor_get_paint_volume() for more
14571  * details.) and it additionally transforms the paint volume into the
14572  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14573  * is passed for @relative_to_ancestor)
14574  *
14575  * This can be used by containers that base their paint volume on
14576  * the volume of their children. Such containers can query the
14577  * transformed paint volume of all of its children and union them
14578  * together using clutter_paint_volume_union().
14579  *
14580  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14581  *   or %NULL if no volume could be determined. The returned pointer is
14582  *   not guaranteed to be valid across multiple frames; if you wish to
14583  *   keep it, you will have to copy it using clutter_paint_volume_copy().
14584  *
14585  * Since: 1.6
14586  */
14587 const ClutterPaintVolume *
14588 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14589                                             ClutterActor *relative_to_ancestor)
14590 {
14591   const ClutterPaintVolume *volume;
14592   ClutterActor *stage;
14593   ClutterPaintVolume *transformed_volume;
14594
14595   stage = _clutter_actor_get_stage_internal (self);
14596   if (G_UNLIKELY (stage == NULL))
14597     return NULL;
14598
14599   if (relative_to_ancestor == NULL)
14600     relative_to_ancestor = stage;
14601
14602   volume = clutter_actor_get_paint_volume (self);
14603   if (volume == NULL)
14604     return NULL;
14605
14606   transformed_volume =
14607     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14608
14609   _clutter_paint_volume_copy_static (volume, transformed_volume);
14610
14611   _clutter_paint_volume_transform_relative (transformed_volume,
14612                                             relative_to_ancestor);
14613
14614   return transformed_volume;
14615 }
14616
14617 /**
14618  * clutter_actor_get_paint_box:
14619  * @self: a #ClutterActor
14620  * @box: (out): return location for a #ClutterActorBox
14621  *
14622  * Retrieves the paint volume of the passed #ClutterActor, and
14623  * transforms it into a 2D bounding box in stage coordinates.
14624  *
14625  * This function is useful to determine the on screen area occupied by
14626  * the actor. The box is only an approximation and may often be
14627  * considerably larger due to the optimizations used to calculate the
14628  * box. The box is never smaller though, so it can reliably be used
14629  * for culling.
14630  *
14631  * There are times when a 2D paint box can't be determined, e.g.
14632  * because the actor isn't yet parented under a stage or because
14633  * the actor is unable to determine a paint volume.
14634  *
14635  * Return value: %TRUE if a 2D paint box could be determined, else
14636  * %FALSE.
14637  *
14638  * Since: 1.6
14639  */
14640 gboolean
14641 clutter_actor_get_paint_box (ClutterActor    *self,
14642                              ClutterActorBox *box)
14643 {
14644   ClutterActor *stage;
14645   ClutterPaintVolume *pv;
14646
14647   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14648   g_return_val_if_fail (box != NULL, FALSE);
14649
14650   stage = _clutter_actor_get_stage_internal (self);
14651   if (G_UNLIKELY (!stage))
14652     return FALSE;
14653
14654   pv = _clutter_actor_get_paint_volume_mutable (self);
14655   if (G_UNLIKELY (!pv))
14656     return FALSE;
14657
14658   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14659
14660   return TRUE;
14661 }
14662
14663 /**
14664  * clutter_actor_has_overlaps:
14665  * @self: A #ClutterActor
14666  *
14667  * Asks the actor's implementation whether it may contain overlapping
14668  * primitives.
14669  *
14670  * For example; Clutter may use this to determine whether the painting
14671  * should be redirected to an offscreen buffer to correctly implement
14672  * the opacity property.
14673  *
14674  * Custom actors can override the default response by implementing the
14675  * #ClutterActor <function>has_overlaps</function> virtual function. See
14676  * clutter_actor_set_offscreen_redirect() for more information.
14677  *
14678  * Return value: %TRUE if the actor may have overlapping primitives, and
14679  *   %FALSE otherwise
14680  *
14681  * Since: 1.8
14682  */
14683 gboolean
14684 clutter_actor_has_overlaps (ClutterActor *self)
14685 {
14686   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14687
14688   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14689 }
14690
14691 /**
14692  * clutter_actor_has_effects:
14693  * @self: A #ClutterActor
14694  *
14695  * Returns whether the actor has any effects applied.
14696  *
14697  * Return value: %TRUE if the actor has any effects,
14698  *   %FALSE otherwise
14699  *
14700  * Since: 1.10
14701  */
14702 gboolean
14703 clutter_actor_has_effects (ClutterActor *self)
14704 {
14705   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14706
14707   if (self->priv->effects == NULL)
14708     return FALSE;
14709
14710   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14711 }
14712
14713 /**
14714  * clutter_actor_has_constraints:
14715  * @self: A #ClutterActor
14716  *
14717  * Returns whether the actor has any constraints applied.
14718  *
14719  * Return value: %TRUE if the actor has any constraints,
14720  *   %FALSE otherwise
14721  *
14722  * Since: 1.10
14723  */
14724 gboolean
14725 clutter_actor_has_constraints (ClutterActor *self)
14726 {
14727   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14728
14729   return self->priv->constraints != NULL;
14730 }
14731
14732 /**
14733  * clutter_actor_has_actions:
14734  * @self: A #ClutterActor
14735  *
14736  * Returns whether the actor has any actions applied.
14737  *
14738  * Return value: %TRUE if the actor has any actions,
14739  *   %FALSE otherwise
14740  *
14741  * Since: 1.10
14742  */
14743 gboolean
14744 clutter_actor_has_actions (ClutterActor *self)
14745 {
14746   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14747
14748   return self->priv->actions != NULL;
14749 }
14750
14751 /**
14752  * clutter_actor_get_n_children:
14753  * @self: a #ClutterActor
14754  *
14755  * Retrieves the number of children of @self.
14756  *
14757  * Return value: the number of children of an actor
14758  *
14759  * Since: 1.10
14760  */
14761 gint
14762 clutter_actor_get_n_children (ClutterActor *self)
14763 {
14764   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14765
14766   return self->priv->n_children;
14767 }
14768
14769 /**
14770  * clutter_actor_get_child_at_index:
14771  * @self: a #ClutterActor
14772  * @index_: the position in the list of children
14773  *
14774  * Retrieves the actor at the given @index_ inside the list of
14775  * children of @self.
14776  *
14777  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14778  *
14779  * Since: 1.10
14780  */
14781 ClutterActor *
14782 clutter_actor_get_child_at_index (ClutterActor *self,
14783                                   gint          index_)
14784 {
14785   ClutterActor *iter;
14786   int i;
14787
14788   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14789   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14790
14791   for (iter = self->priv->first_child, i = 0;
14792        iter != NULL && i < index_;
14793        iter = iter->priv->next_sibling, i += 1)
14794     ;
14795
14796   return iter;
14797 }
14798
14799 /*< private >
14800  * _clutter_actor_foreach_child:
14801  * @actor: The actor whos children you want to iterate
14802  * @callback: The function to call for each child
14803  * @user_data: Private data to pass to @callback
14804  *
14805  * Calls a given @callback once for each child of the specified @actor and
14806  * passing the @user_data pointer each time.
14807  *
14808  * Return value: returns %TRUE if all children were iterated, else
14809  *    %FALSE if a callback broke out of iteration early.
14810  */
14811 gboolean
14812 _clutter_actor_foreach_child (ClutterActor           *self,
14813                               ClutterForeachCallback  callback,
14814                               gpointer                user_data)
14815 {
14816   ClutterActorPrivate *priv = self->priv;
14817   ClutterActor *iter;
14818   gboolean cont;
14819
14820   for (cont = TRUE, iter = priv->first_child;
14821        cont && iter != NULL;
14822        iter = iter->priv->next_sibling)
14823     {
14824       cont = callback (iter, user_data);
14825     }
14826
14827   return cont;
14828 }
14829
14830 /* For debugging purposes this gives us a simple way to print out
14831  * the scenegraph e.g in gdb using:
14832  * [|
14833  *   _clutter_actor_traverse (stage,
14834  *                            0,
14835  *                            _clutter_debug_print_actor_cb,
14836  *                            NULL,
14837  *                            NULL);
14838  * |]
14839  */
14840 ClutterActorTraverseVisitFlags
14841 _clutter_debug_print_actor_cb (ClutterActor *actor,
14842                                int depth,
14843                                void *user_data)
14844 {
14845   g_print ("%*s%s:%p\n",
14846            depth * 2, "",
14847            _clutter_actor_get_debug_name (actor),
14848            actor);
14849
14850   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14851 }
14852
14853 static void
14854 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14855                                  ClutterTraverseCallback callback,
14856                                  gpointer                user_data)
14857 {
14858   GQueue *queue = g_queue_new ();
14859   ClutterActor dummy;
14860   int current_depth = 0;
14861
14862   g_queue_push_tail (queue, actor);
14863   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14864
14865   while ((actor = g_queue_pop_head (queue)))
14866     {
14867       ClutterActorTraverseVisitFlags flags;
14868
14869       if (actor == &dummy)
14870         {
14871           current_depth++;
14872           g_queue_push_tail (queue, &dummy);
14873           continue;
14874         }
14875
14876       flags = callback (actor, current_depth, user_data);
14877       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14878         break;
14879       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14880         {
14881           ClutterActor *iter;
14882
14883           for (iter = actor->priv->first_child;
14884                iter != NULL;
14885                iter = iter->priv->next_sibling)
14886             {
14887               g_queue_push_tail (queue, iter);
14888             }
14889         }
14890     }
14891
14892   g_queue_free (queue);
14893 }
14894
14895 static ClutterActorTraverseVisitFlags
14896 _clutter_actor_traverse_depth (ClutterActor           *actor,
14897                                ClutterTraverseCallback before_children_callback,
14898                                ClutterTraverseCallback after_children_callback,
14899                                int                     current_depth,
14900                                gpointer                user_data)
14901 {
14902   ClutterActorTraverseVisitFlags flags;
14903
14904   flags = before_children_callback (actor, current_depth, user_data);
14905   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14906     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14907
14908   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14909     {
14910       ClutterActor *iter;
14911
14912       for (iter = actor->priv->first_child;
14913            iter != NULL;
14914            iter = iter->priv->next_sibling)
14915         {
14916           flags = _clutter_actor_traverse_depth (iter,
14917                                                  before_children_callback,
14918                                                  after_children_callback,
14919                                                  current_depth + 1,
14920                                                  user_data);
14921
14922           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14923             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14924         }
14925     }
14926
14927   if (after_children_callback)
14928     return after_children_callback (actor, current_depth, user_data);
14929   else
14930     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14931 }
14932
14933 /* _clutter_actor_traverse:
14934  * @actor: The actor to start traversing the graph from
14935  * @flags: These flags may affect how the traversal is done
14936  * @before_children_callback: A function to call before visiting the
14937  *   children of the current actor.
14938  * @after_children_callback: A function to call after visiting the
14939  *   children of the current actor. (Ignored if
14940  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14941  * @user_data: The private data to pass to the callbacks
14942  *
14943  * Traverses the scenegraph starting at the specified @actor and
14944  * descending through all its children and its children's children.
14945  * For each actor traversed @before_children_callback and
14946  * @after_children_callback are called with the specified
14947  * @user_data, before and after visiting that actor's children.
14948  *
14949  * The callbacks can return flags that affect the ongoing traversal
14950  * such as by skipping over an actors children or bailing out of
14951  * any further traversing.
14952  */
14953 void
14954 _clutter_actor_traverse (ClutterActor              *actor,
14955                          ClutterActorTraverseFlags  flags,
14956                          ClutterTraverseCallback    before_children_callback,
14957                          ClutterTraverseCallback    after_children_callback,
14958                          gpointer                   user_data)
14959 {
14960   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
14961     _clutter_actor_traverse_breadth (actor,
14962                                      before_children_callback,
14963                                      user_data);
14964   else /* DEPTH_FIRST */
14965     _clutter_actor_traverse_depth (actor,
14966                                    before_children_callback,
14967                                    after_children_callback,
14968                                    0, /* start depth */
14969                                    user_data);
14970 }
14971
14972 static void
14973 on_layout_manager_changed (ClutterLayoutManager *manager,
14974                            ClutterActor         *self)
14975 {
14976   clutter_actor_queue_relayout (self);
14977 }
14978
14979 /**
14980  * clutter_actor_set_layout_manager:
14981  * @self: a #ClutterActor
14982  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
14983  *
14984  * Sets the #ClutterLayoutManager delegate object that will be used to
14985  * lay out the children of @self.
14986  *
14987  * The #ClutterActor will take a reference on the passed @manager which
14988  * will be released either when the layout manager is removed, or when
14989  * the actor is destroyed.
14990  *
14991  * Since: 1.10
14992  */
14993 void
14994 clutter_actor_set_layout_manager (ClutterActor         *self,
14995                                   ClutterLayoutManager *manager)
14996 {
14997   ClutterActorPrivate *priv;
14998
14999   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15000   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15001
15002   priv = self->priv;
15003
15004   if (priv->layout_manager != NULL)
15005     {
15006       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15007                                             G_CALLBACK (on_layout_manager_changed),
15008                                             self);
15009       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15010       g_object_unref (priv->layout_manager);
15011     }
15012
15013   priv->layout_manager = manager;
15014
15015   if (priv->layout_manager != NULL)
15016     {
15017       g_object_ref_sink (priv->layout_manager);
15018       clutter_layout_manager_set_container (priv->layout_manager,
15019                                             CLUTTER_CONTAINER (self));
15020       g_signal_connect (priv->layout_manager, "layout-changed",
15021                         G_CALLBACK (on_layout_manager_changed),
15022                         self);
15023     }
15024
15025   clutter_actor_queue_relayout (self);
15026
15027   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15028 }
15029
15030 /**
15031  * clutter_actor_get_layout_manager:
15032  * @self: a #ClutterActor
15033  *
15034  * Retrieves the #ClutterLayoutManager used by @self.
15035  *
15036  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15037  *   or %NULL
15038  *
15039  * Since: 1.10
15040  */
15041 ClutterLayoutManager *
15042 clutter_actor_get_layout_manager (ClutterActor *self)
15043 {
15044   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15045
15046   return self->priv->layout_manager;
15047 }
15048
15049 static const ClutterLayoutInfo default_layout_info = {
15050   0.f,                          /* fixed-x */
15051   0.f,                          /* fixed-y */
15052   { 0, 0, 0, 0 },               /* margin */
15053   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15054   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15055   0.f, 0.f,                     /* min_width, natural_width */
15056   0.f, 0.f,                     /* natual_width, natural_height */
15057 };
15058
15059 static void
15060 layout_info_free (gpointer data)
15061 {
15062   if (G_LIKELY (data != NULL))
15063     g_slice_free (ClutterLayoutInfo, data);
15064 }
15065
15066 /*< private >
15067  * _clutter_actor_get_layout_info:
15068  * @self: a #ClutterActor
15069  *
15070  * Retrieves a pointer to the ClutterLayoutInfo structure.
15071  *
15072  * If the actor does not have a ClutterLayoutInfo associated to it, one
15073  * will be created and initialized to the default values.
15074  *
15075  * This function should be used for setters.
15076  *
15077  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15078  * instead.
15079  *
15080  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15081  */
15082 ClutterLayoutInfo *
15083 _clutter_actor_get_layout_info (ClutterActor *self)
15084 {
15085   ClutterLayoutInfo *retval;
15086
15087   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15088   if (retval == NULL)
15089     {
15090       retval = g_slice_new (ClutterLayoutInfo);
15091
15092       *retval = default_layout_info;
15093
15094       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15095                                retval,
15096                                layout_info_free);
15097     }
15098
15099   return retval;
15100 }
15101
15102 /*< private >
15103  * _clutter_actor_get_layout_info_or_defaults:
15104  * @self: a #ClutterActor
15105  *
15106  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15107  *
15108  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15109  * then the default structure will be returned.
15110  *
15111  * This function should only be used for getters.
15112  *
15113  * Return value: a const pointer to the ClutterLayoutInfo structure
15114  */
15115 const ClutterLayoutInfo *
15116 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15117 {
15118   const ClutterLayoutInfo *info;
15119
15120   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15121   if (info == NULL)
15122     return &default_layout_info;
15123
15124   return info;
15125 }
15126
15127 /**
15128  * clutter_actor_set_x_align:
15129  * @self: a #ClutterActor
15130  * @x_align: the horizontal alignment policy
15131  *
15132  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15133  * actor received extra horizontal space.
15134  *
15135  * See also the #ClutterActor:x-align property.
15136  *
15137  * Since: 1.10
15138  */
15139 void
15140 clutter_actor_set_x_align (ClutterActor      *self,
15141                            ClutterActorAlign  x_align)
15142 {
15143   ClutterLayoutInfo *info;
15144
15145   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15146
15147   info = _clutter_actor_get_layout_info (self);
15148
15149   if (info->x_align != x_align)
15150     {
15151       info->x_align = x_align;
15152
15153       clutter_actor_queue_relayout (self);
15154
15155       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15156     }
15157 }
15158
15159 /**
15160  * clutter_actor_get_x_align:
15161  * @self: a #ClutterActor
15162  *
15163  * Retrieves the horizontal alignment policy set using
15164  * clutter_actor_set_x_align().
15165  *
15166  * Return value: the horizontal alignment policy.
15167  *
15168  * Since: 1.10
15169  */
15170 ClutterActorAlign
15171 clutter_actor_get_x_align (ClutterActor *self)
15172 {
15173   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15174
15175   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15176 }
15177
15178 /**
15179  * clutter_actor_set_y_align:
15180  * @self: a #ClutterActor
15181  * @y_align: the vertical alignment policy
15182  *
15183  * Sets the vertical alignment policy of a #ClutterActor, in case the
15184  * actor received extra vertical space.
15185  *
15186  * See also the #ClutterActor:y-align property.
15187  *
15188  * Since: 1.10
15189  */
15190 void
15191 clutter_actor_set_y_align (ClutterActor      *self,
15192                            ClutterActorAlign  y_align)
15193 {
15194   ClutterLayoutInfo *info;
15195
15196   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15197
15198   info = _clutter_actor_get_layout_info (self);
15199
15200   if (info->y_align != y_align)
15201     {
15202       info->y_align = y_align;
15203
15204       clutter_actor_queue_relayout (self);
15205
15206       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15207     }
15208 }
15209
15210 /**
15211  * clutter_actor_get_y_align:
15212  * @self: a #ClutterActor
15213  *
15214  * Retrieves the vertical alignment policy set using
15215  * clutter_actor_set_y_align().
15216  *
15217  * Return value: the vertical alignment policy.
15218  *
15219  * Since: 1.10
15220  */
15221 ClutterActorAlign
15222 clutter_actor_get_y_align (ClutterActor *self)
15223 {
15224   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15225
15226   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15227 }
15228
15229
15230 /**
15231  * clutter_margin_new:
15232  *
15233  * Creates a new #ClutterMargin.
15234  *
15235  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15236  *   clutter_margin_free() to free the resources associated with it when
15237  *   done.
15238  *
15239  * Since: 1.10
15240  */
15241 ClutterMargin *
15242 clutter_margin_new (void)
15243 {
15244   return g_slice_new0 (ClutterMargin);
15245 }
15246
15247 /**
15248  * clutter_margin_copy:
15249  * @margin_: a #ClutterMargin
15250  *
15251  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15252  * the newly created structure.
15253  *
15254  * Return value: (transfer full): a copy of the #ClutterMargin.
15255  *
15256  * Since: 1.10
15257  */
15258 ClutterMargin *
15259 clutter_margin_copy (const ClutterMargin *margin_)
15260 {
15261   if (G_LIKELY (margin_ != NULL))
15262     return g_slice_dup (ClutterMargin, margin_);
15263
15264   return NULL;
15265 }
15266
15267 /**
15268  * clutter_margin_free:
15269  * @margin_: a #ClutterMargin
15270  *
15271  * Frees the resources allocated by clutter_margin_new() and
15272  * clutter_margin_copy().
15273  *
15274  * Since: 1.10
15275  */
15276 void
15277 clutter_margin_free (ClutterMargin *margin_)
15278 {
15279   if (G_LIKELY (margin_ != NULL))
15280     g_slice_free (ClutterMargin, margin_);
15281 }
15282
15283 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15284                      clutter_margin_copy,
15285                      clutter_margin_free)
15286
15287 /**
15288  * clutter_actor_set_margin:
15289  * @self: a #ClutterActor
15290  * @margin: a #ClutterMargin
15291  *
15292  * Sets all the components of the margin of a #ClutterActor.
15293  *
15294  * Since: 1.10
15295  */
15296 void
15297 clutter_actor_set_margin (ClutterActor        *self,
15298                           const ClutterMargin *margin)
15299 {
15300   ClutterLayoutInfo *info;
15301   gboolean changed;
15302   GObject *obj;
15303
15304   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15305   g_return_if_fail (margin != NULL);
15306
15307   obj = G_OBJECT (self);
15308   changed = FALSE;
15309
15310   g_object_freeze_notify (obj);
15311
15312   info = _clutter_actor_get_layout_info (self);
15313
15314   if (info->margin.top != margin->top)
15315     {
15316       info->margin.top = margin->top;
15317       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15318       changed = TRUE;
15319     }
15320
15321   if (info->margin.right != margin->right)
15322     {
15323       info->margin.right = margin->right;
15324       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15325       changed = TRUE;
15326     }
15327
15328   if (info->margin.bottom != margin->bottom)
15329     {
15330       info->margin.bottom = margin->bottom;
15331       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15332       changed = TRUE;
15333     }
15334
15335   if (info->margin.left != margin->left)
15336     {
15337       info->margin.left = margin->left;
15338       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15339       changed = TRUE;
15340     }
15341
15342   if (changed)
15343     clutter_actor_queue_relayout (self);
15344
15345   g_object_thaw_notify (obj);
15346 }
15347
15348 /**
15349  * clutter_actor_get_margin:
15350  * @self: a #ClutterActor
15351  * @margin: (out caller-allocates): return location for a #ClutterMargin
15352  *
15353  * Retrieves all the components of the margin of a #ClutterActor.
15354  *
15355  * Since: 1.10
15356  */
15357 void
15358 clutter_actor_get_margin (ClutterActor  *self,
15359                           ClutterMargin *margin)
15360 {
15361   const ClutterLayoutInfo *info;
15362
15363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15364   g_return_if_fail (margin != NULL);
15365
15366   info = _clutter_actor_get_layout_info_or_defaults (self);
15367
15368   *margin = info->margin;
15369 }
15370
15371 /**
15372  * clutter_actor_set_margin_top:
15373  * @self: a #ClutterActor
15374  * @margin: the top margin
15375  *
15376  * Sets the margin from the top of a #ClutterActor.
15377  *
15378  * Since: 1.10
15379  */
15380 void
15381 clutter_actor_set_margin_top (ClutterActor *self,
15382                               gfloat        margin)
15383 {
15384   ClutterLayoutInfo *info;
15385
15386   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15387   g_return_if_fail (margin >= 0.f);
15388
15389   info = _clutter_actor_get_layout_info (self);
15390
15391   if (info->margin.top == margin)
15392     return;
15393
15394   info->margin.top = margin;
15395
15396   clutter_actor_queue_relayout (self);
15397
15398   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15399 }
15400
15401 /**
15402  * clutter_actor_get_margin_top:
15403  * @self: a #ClutterActor
15404  *
15405  * Retrieves the top margin of a #ClutterActor.
15406  *
15407  * Return value: the top margin
15408  *
15409  * Since: 1.10
15410  */
15411 gfloat
15412 clutter_actor_get_margin_top (ClutterActor *self)
15413 {
15414   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15415
15416   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15417 }
15418
15419 /**
15420  * clutter_actor_set_margin_bottom:
15421  * @self: a #ClutterActor
15422  * @margin: the bottom margin
15423  *
15424  * Sets the margin from the bottom of a #ClutterActor.
15425  *
15426  * Since: 1.10
15427  */
15428 void
15429 clutter_actor_set_margin_bottom (ClutterActor *self,
15430                                  gfloat        margin)
15431 {
15432   ClutterLayoutInfo *info;
15433
15434   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15435   g_return_if_fail (margin >= 0.f);
15436
15437   info = _clutter_actor_get_layout_info (self);
15438
15439   if (info->margin.bottom == margin)
15440     return;
15441
15442   info->margin.bottom = margin;
15443
15444   clutter_actor_queue_relayout (self);
15445
15446   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15447 }
15448
15449 /**
15450  * clutter_actor_get_margin_bottom:
15451  * @self: a #ClutterActor
15452  *
15453  * Retrieves the bottom margin of a #ClutterActor.
15454  *
15455  * Return value: the bottom margin
15456  *
15457  * Since: 1.10
15458  */
15459 gfloat
15460 clutter_actor_get_margin_bottom (ClutterActor *self)
15461 {
15462   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15463
15464   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15465 }
15466
15467 /**
15468  * clutter_actor_set_margin_left:
15469  * @self: a #ClutterActor
15470  * @margin: the left margin
15471  *
15472  * Sets the margin from the left of a #ClutterActor.
15473  *
15474  * Since: 1.10
15475  */
15476 void
15477 clutter_actor_set_margin_left (ClutterActor *self,
15478                                gfloat        margin)
15479 {
15480   ClutterLayoutInfo *info;
15481
15482   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15483   g_return_if_fail (margin >= 0.f);
15484
15485   info = _clutter_actor_get_layout_info (self);
15486
15487   if (info->margin.left == margin)
15488     return;
15489
15490   info->margin.left = margin;
15491
15492   clutter_actor_queue_relayout (self);
15493
15494   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15495 }
15496
15497 /**
15498  * clutter_actor_get_margin_left:
15499  * @self: a #ClutterActor
15500  *
15501  * Retrieves the left margin of a #ClutterActor.
15502  *
15503  * Return value: the left margin
15504  *
15505  * Since: 1.10
15506  */
15507 gfloat
15508 clutter_actor_get_margin_left (ClutterActor *self)
15509 {
15510   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15511
15512   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15513 }
15514
15515 /**
15516  * clutter_actor_set_margin_right:
15517  * @self: a #ClutterActor
15518  * @margin: the right margin
15519  *
15520  * Sets the margin from the right of a #ClutterActor.
15521  *
15522  * Since: 1.10
15523  */
15524 void
15525 clutter_actor_set_margin_right (ClutterActor *self,
15526                                 gfloat        margin)
15527 {
15528   ClutterLayoutInfo *info;
15529
15530   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15531   g_return_if_fail (margin >= 0.f);
15532
15533   info = _clutter_actor_get_layout_info (self);
15534
15535   if (info->margin.right == margin)
15536     return;
15537
15538   info->margin.right = margin;
15539
15540   clutter_actor_queue_relayout (self);
15541
15542   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15543 }
15544
15545 /**
15546  * clutter_actor_get_margin_right:
15547  * @self: a #ClutterActor
15548  *
15549  * Retrieves the right margin of a #ClutterActor.
15550  *
15551  * Return value: the right margin
15552  *
15553  * Since: 1.10
15554  */
15555 gfloat
15556 clutter_actor_get_margin_right (ClutterActor *self)
15557 {
15558   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15559
15560   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15561 }
15562
15563 /**
15564  * clutter_actor_set_background_color:
15565  * @self: a #ClutterActor
15566  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15567  *  set color
15568  *
15569  * Sets the background color of a #ClutterActor.
15570  *
15571  * The background color will be used to cover the whole allocation of the
15572  * actor. The default background color of an actor is transparent.
15573  *
15574  * To check whether an actor has a background color, you can use the
15575  * #ClutterActor:background-color-set actor property.
15576  *
15577  * Since: 1.10
15578  */
15579 void
15580 clutter_actor_set_background_color (ClutterActor       *self,
15581                                     const ClutterColor *color)
15582 {
15583   ClutterActorPrivate *priv;
15584
15585   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15586
15587   priv = self->priv;
15588
15589   if (color == NULL)
15590     {
15591       priv->bg_color_set = FALSE;
15592       g_object_notify_by_pspec (G_OBJECT (self),
15593                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15594       return;
15595     }
15596
15597   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15598     return;
15599
15600   priv->bg_color = *color;
15601   priv->bg_color_set = TRUE;
15602
15603   clutter_actor_queue_redraw (self);
15604
15605   g_object_notify_by_pspec (G_OBJECT (self),
15606                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15607   g_object_notify_by_pspec (G_OBJECT (self),
15608                             obj_props[PROP_BACKGROUND_COLOR]);
15609 }
15610
15611 /**
15612  * clutter_actor_get_background_color:
15613  * @self: a #ClutterActor
15614  * @color: (out caller-allocates): return location for a #ClutterColor
15615  *
15616  * Retrieves the color set using clutter_actor_set_background_color().
15617  *
15618  * Since: 1.10
15619  */
15620 void
15621 clutter_actor_get_background_color (ClutterActor *self,
15622                                     ClutterColor *color)
15623 {
15624   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15625   g_return_if_fail (color != NULL);
15626
15627   *color = self->priv->bg_color;
15628 }
15629
15630 /**
15631  * clutter_actor_get_previous_sibling:
15632  * @self: a #ClutterActor
15633  *
15634  * Retrieves the sibling of @self that comes before it in the list
15635  * of children of @self's parent.
15636  *
15637  * The returned pointer is only valid until the scene graph changes; it
15638  * is not safe to modify the list of children of @self while iterating
15639  * it.
15640  *
15641  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15642  *
15643  * Since: 1.10
15644  */
15645 ClutterActor *
15646 clutter_actor_get_previous_sibling (ClutterActor *self)
15647 {
15648   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15649
15650   return self->priv->prev_sibling;
15651 }
15652
15653 /**
15654  * clutter_actor_get_next_sibling:
15655  * @self: a #ClutterActor
15656  *
15657  * Retrieves the sibling of @self that comes after it in the list
15658  * of children of @self's parent.
15659  *
15660  * The returned pointer is only valid until the scene graph changes; it
15661  * is not safe to modify the list of children of @self while iterating
15662  * it.
15663  *
15664  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15665  *
15666  * Since: 1.10
15667  */
15668 ClutterActor *
15669 clutter_actor_get_next_sibling (ClutterActor *self)
15670 {
15671   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15672
15673   return self->priv->next_sibling;
15674 }
15675
15676 /**
15677  * clutter_actor_get_first_child:
15678  * @self: a #ClutterActor
15679  *
15680  * Retrieves the first child of @self.
15681  *
15682  * The returned pointer is only valid until the scene graph changes; it
15683  * is not safe to modify the list of children of @self while iterating
15684  * it.
15685  *
15686  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15687  *
15688  * Since: 1.10
15689  */
15690 ClutterActor *
15691 clutter_actor_get_first_child (ClutterActor *self)
15692 {
15693   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15694
15695   return self->priv->first_child;
15696 }
15697
15698 /**
15699  * clutter_actor_get_last_child:
15700  * @self: a #ClutterActor
15701  *
15702  * Retrieves the last child of @self.
15703  *
15704  * The returned pointer is only valid until the scene graph changes; it
15705  * is not safe to modify the list of children of @self while iterating
15706  * it.
15707  *
15708  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15709  *
15710  * Since: 1.10
15711  */
15712 ClutterActor *
15713 clutter_actor_get_last_child (ClutterActor *self)
15714 {
15715   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15716
15717   return self->priv->last_child;
15718 }
15719
15720 /* easy way to have properly named fields instead of the dummy ones
15721  * we use in the public structure
15722  */
15723 typedef struct _RealActorIter
15724 {
15725   ClutterActor *root;           /* dummy1 */
15726   ClutterActor *current;        /* dummy2 */
15727   gpointer padding_1;           /* dummy3 */
15728   gint age;                     /* dummy4 */
15729   gpointer padding_2;           /* dummy5 */
15730 } RealActorIter;
15731
15732 /**
15733  * clutter_actor_iter_init:
15734  * @iter: a #ClutterActorIter
15735  * @root: a #ClutterActor
15736  *
15737  * Initializes a #ClutterActorIter, which can then be used to iterate
15738  * efficiently over a section of the scene graph, and associates it
15739  * with @root.
15740  *
15741  * Modifying the scene graph section that contains @root will invalidate
15742  * the iterator.
15743  *
15744  * |[
15745  *   ClutterActorIter iter;
15746  *   ClutterActor *child;
15747  *
15748  *   clutter_actor_iter_init (&iter, container);
15749  *   while (clutter_actor_iter_next (&iter, &child))
15750  *     {
15751  *       /&ast; do something with child &ast;/
15752  *     }
15753  * ]|
15754  *
15755  * Since: 1.10
15756  */
15757 void
15758 clutter_actor_iter_init (ClutterActorIter *iter,
15759                          ClutterActor     *root)
15760 {
15761   RealActorIter *ri = (RealActorIter *) iter;
15762
15763   g_return_if_fail (iter != NULL);
15764   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15765
15766   ri->root = root;
15767   ri->current = NULL;
15768   ri->age = root->priv->age;
15769 }
15770
15771 /**
15772  * clutter_actor_iter_next:
15773  * @iter: a #ClutterActorIter
15774  * @child: (out): return location for a #ClutterActor
15775  *
15776  * Advances the @iter and retrieves the next child of the root #ClutterActor
15777  * that was used to initialize the #ClutterActorIterator.
15778  *
15779  * If the iterator can advance, this function returns %TRUE and sets the
15780  * @child argument.
15781  *
15782  * If the iterator cannot advance, this function returns %FALSE, and
15783  * the contents of @child are undefined.
15784  *
15785  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15786  *
15787  * Since: 1.10
15788  */
15789 gboolean
15790 clutter_actor_iter_next (ClutterActorIter  *iter,
15791                          ClutterActor     **child)
15792 {
15793   RealActorIter *ri = (RealActorIter *) iter;
15794
15795   g_return_val_if_fail (iter != NULL, FALSE);
15796   g_return_val_if_fail (ri->root != NULL, FALSE);
15797 #ifndef G_DISABLE_ASSERT
15798   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15799 #endif
15800
15801   if (ri->current == NULL)
15802     ri->current = ri->root->priv->first_child;
15803   else
15804     ri->current = ri->current->priv->next_sibling;
15805
15806   if (child != NULL)
15807     *child = ri->current;
15808
15809   return ri->current != NULL;
15810 }
15811
15812 /**
15813  * clutter_actor_iter_prev:
15814  * @iter: a #ClutterActorIter
15815  * @child: (out): return location for a #ClutterActor
15816  *
15817  * Advances the @iter and retrieves the previous child of the root
15818  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15819  *
15820  * If the iterator can advance, this function returns %TRUE and sets the
15821  * @child argument.
15822  *
15823  * If the iterator cannot advance, this function returns %FALSE, and
15824  * the contents of @child are undefined.
15825  *
15826  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15827  *
15828  * Since: 1.10
15829  */
15830 gboolean
15831 clutter_actor_iter_prev (ClutterActorIter  *iter,
15832                          ClutterActor     **child)
15833 {
15834   RealActorIter *ri = (RealActorIter *) iter;
15835
15836   g_return_val_if_fail (iter != NULL, FALSE);
15837   g_return_val_if_fail (ri->root != NULL, FALSE);
15838 #ifndef G_DISABLE_ASSERT
15839   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15840 #endif
15841
15842   if (ri->current == NULL)
15843     ri->current = ri->root->priv->last_child;
15844   else
15845     ri->current = ri->current->priv->prev_sibling;
15846
15847   if (child != NULL)
15848     *child = ri->current;
15849
15850   return ri->current != NULL;
15851 }
15852
15853 /**
15854  * clutter_actor_iter_remove:
15855  * @iter: a #ClutterActorIter
15856  *
15857  * Safely removes the #ClutterActor currently pointer to by the iterator
15858  * from its parent.
15859  *
15860  * This function can only be called after clutter_actor_iter_next() or
15861  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15862  * than once for the same actor.
15863  *
15864  * This function will call clutter_actor_remove_child() internally.
15865  *
15866  * Since: 1.10
15867  */
15868 void
15869 clutter_actor_iter_remove (ClutterActorIter *iter)
15870 {
15871   RealActorIter *ri = (RealActorIter *) iter;
15872   ClutterActor *cur;
15873
15874   g_return_if_fail (iter != NULL);
15875   g_return_if_fail (ri->root != NULL);
15876 #ifndef G_DISABLE_ASSERT
15877   g_return_if_fail (ri->age == ri->root->priv->age);
15878 #endif
15879   g_return_if_fail (ri->current != NULL);
15880
15881   cur = ri->current;
15882
15883   if (cur != NULL)
15884     {
15885       ri->current = cur->priv->prev_sibling;
15886
15887       clutter_actor_remove_child_internal (ri->root, cur,
15888                                            REMOVE_CHILD_DEFAULT_FLAGS);
15889
15890       ri->age += 1;
15891     }
15892 }
15893
15894 /**
15895  * clutter_actor_iter_destroy:
15896  * @iter: a #ClutterActorIter
15897  *
15898  * Safely destroys the #ClutterActor currently pointer to by the iterator
15899  * from its parent.
15900  *
15901  * This function can only be called after clutter_actor_iter_next() or
15902  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15903  * than once for the same actor.
15904  *
15905  * This function will call clutter_actor_destroy() internally.
15906  *
15907  * Since: 1.10
15908  */
15909 void
15910 clutter_actor_iter_destroy (ClutterActorIter *iter)
15911 {
15912   RealActorIter *ri = (RealActorIter *) iter;
15913   ClutterActor *cur;
15914
15915   g_return_if_fail (iter != NULL);
15916   g_return_if_fail (ri->root != NULL);
15917 #ifndef G_DISABLE_ASSERT
15918   g_return_if_fail (ri->age == ri->root->priv->age);
15919 #endif
15920   g_return_if_fail (ri->current != NULL);
15921
15922   cur = ri->current;
15923
15924   if (cur != NULL)
15925     {
15926       ri->current = cur->priv->prev_sibling;
15927
15928       clutter_actor_destroy (cur);
15929
15930       ri->age += 1;
15931     }
15932 }