actor: Only care about a child's paint volume when clip_to_allocation isn't set
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="bin-layout">
113  *     <title>Actors</title>
114  *     <graphic fileref="test-actor.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  */
243
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
327
328 #include "clutter-actor-private.h"
329
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-main.h"
342 #include "clutter-marshal.h"
343 #include "clutter-flatten-effect.h"
344 #include "clutter-paint-volume-private.h"
345 #include "clutter-private.h"
346 #include "clutter-profile.h"
347 #include "clutter-scriptable.h"
348 #include "clutter-script-private.h"
349 #include "clutter-stage-private.h"
350 #include "clutter-units.h"
351
352 #include "deprecated/clutter-behaviour.h"
353 #include "deprecated/clutter-container.h"
354
355 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
356 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
357
358 /* Internal enum used to control mapped state update.  This is a hint
359  * which indicates when to do something other than just enforce
360  * invariants.
361  */
362 typedef enum {
363   MAP_STATE_CHECK,           /* just enforce invariants. */
364   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
365                               * used when about to unparent.
366                               */
367   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
368                               * used to set mapped on toplevels.
369                               */
370   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
371                               * used just before unmapping parent.
372                               */
373 } MapStateChange;
374
375 /* 3 entries should be a good compromise, few layout managers
376  * will ask for 3 different preferred size in each allocation cycle */
377 #define N_CACHED_SIZE_REQUESTS 3
378
379 struct _ClutterActorPrivate
380 {
381   /* request mode */
382   ClutterRequestMode request_mode;
383
384   /* our cached size requests for different width / height */
385   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
386   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
387
388   /* An age of 0 means the entry is not set */
389   guint cached_height_age;
390   guint cached_width_age;
391
392   /* the bounding box of the actor, relative to the parent's
393    * allocation
394    */
395   ClutterActorBox allocation;
396   ClutterAllocationFlags allocation_flags;
397
398   /* depth */
399   gfloat z;
400
401   /* clip, in actor coordinates */
402   cairo_rectangle_t clip;
403
404   /* the cached transformation matrix; see apply_transform() */
405   CoglMatrix transform;
406
407   guint8 opacity;
408   gint opacity_override;
409
410   ClutterOffscreenRedirect offscreen_redirect;
411
412   /* This is an internal effect used to implement the
413      offscreen-redirect property */
414   ClutterEffect *flatten_effect;
415
416   /* scene graph */
417   ClutterActor *parent;
418   ClutterActor *prev_sibling;
419   ClutterActor *next_sibling;
420   ClutterActor *first_child;
421   ClutterActor *last_child;
422
423   gint n_children;
424
425   /* tracks whenever the children of an actor are changed; the
426    * age is incremented by 1 whenever an actor is added or
427    * removed. the age is not incremented when the first or the
428    * last child pointers are changed, or when grandchildren of
429    * an actor are changed.
430    */
431   gint age;
432
433   gchar *name; /* a non-unique name, used for debugging */
434   guint32 id; /* unique id, used for backward compatibility */
435
436   gint32 pick_id; /* per-stage unique id, used for picking */
437
438   /* a back-pointer to the Pango context that we can use
439    * to create pre-configured PangoLayout
440    */
441   PangoContext *pango_context;
442
443   /* the text direction configured for this child - either by
444    * application code, or by the actor's parent
445    */
446   ClutterTextDirection text_direction;
447
448   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
449   gint internal_child;
450
451   /* meta classes */
452   ClutterMetaGroup *actions;
453   ClutterMetaGroup *constraints;
454   ClutterMetaGroup *effects;
455
456   /* delegate object used to allocate the children of this actor */
457   ClutterLayoutManager *layout_manager;
458
459   /* used when painting, to update the paint volume */
460   ClutterEffect *current_effect;
461
462   /* This is used to store an effect which needs to be redrawn. A
463      redraw can be queued to start from a particular effect. This is
464      used by parametrised effects that can cache an image of the
465      actor. If a parameter of the effect changes then it only needs to
466      redraw the cached image, not the actual actor. The pointer is
467      only valid if is_dirty == TRUE. If the pointer is NULL then the
468      whole actor is dirty. */
469   ClutterEffect *effect_to_redraw;
470
471   /* This is used when painting effects to implement the
472      clutter_actor_continue_paint() function. It points to the node in
473      the list of effects that is next in the chain */
474   const GList *next_effect_to_paint;
475
476   ClutterPaintVolume paint_volume;
477
478   /* NB: This volume isn't relative to this actor, it is in eye
479    * coordinates so that it can remain valid after the actor changes.
480    */
481   ClutterPaintVolume last_paint_volume;
482
483   ClutterStageQueueRedrawEntry *queue_redraw_entry;
484
485   ClutterColor bg_color;
486
487   /* bitfields */
488
489   /* fixed position and sizes */
490   guint position_set                : 1;
491   guint min_width_set               : 1;
492   guint min_height_set              : 1;
493   guint natural_width_set           : 1;
494   guint natural_height_set          : 1;
495   /* cached request is invalid (implies allocation is too) */
496   guint needs_width_request         : 1;
497   /* cached request is invalid (implies allocation is too) */
498   guint needs_height_request        : 1;
499   /* cached allocation is invalid (request has changed, probably) */
500   guint needs_allocation            : 1;
501   guint show_on_set_parent          : 1;
502   guint has_clip                    : 1;
503   guint clip_to_allocation          : 1;
504   guint enable_model_view_transform : 1;
505   guint enable_paint_unmapped       : 1;
506   guint has_pointer                 : 1;
507   guint propagated_one_redraw       : 1;
508   guint paint_volume_valid          : 1;
509   guint last_paint_volume_valid     : 1;
510   guint in_clone_paint              : 1;
511   guint transform_valid             : 1;
512   /* This is TRUE if anything has queued a redraw since we were last
513      painted. In this case effect_to_redraw will point to an effect
514      the redraw was queued from or it will be NULL if the redraw was
515      queued without an effect. */
516   guint is_dirty                    : 1;
517   guint bg_color_set                : 1;
518 };
519
520 enum
521 {
522   PROP_0,
523
524   PROP_NAME,
525
526   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
527    * when set they force a size request, when gotten they
528    * get the allocation if the allocation is valid, and the
529    * request otherwise
530    */
531   PROP_X,
532   PROP_Y,
533   PROP_WIDTH,
534   PROP_HEIGHT,
535
536   /* Then the rest of these size-related properties are the "actual"
537    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
538    */
539   PROP_FIXED_X,
540   PROP_FIXED_Y,
541
542   PROP_FIXED_POSITION_SET,
543
544   PROP_MIN_WIDTH,
545   PROP_MIN_WIDTH_SET,
546
547   PROP_MIN_HEIGHT,
548   PROP_MIN_HEIGHT_SET,
549
550   PROP_NATURAL_WIDTH,
551   PROP_NATURAL_WIDTH_SET,
552
553   PROP_NATURAL_HEIGHT,
554   PROP_NATURAL_HEIGHT_SET,
555
556   PROP_REQUEST_MODE,
557
558   /* Allocation properties are read-only */
559   PROP_ALLOCATION,
560
561   PROP_DEPTH,
562
563   PROP_CLIP,
564   PROP_HAS_CLIP,
565   PROP_CLIP_TO_ALLOCATION,
566
567   PROP_OPACITY,
568
569   PROP_OFFSCREEN_REDIRECT,
570
571   PROP_VISIBLE,
572   PROP_MAPPED,
573   PROP_REALIZED,
574   PROP_REACTIVE,
575
576   PROP_SCALE_X,
577   PROP_SCALE_Y,
578   PROP_SCALE_CENTER_X,
579   PROP_SCALE_CENTER_Y,
580   PROP_SCALE_GRAVITY,
581
582   PROP_ROTATION_ANGLE_X,
583   PROP_ROTATION_ANGLE_Y,
584   PROP_ROTATION_ANGLE_Z,
585   PROP_ROTATION_CENTER_X,
586   PROP_ROTATION_CENTER_Y,
587   PROP_ROTATION_CENTER_Z,
588   /* This property only makes sense for the z rotation because the
589      others would depend on the actor having a size along the
590      z-axis */
591   PROP_ROTATION_CENTER_Z_GRAVITY,
592
593   PROP_ANCHOR_X,
594   PROP_ANCHOR_Y,
595   PROP_ANCHOR_GRAVITY,
596
597   PROP_SHOW_ON_SET_PARENT,
598
599   PROP_TEXT_DIRECTION,
600   PROP_HAS_POINTER,
601
602   PROP_ACTIONS,
603   PROP_CONSTRAINTS,
604   PROP_EFFECT,
605
606   PROP_LAYOUT_MANAGER,
607
608   PROP_X_ALIGN,
609   PROP_Y_ALIGN,
610   PROP_MARGIN_TOP,
611   PROP_MARGIN_BOTTOM,
612   PROP_MARGIN_LEFT,
613   PROP_MARGIN_RIGHT,
614
615   PROP_BACKGROUND_COLOR,
616   PROP_BACKGROUND_COLOR_SET,
617
618   PROP_FIRST_CHILD,
619   PROP_LAST_CHILD,
620
621   PROP_LAST
622 };
623
624 static GParamSpec *obj_props[PROP_LAST];
625
626 enum
627 {
628   SHOW,
629   HIDE,
630   DESTROY,
631   PARENT_SET,
632   KEY_FOCUS_IN,
633   KEY_FOCUS_OUT,
634   PAINT,
635   PICK,
636   REALIZE,
637   UNREALIZE,
638   QUEUE_REDRAW,
639   QUEUE_RELAYOUT,
640   EVENT,
641   CAPTURED_EVENT,
642   BUTTON_PRESS_EVENT,
643   BUTTON_RELEASE_EVENT,
644   SCROLL_EVENT,
645   KEY_PRESS_EVENT,
646   KEY_RELEASE_EVENT,
647   MOTION_EVENT,
648   ENTER_EVENT,
649   LEAVE_EVENT,
650   ALLOCATION_CHANGED,
651
652   LAST_SIGNAL
653 };
654
655 static guint actor_signals[LAST_SIGNAL] = { 0, };
656
657 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
658 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
659 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
660 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
661
662 /* These setters are all static for now, maybe they should be in the
663  * public API, but they are perhaps obscure enough to leave only as
664  * properties
665  */
666 static void clutter_actor_set_min_width          (ClutterActor *self,
667                                                   gfloat        min_width);
668 static void clutter_actor_set_min_height         (ClutterActor *self,
669                                                   gfloat        min_height);
670 static void clutter_actor_set_natural_width      (ClutterActor *self,
671                                                   gfloat        natural_width);
672 static void clutter_actor_set_natural_height     (ClutterActor *self,
673                                                   gfloat        natural_height);
674 static void clutter_actor_set_min_width_set      (ClutterActor *self,
675                                                   gboolean      use_min_width);
676 static void clutter_actor_set_min_height_set     (ClutterActor *self,
677                                                   gboolean      use_min_height);
678 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
679                                                   gboolean  use_natural_width);
680 static void clutter_actor_set_natural_height_set (ClutterActor *self,
681                                                   gboolean  use_natural_height);
682 static void clutter_actor_update_map_state       (ClutterActor  *self,
683                                                   MapStateChange change);
684 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
685
686 /* Helper routines for managing anchor coords */
687 static void clutter_anchor_coord_get_units (ClutterActor      *self,
688                                             const AnchorCoord *coord,
689                                             gfloat            *x,
690                                             gfloat            *y,
691                                             gfloat            *z);
692 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
693                                             gfloat             x,
694                                             gfloat             y,
695                                             gfloat             z);
696
697 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
698 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
699                                                         ClutterGravity     gravity);
700
701 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
702
703 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
704
705 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
706                                                                ClutterActor *ancestor,
707                                                                CoglMatrix *matrix);
708
709 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
710
711 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
712
713 static void on_layout_manager_changed (ClutterLayoutManager *manager,
714                                        ClutterActor         *self);
715
716 /* Helper macro which translates by the anchor coord, applies the
717    given transformation and then translates back */
718 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
719   gfloat _tx, _ty, _tz;                                                \
720   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
721   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
722   { _transform; }                                                      \
723   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
724
725 static GQuark quark_shader_data = 0;
726 static GQuark quark_actor_layout_info = 0;
727 static GQuark quark_actor_transform_info = 0;
728
729 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
730                          clutter_actor,
731                          G_TYPE_INITIALLY_UNOWNED,
732                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
733                                                 clutter_container_iface_init)
734                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
735                                                 clutter_scriptable_iface_init)
736                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
737                                                 clutter_animatable_iface_init)
738                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
739                                                 atk_implementor_iface_init));
740
741 /*< private >
742  * clutter_actor_get_debug_name:
743  * @actor: a #ClutterActor
744  *
745  * Retrieves a printable name of @actor for debugging messages
746  *
747  * Return value: a string with a printable name
748  */
749 const gchar *
750 _clutter_actor_get_debug_name (ClutterActor *actor)
751 {
752   return actor->priv->name != NULL ? actor->priv->name
753                                    : G_OBJECT_TYPE_NAME (actor);
754 }
755
756 #ifdef CLUTTER_ENABLE_DEBUG
757 /* XXX - this is for debugging only, remove once working (or leave
758  * in only in some debug mode). Should leave it for a little while
759  * until we're confident in the new map/realize/visible handling.
760  */
761 static inline void
762 clutter_actor_verify_map_state (ClutterActor *self)
763 {
764   ClutterActorPrivate *priv = self->priv;
765
766   if (CLUTTER_ACTOR_IS_REALIZED (self))
767     {
768       /* all bets are off during reparent when we're potentially realized,
769        * but should not be according to invariants
770        */
771       if (!CLUTTER_ACTOR_IN_REPARENT (self))
772         {
773           if (priv->parent == NULL)
774             {
775               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
776                 {
777                 }
778               else
779                 g_warning ("Realized non-toplevel actor '%s' should "
780                            "have a parent",
781                            _clutter_actor_get_debug_name (self));
782             }
783           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
784             {
785               g_warning ("Realized actor %s has an unrealized parent %s",
786                          _clutter_actor_get_debug_name (self),
787                          _clutter_actor_get_debug_name (priv->parent));
788             }
789         }
790     }
791
792   if (CLUTTER_ACTOR_IS_MAPPED (self))
793     {
794       if (!CLUTTER_ACTOR_IS_REALIZED (self))
795         g_warning ("Actor '%s' is mapped but not realized",
796                    _clutter_actor_get_debug_name (self));
797
798       /* remaining bets are off during reparent when we're potentially
799        * mapped, but should not be according to invariants
800        */
801       if (!CLUTTER_ACTOR_IN_REPARENT (self))
802         {
803           if (priv->parent == NULL)
804             {
805               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
806                 {
807                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
808                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
809                     {
810                       g_warning ("Toplevel actor '%s' is mapped "
811                                  "but not visible",
812                                  _clutter_actor_get_debug_name (self));
813                     }
814                 }
815               else
816                 {
817                   g_warning ("Mapped actor '%s' should have a parent",
818                              _clutter_actor_get_debug_name (self));
819                 }
820             }
821           else
822             {
823               ClutterActor *iter = self;
824
825               /* check for the enable_paint_unmapped flag on the actor
826                * and parents; if the flag is enabled at any point of this
827                * branch of the scene graph then all the later checks
828                * become pointless
829                */
830               while (iter != NULL)
831                 {
832                   if (iter->priv->enable_paint_unmapped)
833                     return;
834
835                   iter = iter->priv->parent;
836                 }
837
838               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
839                 {
840                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
841                              "is not visible",
842                              _clutter_actor_get_debug_name (self),
843                              _clutter_actor_get_debug_name (priv->parent));
844                 }
845
846               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
847                 {
848                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
849                              "is not realized",
850                              _clutter_actor_get_debug_name (self),
851                              _clutter_actor_get_debug_name (priv->parent));
852                 }
853
854               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
855                 {
856                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
857                     g_warning ("Actor '%s' is mapped but its non-toplevel "
858                                "parent '%s' is not mapped",
859                                _clutter_actor_get_debug_name (self),
860                                _clutter_actor_get_debug_name (priv->parent));
861                 }
862             }
863         }
864     }
865 }
866
867 #endif /* CLUTTER_ENABLE_DEBUG */
868
869 static void
870 clutter_actor_set_mapped (ClutterActor *self,
871                           gboolean      mapped)
872 {
873   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
874     return;
875
876   if (mapped)
877     {
878       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
879       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
880     }
881   else
882     {
883       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
884       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
885     }
886 }
887
888 /* this function updates the mapped and realized states according to
889  * invariants, in the appropriate order.
890  */
891 static void
892 clutter_actor_update_map_state (ClutterActor  *self,
893                                 MapStateChange change)
894 {
895   gboolean was_mapped;
896
897   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
898
899   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
900     {
901       /* the mapped flag on top-level actors must be set by the
902        * per-backend implementation because it might be asynchronous.
903        *
904        * That is, the MAPPED flag on toplevels currently tracks the X
905        * server mapped-ness of the window, while the expected behavior
906        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
907        * This creates some weird complexity by breaking the invariant
908        * that if we're visible and all ancestors shown then we are
909        * also mapped - instead, we are mapped if all ancestors
910        * _possibly excepting_ the stage are mapped. The stage
911        * will map/unmap for example when it is minimized or
912        * moved to another workspace.
913        *
914        * So, the only invariant on the stage is that if visible it
915        * should be realized, and that it has to be visible to be
916        * mapped.
917        */
918       if (CLUTTER_ACTOR_IS_VISIBLE (self))
919         clutter_actor_realize (self);
920
921       switch (change)
922         {
923         case MAP_STATE_CHECK:
924           break;
925
926         case MAP_STATE_MAKE_MAPPED:
927           g_assert (!was_mapped);
928           clutter_actor_set_mapped (self, TRUE);
929           break;
930
931         case MAP_STATE_MAKE_UNMAPPED:
932           g_assert (was_mapped);
933           clutter_actor_set_mapped (self, FALSE);
934           break;
935
936         case MAP_STATE_MAKE_UNREALIZED:
937           /* we only use MAKE_UNREALIZED in unparent,
938            * and unparenting a stage isn't possible.
939            * If someone wants to just unrealize a stage
940            * then clutter_actor_unrealize() doesn't
941            * go through this codepath.
942            */
943           g_warning ("Trying to force unrealize stage is not allowed");
944           break;
945         }
946
947       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
948           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
949           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
950         {
951           g_warning ("Clutter toplevel of type '%s' is not visible, but "
952                      "it is somehow still mapped",
953                      _clutter_actor_get_debug_name (self));
954         }
955     }
956   else
957     {
958       ClutterActorPrivate *priv = self->priv;
959       ClutterActor *parent = priv->parent;
960       gboolean should_be_mapped;
961       gboolean may_be_realized;
962       gboolean must_be_realized;
963
964       should_be_mapped = FALSE;
965       may_be_realized = TRUE;
966       must_be_realized = FALSE;
967
968       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
969         {
970           may_be_realized = FALSE;
971         }
972       else
973         {
974           /* Maintain invariant that if parent is mapped, and we are
975            * visible, then we are mapped ...  unless parent is a
976            * stage, in which case we map regardless of parent's map
977            * state but do require stage to be visible and realized.
978            *
979            * If parent is realized, that does not force us to be
980            * realized; but if parent is unrealized, that does force
981            * us to be unrealized.
982            *
983            * The reason we don't force children to realize with
984            * parents is _clutter_actor_rerealize(); if we require that
985            * a realized parent means children are realized, then to
986            * unrealize an actor we would have to unrealize its
987            * parents, which would end up meaning unrealizing and
988            * hiding the entire stage. So we allow unrealizing a
989            * child (as long as that child is not mapped) while that
990            * child still has a realized parent.
991            *
992            * Also, if we unrealize from leaf nodes to root, and
993            * realize from root to leaf, the invariants are never
994            * violated if we allow children to be unrealized
995            * while parents are realized.
996            *
997            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
998            * to force us to unmap, even though parent is still
999            * mapped. This is because we're unmapping from leaf nodes
1000            * up to root nodes.
1001            */
1002           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1003               change != MAP_STATE_MAKE_UNMAPPED)
1004             {
1005               gboolean parent_is_visible_realized_toplevel;
1006
1007               parent_is_visible_realized_toplevel =
1008                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1009                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1010                  CLUTTER_ACTOR_IS_REALIZED (parent));
1011
1012               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1013                   parent_is_visible_realized_toplevel)
1014                 {
1015                   must_be_realized = TRUE;
1016                   should_be_mapped = TRUE;
1017                 }
1018             }
1019
1020           /* if the actor has been set to be painted even if unmapped
1021            * then we should map it and check for realization as well;
1022            * this is an override for the branch of the scene graph
1023            * which begins with this node
1024            */
1025           if (priv->enable_paint_unmapped)
1026             {
1027               if (priv->parent == NULL)
1028                 g_warning ("Attempting to map an unparented actor '%s'",
1029                            _clutter_actor_get_debug_name (self));
1030
1031               should_be_mapped = TRUE;
1032               must_be_realized = TRUE;
1033             }
1034
1035           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1036             may_be_realized = FALSE;
1037         }
1038
1039       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1040         {
1041           if (parent == NULL)
1042             g_warning ("Attempting to map a child that does not "
1043                        "meet the necessary invariants: the actor '%s' "
1044                        "has no parent",
1045                        _clutter_actor_get_debug_name (self));
1046           else
1047             g_warning ("Attempting to map a child that does not "
1048                        "meet the necessary invariants: the actor '%s' "
1049                        "is parented to an unmapped actor '%s'",
1050                        _clutter_actor_get_debug_name (self),
1051                        _clutter_actor_get_debug_name (priv->parent));
1052         }
1053
1054       /* If in reparent, we temporarily suspend unmap and unrealize.
1055        *
1056        * We want to go in the order "realize, map" and "unmap, unrealize"
1057        */
1058
1059       /* Unmap */
1060       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1061         clutter_actor_set_mapped (self, FALSE);
1062
1063       /* Realize */
1064       if (must_be_realized)
1065         clutter_actor_realize (self);
1066
1067       /* if we must be realized then we may be, presumably */
1068       g_assert (!(must_be_realized && !may_be_realized));
1069
1070       /* Unrealize */
1071       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1072         clutter_actor_unrealize_not_hiding (self);
1073
1074       /* Map */
1075       if (should_be_mapped)
1076         {
1077           if (!must_be_realized)
1078             g_warning ("Somehow we think actor '%s' should be mapped but "
1079                        "not realized, which isn't allowed",
1080                        _clutter_actor_get_debug_name (self));
1081
1082           /* realization is allowed to fail (though I don't know what
1083            * an app is supposed to do about that - shouldn't it just
1084            * be a g_error? anyway, we have to avoid mapping if this
1085            * happens)
1086            */
1087           if (CLUTTER_ACTOR_IS_REALIZED (self))
1088             clutter_actor_set_mapped (self, TRUE);
1089         }
1090     }
1091
1092 #ifdef CLUTTER_ENABLE_DEBUG
1093   /* check all invariants were kept */
1094   clutter_actor_verify_map_state (self);
1095 #endif
1096 }
1097
1098 static void
1099 clutter_actor_real_map (ClutterActor *self)
1100 {
1101   ClutterActorPrivate *priv = self->priv;
1102   ClutterActor *stage, *iter;
1103
1104   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1105
1106   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1107                 _clutter_actor_get_debug_name (self));
1108
1109   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1110
1111   stage = _clutter_actor_get_stage_internal (self);
1112   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1113
1114   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1115                 priv->pick_id,
1116                 _clutter_actor_get_debug_name (self));
1117
1118   /* notify on parent mapped before potentially mapping
1119    * children, so apps see a top-down notification.
1120    */
1121   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1122
1123   for (iter = self->priv->first_child;
1124        iter != NULL;
1125        iter = iter->priv->next_sibling)
1126     {
1127       clutter_actor_map (iter);
1128     }
1129 }
1130
1131 /**
1132  * clutter_actor_map:
1133  * @self: A #ClutterActor
1134  *
1135  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1136  * and realizes its children if they are visible. Does nothing if the
1137  * actor is not visible.
1138  *
1139  * Calling this function is strongly disencouraged: the default
1140  * implementation of #ClutterActorClass.map() will map all the children
1141  * of an actor when mapping its parent.
1142  *
1143  * When overriding map, it is mandatory to chain up to the parent
1144  * implementation.
1145  *
1146  * Since: 1.0
1147  */
1148 void
1149 clutter_actor_map (ClutterActor *self)
1150 {
1151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1152
1153   if (CLUTTER_ACTOR_IS_MAPPED (self))
1154     return;
1155
1156   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1157     return;
1158
1159   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1160 }
1161
1162 static void
1163 clutter_actor_real_unmap (ClutterActor *self)
1164 {
1165   ClutterActorPrivate *priv = self->priv;
1166   ClutterActor *iter;
1167
1168   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1169
1170   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1171                 _clutter_actor_get_debug_name (self));
1172
1173   for (iter = self->priv->first_child;
1174        iter != NULL;
1175        iter = iter->priv->next_sibling)
1176     {
1177       clutter_actor_unmap (iter);
1178     }
1179
1180   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1181
1182   /* clear the contents of the last paint volume, so that hiding + moving +
1183    * showing will not result in the wrong area being repainted
1184    */
1185   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1186   priv->last_paint_volume_valid = TRUE;
1187
1188   /* notify on parent mapped after potentially unmapping
1189    * children, so apps see a bottom-up notification.
1190    */
1191   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1192
1193   /* relinquish keyboard focus if we were unmapped while owning it */
1194   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1195     {
1196       ClutterStage *stage;
1197
1198       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1199
1200       if (stage != NULL)
1201         _clutter_stage_release_pick_id (stage, priv->pick_id);
1202
1203       priv->pick_id = -1;
1204
1205       if (stage != NULL &&
1206           clutter_stage_get_key_focus (stage) == self)
1207         {
1208           clutter_stage_set_key_focus (stage, NULL);
1209         }
1210     }
1211 }
1212
1213 /**
1214  * clutter_actor_unmap:
1215  * @self: A #ClutterActor
1216  *
1217  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1218  * unmaps its children if they were mapped.
1219  *
1220  * Calling this function is not encouraged: the default #ClutterActor
1221  * implementation of #ClutterActorClass.unmap() will also unmap any
1222  * eventual children by default when their parent is unmapped.
1223  *
1224  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1225  * chain up to the parent implementation.
1226  *
1227  * <note>It is important to note that the implementation of the
1228  * #ClutterActorClass.unmap() virtual function may be called after
1229  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1230  * implementation, but it is guaranteed to be called before the
1231  * #GObjectClass.finalize() implementation.</note>
1232  *
1233  * Since: 1.0
1234  */
1235 void
1236 clutter_actor_unmap (ClutterActor *self)
1237 {
1238   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1239
1240   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1241     return;
1242
1243   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1244 }
1245
1246 static void
1247 clutter_actor_real_show (ClutterActor *self)
1248 {
1249   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1250     {
1251       ClutterActorPrivate *priv = self->priv;
1252
1253       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1254
1255       /* we notify on the "visible" flag in the clutter_actor_show()
1256        * wrapper so the entire show signal emission completes first
1257        * (?)
1258        */
1259       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1260
1261       /* we queue a relayout unless the actor is inside a
1262        * container that explicitly told us not to
1263        */
1264       if (priv->parent != NULL &&
1265           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1266         {
1267           /* While an actor is hidden the parent may not have
1268            * allocated/requested so we need to start from scratch
1269            * and avoid the short-circuiting in
1270            * clutter_actor_queue_relayout().
1271            */
1272           priv->needs_width_request  = FALSE;
1273           priv->needs_height_request = FALSE;
1274           priv->needs_allocation     = FALSE;
1275           clutter_actor_queue_relayout (self);
1276         }
1277     }
1278 }
1279
1280 static inline void
1281 set_show_on_set_parent (ClutterActor *self,
1282                         gboolean      set_show)
1283 {
1284   ClutterActorPrivate *priv = self->priv;
1285
1286   set_show = !!set_show;
1287
1288   if (priv->show_on_set_parent == set_show)
1289     return;
1290
1291   if (priv->parent == NULL)
1292     {
1293       priv->show_on_set_parent = set_show;
1294       g_object_notify_by_pspec (G_OBJECT (self),
1295                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1296     }
1297 }
1298
1299 /**
1300  * clutter_actor_show:
1301  * @self: A #ClutterActor
1302  *
1303  * Flags an actor to be displayed. An actor that isn't shown will not
1304  * be rendered on the stage.
1305  *
1306  * Actors are visible by default.
1307  *
1308  * If this function is called on an actor without a parent, the
1309  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1310  * effect.
1311  */
1312 void
1313 clutter_actor_show (ClutterActor *self)
1314 {
1315   ClutterActorPrivate *priv;
1316
1317   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1318
1319   /* simple optimization */
1320   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1321     {
1322       /* we still need to set the :show-on-set-parent property, in
1323        * case show() is called on an unparented actor
1324        */
1325       set_show_on_set_parent (self, TRUE);
1326       return;
1327     }
1328
1329 #ifdef CLUTTER_ENABLE_DEBUG
1330   clutter_actor_verify_map_state (self);
1331 #endif
1332
1333   priv = self->priv;
1334
1335   g_object_freeze_notify (G_OBJECT (self));
1336
1337   set_show_on_set_parent (self, TRUE);
1338
1339   g_signal_emit (self, actor_signals[SHOW], 0);
1340   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1341
1342   if (priv->parent != NULL)
1343     clutter_actor_queue_redraw (priv->parent);
1344
1345   g_object_thaw_notify (G_OBJECT (self));
1346 }
1347
1348 /**
1349  * clutter_actor_show_all:
1350  * @self: a #ClutterActor
1351  *
1352  * Calls clutter_actor_show() on all children of an actor (if any).
1353  *
1354  * Since: 0.2
1355  *
1356  * Deprecated: 1.10: Actors are visible by default
1357  */
1358 void
1359 clutter_actor_show_all (ClutterActor *self)
1360 {
1361   ClutterActorClass *klass;
1362
1363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1364
1365   klass = CLUTTER_ACTOR_GET_CLASS (self);
1366   if (klass->show_all)
1367     klass->show_all (self);
1368 }
1369
1370 static void
1371 clutter_actor_real_hide (ClutterActor *self)
1372 {
1373   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1374     {
1375       ClutterActorPrivate *priv = self->priv;
1376
1377       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1378
1379       /* we notify on the "visible" flag in the clutter_actor_hide()
1380        * wrapper so the entire hide signal emission completes first
1381        * (?)
1382        */
1383       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1384
1385       /* we queue a relayout unless the actor is inside a
1386        * container that explicitly told us not to
1387        */
1388       if (priv->parent != NULL &&
1389           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1390         clutter_actor_queue_relayout (priv->parent);
1391     }
1392 }
1393
1394 /**
1395  * clutter_actor_hide:
1396  * @self: A #ClutterActor
1397  *
1398  * Flags an actor to be hidden. A hidden actor will not be
1399  * rendered on the stage.
1400  *
1401  * Actors are visible by default.
1402  *
1403  * If this function is called on an actor without a parent, the
1404  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1405  * as a side-effect.
1406  */
1407 void
1408 clutter_actor_hide (ClutterActor *self)
1409 {
1410   ClutterActorPrivate *priv;
1411
1412   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1413
1414   /* simple optimization */
1415   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1416     {
1417       /* we still need to set the :show-on-set-parent property, in
1418        * case hide() is called on an unparented actor
1419        */
1420       set_show_on_set_parent (self, FALSE);
1421       return;
1422     }
1423
1424 #ifdef CLUTTER_ENABLE_DEBUG
1425   clutter_actor_verify_map_state (self);
1426 #endif
1427
1428   priv = self->priv;
1429
1430   g_object_freeze_notify (G_OBJECT (self));
1431
1432   set_show_on_set_parent (self, FALSE);
1433
1434   g_signal_emit (self, actor_signals[HIDE], 0);
1435   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1436
1437   if (priv->parent != NULL)
1438     clutter_actor_queue_redraw (priv->parent);
1439
1440   g_object_thaw_notify (G_OBJECT (self));
1441 }
1442
1443 /**
1444  * clutter_actor_hide_all:
1445  * @self: a #ClutterActor
1446  *
1447  * Calls clutter_actor_hide() on all child actors (if any).
1448  *
1449  * Since: 0.2
1450  *
1451  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1452  *   prevent its children from being painted as well.
1453  */
1454 void
1455 clutter_actor_hide_all (ClutterActor *self)
1456 {
1457   ClutterActorClass *klass;
1458
1459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1460
1461   klass = CLUTTER_ACTOR_GET_CLASS (self);
1462   if (klass->hide_all)
1463     klass->hide_all (self);
1464 }
1465
1466 /**
1467  * clutter_actor_realize:
1468  * @self: A #ClutterActor
1469  *
1470  * Realization informs the actor that it is attached to a stage. It
1471  * can use this to allocate resources if it wanted to delay allocation
1472  * until it would be rendered. However it is perfectly acceptable for
1473  * an actor to create resources before being realized because Clutter
1474  * only ever has a single rendering context so that actor is free to
1475  * be moved from one stage to another.
1476  *
1477  * This function does nothing if the actor is already realized.
1478  *
1479  * Because a realized actor must have realized parent actors, calling
1480  * clutter_actor_realize() will also realize all parents of the actor.
1481  *
1482  * This function does not realize child actors, except in the special
1483  * case that realizing the stage, when the stage is visible, will
1484  * suddenly map (and thus realize) the children of the stage.
1485  **/
1486 void
1487 clutter_actor_realize (ClutterActor *self)
1488 {
1489   ClutterActorPrivate *priv;
1490
1491   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1492
1493   priv = self->priv;
1494
1495 #ifdef CLUTTER_ENABLE_DEBUG
1496   clutter_actor_verify_map_state (self);
1497 #endif
1498
1499   if (CLUTTER_ACTOR_IS_REALIZED (self))
1500     return;
1501
1502   /* To be realized, our parent actors must be realized first.
1503    * This will only succeed if we're inside a toplevel.
1504    */
1505   if (priv->parent != NULL)
1506     clutter_actor_realize (priv->parent);
1507
1508   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1509     {
1510       /* toplevels can be realized at any time */
1511     }
1512   else
1513     {
1514       /* "Fail" the realization if parent is missing or unrealized;
1515        * this should really be a g_warning() not some kind of runtime
1516        * failure; how can an app possibly recover? Instead it's a bug
1517        * in the app and the app should get an explanatory warning so
1518        * someone can fix it. But for now it's too hard to fix this
1519        * because e.g. ClutterTexture needs reworking.
1520        */
1521       if (priv->parent == NULL ||
1522           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1523         return;
1524     }
1525
1526   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1527
1528   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1529   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1530
1531   g_signal_emit (self, actor_signals[REALIZE], 0);
1532
1533   /* Stage actor is allowed to unset the realized flag again in its
1534    * default signal handler, though that is a pathological situation.
1535    */
1536
1537   /* If realization "failed" we'll have to update child state. */
1538   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1539 }
1540
1541 static void
1542 clutter_actor_real_unrealize (ClutterActor *self)
1543 {
1544   /* we must be unmapped (implying our children are also unmapped) */
1545   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1546 }
1547
1548 /**
1549  * clutter_actor_unrealize:
1550  * @self: A #ClutterActor
1551  *
1552  * Unrealization informs the actor that it may be being destroyed or
1553  * moved to another stage. The actor may want to destroy any
1554  * underlying graphics resources at this point. However it is
1555  * perfectly acceptable for it to retain the resources until the actor
1556  * is destroyed because Clutter only ever uses a single rendering
1557  * context and all of the graphics resources are valid on any stage.
1558  *
1559  * Because mapped actors must be realized, actors may not be
1560  * unrealized if they are mapped. This function hides the actor to be
1561  * sure it isn't mapped, an application-visible side effect that you
1562  * may not be expecting.
1563  *
1564  * This function should not be called by application code.
1565  */
1566 void
1567 clutter_actor_unrealize (ClutterActor *self)
1568 {
1569   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1570   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1571
1572 /* This function should not really be in the public API, because
1573  * there isn't a good reason to call it. ClutterActor will already
1574  * unrealize things for you when it's important to do so.
1575  *
1576  * If you were using clutter_actor_unrealize() in a dispose
1577  * implementation, then don't, just chain up to ClutterActor's
1578  * dispose.
1579  *
1580  * If you were using clutter_actor_unrealize() to implement
1581  * unrealizing children of your container, then don't, ClutterActor
1582  * will already take care of that.
1583  *
1584  * If you were using clutter_actor_unrealize() to re-realize to
1585  * create your resources in a different way, then use
1586  * _clutter_actor_rerealize() (inside Clutter) or just call your
1587  * code that recreates your resources directly (outside Clutter).
1588  */
1589
1590 #ifdef CLUTTER_ENABLE_DEBUG
1591   clutter_actor_verify_map_state (self);
1592 #endif
1593
1594   clutter_actor_hide (self);
1595
1596   clutter_actor_unrealize_not_hiding (self);
1597 }
1598
1599 static ClutterActorTraverseVisitFlags
1600 unrealize_actor_before_children_cb (ClutterActor *self,
1601                                     int depth,
1602                                     void *user_data)
1603 {
1604   /* If an actor is already unrealized we know its children have also
1605    * already been unrealized... */
1606   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1607     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1608
1609   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1610
1611   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1612 }
1613
1614 static ClutterActorTraverseVisitFlags
1615 unrealize_actor_after_children_cb (ClutterActor *self,
1616                                    int depth,
1617                                    void *user_data)
1618 {
1619   /* We want to unset the realized flag only _after_
1620    * child actors are unrealized, to maintain invariants.
1621    */
1622   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1623   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1624   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1625 }
1626
1627 /*
1628  * clutter_actor_unrealize_not_hiding:
1629  * @self: A #ClutterActor
1630  *
1631  * Unrealization informs the actor that it may be being destroyed or
1632  * moved to another stage. The actor may want to destroy any
1633  * underlying graphics resources at this point. However it is
1634  * perfectly acceptable for it to retain the resources until the actor
1635  * is destroyed because Clutter only ever uses a single rendering
1636  * context and all of the graphics resources are valid on any stage.
1637  *
1638  * Because mapped actors must be realized, actors may not be
1639  * unrealized if they are mapped. You must hide the actor or one of
1640  * its parents before attempting to unrealize.
1641  *
1642  * This function is separate from clutter_actor_unrealize() because it
1643  * does not automatically hide the actor.
1644  * Actors need not be hidden to be unrealized, they just need to
1645  * be unmapped. In fact we don't want to mess up the application's
1646  * setting of the "visible" flag, so hiding is very undesirable.
1647  *
1648  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1649  * backward compatibility.
1650  */
1651 static void
1652 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1653 {
1654   _clutter_actor_traverse (self,
1655                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1656                            unrealize_actor_before_children_cb,
1657                            unrealize_actor_after_children_cb,
1658                            NULL);
1659 }
1660
1661 /*
1662  * _clutter_actor_rerealize:
1663  * @self: A #ClutterActor
1664  * @callback: Function to call while unrealized
1665  * @data: data for callback
1666  *
1667  * If an actor is already unrealized, this just calls the callback.
1668  *
1669  * If it is realized, it unrealizes temporarily, calls the callback,
1670  * and then re-realizes the actor.
1671  *
1672  * As a side effect, leaves all children of the actor unrealized if
1673  * the actor was realized but not showing.  This is because when we
1674  * unrealize the actor temporarily we must unrealize its children
1675  * (e.g. children of a stage can't be realized if stage window is
1676  * gone). And we aren't clever enough to save the realization state of
1677  * all children. In most cases this should not matter, because
1678  * the children will automatically realize when they next become mapped.
1679  */
1680 void
1681 _clutter_actor_rerealize (ClutterActor    *self,
1682                           ClutterCallback  callback,
1683                           void            *data)
1684 {
1685   gboolean was_mapped;
1686   gboolean was_showing;
1687   gboolean was_realized;
1688
1689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1690
1691 #ifdef CLUTTER_ENABLE_DEBUG
1692   clutter_actor_verify_map_state (self);
1693 #endif
1694
1695   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1696   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1697   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1698
1699   /* Must be unmapped to unrealize. Note we only have to hide this
1700    * actor if it was mapped (if all parents were showing).  If actor
1701    * is merely visible (but not mapped), then that's fine, we can
1702    * leave it visible.
1703    */
1704   if (was_mapped)
1705     clutter_actor_hide (self);
1706
1707   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1708
1709   /* unrealize self and all children */
1710   clutter_actor_unrealize_not_hiding (self);
1711
1712   if (callback != NULL)
1713     {
1714       (* callback) (self, data);
1715     }
1716
1717   if (was_showing)
1718     clutter_actor_show (self); /* will realize only if mapping implies it */
1719   else if (was_realized)
1720     clutter_actor_realize (self); /* realize self and all parents */
1721 }
1722
1723 static void
1724 clutter_actor_real_pick (ClutterActor       *self,
1725                          const ClutterColor *color)
1726 {
1727   /* the default implementation is just to paint a rectangle
1728    * with the same size of the actor using the passed color
1729    */
1730   if (clutter_actor_should_pick_paint (self))
1731     {
1732       ClutterActorBox box = { 0, };
1733       float width, height;
1734
1735       clutter_actor_get_allocation_box (self, &box);
1736
1737       width = box.x2 - box.x1;
1738       height = box.y2 - box.y1;
1739
1740       cogl_set_source_color4ub (color->red,
1741                                 color->green,
1742                                 color->blue,
1743                                 color->alpha);
1744
1745       cogl_rectangle (0, 0, width, height);
1746     }
1747
1748   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1749    * with existing container classes that override the pick() virtual
1750    * and chain up to the default implementation - otherwise we'll end up
1751    * painting our children twice.
1752    *
1753    * this has to go away for 2.0; hopefully along the pick() itself.
1754    */
1755   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1756     {
1757       ClutterActor *iter;
1758
1759       for (iter = self->priv->first_child;
1760            iter != NULL;
1761            iter = iter->priv->next_sibling)
1762         clutter_actor_paint (iter);
1763     }
1764 }
1765
1766 /**
1767  * clutter_actor_should_pick_paint:
1768  * @self: A #ClutterActor
1769  *
1770  * Should be called inside the implementation of the
1771  * #ClutterActor::pick virtual function in order to check whether
1772  * the actor should paint itself in pick mode or not.
1773  *
1774  * This function should never be called directly by applications.
1775  *
1776  * Return value: %TRUE if the actor should paint its silhouette,
1777  *   %FALSE otherwise
1778  */
1779 gboolean
1780 clutter_actor_should_pick_paint (ClutterActor *self)
1781 {
1782   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1783
1784   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1785       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1786        CLUTTER_ACTOR_IS_REACTIVE (self)))
1787     return TRUE;
1788
1789   return FALSE;
1790 }
1791
1792 static void
1793 clutter_actor_real_get_preferred_width (ClutterActor *self,
1794                                         gfloat        for_height,
1795                                         gfloat       *min_width_p,
1796                                         gfloat       *natural_width_p)
1797 {
1798   ClutterActorPrivate *priv = self->priv;
1799
1800   if (priv->n_children != 0 &&
1801       priv->layout_manager != NULL)
1802     {
1803       ClutterContainer *container = CLUTTER_CONTAINER (self);
1804
1805       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1806                     "for the preferred width",
1807                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1808                     priv->layout_manager);
1809
1810       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1811                                                   container,
1812                                                   for_height,
1813                                                   min_width_p,
1814                                                   natural_width_p);
1815
1816       return;
1817     }
1818
1819   /* Default implementation is always 0x0, usually an actor
1820    * using this default is relying on someone to set the
1821    * request manually
1822    */
1823   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1824
1825   if (min_width_p)
1826     *min_width_p = 0;
1827
1828   if (natural_width_p)
1829     *natural_width_p = 0;
1830 }
1831
1832 static void
1833 clutter_actor_real_get_preferred_height (ClutterActor *self,
1834                                          gfloat        for_width,
1835                                          gfloat       *min_height_p,
1836                                          gfloat       *natural_height_p)
1837 {
1838   ClutterActorPrivate *priv = self->priv;
1839
1840   if (priv->n_children != 0 &&
1841       priv->layout_manager != NULL)
1842     {
1843       ClutterContainer *container = CLUTTER_CONTAINER (self);
1844
1845       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1846                     "for the preferred height",
1847                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1848                     priv->layout_manager);
1849
1850       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1851                                                    container,
1852                                                    for_width,
1853                                                    min_height_p,
1854                                                    natural_height_p);
1855
1856       return;
1857     }
1858   /* Default implementation is always 0x0, usually an actor
1859    * using this default is relying on someone to set the
1860    * request manually
1861    */
1862   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1863
1864   if (min_height_p)
1865     *min_height_p = 0;
1866
1867   if (natural_height_p)
1868     *natural_height_p = 0;
1869 }
1870
1871 static void
1872 clutter_actor_store_old_geometry (ClutterActor    *self,
1873                                   ClutterActorBox *box)
1874 {
1875   *box = self->priv->allocation;
1876 }
1877
1878 static inline void
1879 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1880                                           const ClutterActorBox *old)
1881 {
1882   ClutterActorPrivate *priv = self->priv;
1883   GObject *obj = G_OBJECT (self);
1884
1885   g_object_freeze_notify (obj);
1886
1887   /* to avoid excessive requisition or allocation cycles we
1888    * use the cached values.
1889    *
1890    * - if we don't have an allocation we assume that we need
1891    *   to notify anyway
1892    * - if we don't have a width or a height request we notify
1893    *   width and height
1894    * - if we have a valid allocation then we check the old
1895    *   bounding box with the current allocation and we notify
1896    *   the changes
1897    */
1898   if (priv->needs_allocation)
1899     {
1900       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1901       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1904     }
1905   else if (priv->needs_width_request || priv->needs_height_request)
1906     {
1907       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1908       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1909     }
1910   else
1911     {
1912       gfloat xu, yu;
1913       gfloat widthu, heightu;
1914
1915       xu = priv->allocation.x1;
1916       yu = priv->allocation.y1;
1917       widthu = priv->allocation.x2 - priv->allocation.x1;
1918       heightu = priv->allocation.y2 - priv->allocation.y1;
1919
1920       if (xu != old->x1)
1921         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1922
1923       if (yu != old->y1)
1924         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1925
1926       if (widthu != (old->x2 - old->x1))
1927         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1928
1929       if (heightu != (old->y2 - old->y1))
1930         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1931     }
1932
1933   g_object_thaw_notify (obj);
1934 }
1935
1936 /*< private >
1937  * clutter_actor_set_allocation_internal:
1938  * @self: a #ClutterActor
1939  * @box: a #ClutterActorBox
1940  * @flags: allocation flags
1941  *
1942  * Stores the allocation of @self.
1943  *
1944  * This function only performs basic storage and property notification.
1945  *
1946  * This function should be called by clutter_actor_set_allocation()
1947  * and by the default implementation of #ClutterActorClass.allocate().
1948  *
1949  * Return value: %TRUE if the allocation of the #ClutterActor has been
1950  *   changed, and %FALSE otherwise
1951  */
1952 static inline gboolean
1953 clutter_actor_set_allocation_internal (ClutterActor           *self,
1954                                        const ClutterActorBox  *box,
1955                                        ClutterAllocationFlags  flags)
1956 {
1957   ClutterActorPrivate *priv = self->priv;
1958   GObject *obj;
1959   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1960   gboolean flags_changed;
1961   gboolean retval;
1962   ClutterActorBox old_alloc = { 0, };
1963
1964   obj = G_OBJECT (self);
1965
1966   g_object_freeze_notify (obj);
1967
1968   clutter_actor_store_old_geometry (self, &old_alloc);
1969
1970   x1_changed = priv->allocation.x1 != box->x1;
1971   y1_changed = priv->allocation.y1 != box->y1;
1972   x2_changed = priv->allocation.x2 != box->x2;
1973   y2_changed = priv->allocation.y2 != box->y2;
1974
1975   flags_changed = priv->allocation_flags != flags;
1976
1977   priv->allocation = *box;
1978   priv->allocation_flags = flags;
1979
1980   /* allocation is authoritative */
1981   priv->needs_width_request = FALSE;
1982   priv->needs_height_request = FALSE;
1983   priv->needs_allocation = FALSE;
1984
1985   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1986     {
1987       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1988                     _clutter_actor_get_debug_name (self));
1989
1990       priv->transform_valid = FALSE;
1991
1992       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1993
1994       retval = TRUE;
1995     }
1996   else
1997     retval = FALSE;
1998
1999   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2000
2001   g_object_thaw_notify (obj);
2002
2003   return retval;
2004 }
2005
2006 static void clutter_actor_real_allocate (ClutterActor           *self,
2007                                          const ClutterActorBox  *box,
2008                                          ClutterAllocationFlags  flags);
2009
2010 static inline void
2011 clutter_actor_maybe_layout_children (ClutterActor           *self,
2012                                      const ClutterActorBox  *allocation,
2013                                      ClutterAllocationFlags  flags)
2014 {
2015   ClutterActorPrivate *priv = self->priv;
2016
2017   /* this is going to be a bit hard to follow, so let's put an explanation
2018    * here.
2019    *
2020    * we want ClutterActor to have a default layout manager if the actor was
2021    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2022    *
2023    * we also want any subclass of ClutterActor that does not override the
2024    * ::allocate() virtual function to delegate to a layout manager.
2025    *
2026    * finally, we want to allow people subclassing ClutterActor and overriding
2027    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2028    *
2029    * on the other hand, we want existing actor subclasses overriding the
2030    * ::allocate() virtual function and chaining up to the parent's
2031    * implementation to continue working without allocating their children
2032    * twice, or without entering an allocation loop.
2033    *
2034    * for the first two points, we check if the class of the actor is
2035    * overridding the ::allocate() virtual function; if it isn't, then we
2036    * follow through with checking whether we have children and a layout
2037    * manager, and eventually calling clutter_layout_manager_allocate().
2038    *
2039    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2040    * allocation flags that we got passed, and if it is present, we continue
2041    * with the check above.
2042    *
2043    * if neither of these two checks yields a positive result, we just
2044    * assume that the ::allocate() virtual function that resulted in this
2045    * function being called will also allocate the children of the actor.
2046    */
2047
2048   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2049     goto check_layout;
2050
2051   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2052     goto check_layout;
2053
2054   return;
2055
2056 check_layout:
2057   if (priv->n_children != 0 &&
2058       priv->layout_manager != NULL)
2059     {
2060       ClutterContainer *container = CLUTTER_CONTAINER (self);
2061       ClutterAllocationFlags children_flags;
2062       ClutterActorBox children_box;
2063
2064       /* normalize the box passed to the layout manager */
2065       children_box.x1 = children_box.y1 = 0.f;
2066       children_box.x2 = (allocation->x2 - allocation->x1);
2067       children_box.y2 = (allocation->y2 - allocation->y1);
2068
2069       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2070        * the actor's children, since it refers only to the current
2071        * actor's allocation.
2072        */
2073       children_flags = flags;
2074       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2075
2076       CLUTTER_NOTE (LAYOUT,
2077                     "Allocating %d children of %s "
2078                     "at { %.2f, %.2f - %.2f x %.2f } "
2079                     "using %s",
2080                     priv->n_children,
2081                     _clutter_actor_get_debug_name (self),
2082                     allocation->x1,
2083                     allocation->y1,
2084                     (allocation->x2 - allocation->x1),
2085                     (allocation->y2 - allocation->y1),
2086                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2087
2088       clutter_layout_manager_allocate (priv->layout_manager,
2089                                        container,
2090                                        &children_box,
2091                                        children_flags);
2092     }
2093 }
2094
2095 static void
2096 clutter_actor_real_allocate (ClutterActor           *self,
2097                              const ClutterActorBox  *box,
2098                              ClutterAllocationFlags  flags)
2099 {
2100   ClutterActorPrivate *priv = self->priv;
2101   gboolean changed;
2102
2103   g_object_freeze_notify (G_OBJECT (self));
2104
2105   changed = clutter_actor_set_allocation_internal (self, box, flags);
2106
2107   /* we allocate our children before we notify changes in our geometry,
2108    * so that people connecting to properties will be able to get valid
2109    * data out of the sub-tree of the scene graph that has this actor at
2110    * the root.
2111    */
2112   clutter_actor_maybe_layout_children (self, box, flags);
2113
2114   if (changed)
2115     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2116                    &priv->allocation,
2117                    priv->allocation_flags);
2118
2119   g_object_thaw_notify (G_OBJECT (self));
2120 }
2121
2122 static void
2123 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2124                                     ClutterActor *origin)
2125 {
2126   /* no point in queuing a redraw on a destroyed actor */
2127   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2128     return;
2129
2130   /* NB: We can't bail out early here if the actor is hidden in case
2131    * the actor bas been cloned. In this case the clone will need to
2132    * receive the signal so it can queue its own redraw.
2133    */
2134
2135   /* calls klass->queue_redraw in default handler */
2136   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2137 }
2138
2139 static void
2140 clutter_actor_real_queue_redraw (ClutterActor *self,
2141                                  ClutterActor *origin)
2142 {
2143   ClutterActor *parent;
2144
2145   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2146                 _clutter_actor_get_debug_name (self),
2147                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2148                                : "same actor");
2149
2150   /* no point in queuing a redraw on a destroyed actor */
2151   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2152     return;
2153
2154   /* If the queue redraw is coming from a child then the actor has
2155      become dirty and any queued effect is no longer valid */
2156   if (self != origin)
2157     {
2158       self->priv->is_dirty = TRUE;
2159       self->priv->effect_to_redraw = NULL;
2160     }
2161
2162   /* If the actor isn't visible, we still had to emit the signal
2163    * to allow for a ClutterClone, but the appearance of the parent
2164    * won't change so we don't have to propagate up the hierarchy.
2165    */
2166   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2167     return;
2168
2169   /* Although we could determine here that a full stage redraw
2170    * has already been queued and immediately bail out, we actually
2171    * guarantee that we will propagate a queue-redraw signal to our
2172    * parent at least once so that it's possible to implement a
2173    * container that tracks which of its children have queued a
2174    * redraw.
2175    */
2176   if (self->priv->propagated_one_redraw)
2177     {
2178       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2179       if (stage != NULL &&
2180           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2181         return;
2182     }
2183
2184   self->priv->propagated_one_redraw = TRUE;
2185
2186   /* notify parents, if they are all visible eventually we'll
2187    * queue redraw on the stage, which queues the redraw idle.
2188    */
2189   parent = clutter_actor_get_parent (self);
2190   if (parent != NULL)
2191     {
2192       /* this will go up recursively */
2193       _clutter_actor_signal_queue_redraw (parent, origin);
2194     }
2195 }
2196
2197 static void
2198 clutter_actor_real_queue_relayout (ClutterActor *self)
2199 {
2200   ClutterActorPrivate *priv = self->priv;
2201
2202   /* no point in queueing a redraw on a destroyed actor */
2203   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2204     return;
2205
2206   priv->needs_width_request  = TRUE;
2207   priv->needs_height_request = TRUE;
2208   priv->needs_allocation     = TRUE;
2209
2210   /* reset the cached size requests */
2211   memset (priv->width_requests, 0,
2212           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2213   memset (priv->height_requests, 0,
2214           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2215
2216   /* We need to go all the way up the hierarchy */
2217   if (priv->parent != NULL)
2218     _clutter_actor_queue_only_relayout (priv->parent);
2219 }
2220
2221 /**
2222  * clutter_actor_apply_relative_transform_to_point:
2223  * @self: A #ClutterActor
2224  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2225  *   default #ClutterStage
2226  * @point: A point as #ClutterVertex
2227  * @vertex: (out caller-allocates): The translated #ClutterVertex
2228  *
2229  * Transforms @point in coordinates relative to the actor into
2230  * ancestor-relative coordinates using the relevant transform
2231  * stack (i.e. scale, rotation, etc).
2232  *
2233  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2234  * this case, the coordinates returned will be the coordinates on
2235  * the stage before the projection is applied. This is different from
2236  * the behaviour of clutter_actor_apply_transform_to_point().
2237  *
2238  * Since: 0.6
2239  */
2240 void
2241 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2242                                                  ClutterActor        *ancestor,
2243                                                  const ClutterVertex *point,
2244                                                  ClutterVertex       *vertex)
2245 {
2246   gfloat w;
2247   CoglMatrix matrix;
2248
2249   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2250   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2251   g_return_if_fail (point != NULL);
2252   g_return_if_fail (vertex != NULL);
2253
2254   *vertex = *point;
2255   w = 1.0;
2256
2257   if (ancestor == NULL)
2258     ancestor = _clutter_actor_get_stage_internal (self);
2259
2260   if (ancestor == NULL)
2261     {
2262       *vertex = *point;
2263       return;
2264     }
2265
2266   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2267   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2268 }
2269
2270 static gboolean
2271 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2272                                          const ClutterVertex *vertices_in,
2273                                          ClutterVertex *vertices_out,
2274                                          int n_vertices)
2275 {
2276   ClutterActor *stage;
2277   CoglMatrix modelview;
2278   CoglMatrix projection;
2279   float viewport[4];
2280
2281   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2282
2283   stage = _clutter_actor_get_stage_internal (self);
2284
2285   /* We really can't do anything meaningful in this case so don't try
2286    * to do any transform */
2287   if (stage == NULL)
2288     return FALSE;
2289
2290   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2291    * that gets us to stage coordinates, we want to go all the way to eye
2292    * coordinates */
2293   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2294
2295   /* Fetch the projection and viewport */
2296   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2297   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2298                                &viewport[0],
2299                                &viewport[1],
2300                                &viewport[2],
2301                                &viewport[3]);
2302
2303   _clutter_util_fully_transform_vertices (&modelview,
2304                                           &projection,
2305                                           viewport,
2306                                           vertices_in,
2307                                           vertices_out,
2308                                           n_vertices);
2309
2310   return TRUE;
2311 }
2312
2313 /**
2314  * clutter_actor_apply_transform_to_point:
2315  * @self: A #ClutterActor
2316  * @point: A point as #ClutterVertex
2317  * @vertex: (out caller-allocates): The translated #ClutterVertex
2318  *
2319  * Transforms @point in coordinates relative to the actor
2320  * into screen-relative coordinates with the current actor
2321  * transformation (i.e. scale, rotation, etc)
2322  *
2323  * Since: 0.4
2324  **/
2325 void
2326 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2327                                         const ClutterVertex *point,
2328                                         ClutterVertex       *vertex)
2329 {
2330   g_return_if_fail (point != NULL);
2331   g_return_if_fail (vertex != NULL);
2332   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2333 }
2334
2335 /*
2336  * _clutter_actor_get_relative_transformation_matrix:
2337  * @self: The actor whose coordinate space you want to transform from.
2338  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2339  *            or %NULL if you want to transform all the way to eye coordinates.
2340  * @matrix: A #CoglMatrix to store the transformation
2341  *
2342  * This gets a transformation @matrix that will transform coordinates from the
2343  * coordinate space of @self into the coordinate space of @ancestor.
2344  *
2345  * For example if you need a matrix that can transform the local actor
2346  * coordinates of @self into stage coordinates you would pass the actor's stage
2347  * pointer as the @ancestor.
2348  *
2349  * If you pass %NULL then the transformation will take you all the way through
2350  * to eye coordinates. This can be useful if you want to extract the entire
2351  * modelview transform that Clutter applies before applying the projection
2352  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2353  * using cogl_set_modelview_matrix() for example then you would want a matrix
2354  * that transforms into eye coordinates.
2355  *
2356  * <note><para>This function explicitly initializes the given @matrix. If you just
2357  * want clutter to multiply a relative transformation with an existing matrix
2358  * you can use clutter_actor_apply_relative_transformation_matrix()
2359  * instead.</para></note>
2360  *
2361  */
2362 /* XXX: We should consider caching the stage relative modelview along with
2363  * the actor itself */
2364 static void
2365 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2366                                                    ClutterActor *ancestor,
2367                                                    CoglMatrix *matrix)
2368 {
2369   cogl_matrix_init_identity (matrix);
2370
2371   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2372 }
2373
2374 /* Project the given @box into stage window coordinates, writing the
2375  * transformed vertices to @verts[]. */
2376 static gboolean
2377 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2378                                           const ClutterActorBox *box,
2379                                           ClutterVertex          verts[])
2380 {
2381   ClutterVertex box_vertices[4];
2382
2383   box_vertices[0].x = box->x1;
2384   box_vertices[0].y = box->y1;
2385   box_vertices[0].z = 0;
2386   box_vertices[1].x = box->x2;
2387   box_vertices[1].y = box->y1;
2388   box_vertices[1].z = 0;
2389   box_vertices[2].x = box->x1;
2390   box_vertices[2].y = box->y2;
2391   box_vertices[2].z = 0;
2392   box_vertices[3].x = box->x2;
2393   box_vertices[3].y = box->y2;
2394   box_vertices[3].z = 0;
2395
2396   return
2397     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2398 }
2399
2400 /**
2401  * clutter_actor_get_allocation_vertices:
2402  * @self: A #ClutterActor
2403  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2404  *   against, or %NULL to use the #ClutterStage
2405  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2406  *   location for an array of 4 #ClutterVertex in which to store the result
2407  *
2408  * Calculates the transformed coordinates of the four corners of the
2409  * actor in the plane of @ancestor. The returned vertices relate to
2410  * the #ClutterActorBox coordinates as follows:
2411  * <itemizedlist>
2412  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2413  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2414  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2415  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2416  * </itemizedlist>
2417  *
2418  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2419  * this case, the coordinates returned will be the coordinates on
2420  * the stage before the projection is applied. This is different from
2421  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2422  *
2423  * Since: 0.6
2424  */
2425 void
2426 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2427                                        ClutterActor  *ancestor,
2428                                        ClutterVertex  verts[])
2429 {
2430   ClutterActorPrivate *priv;
2431   ClutterActorBox box;
2432   ClutterVertex vertices[4];
2433   CoglMatrix modelview;
2434
2435   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2436   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2437
2438   if (ancestor == NULL)
2439     ancestor = _clutter_actor_get_stage_internal (self);
2440
2441   /* Fallback to a NOP transform if the actor isn't parented under a
2442    * stage. */
2443   if (ancestor == NULL)
2444     ancestor = self;
2445
2446   priv = self->priv;
2447
2448   /* if the actor needs to be allocated we force a relayout, so that
2449    * we will have valid values to use in the transformations */
2450   if (priv->needs_allocation)
2451     {
2452       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2453       if (stage)
2454         _clutter_stage_maybe_relayout (stage);
2455       else
2456         {
2457           box.x1 = box.y1 = 0;
2458           /* The result isn't really meaningful in this case but at
2459            * least try to do something *vaguely* reasonable... */
2460           clutter_actor_get_size (self, &box.x2, &box.y2);
2461         }
2462     }
2463
2464   clutter_actor_get_allocation_box (self, &box);
2465
2466   vertices[0].x = box.x1;
2467   vertices[0].y = box.y1;
2468   vertices[0].z = 0;
2469   vertices[1].x = box.x2;
2470   vertices[1].y = box.y1;
2471   vertices[1].z = 0;
2472   vertices[2].x = box.x1;
2473   vertices[2].y = box.y2;
2474   vertices[2].z = 0;
2475   vertices[3].x = box.x2;
2476   vertices[3].y = box.y2;
2477   vertices[3].z = 0;
2478
2479   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2480                                                      &modelview);
2481
2482   cogl_matrix_transform_points (&modelview,
2483                                 3,
2484                                 sizeof (ClutterVertex),
2485                                 vertices,
2486                                 sizeof (ClutterVertex),
2487                                 vertices,
2488                                 4);
2489 }
2490
2491 /**
2492  * clutter_actor_get_abs_allocation_vertices:
2493  * @self: A #ClutterActor
2494  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2495  *   of 4 #ClutterVertex where to store the result.
2496  *
2497  * Calculates the transformed screen coordinates of the four corners of
2498  * the actor; the returned vertices relate to the #ClutterActorBox
2499  * coordinates  as follows:
2500  * <itemizedlist>
2501  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2502  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2503  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2504  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2505  * </itemizedlist>
2506  *
2507  * Since: 0.4
2508  */
2509 void
2510 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2511                                            ClutterVertex  verts[])
2512 {
2513   ClutterActorPrivate *priv;
2514   ClutterActorBox actor_space_allocation;
2515
2516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2517
2518   priv = self->priv;
2519
2520   /* if the actor needs to be allocated we force a relayout, so that
2521    * the actor allocation box will be valid for
2522    * _clutter_actor_transform_and_project_box()
2523    */
2524   if (priv->needs_allocation)
2525     {
2526       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2527       /* There's nothing meaningful we can do now */
2528       if (!stage)
2529         return;
2530
2531       _clutter_stage_maybe_relayout (stage);
2532     }
2533
2534   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2535    * own coordinate space... */
2536   actor_space_allocation.x1 = 0;
2537   actor_space_allocation.y1 = 0;
2538   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2539   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2540   _clutter_actor_transform_and_project_box (self,
2541                                             &actor_space_allocation,
2542                                             verts);
2543 }
2544
2545 static void
2546 clutter_actor_real_apply_transform (ClutterActor *self,
2547                                     CoglMatrix   *matrix)
2548 {
2549   ClutterActorPrivate *priv = self->priv;
2550
2551   if (!priv->transform_valid)
2552     {
2553       CoglMatrix *transform = &priv->transform;
2554       const ClutterTransformInfo *info;
2555
2556       info = _clutter_actor_get_transform_info_or_defaults (self);
2557
2558       cogl_matrix_init_identity (transform);
2559
2560       cogl_matrix_translate (transform,
2561                              priv->allocation.x1,
2562                              priv->allocation.y1,
2563                              0.0);
2564
2565       if (priv->z)
2566         cogl_matrix_translate (transform, 0, 0, priv->z);
2567
2568       /*
2569        * because the rotation involves translations, we must scale
2570        * before applying the rotations (if we apply the scale after
2571        * the rotations, the translations included in the rotation are
2572        * not scaled and so the entire object will move on the screen
2573        * as a result of rotating it).
2574        */
2575       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2576         {
2577           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2578                                         &info->scale_center,
2579                                         cogl_matrix_scale (transform,
2580                                                            info->scale_x,
2581                                                            info->scale_y,
2582                                                            1.0));
2583         }
2584
2585       if (info->rz_angle)
2586         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2587                                       &info->rz_center,
2588                                       cogl_matrix_rotate (transform,
2589                                                           info->rz_angle,
2590                                                           0, 0, 1.0));
2591
2592       if (info->ry_angle)
2593         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2594                                       &info->ry_center,
2595                                       cogl_matrix_rotate (transform,
2596                                                           info->ry_angle,
2597                                                           0, 1.0, 0));
2598
2599       if (info->rx_angle)
2600         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2601                                       &info->rx_center,
2602                                       cogl_matrix_rotate (transform,
2603                                                           info->rx_angle,
2604                                                           1.0, 0, 0));
2605
2606       if (!clutter_anchor_coord_is_zero (&info->anchor))
2607         {
2608           gfloat x, y, z;
2609
2610           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2611           cogl_matrix_translate (transform, -x, -y, -z);
2612         }
2613
2614       priv->transform_valid = TRUE;
2615     }
2616
2617   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2618 }
2619
2620 /* Applies the transforms associated with this actor to the given
2621  * matrix. */
2622 void
2623 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2624                                           CoglMatrix *matrix)
2625 {
2626   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2627 }
2628
2629 /*
2630  * clutter_actor_apply_relative_transformation_matrix:
2631  * @self: The actor whose coordinate space you want to transform from.
2632  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2633  *            or %NULL if you want to transform all the way to eye coordinates.
2634  * @matrix: A #CoglMatrix to apply the transformation too.
2635  *
2636  * This multiplies a transform with @matrix that will transform coordinates
2637  * from the coordinate space of @self into the coordinate space of @ancestor.
2638  *
2639  * For example if you need a matrix that can transform the local actor
2640  * coordinates of @self into stage coordinates you would pass the actor's stage
2641  * pointer as the @ancestor.
2642  *
2643  * If you pass %NULL then the transformation will take you all the way through
2644  * to eye coordinates. This can be useful if you want to extract the entire
2645  * modelview transform that Clutter applies before applying the projection
2646  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2647  * using cogl_set_modelview_matrix() for example then you would want a matrix
2648  * that transforms into eye coordinates.
2649  *
2650  * <note>This function doesn't initialize the given @matrix, it simply
2651  * multiplies the requested transformation matrix with the existing contents of
2652  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2653  * before calling this function, or you can use
2654  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2655  */
2656 void
2657 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2658                                                      ClutterActor *ancestor,
2659                                                      CoglMatrix *matrix)
2660 {
2661   ClutterActor *parent;
2662
2663   /* Note we terminate before ever calling stage->apply_transform()
2664    * since that would conceptually be relative to the underlying
2665    * window OpenGL coordinates so we'd need a special @ancestor
2666    * value to represent the fake parent of the stage. */
2667   if (self == ancestor)
2668     return;
2669
2670   parent = clutter_actor_get_parent (self);
2671
2672   if (parent != NULL)
2673     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2674                                                          matrix);
2675
2676   _clutter_actor_apply_modelview_transform (self, matrix);
2677 }
2678
2679 static void
2680 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2681                                        ClutterPaintVolume *pv,
2682                                        const char *label,
2683                                        const CoglColor *color)
2684 {
2685   static CoglPipeline *outline = NULL;
2686   CoglPrimitive *prim;
2687   ClutterVertex line_ends[12 * 2];
2688   int n_vertices;
2689   CoglContext *ctx =
2690     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2691   /* XXX: at some point we'll query this from the stage but we can't
2692    * do that until the osx backend uses Cogl natively. */
2693   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2694
2695   if (outline == NULL)
2696     outline = cogl_pipeline_new ();
2697
2698   _clutter_paint_volume_complete (pv);
2699
2700   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2701
2702   /* Front face */
2703   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2704   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2705   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2706   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2707
2708   if (!pv->is_2d)
2709     {
2710       /* Back face */
2711       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2712       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2713       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2714       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2715
2716       /* Lines connecting front face to back face */
2717       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2718       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2719       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2720       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2721     }
2722
2723   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES, n_vertices,
2724                                 (CoglVertexP3 *)line_ends);
2725
2726   cogl_pipeline_set_color (outline, color);
2727   cogl_framebuffer_draw_primitive (fb, outline, prim);
2728   cogl_object_unref (prim);
2729
2730   if (label)
2731     {
2732       PangoLayout *layout;
2733       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2734       pango_layout_set_text (layout, label, -1);
2735       cogl_pango_render_layout (layout,
2736                                 pv->vertices[0].x,
2737                                 pv->vertices[0].y,
2738                                 color,
2739                                 0);
2740       g_object_unref (layout);
2741     }
2742 }
2743
2744 static void
2745 _clutter_actor_draw_paint_volume (ClutterActor *self)
2746 {
2747   ClutterPaintVolume *pv;
2748   CoglColor color;
2749
2750   pv = _clutter_actor_get_paint_volume_mutable (self);
2751   if (!pv)
2752     {
2753       gfloat width, height;
2754       ClutterPaintVolume fake_pv;
2755
2756       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2757       _clutter_paint_volume_init_static (&fake_pv, stage);
2758
2759       clutter_actor_get_size (self, &width, &height);
2760       clutter_paint_volume_set_width (&fake_pv, width);
2761       clutter_paint_volume_set_height (&fake_pv, height);
2762
2763       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2764       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2765                                              _clutter_actor_get_debug_name (self),
2766                                              &color);
2767
2768       clutter_paint_volume_free (&fake_pv);
2769     }
2770   else
2771     {
2772       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2773       _clutter_actor_draw_paint_volume_full (self, pv,
2774                                              _clutter_actor_get_debug_name (self),
2775                                              &color);
2776     }
2777 }
2778
2779 static void
2780 _clutter_actor_paint_cull_result (ClutterActor *self,
2781                                   gboolean success,
2782                                   ClutterCullResult result)
2783 {
2784   ClutterPaintVolume *pv;
2785   CoglColor color;
2786
2787   if (success)
2788     {
2789       if (result == CLUTTER_CULL_RESULT_IN)
2790         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2791       else if (result == CLUTTER_CULL_RESULT_OUT)
2792         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2793       else
2794         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2795     }
2796   else
2797     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2798
2799   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2800     _clutter_actor_draw_paint_volume_full (self, pv,
2801                                            _clutter_actor_get_debug_name (self),
2802                                            &color);
2803   else
2804     {
2805       PangoLayout *layout;
2806       char *label =
2807         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2808       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2809       cogl_set_source_color (&color);
2810
2811       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2812       pango_layout_set_text (layout, label, -1);
2813       cogl_pango_render_layout (layout,
2814                                 0,
2815                                 0,
2816                                 &color,
2817                                 0);
2818       g_free (label);
2819       g_object_unref (layout);
2820     }
2821 }
2822
2823 static int clone_paint_level = 0;
2824
2825 void
2826 _clutter_actor_push_clone_paint (void)
2827 {
2828   clone_paint_level++;
2829 }
2830
2831 void
2832 _clutter_actor_pop_clone_paint (void)
2833 {
2834   clone_paint_level--;
2835 }
2836
2837 static gboolean
2838 in_clone_paint (void)
2839 {
2840   return clone_paint_level > 0;
2841 }
2842
2843 /* Returns TRUE if the actor can be ignored */
2844 /* FIXME: we should return a ClutterCullResult, and
2845  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2846  * means there's no point in trying to cull descendants of the current
2847  * node. */
2848 static gboolean
2849 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2850 {
2851   ClutterActorPrivate *priv = self->priv;
2852   ClutterActor *stage;
2853   const ClutterPlane *stage_clip;
2854
2855   if (!priv->last_paint_volume_valid)
2856     {
2857       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2858                     "->last_paint_volume_valid == FALSE",
2859                     _clutter_actor_get_debug_name (self));
2860       return FALSE;
2861     }
2862
2863   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2864     return FALSE;
2865
2866   stage = _clutter_actor_get_stage_internal (self);
2867   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2868   if (G_UNLIKELY (!stage_clip))
2869     {
2870       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2871                     "No stage clip set",
2872                     _clutter_actor_get_debug_name (self));
2873       return FALSE;
2874     }
2875
2876   if (cogl_get_draw_framebuffer () !=
2877       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2878     {
2879       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2880                     "Current framebuffer doesn't correspond to stage",
2881                     _clutter_actor_get_debug_name (self));
2882       return FALSE;
2883     }
2884
2885   *result_out =
2886     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2887   return TRUE;
2888 }
2889
2890 static void
2891 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2892 {
2893   ClutterActorPrivate *priv = self->priv;
2894   const ClutterPaintVolume *pv;
2895
2896   if (priv->last_paint_volume_valid)
2897     {
2898       clutter_paint_volume_free (&priv->last_paint_volume);
2899       priv->last_paint_volume_valid = FALSE;
2900     }
2901
2902   pv = clutter_actor_get_paint_volume (self);
2903   if (!pv)
2904     {
2905       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2906                     "Actor failed to report a paint volume",
2907                     _clutter_actor_get_debug_name (self));
2908       return;
2909     }
2910
2911   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2912
2913   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2914                                             NULL); /* eye coordinates */
2915
2916   priv->last_paint_volume_valid = TRUE;
2917 }
2918
2919 static inline gboolean
2920 actor_has_shader_data (ClutterActor *self)
2921 {
2922   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2923 }
2924
2925 guint32
2926 _clutter_actor_get_pick_id (ClutterActor *self)
2927 {
2928   if (self->priv->pick_id < 0)
2929     return 0;
2930
2931   return self->priv->pick_id;
2932 }
2933
2934 /* This is the same as clutter_actor_add_effect except that it doesn't
2935    queue a redraw and it doesn't notify on the effect property */
2936 static void
2937 _clutter_actor_add_effect_internal (ClutterActor  *self,
2938                                     ClutterEffect *effect)
2939 {
2940   ClutterActorPrivate *priv = self->priv;
2941
2942   if (priv->effects == NULL)
2943     {
2944       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2945       priv->effects->actor = self;
2946     }
2947
2948   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2949 }
2950
2951 /* This is the same as clutter_actor_remove_effect except that it doesn't
2952    queue a redraw and it doesn't notify on the effect property */
2953 static void
2954 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2955                                        ClutterEffect *effect)
2956 {
2957   ClutterActorPrivate *priv = self->priv;
2958
2959   if (priv->effects == NULL)
2960     return;
2961
2962   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2963 }
2964
2965 static gboolean
2966 needs_flatten_effect (ClutterActor *self)
2967 {
2968   ClutterActorPrivate *priv = self->priv;
2969
2970   if (G_UNLIKELY (clutter_paint_debug_flags &
2971                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2972     return FALSE;
2973
2974   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2975     return TRUE;
2976   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2977     {
2978       if (clutter_actor_get_paint_opacity (self) < 255 &&
2979           clutter_actor_has_overlaps (self))
2980         return TRUE;
2981     }
2982
2983   return FALSE;
2984 }
2985
2986 static void
2987 add_or_remove_flatten_effect (ClutterActor *self)
2988 {
2989   ClutterActorPrivate *priv = self->priv;
2990
2991   /* Add or remove the flatten effect depending on the
2992      offscreen-redirect property. */
2993   if (needs_flatten_effect (self))
2994     {
2995       if (priv->flatten_effect == NULL)
2996         {
2997           ClutterActorMeta *actor_meta;
2998           gint priority;
2999
3000           priv->flatten_effect = _clutter_flatten_effect_new ();
3001           /* Keep a reference to the effect so that we can queue
3002              redraws from it */
3003           g_object_ref_sink (priv->flatten_effect);
3004
3005           /* Set the priority of the effect to high so that it will
3006              always be applied to the actor first. It uses an internal
3007              priority so that it won't be visible to applications */
3008           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3009           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3010           _clutter_actor_meta_set_priority (actor_meta, priority);
3011
3012           /* This will add the effect without queueing a redraw */
3013           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3014         }
3015     }
3016   else
3017     {
3018       if (priv->flatten_effect != NULL)
3019         {
3020           /* Destroy the effect so that it will lose its fbo cache of
3021              the actor */
3022           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3023           g_object_unref (priv->flatten_effect);
3024           priv->flatten_effect = NULL;
3025         }
3026     }
3027 }
3028
3029 static void
3030 clutter_actor_real_paint (ClutterActor *actor)
3031 {
3032   ClutterActorPrivate *priv = actor->priv;
3033   ClutterActor *iter;
3034
3035   /* paint the background color, if set */
3036   if (priv->bg_color_set)
3037     {
3038       float width, height;
3039       guint8 real_alpha;
3040
3041       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3042
3043       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3044                  * priv->bg_color.alpha
3045                  / 255;
3046
3047       cogl_set_source_color4ub (priv->bg_color.red,
3048                                 priv->bg_color.green,
3049                                 priv->bg_color.blue,
3050                                 real_alpha);
3051
3052       cogl_rectangle (0, 0, width, height);
3053     }
3054
3055   for (iter = priv->first_child;
3056        iter != NULL;
3057        iter = iter->priv->next_sibling)
3058     {
3059       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3060                     _clutter_actor_get_debug_name (iter),
3061                     _clutter_actor_get_debug_name (actor),
3062                     iter->priv->allocation.x1,
3063                     iter->priv->allocation.y1,
3064                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3065                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3066
3067       clutter_actor_paint (iter);
3068     }
3069 }
3070
3071 /**
3072  * clutter_actor_paint:
3073  * @self: A #ClutterActor
3074  *
3075  * Renders the actor to display.
3076  *
3077  * This function should not be called directly by applications.
3078  * Call clutter_actor_queue_redraw() to queue paints, instead.
3079  *
3080  * This function is context-aware, and will either cause a
3081  * regular paint or a pick paint.
3082  *
3083  * This function will emit the #ClutterActor::paint signal or
3084  * the #ClutterActor::pick signal, depending on the context.
3085  *
3086  * This function does not paint the actor if the actor is set to 0,
3087  * unless it is performing a pick paint.
3088  */
3089 void
3090 clutter_actor_paint (ClutterActor *self)
3091 {
3092   ClutterActorPrivate *priv;
3093   ClutterPickMode pick_mode;
3094   gboolean clip_set = FALSE;
3095   gboolean shader_applied = FALSE;
3096
3097   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3098                           "Actor real-paint counter",
3099                           "Increments each time any actor is painted",
3100                           0 /* no application private data */);
3101   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3102                           "Actor pick-paint counter",
3103                           "Increments each time any actor is painted "
3104                           "for picking",
3105                           0 /* no application private data */);
3106
3107   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3108
3109   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3110     return;
3111
3112   priv = self->priv;
3113
3114   pick_mode = _clutter_context_get_pick_mode ();
3115
3116   if (pick_mode == CLUTTER_PICK_NONE)
3117     priv->propagated_one_redraw = FALSE;
3118
3119   /* It's an important optimization that we consider painting of
3120    * actors with 0 opacity to be a NOP... */
3121   if (pick_mode == CLUTTER_PICK_NONE &&
3122       /* ignore top-levels, since they might be transparent */
3123       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3124       /* Use the override opacity if its been set */
3125       ((priv->opacity_override >= 0) ?
3126        priv->opacity_override : priv->opacity) == 0)
3127     return;
3128
3129   /* if we aren't paintable (not in a toplevel with all
3130    * parents paintable) then do nothing.
3131    */
3132   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3133     return;
3134
3135   /* mark that we are in the paint process */
3136   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3137
3138   cogl_push_matrix();
3139
3140   if (priv->enable_model_view_transform)
3141     {
3142       CoglMatrix matrix;
3143
3144       /* XXX: It could be better to cache the modelview with the actor
3145        * instead of progressively building up the transformations on
3146        * the matrix stack every time we paint. */
3147       cogl_get_modelview_matrix (&matrix);
3148       _clutter_actor_apply_modelview_transform (self, &matrix);
3149
3150 #ifdef CLUTTER_ENABLE_DEBUG
3151       /* Catch when out-of-band transforms have been made by actors not as part
3152        * of an apply_transform vfunc... */
3153       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3154         {
3155           CoglMatrix expected_matrix;
3156
3157           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3158                                                              &expected_matrix);
3159
3160           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3161             {
3162               GString *buf = g_string_sized_new (1024);
3163               ClutterActor *parent;
3164
3165               parent = self;
3166               while (parent != NULL)
3167                 {
3168                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3169
3170                   if (parent->priv->parent != NULL)
3171                     g_string_append (buf, "->");
3172
3173                   parent = parent->priv->parent;
3174                 }
3175
3176               g_warning ("Unexpected transform found when painting actor "
3177                          "\"%s\". This will be caused by one of the actor's "
3178                          "ancestors (%s) using the Cogl API directly to transform "
3179                          "children instead of using ::apply_transform().",
3180                          _clutter_actor_get_debug_name (self),
3181                          buf->str);
3182
3183               g_string_free (buf, TRUE);
3184             }
3185         }
3186 #endif /* CLUTTER_ENABLE_DEBUG */
3187
3188       cogl_set_modelview_matrix (&matrix);
3189     }
3190
3191   if (priv->has_clip)
3192     {
3193       cogl_clip_push_rectangle (priv->clip.x,
3194                                 priv->clip.y,
3195                                 priv->clip.x + priv->clip.width,
3196                                 priv->clip.y + priv->clip.height);
3197       clip_set = TRUE;
3198     }
3199   else if (priv->clip_to_allocation)
3200     {
3201       gfloat width, height;
3202
3203       width  = priv->allocation.x2 - priv->allocation.x1;
3204       height = priv->allocation.y2 - priv->allocation.y1;
3205
3206       cogl_clip_push_rectangle (0, 0, width, height);
3207       clip_set = TRUE;
3208     }
3209
3210   if (pick_mode == CLUTTER_PICK_NONE)
3211     {
3212       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3213
3214       /* We check whether we need to add the flatten effect before
3215          each paint so that we can avoid having a mechanism for
3216          applications to notify when the value of the
3217          has_overlaps virtual changes. */
3218       add_or_remove_flatten_effect (self);
3219     }
3220   else
3221     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3222
3223   /* We save the current paint volume so that the next time the
3224    * actor queues a redraw we can constrain the redraw to just
3225    * cover the union of the new bounding box and the old.
3226    *
3227    * We also fetch the current paint volume to perform culling so
3228    * we can avoid painting actors outside the current clip region.
3229    *
3230    * If we are painting inside a clone, we should neither update
3231    * the paint volume or use it to cull painting, since the paint
3232    * box represents the location of the source actor on the
3233    * screen.
3234    *
3235    * XXX: We are starting to do a lot of vertex transforms on
3236    * the CPU in a typical paint, so at some point we should
3237    * audit these and consider caching some things.
3238    *
3239    * NB: We don't perform culling while picking at this point because
3240    * clutter-stage.c doesn't setup the clipping planes appropriately.
3241    *
3242    * NB: We don't want to update the last-paint-volume during picking
3243    * because the last-paint-volume is used to determine the old screen
3244    * space location of an actor that has moved so we can know the
3245    * minimal region to redraw to clear an old view of the actor. If we
3246    * update this during picking then by the time we come around to
3247    * paint then the last-paint-volume would likely represent the new
3248    * actor position not the old.
3249    */
3250   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3251     {
3252       gboolean success;
3253       /* annoyingly gcc warns if uninitialized even though
3254        * the initialization is redundant :-( */
3255       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3256
3257       if (G_LIKELY ((clutter_paint_debug_flags &
3258                      (CLUTTER_DEBUG_DISABLE_CULLING |
3259                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3260                     (CLUTTER_DEBUG_DISABLE_CULLING |
3261                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3262         _clutter_actor_update_last_paint_volume (self);
3263
3264       success = cull_actor (self, &result);
3265
3266       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3267         _clutter_actor_paint_cull_result (self, success, result);
3268       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3269         goto done;
3270     }
3271
3272   if (priv->effects == NULL)
3273     {
3274       if (pick_mode == CLUTTER_PICK_NONE &&
3275           actor_has_shader_data (self))
3276         {
3277           _clutter_actor_shader_pre_paint (self, FALSE);
3278           shader_applied = TRUE;
3279         }
3280
3281       priv->next_effect_to_paint = NULL;
3282     }
3283   else
3284     priv->next_effect_to_paint =
3285       _clutter_meta_group_peek_metas (priv->effects);
3286
3287   clutter_actor_continue_paint (self);
3288
3289   if (shader_applied)
3290     _clutter_actor_shader_post_paint (self);
3291
3292   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3293                   pick_mode == CLUTTER_PICK_NONE))
3294     _clutter_actor_draw_paint_volume (self);
3295
3296 done:
3297   /* If we make it here then the actor has run through a complete
3298      paint run including all the effects so it's no longer dirty */
3299   if (pick_mode == CLUTTER_PICK_NONE)
3300     priv->is_dirty = FALSE;
3301
3302   if (clip_set)
3303     cogl_clip_pop();
3304
3305   cogl_pop_matrix();
3306
3307   /* paint sequence complete */
3308   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3309 }
3310
3311 /**
3312  * clutter_actor_continue_paint:
3313  * @self: A #ClutterActor
3314  *
3315  * Run the next stage of the paint sequence. This function should only
3316  * be called within the implementation of the ‘run’ virtual of a
3317  * #ClutterEffect. It will cause the run method of the next effect to
3318  * be applied, or it will paint the actual actor if the current effect
3319  * is the last effect in the chain.
3320  *
3321  * Since: 1.8
3322  */
3323 void
3324 clutter_actor_continue_paint (ClutterActor *self)
3325 {
3326   ClutterActorPrivate *priv;
3327
3328   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3329   /* This should only be called from with in the ‘run’ implementation
3330      of a ClutterEffect */
3331   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3332
3333   priv = self->priv;
3334
3335   /* Skip any effects that are disabled */
3336   while (priv->next_effect_to_paint &&
3337          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3338     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3339
3340   /* If this has come from the last effect then we'll just paint the
3341      actual actor */
3342   if (priv->next_effect_to_paint == NULL)
3343     {
3344       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3345         {
3346           g_signal_emit (self, actor_signals[PAINT], 0);
3347         }
3348       else
3349         {
3350           ClutterColor col = { 0, };
3351
3352           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3353
3354           /* Actor will then paint silhouette of itself in supplied
3355            * color.  See clutter_stage_get_actor_at_pos() for where
3356            * picking is enabled.
3357            */
3358           g_signal_emit (self, actor_signals[PICK], 0, &col);
3359         }
3360     }
3361   else
3362     {
3363       ClutterEffect *old_current_effect;
3364       ClutterEffectPaintFlags run_flags = 0;
3365
3366       /* Cache the current effect so that we can put it back before
3367          returning */
3368       old_current_effect = priv->current_effect;
3369
3370       priv->current_effect = priv->next_effect_to_paint->data;
3371       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3372
3373       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3374         {
3375           if (priv->is_dirty)
3376             {
3377               /* If there's an effect queued with this redraw then all
3378                  effects up to that one will be considered dirty. It
3379                  is expected the queued effect will paint the cached
3380                  image and not call clutter_actor_continue_paint again
3381                  (although it should work ok if it does) */
3382               if (priv->effect_to_redraw == NULL ||
3383                   priv->current_effect != priv->effect_to_redraw)
3384                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3385             }
3386
3387           _clutter_effect_paint (priv->current_effect, run_flags);
3388         }
3389       else
3390         {
3391           /* We can't determine when an actor has been modified since
3392              its last pick so lets just assume it has always been
3393              modified */
3394           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3395
3396           _clutter_effect_pick (priv->current_effect, run_flags);
3397         }
3398
3399       priv->current_effect = old_current_effect;
3400     }
3401 }
3402
3403 static ClutterActorTraverseVisitFlags
3404 invalidate_queue_redraw_entry (ClutterActor *self,
3405                                int           depth,
3406                                gpointer      user_data)
3407 {
3408   ClutterActorPrivate *priv = self->priv;
3409
3410   if (priv->queue_redraw_entry != NULL)
3411     {
3412       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3413       priv->queue_redraw_entry = NULL;
3414     }
3415
3416   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3417 }
3418
3419 static inline void
3420 remove_child (ClutterActor *self,
3421               ClutterActor *child)
3422 {
3423   ClutterActor *prev_sibling, *next_sibling;
3424
3425   prev_sibling = child->priv->prev_sibling;
3426   next_sibling = child->priv->next_sibling;
3427
3428   if (prev_sibling != NULL)
3429     prev_sibling->priv->next_sibling = next_sibling;
3430
3431   if (next_sibling != NULL)
3432     next_sibling->priv->prev_sibling = prev_sibling;
3433
3434   if (self->priv->first_child == child)
3435     self->priv->first_child = next_sibling;
3436
3437   if (self->priv->last_child == child)
3438     self->priv->last_child = prev_sibling;
3439
3440   child->priv->parent = NULL;
3441   child->priv->prev_sibling = NULL;
3442   child->priv->next_sibling = NULL;
3443 }
3444
3445 typedef enum {
3446   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3447   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3448   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3449   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3450   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3451   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3452
3453   /* default flags for public API */
3454   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3455                                     REMOVE_CHILD_EMIT_PARENT_SET |
3456                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3457                                     REMOVE_CHILD_CHECK_STATE |
3458                                     REMOVE_CHILD_FLUSH_QUEUE |
3459                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3460
3461   /* flags for legacy/deprecated API */
3462   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3463                                     REMOVE_CHILD_FLUSH_QUEUE |
3464                                     REMOVE_CHILD_EMIT_PARENT_SET |
3465                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3466 } ClutterActorRemoveChildFlags;
3467
3468 /*< private >
3469  * clutter_actor_remove_child_internal:
3470  * @self: a #ClutterActor
3471  * @child: the child of @self that has to be removed
3472  * @flags: control the removal operations
3473  *
3474  * Removes @child from the list of children of @self.
3475  */
3476 static void
3477 clutter_actor_remove_child_internal (ClutterActor                 *self,
3478                                      ClutterActor                 *child,
3479                                      ClutterActorRemoveChildFlags  flags)
3480 {
3481   ClutterActor *old_first, *old_last;
3482   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3483   gboolean flush_queue;
3484   gboolean notify_first_last;
3485   gboolean was_mapped;
3486
3487   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3488   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3489   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3490   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3491   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3492   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3493
3494   if (destroy_meta)
3495     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3496
3497   if (check_state)
3498     {
3499       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3500
3501       /* we need to unrealize *before* we set parent_actor to NULL,
3502        * because in an unrealize method actors are dissociating from the
3503        * stage, which means they need to be able to
3504        * clutter_actor_get_stage().
3505        *
3506        * yhis should unmap and unrealize, unless we're reparenting.
3507        */
3508       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3509     }
3510   else
3511     was_mapped = FALSE;
3512
3513   if (flush_queue)
3514     {
3515       /* We take this opportunity to invalidate any queue redraw entry
3516        * associated with the actor and descendants since we won't be able to
3517        * determine the appropriate stage after this.
3518        *
3519        * we do this after we updated the mapped state because actors might
3520        * end up queueing redraws inside their mapped/unmapped virtual
3521        * functions, and if we invalidate the redraw entry we could end up
3522        * with an inconsistent state and weird memory corruption. see
3523        * bugs:
3524        *
3525        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3526        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3527        */
3528       _clutter_actor_traverse (child,
3529                                0,
3530                                invalidate_queue_redraw_entry,
3531                                NULL,
3532                                NULL);
3533     }
3534
3535   old_first = self->priv->first_child;
3536   old_last = self->priv->last_child;
3537
3538   remove_child (self, child);
3539
3540   self->priv->n_children -= 1;
3541
3542   self->priv->age += 1;
3543
3544   /* clutter_actor_reparent() will emit ::parent-set for us */
3545   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3546     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3547
3548   /* if the child was mapped then we need to relayout ourselves to account
3549    * for the removed child
3550    */
3551   if (was_mapped)
3552     clutter_actor_queue_relayout (self);
3553
3554   /* we need to emit the signal before dropping the reference */
3555   if (emit_actor_removed)
3556     g_signal_emit_by_name (self, "actor-removed", child);
3557
3558   if (notify_first_last)
3559     {
3560       if (old_first != self->priv->first_child)
3561         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3562
3563       if (old_last != self->priv->last_child)
3564         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3565     }
3566
3567   /* remove the reference we acquired in clutter_actor_add_child() */
3568   g_object_unref (child);
3569 }
3570
3571 static const ClutterTransformInfo default_transform_info = {
3572   0.0, { 0, },          /* rotation-x */
3573   0.0, { 0, },          /* rotation-y */
3574   0.0, { 0, },          /* rotation-z */
3575
3576   1.0, 1.0, { 0, },     /* scale */
3577
3578   { 0, },               /* anchor */
3579 };
3580
3581 /*< private >
3582  * _clutter_actor_get_transform_info_or_defaults:
3583  * @self: a #ClutterActor
3584  *
3585  * Retrieves the ClutterTransformInfo structure associated to an actor.
3586  *
3587  * If the actor does not have a ClutterTransformInfo structure associated
3588  * to it, then the default structure will be returned.
3589  *
3590  * This function should only be used for getters.
3591  *
3592  * Return value: a const pointer to the ClutterTransformInfo structure
3593  */
3594 const ClutterTransformInfo *
3595 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3596 {
3597   ClutterTransformInfo *info;
3598
3599   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3600   if (info != NULL)
3601     return info;
3602
3603   return &default_transform_info;
3604 }
3605
3606 static void
3607 clutter_transform_info_free (gpointer data)
3608 {
3609   if (data != NULL)
3610     g_slice_free (ClutterTransformInfo, data);
3611 }
3612
3613 /*< private >
3614  * _clutter_actor_get_transform_info:
3615  * @self: a #ClutterActor
3616  *
3617  * Retrieves a pointer to the ClutterTransformInfo structure.
3618  *
3619  * If the actor does not have a ClutterTransformInfo associated to it, one
3620  * will be created and initialized to the default values.
3621  *
3622  * This function should be used for setters.
3623  *
3624  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3625  * instead.
3626  *
3627  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3628  *   structure
3629  */
3630 ClutterTransformInfo *
3631 _clutter_actor_get_transform_info (ClutterActor *self)
3632 {
3633   ClutterTransformInfo *info;
3634
3635   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3636   if (info == NULL)
3637     {
3638       info = g_slice_new (ClutterTransformInfo);
3639
3640       *info = default_transform_info;
3641
3642       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3643                                info,
3644                                clutter_transform_info_free);
3645     }
3646
3647   return info;
3648 }
3649
3650 /*< private >
3651  * clutter_actor_set_rotation_angle_internal:
3652  * @self: a #ClutterActor
3653  * @axis: the axis of the angle to change
3654  * @angle: the angle of rotation
3655  *
3656  * Sets the rotation angle on the given axis without affecting the
3657  * rotation center point.
3658  */
3659 static inline void
3660 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3661                                            ClutterRotateAxis  axis,
3662                                            gdouble            angle)
3663 {
3664   GObject *obj = G_OBJECT (self);
3665   ClutterTransformInfo *info;
3666
3667   info = _clutter_actor_get_transform_info (self);
3668
3669   g_object_freeze_notify (obj);
3670
3671   switch (axis)
3672     {
3673     case CLUTTER_X_AXIS:
3674       info->rx_angle = angle;
3675       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3676       break;
3677
3678     case CLUTTER_Y_AXIS:
3679       info->ry_angle = angle;
3680       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3681       break;
3682
3683     case CLUTTER_Z_AXIS:
3684       info->rz_angle = angle;
3685       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3686       break;
3687     }
3688
3689   self->priv->transform_valid = FALSE;
3690
3691   g_object_thaw_notify (obj);
3692
3693   clutter_actor_queue_redraw (self);
3694 }
3695
3696 /*< private >
3697  * clutter_actor_set_rotation_center_internal:
3698  * @self: a #ClutterActor
3699  * @axis: the axis of the center to change
3700  * @center: the coordinates of the rotation center
3701  *
3702  * Sets the rotation center on the given axis without affecting the
3703  * rotation angle.
3704  */
3705 static inline void
3706 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3707                                             ClutterRotateAxis    axis,
3708                                             const ClutterVertex *center)
3709 {
3710   GObject *obj = G_OBJECT (self);
3711   ClutterTransformInfo *info;
3712   ClutterVertex v = { 0, 0, 0 };
3713
3714   info = _clutter_actor_get_transform_info (self);
3715
3716   if (center != NULL)
3717     v = *center;
3718
3719   g_object_freeze_notify (obj);
3720
3721   switch (axis)
3722     {
3723     case CLUTTER_X_AXIS:
3724       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3725       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3726       break;
3727
3728     case CLUTTER_Y_AXIS:
3729       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3730       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3731       break;
3732
3733     case CLUTTER_Z_AXIS:
3734       /* if the previously set rotation center was fractional, then
3735        * setting explicit coordinates will have to notify the
3736        * :rotation-center-z-gravity property as well
3737        */
3738       if (info->rz_center.is_fractional)
3739         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3740
3741       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3742       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3743       break;
3744     }
3745
3746   self->priv->transform_valid = FALSE;
3747
3748   g_object_thaw_notify (obj);
3749
3750   clutter_actor_queue_redraw (self);
3751 }
3752
3753 static inline void
3754 clutter_actor_set_scale_factor (ClutterActor      *self,
3755                                 ClutterRotateAxis  axis,
3756                                 gdouble            factor)
3757 {
3758   GObject *obj = G_OBJECT (self);
3759   ClutterTransformInfo *info;
3760
3761   info = _clutter_actor_get_transform_info (self);
3762
3763   g_object_freeze_notify (obj);
3764
3765   switch (axis)
3766     {
3767     case CLUTTER_X_AXIS:
3768       info->scale_x = factor;
3769       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3770       break;
3771
3772     case CLUTTER_Y_AXIS:
3773       info->scale_y = factor;
3774       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3775       break;
3776
3777     default:
3778       g_assert_not_reached ();
3779     }
3780
3781   self->priv->transform_valid = FALSE;
3782
3783   clutter_actor_queue_redraw (self);
3784
3785   g_object_thaw_notify (obj);
3786 }
3787
3788 static inline void
3789 clutter_actor_set_scale_center (ClutterActor      *self,
3790                                 ClutterRotateAxis  axis,
3791                                 gfloat             coord)
3792 {
3793   GObject *obj = G_OBJECT (self);
3794   ClutterTransformInfo *info;
3795   gfloat center_x, center_y;
3796
3797   info = _clutter_actor_get_transform_info (self);
3798
3799   g_object_freeze_notify (obj);
3800
3801   /* get the current scale center coordinates */
3802   clutter_anchor_coord_get_units (self, &info->scale_center,
3803                                   &center_x,
3804                                   &center_y,
3805                                   NULL);
3806
3807   /* we need to notify this too, because setting explicit coordinates will
3808    * change the gravity as a side effect
3809    */
3810   if (info->scale_center.is_fractional)
3811     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3812
3813   switch (axis)
3814     {
3815     case CLUTTER_X_AXIS:
3816       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3817       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3818       break;
3819
3820     case CLUTTER_Y_AXIS:
3821       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3822       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3823       break;
3824
3825     default:
3826       g_assert_not_reached ();
3827     }
3828
3829   self->priv->transform_valid = FALSE;
3830
3831   clutter_actor_queue_redraw (self);
3832
3833   g_object_thaw_notify (obj);
3834 }
3835
3836 static inline void
3837 clutter_actor_set_anchor_coord (ClutterActor      *self,
3838                                 ClutterRotateAxis  axis,
3839                                 gfloat             coord)
3840 {
3841   GObject *obj = G_OBJECT (self);
3842   ClutterTransformInfo *info;
3843   gfloat anchor_x, anchor_y;
3844
3845   info = _clutter_actor_get_transform_info (self);
3846
3847   g_object_freeze_notify (obj);
3848
3849   clutter_anchor_coord_get_units (self, &info->anchor,
3850                                   &anchor_x,
3851                                   &anchor_y,
3852                                   NULL);
3853
3854   if (info->anchor.is_fractional)
3855     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3856
3857   switch (axis)
3858     {
3859     case CLUTTER_X_AXIS:
3860       clutter_anchor_coord_set_units (&info->anchor,
3861                                       coord,
3862                                       anchor_y,
3863                                       0.0);
3864       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3865       break;
3866
3867     case CLUTTER_Y_AXIS:
3868       clutter_anchor_coord_set_units (&info->anchor,
3869                                       anchor_x,
3870                                       coord,
3871                                       0.0);
3872       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3873       break;
3874
3875     default:
3876       g_assert_not_reached ();
3877     }
3878
3879   self->priv->transform_valid = FALSE;
3880
3881   clutter_actor_queue_redraw (self);
3882
3883   g_object_thaw_notify (obj);
3884 }
3885
3886 static void
3887 clutter_actor_set_property (GObject      *object,
3888                             guint         prop_id,
3889                             const GValue *value,
3890                             GParamSpec   *pspec)
3891 {
3892   ClutterActor *actor = CLUTTER_ACTOR (object);
3893   ClutterActorPrivate *priv = actor->priv;
3894
3895   switch (prop_id)
3896     {
3897     case PROP_X:
3898       clutter_actor_set_x (actor, g_value_get_float (value));
3899       break;
3900
3901     case PROP_Y:
3902       clutter_actor_set_y (actor, g_value_get_float (value));
3903       break;
3904
3905     case PROP_WIDTH:
3906       clutter_actor_set_width (actor, g_value_get_float (value));
3907       break;
3908
3909     case PROP_HEIGHT:
3910       clutter_actor_set_height (actor, g_value_get_float (value));
3911       break;
3912
3913     case PROP_FIXED_X:
3914       clutter_actor_set_x (actor, g_value_get_float (value));
3915       break;
3916
3917     case PROP_FIXED_Y:
3918       clutter_actor_set_y (actor, g_value_get_float (value));
3919       break;
3920
3921     case PROP_FIXED_POSITION_SET:
3922       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3923       break;
3924
3925     case PROP_MIN_WIDTH:
3926       clutter_actor_set_min_width (actor, g_value_get_float (value));
3927       break;
3928
3929     case PROP_MIN_HEIGHT:
3930       clutter_actor_set_min_height (actor, g_value_get_float (value));
3931       break;
3932
3933     case PROP_NATURAL_WIDTH:
3934       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3935       break;
3936
3937     case PROP_NATURAL_HEIGHT:
3938       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3939       break;
3940
3941     case PROP_MIN_WIDTH_SET:
3942       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3943       break;
3944
3945     case PROP_MIN_HEIGHT_SET:
3946       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3947       break;
3948
3949     case PROP_NATURAL_WIDTH_SET:
3950       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3951       break;
3952
3953     case PROP_NATURAL_HEIGHT_SET:
3954       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3955       break;
3956
3957     case PROP_REQUEST_MODE:
3958       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3959       break;
3960
3961     case PROP_DEPTH:
3962       clutter_actor_set_depth (actor, g_value_get_float (value));
3963       break;
3964
3965     case PROP_OPACITY:
3966       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3967       break;
3968
3969     case PROP_OFFSCREEN_REDIRECT:
3970       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3971       break;
3972
3973     case PROP_NAME:
3974       clutter_actor_set_name (actor, g_value_get_string (value));
3975       break;
3976
3977     case PROP_VISIBLE:
3978       if (g_value_get_boolean (value) == TRUE)
3979         clutter_actor_show (actor);
3980       else
3981         clutter_actor_hide (actor);
3982       break;
3983
3984     case PROP_SCALE_X:
3985       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3986                                       g_value_get_double (value));
3987       break;
3988
3989     case PROP_SCALE_Y:
3990       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3991                                       g_value_get_double (value));
3992       break;
3993
3994     case PROP_SCALE_CENTER_X:
3995       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
3996                                       g_value_get_float (value));
3997       break;
3998
3999     case PROP_SCALE_CENTER_Y:
4000       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4001                                       g_value_get_float (value));
4002       break;
4003
4004     case PROP_SCALE_GRAVITY:
4005       {
4006         const ClutterTransformInfo *info;
4007         ClutterGravity gravity;
4008
4009         info = _clutter_actor_get_transform_info_or_defaults (actor);
4010         gravity = g_value_get_enum (value);
4011
4012         clutter_actor_set_scale_with_gravity (actor,
4013                                               info->scale_x,
4014                                               info->scale_y,
4015                                               gravity);
4016       }
4017       break;
4018
4019     case PROP_CLIP:
4020       {
4021         const ClutterGeometry *geom = g_value_get_boxed (value);
4022
4023         clutter_actor_set_clip (actor,
4024                                 geom->x, geom->y,
4025                                 geom->width, geom->height);
4026       }
4027       break;
4028
4029     case PROP_CLIP_TO_ALLOCATION:
4030       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4031       break;
4032
4033     case PROP_REACTIVE:
4034       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4035       break;
4036
4037     case PROP_ROTATION_ANGLE_X:
4038       clutter_actor_set_rotation_angle_internal (actor,
4039                                                  CLUTTER_X_AXIS,
4040                                                  g_value_get_double (value));
4041       break;
4042
4043     case PROP_ROTATION_ANGLE_Y:
4044       clutter_actor_set_rotation_angle_internal (actor,
4045                                                  CLUTTER_Y_AXIS,
4046                                                  g_value_get_double (value));
4047       break;
4048
4049     case PROP_ROTATION_ANGLE_Z:
4050       clutter_actor_set_rotation_angle_internal (actor,
4051                                                  CLUTTER_Z_AXIS,
4052                                                  g_value_get_double (value));
4053       break;
4054
4055     case PROP_ROTATION_CENTER_X:
4056       clutter_actor_set_rotation_center_internal (actor,
4057                                                   CLUTTER_X_AXIS,
4058                                                   g_value_get_boxed (value));
4059       break;
4060
4061     case PROP_ROTATION_CENTER_Y:
4062       clutter_actor_set_rotation_center_internal (actor,
4063                                                   CLUTTER_Y_AXIS,
4064                                                   g_value_get_boxed (value));
4065       break;
4066
4067     case PROP_ROTATION_CENTER_Z:
4068       clutter_actor_set_rotation_center_internal (actor,
4069                                                   CLUTTER_Z_AXIS,
4070                                                   g_value_get_boxed (value));
4071       break;
4072
4073     case PROP_ROTATION_CENTER_Z_GRAVITY:
4074       {
4075         const ClutterTransformInfo *info;
4076
4077         info = _clutter_actor_get_transform_info_or_defaults (actor);
4078         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4079                                                    g_value_get_enum (value));
4080       }
4081       break;
4082
4083     case PROP_ANCHOR_X:
4084       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4085                                       g_value_get_float (value));
4086       break;
4087
4088     case PROP_ANCHOR_Y:
4089       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4090                                       g_value_get_float (value));
4091       break;
4092
4093     case PROP_ANCHOR_GRAVITY:
4094       clutter_actor_set_anchor_point_from_gravity (actor,
4095                                                    g_value_get_enum (value));
4096       break;
4097
4098     case PROP_SHOW_ON_SET_PARENT:
4099       priv->show_on_set_parent = g_value_get_boolean (value);
4100       break;
4101
4102     case PROP_TEXT_DIRECTION:
4103       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4104       break;
4105
4106     case PROP_ACTIONS:
4107       clutter_actor_add_action (actor, g_value_get_object (value));
4108       break;
4109
4110     case PROP_CONSTRAINTS:
4111       clutter_actor_add_constraint (actor, g_value_get_object (value));
4112       break;
4113
4114     case PROP_EFFECT:
4115       clutter_actor_add_effect (actor, g_value_get_object (value));
4116       break;
4117
4118     case PROP_LAYOUT_MANAGER:
4119       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4120       break;
4121
4122     case PROP_X_ALIGN:
4123       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4124       break;
4125
4126     case PROP_Y_ALIGN:
4127       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4128       break;
4129
4130     case PROP_MARGIN_TOP:
4131       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4132       break;
4133
4134     case PROP_MARGIN_BOTTOM:
4135       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4136       break;
4137
4138     case PROP_MARGIN_LEFT:
4139       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4140       break;
4141
4142     case PROP_MARGIN_RIGHT:
4143       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4144       break;
4145
4146     case PROP_BACKGROUND_COLOR:
4147       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4148       break;
4149
4150     default:
4151       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4152       break;
4153     }
4154 }
4155
4156 static void
4157 clutter_actor_get_property (GObject    *object,
4158                             guint       prop_id,
4159                             GValue     *value,
4160                             GParamSpec *pspec)
4161 {
4162   ClutterActor *actor = CLUTTER_ACTOR (object);
4163   ClutterActorPrivate *priv = actor->priv;
4164
4165   switch (prop_id)
4166     {
4167     case PROP_X:
4168       g_value_set_float (value, clutter_actor_get_x (actor));
4169       break;
4170
4171     case PROP_Y:
4172       g_value_set_float (value, clutter_actor_get_y (actor));
4173       break;
4174
4175     case PROP_WIDTH:
4176       g_value_set_float (value, clutter_actor_get_width (actor));
4177       break;
4178
4179     case PROP_HEIGHT:
4180       g_value_set_float (value, clutter_actor_get_height (actor));
4181       break;
4182
4183     case PROP_FIXED_X:
4184       {
4185         const ClutterLayoutInfo *info;
4186
4187         info = _clutter_actor_get_layout_info_or_defaults (actor);
4188         g_value_set_float (value, info->fixed_x);
4189       }
4190       break;
4191
4192     case PROP_FIXED_Y:
4193       {
4194         const ClutterLayoutInfo *info;
4195
4196         info = _clutter_actor_get_layout_info_or_defaults (actor);
4197         g_value_set_float (value, info->fixed_y);
4198       }
4199       break;
4200
4201     case PROP_FIXED_POSITION_SET:
4202       g_value_set_boolean (value, priv->position_set);
4203       break;
4204
4205     case PROP_MIN_WIDTH:
4206       {
4207         const ClutterLayoutInfo *info;
4208
4209         info = _clutter_actor_get_layout_info_or_defaults (actor);
4210         g_value_set_float (value, info->min_width);
4211       }
4212       break;
4213
4214     case PROP_MIN_HEIGHT:
4215       {
4216         const ClutterLayoutInfo *info;
4217
4218         info = _clutter_actor_get_layout_info_or_defaults (actor);
4219         g_value_set_float (value, info->min_height);
4220       }
4221       break;
4222
4223     case PROP_NATURAL_WIDTH:
4224       {
4225         const ClutterLayoutInfo *info;
4226
4227         info = _clutter_actor_get_layout_info_or_defaults (actor);
4228         g_value_set_float (value, info->natural_width);
4229       }
4230       break;
4231
4232     case PROP_NATURAL_HEIGHT:
4233       {
4234         const ClutterLayoutInfo *info;
4235
4236         info = _clutter_actor_get_layout_info_or_defaults (actor);
4237         g_value_set_float (value, info->natural_height);
4238       }
4239       break;
4240
4241     case PROP_MIN_WIDTH_SET:
4242       g_value_set_boolean (value, priv->min_width_set);
4243       break;
4244
4245     case PROP_MIN_HEIGHT_SET:
4246       g_value_set_boolean (value, priv->min_height_set);
4247       break;
4248
4249     case PROP_NATURAL_WIDTH_SET:
4250       g_value_set_boolean (value, priv->natural_width_set);
4251       break;
4252
4253     case PROP_NATURAL_HEIGHT_SET:
4254       g_value_set_boolean (value, priv->natural_height_set);
4255       break;
4256
4257     case PROP_REQUEST_MODE:
4258       g_value_set_enum (value, priv->request_mode);
4259       break;
4260
4261     case PROP_ALLOCATION:
4262       g_value_set_boxed (value, &priv->allocation);
4263       break;
4264
4265     case PROP_DEPTH:
4266       g_value_set_float (value, clutter_actor_get_depth (actor));
4267       break;
4268
4269     case PROP_OPACITY:
4270       g_value_set_uint (value, priv->opacity);
4271       break;
4272
4273     case PROP_OFFSCREEN_REDIRECT:
4274       g_value_set_enum (value, priv->offscreen_redirect);
4275       break;
4276
4277     case PROP_NAME:
4278       g_value_set_string (value, priv->name);
4279       break;
4280
4281     case PROP_VISIBLE:
4282       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4283       break;
4284
4285     case PROP_MAPPED:
4286       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4287       break;
4288
4289     case PROP_REALIZED:
4290       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4291       break;
4292
4293     case PROP_HAS_CLIP:
4294       g_value_set_boolean (value, priv->has_clip);
4295       break;
4296
4297     case PROP_CLIP:
4298       {
4299         ClutterGeometry clip;
4300
4301         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4302         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4303         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4304         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4305
4306         g_value_set_boxed (value, &clip);
4307       }
4308       break;
4309
4310     case PROP_CLIP_TO_ALLOCATION:
4311       g_value_set_boolean (value, priv->clip_to_allocation);
4312       break;
4313
4314     case PROP_SCALE_X:
4315       {
4316         const ClutterTransformInfo *info;
4317
4318         info = _clutter_actor_get_transform_info_or_defaults (actor);
4319         g_value_set_double (value, info->scale_x);
4320       }
4321       break;
4322
4323     case PROP_SCALE_Y:
4324       {
4325         const ClutterTransformInfo *info;
4326
4327         info = _clutter_actor_get_transform_info_or_defaults (actor);
4328         g_value_set_double (value, info->scale_y);
4329       }
4330       break;
4331
4332     case PROP_SCALE_CENTER_X:
4333       {
4334         gfloat center;
4335
4336         clutter_actor_get_scale_center (actor, &center, NULL);
4337
4338         g_value_set_float (value, center);
4339       }
4340       break;
4341
4342     case PROP_SCALE_CENTER_Y:
4343       {
4344         gfloat center;
4345
4346         clutter_actor_get_scale_center (actor, NULL, &center);
4347
4348         g_value_set_float (value, center);
4349       }
4350       break;
4351
4352     case PROP_SCALE_GRAVITY:
4353       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4354       break;
4355
4356     case PROP_REACTIVE:
4357       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4358       break;
4359
4360     case PROP_ROTATION_ANGLE_X:
4361       {
4362         const ClutterTransformInfo *info;
4363
4364         info = _clutter_actor_get_transform_info_or_defaults (actor);
4365         g_value_set_double (value, info->rx_angle);
4366       }
4367       break;
4368
4369     case PROP_ROTATION_ANGLE_Y:
4370       {
4371         const ClutterTransformInfo *info;
4372
4373         info = _clutter_actor_get_transform_info_or_defaults (actor);
4374         g_value_set_double (value, info->ry_angle);
4375       }
4376       break;
4377
4378     case PROP_ROTATION_ANGLE_Z:
4379       {
4380         const ClutterTransformInfo *info;
4381
4382         info = _clutter_actor_get_transform_info_or_defaults (actor);
4383         g_value_set_double (value, info->rz_angle);
4384       }
4385       break;
4386
4387     case PROP_ROTATION_CENTER_X:
4388       {
4389         ClutterVertex center;
4390
4391         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4392                                     &center.x,
4393                                     &center.y,
4394                                     &center.z);
4395
4396         g_value_set_boxed (value, &center);
4397       }
4398       break;
4399
4400     case PROP_ROTATION_CENTER_Y:
4401       {
4402         ClutterVertex center;
4403
4404         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4405                                     &center.x,
4406                                     &center.y,
4407                                     &center.z);
4408
4409         g_value_set_boxed (value, &center);
4410       }
4411       break;
4412
4413     case PROP_ROTATION_CENTER_Z:
4414       {
4415         ClutterVertex center;
4416
4417         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4418                                     &center.x,
4419                                     &center.y,
4420                                     &center.z);
4421
4422         g_value_set_boxed (value, &center);
4423       }
4424       break;
4425
4426     case PROP_ROTATION_CENTER_Z_GRAVITY:
4427       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4428       break;
4429
4430     case PROP_ANCHOR_X:
4431       {
4432         const ClutterTransformInfo *info;
4433         gfloat anchor_x;
4434
4435         info = _clutter_actor_get_transform_info_or_defaults (actor);
4436         clutter_anchor_coord_get_units (actor, &info->anchor,
4437                                         &anchor_x,
4438                                         NULL,
4439                                         NULL);
4440         g_value_set_float (value, anchor_x);
4441       }
4442       break;
4443
4444     case PROP_ANCHOR_Y:
4445       {
4446         const ClutterTransformInfo *info;
4447         gfloat anchor_y;
4448
4449         info = _clutter_actor_get_transform_info_or_defaults (actor);
4450         clutter_anchor_coord_get_units (actor, &info->anchor,
4451                                         NULL,
4452                                         &anchor_y,
4453                                         NULL);
4454         g_value_set_float (value, anchor_y);
4455       }
4456       break;
4457
4458     case PROP_ANCHOR_GRAVITY:
4459       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4460       break;
4461
4462     case PROP_SHOW_ON_SET_PARENT:
4463       g_value_set_boolean (value, priv->show_on_set_parent);
4464       break;
4465
4466     case PROP_TEXT_DIRECTION:
4467       g_value_set_enum (value, priv->text_direction);
4468       break;
4469
4470     case PROP_HAS_POINTER:
4471       g_value_set_boolean (value, priv->has_pointer);
4472       break;
4473
4474     case PROP_LAYOUT_MANAGER:
4475       g_value_set_object (value, priv->layout_manager);
4476       break;
4477
4478     case PROP_X_ALIGN:
4479       {
4480         const ClutterLayoutInfo *info;
4481
4482         info = _clutter_actor_get_layout_info_or_defaults (actor);
4483         g_value_set_enum (value, info->x_align);
4484       }
4485       break;
4486
4487     case PROP_Y_ALIGN:
4488       {
4489         const ClutterLayoutInfo *info;
4490
4491         info = _clutter_actor_get_layout_info_or_defaults (actor);
4492         g_value_set_enum (value, info->y_align);
4493       }
4494       break;
4495
4496     case PROP_MARGIN_TOP:
4497       {
4498         const ClutterLayoutInfo *info;
4499
4500         info = _clutter_actor_get_layout_info_or_defaults (actor);
4501         g_value_set_float (value, info->margin.top);
4502       }
4503       break;
4504
4505     case PROP_MARGIN_BOTTOM:
4506       {
4507         const ClutterLayoutInfo *info;
4508
4509         info = _clutter_actor_get_layout_info_or_defaults (actor);
4510         g_value_set_float (value, info->margin.bottom);
4511       }
4512       break;
4513
4514     case PROP_MARGIN_LEFT:
4515       {
4516         const ClutterLayoutInfo *info;
4517
4518         info = _clutter_actor_get_layout_info_or_defaults (actor);
4519         g_value_set_float (value, info->margin.left);
4520       }
4521       break;
4522
4523     case PROP_MARGIN_RIGHT:
4524       {
4525         const ClutterLayoutInfo *info;
4526
4527         info = _clutter_actor_get_layout_info_or_defaults (actor);
4528         g_value_set_float (value, info->margin.right);
4529       }
4530       break;
4531
4532     case PROP_BACKGROUND_COLOR_SET:
4533       g_value_set_boolean (value, priv->bg_color_set);
4534       break;
4535
4536     case PROP_BACKGROUND_COLOR:
4537       g_value_set_boxed (value, &priv->bg_color);
4538       break;
4539
4540     case PROP_FIRST_CHILD:
4541       g_value_set_object (value, priv->first_child);
4542       break;
4543
4544     case PROP_LAST_CHILD:
4545       g_value_set_object (value, priv->last_child);
4546       break;
4547
4548     default:
4549       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4550       break;
4551     }
4552 }
4553
4554 static void
4555 clutter_actor_dispose (GObject *object)
4556 {
4557   ClutterActor *self = CLUTTER_ACTOR (object);
4558   ClutterActorPrivate *priv = self->priv;
4559
4560   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4561                 priv->id,
4562                 g_type_name (G_OBJECT_TYPE (self)),
4563                 object->ref_count);
4564
4565   g_signal_emit (self, actor_signals[DESTROY], 0);
4566
4567   /* avoid recursing when called from clutter_actor_destroy() */
4568   if (priv->parent != NULL)
4569     {
4570       ClutterActor *parent = priv->parent;
4571
4572       /* go through the Container implementation unless this
4573        * is an internal child and has been marked as such.
4574        *
4575        * removing the actor from its parent will reset the
4576        * realized and mapped states.
4577        */
4578       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4579         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4580       else
4581         clutter_actor_remove_child_internal (parent, self,
4582                                              REMOVE_CHILD_LEGACY_FLAGS);
4583     }
4584
4585   /* parent must be gone at this point */
4586   g_assert (priv->parent == NULL);
4587
4588   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4589     {
4590       /* can't be mapped or realized with no parent */
4591       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4592       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4593     }
4594
4595   g_clear_object (&priv->pango_context);
4596   g_clear_object (&priv->actions);
4597   g_clear_object (&priv->constraints);
4598   g_clear_object (&priv->effects);
4599   g_clear_object (&priv->flatten_effect);
4600
4601   if (priv->layout_manager != NULL)
4602     {
4603       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4604       g_object_unref (priv->layout_manager);
4605       priv->layout_manager = NULL;
4606     }
4607
4608   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4609 }
4610
4611 static void
4612 clutter_actor_finalize (GObject *object)
4613 {
4614   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4615
4616   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4617                 priv->name != NULL ? priv->name : "<none>",
4618                 priv->id,
4619                 g_type_name (G_OBJECT_TYPE (object)));
4620
4621   _clutter_context_release_id (priv->id);
4622
4623   g_free (priv->name);
4624
4625   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4626 }
4627
4628
4629 /**
4630  * clutter_actor_get_accessible:
4631  * @self: a #ClutterActor
4632  *
4633  * Returns the accessible object that describes the actor to an
4634  * assistive technology.
4635  *
4636  * If no class-specific #AtkObject implementation is available for the
4637  * actor instance in question, it will inherit an #AtkObject
4638  * implementation from the first ancestor class for which such an
4639  * implementation is defined.
4640  *
4641  * The documentation of the <ulink
4642  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4643  * library contains more information about accessible objects and
4644  * their uses.
4645  *
4646  * Returns: (transfer none): the #AtkObject associated with @actor
4647  */
4648 AtkObject *
4649 clutter_actor_get_accessible (ClutterActor *self)
4650 {
4651   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4652
4653   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4654 }
4655
4656 static AtkObject *
4657 clutter_actor_real_get_accessible (ClutterActor *actor)
4658 {
4659   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4660 }
4661
4662 static AtkObject *
4663 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4664 {
4665   AtkObject *accessible;
4666
4667   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4668   if (accessible != NULL)
4669     g_object_ref (accessible);
4670
4671   return accessible;
4672 }
4673
4674 static void
4675 atk_implementor_iface_init (AtkImplementorIface *iface)
4676 {
4677   iface->ref_accessible = _clutter_actor_ref_accessible;
4678 }
4679
4680 static gboolean
4681 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4682                                      ClutterPaintVolume *volume)
4683 {
4684   ClutterActorPrivate *priv = self->priv;
4685   ClutterActor *child;
4686   gboolean res;
4687
4688   /* this is the default return value: we cannot know if a class
4689    * is going to paint outside its allocation, so we take the
4690    * conservative approach.
4691    */
4692   res = FALSE;
4693
4694   /* we start from the allocation */
4695   clutter_paint_volume_set_from_allocation (volume, self);
4696
4697   /* if the actor has a clip set then we have a pretty definite
4698    * size for the paint volume: the actor cannot possibly paint
4699    * outside the clip region.
4700    */
4701   if (priv->clip_to_allocation)
4702     {
4703       /* the allocation has already been set, so we just flip the
4704        * return value
4705        */
4706       res = TRUE;
4707     }
4708   else
4709     {
4710       if (priv->has_clip &&
4711           priv->clip.width >= 0 &&
4712           priv->clip.height >= 0)
4713         {
4714           ClutterVertex origin;
4715
4716           origin.x = priv->clip.x;
4717           origin.y = priv->clip.y;
4718           origin.z = 0;
4719
4720           clutter_paint_volume_set_origin (volume, &origin);
4721           clutter_paint_volume_set_width (volume, priv->clip.width);
4722           clutter_paint_volume_set_height (volume, priv->clip.height);
4723
4724           res = TRUE;
4725         }
4726
4727       /* if we don't have children we just bail out here... */
4728       if (priv->n_children == 0)
4729         return res;
4730
4731       /* ...but if we have children then we ask for their paint volume in
4732        * our coordinates. if any of our children replies that it doesn't
4733        * have a paint volume, we bail out
4734        */
4735       for (child = priv->first_child;
4736            child != NULL;
4737            child = child->priv->next_sibling)
4738         {
4739           const ClutterPaintVolume *child_volume;
4740
4741           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4742           if (child_volume == NULL)
4743             {
4744               res = FALSE;
4745               break;
4746             }
4747
4748           clutter_paint_volume_union (volume, child_volume);
4749           res = TRUE;
4750         }
4751     }
4752
4753   return res;
4754 }
4755
4756 static gboolean
4757 clutter_actor_real_has_overlaps (ClutterActor *self)
4758 {
4759   /* By default we'll assume that all actors need an offscreen redirect to get
4760    * the correct opacity. Actors such as ClutterTexture that would never need
4761    * an offscreen redirect can override this to return FALSE. */
4762   return TRUE;
4763 }
4764
4765 static void
4766 clutter_actor_real_destroy (ClutterActor *actor)
4767 {
4768   ClutterActorIter iter;
4769
4770   clutter_actor_iter_init (&iter, actor);
4771   while (clutter_actor_iter_next (&iter, NULL))
4772     clutter_actor_iter_destroy (&iter);
4773 }
4774
4775 static GObject *
4776 clutter_actor_constructor (GType gtype,
4777                            guint n_props,
4778                            GObjectConstructParam *props)
4779 {
4780   GObjectClass *gobject_class;
4781   ClutterActor *self;
4782   GObject *retval;
4783
4784   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4785   retval = gobject_class->constructor (gtype, n_props, props);
4786   self = CLUTTER_ACTOR (retval);
4787
4788   if (self->priv->layout_manager == NULL)
4789     {
4790       ClutterLayoutManager *default_layout;
4791
4792       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4793
4794       default_layout = clutter_fixed_layout_new ();
4795       clutter_actor_set_layout_manager (self, default_layout);
4796     }
4797
4798   return retval;
4799 }
4800
4801 static void
4802 clutter_actor_class_init (ClutterActorClass *klass)
4803 {
4804   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4805
4806   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4807   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4808   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4809
4810   object_class->constructor = clutter_actor_constructor;
4811   object_class->set_property = clutter_actor_set_property;
4812   object_class->get_property = clutter_actor_get_property;
4813   object_class->dispose = clutter_actor_dispose;
4814   object_class->finalize = clutter_actor_finalize;
4815
4816   klass->show = clutter_actor_real_show;
4817   klass->show_all = clutter_actor_show;
4818   klass->hide = clutter_actor_real_hide;
4819   klass->hide_all = clutter_actor_hide;
4820   klass->map = clutter_actor_real_map;
4821   klass->unmap = clutter_actor_real_unmap;
4822   klass->unrealize = clutter_actor_real_unrealize;
4823   klass->pick = clutter_actor_real_pick;
4824   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4825   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4826   klass->allocate = clutter_actor_real_allocate;
4827   klass->queue_redraw = clutter_actor_real_queue_redraw;
4828   klass->queue_relayout = clutter_actor_real_queue_relayout;
4829   klass->apply_transform = clutter_actor_real_apply_transform;
4830   klass->get_accessible = clutter_actor_real_get_accessible;
4831   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4832   klass->has_overlaps = clutter_actor_real_has_overlaps;
4833   klass->paint = clutter_actor_real_paint;
4834   klass->destroy = clutter_actor_real_destroy;
4835
4836   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4837
4838   /**
4839    * ClutterActor:x:
4840    *
4841    * X coordinate of the actor in pixels. If written, forces a fixed
4842    * position for the actor. If read, returns the fixed position if any,
4843    * otherwise the allocation if available, otherwise 0.
4844    */
4845   obj_props[PROP_X] =
4846     g_param_spec_float ("x",
4847                         P_("X coordinate"),
4848                         P_("X coordinate of the actor"),
4849                         -G_MAXFLOAT, G_MAXFLOAT,
4850                         0.0,
4851                         CLUTTER_PARAM_READWRITE);
4852
4853   /**
4854    * ClutterActor:y:
4855    *
4856    * Y coordinate of the actor in pixels. If written, forces a fixed
4857    * position for the actor.  If read, returns the fixed position if
4858    * any, otherwise the allocation if available, otherwise 0.
4859    */
4860   obj_props[PROP_Y] =
4861     g_param_spec_float ("y",
4862                         P_("Y coordinate"),
4863                         P_("Y coordinate of the actor"),
4864                         -G_MAXFLOAT, G_MAXFLOAT,
4865                         0.0,
4866                         CLUTTER_PARAM_READWRITE);
4867
4868   /**
4869    * ClutterActor:width:
4870    *
4871    * Width of the actor (in pixels). If written, forces the minimum and
4872    * natural size request of the actor to the given width. If read, returns
4873    * the allocated width if available, otherwise the width request.
4874    */
4875   obj_props[PROP_WIDTH] =
4876     g_param_spec_float ("width",
4877                         P_("Width"),
4878                         P_("Width of the actor"),
4879                         0.0, G_MAXFLOAT,
4880                         0.0,
4881                         CLUTTER_PARAM_READWRITE);
4882
4883   /**
4884    * ClutterActor:height:
4885    *
4886    * Height of the actor (in pixels).  If written, forces the minimum and
4887    * natural size request of the actor to the given height. If read, returns
4888    * the allocated height if available, otherwise the height request.
4889    */
4890   obj_props[PROP_HEIGHT] =
4891     g_param_spec_float ("height",
4892                         P_("Height"),
4893                         P_("Height of the actor"),
4894                         0.0, G_MAXFLOAT,
4895                         0.0,
4896                         CLUTTER_PARAM_READWRITE);
4897
4898   /**
4899    * ClutterActor:fixed-x:
4900    *
4901    * The fixed X position of the actor in pixels.
4902    *
4903    * Writing this property sets #ClutterActor:fixed-position-set
4904    * property as well, as a side effect
4905    *
4906    * Since: 0.8
4907    */
4908   obj_props[PROP_FIXED_X] =
4909     g_param_spec_float ("fixed-x",
4910                         P_("Fixed X"),
4911                         P_("Forced X position of the actor"),
4912                         -G_MAXFLOAT, G_MAXFLOAT,
4913                         0.0,
4914                         CLUTTER_PARAM_READWRITE);
4915
4916   /**
4917    * ClutterActor:fixed-y:
4918    *
4919    * The fixed Y position of the actor in pixels.
4920    *
4921    * Writing this property sets the #ClutterActor:fixed-position-set
4922    * property as well, as a side effect
4923    *
4924    * Since: 0.8
4925    */
4926   obj_props[PROP_FIXED_Y] =
4927     g_param_spec_float ("fixed-y",
4928                         P_("Fixed Y"),
4929                         P_("Forced Y position of the actor"),
4930                         -G_MAXFLOAT, G_MAXFLOAT,
4931                         0,
4932                         CLUTTER_PARAM_READWRITE);
4933
4934   /**
4935    * ClutterActor:fixed-position-set:
4936    *
4937    * This flag controls whether the #ClutterActor:fixed-x and
4938    * #ClutterActor:fixed-y properties are used
4939    *
4940    * Since: 0.8
4941    */
4942   obj_props[PROP_FIXED_POSITION_SET] =
4943     g_param_spec_boolean ("fixed-position-set",
4944                           P_("Fixed position set"),
4945                           P_("Whether to use fixed positioning for the actor"),
4946                           FALSE,
4947                           CLUTTER_PARAM_READWRITE);
4948
4949   /**
4950    * ClutterActor:min-width:
4951    *
4952    * A forced minimum width request for the actor, in pixels
4953    *
4954    * Writing this property sets the #ClutterActor:min-width-set property
4955    * as well, as a side effect.
4956    *
4957    *This property overrides the usual width request of the actor.
4958    *
4959    * Since: 0.8
4960    */
4961   obj_props[PROP_MIN_WIDTH] =
4962     g_param_spec_float ("min-width",
4963                         P_("Min Width"),
4964                         P_("Forced minimum width request for the actor"),
4965                         0.0, G_MAXFLOAT,
4966                         0.0,
4967                         CLUTTER_PARAM_READWRITE);
4968
4969   /**
4970    * ClutterActor:min-height:
4971    *
4972    * A forced minimum height request for the actor, in pixels
4973    *
4974    * Writing this property sets the #ClutterActor:min-height-set property
4975    * as well, as a side effect. This property overrides the usual height
4976    * request of the actor.
4977    *
4978    * Since: 0.8
4979    */
4980   obj_props[PROP_MIN_HEIGHT] =
4981     g_param_spec_float ("min-height",
4982                         P_("Min Height"),
4983                         P_("Forced minimum height request for the actor"),
4984                         0.0, G_MAXFLOAT,
4985                         0.0,
4986                         CLUTTER_PARAM_READWRITE);
4987
4988   /**
4989    * ClutterActor:natural-width:
4990    *
4991    * A forced natural width request for the actor, in pixels
4992    *
4993    * Writing this property sets the #ClutterActor:natural-width-set
4994    * property as well, as a side effect. This property overrides the
4995    * usual width request of the actor
4996    *
4997    * Since: 0.8
4998    */
4999   obj_props[PROP_NATURAL_WIDTH] =
5000     g_param_spec_float ("natural-width",
5001                         P_("Natural Width"),
5002                         P_("Forced natural width request for the actor"),
5003                         0.0, G_MAXFLOAT,
5004                         0.0,
5005                         CLUTTER_PARAM_READWRITE);
5006
5007   /**
5008    * ClutterActor:natural-height:
5009    *
5010    * A forced natural height request for the actor, in pixels
5011    *
5012    * Writing this property sets the #ClutterActor:natural-height-set
5013    * property as well, as a side effect. This property overrides the
5014    * usual height request of the actor
5015    *
5016    * Since: 0.8
5017    */
5018   obj_props[PROP_NATURAL_HEIGHT] =
5019     g_param_spec_float ("natural-height",
5020                         P_("Natural Height"),
5021                         P_("Forced natural height request for the actor"),
5022                         0.0, G_MAXFLOAT,
5023                         0.0,
5024                         CLUTTER_PARAM_READWRITE);
5025
5026   /**
5027    * ClutterActor:min-width-set:
5028    *
5029    * This flag controls whether the #ClutterActor:min-width property
5030    * is used
5031    *
5032    * Since: 0.8
5033    */
5034   obj_props[PROP_MIN_WIDTH_SET] =
5035     g_param_spec_boolean ("min-width-set",
5036                           P_("Minimum width set"),
5037                           P_("Whether to use the min-width property"),
5038                           FALSE,
5039                           CLUTTER_PARAM_READWRITE);
5040
5041   /**
5042    * ClutterActor:min-height-set:
5043    *
5044    * This flag controls whether the #ClutterActor:min-height property
5045    * is used
5046    *
5047    * Since: 0.8
5048    */
5049   obj_props[PROP_MIN_HEIGHT_SET] =
5050     g_param_spec_boolean ("min-height-set",
5051                           P_("Minimum height set"),
5052                           P_("Whether to use the min-height property"),
5053                           FALSE,
5054                           CLUTTER_PARAM_READWRITE);
5055
5056   /**
5057    * ClutterActor:natural-width-set:
5058    *
5059    * This flag controls whether the #ClutterActor:natural-width property
5060    * is used
5061    *
5062    * Since: 0.8
5063    */
5064   obj_props[PROP_NATURAL_WIDTH_SET] =
5065     g_param_spec_boolean ("natural-width-set",
5066                           P_("Natural width set"),
5067                           P_("Whether to use the natural-width property"),
5068                           FALSE,
5069                           CLUTTER_PARAM_READWRITE);
5070
5071   /**
5072    * ClutterActor:natural-height-set:
5073    *
5074    * This flag controls whether the #ClutterActor:natural-height property
5075    * is used
5076    *
5077    * Since: 0.8
5078    */
5079   obj_props[PROP_NATURAL_HEIGHT_SET] =
5080     g_param_spec_boolean ("natural-height-set",
5081                           P_("Natural height set"),
5082                           P_("Whether to use the natural-height property"),
5083                           FALSE,
5084                           CLUTTER_PARAM_READWRITE);
5085
5086   /**
5087    * ClutterActor:allocation:
5088    *
5089    * The allocation for the actor, in pixels
5090    *
5091    * This is property is read-only, but you might monitor it to know when an
5092    * actor moves or resizes
5093    *
5094    * Since: 0.8
5095    */
5096   obj_props[PROP_ALLOCATION] =
5097     g_param_spec_boxed ("allocation",
5098                         P_("Allocation"),
5099                         P_("The actor's allocation"),
5100                         CLUTTER_TYPE_ACTOR_BOX,
5101                         CLUTTER_PARAM_READABLE);
5102
5103   /**
5104    * ClutterActor:request-mode:
5105    *
5106    * Request mode for the #ClutterActor. The request mode determines the
5107    * type of geometry management used by the actor, either height for width
5108    * (the default) or width for height.
5109    *
5110    * For actors implementing height for width, the parent container should get
5111    * the preferred width first, and then the preferred height for that width.
5112    *
5113    * For actors implementing width for height, the parent container should get
5114    * the preferred height first, and then the preferred width for that height.
5115    *
5116    * For instance:
5117    *
5118    * |[
5119    *   ClutterRequestMode mode;
5120    *   gfloat natural_width, min_width;
5121    *   gfloat natural_height, min_height;
5122    *
5123    *   mode = clutter_actor_get_request_mode (child);
5124    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5125    *     {
5126    *       clutter_actor_get_preferred_width (child, -1,
5127    *                                          &amp;min_width,
5128    *                                          &amp;natural_width);
5129    *       clutter_actor_get_preferred_height (child, natural_width,
5130    *                                           &amp;min_height,
5131    *                                           &amp;natural_height);
5132    *     }
5133    *   else
5134    *     {
5135    *       clutter_actor_get_preferred_height (child, -1,
5136    *                                           &amp;min_height,
5137    *                                           &amp;natural_height);
5138    *       clutter_actor_get_preferred_width (child, natural_height,
5139    *                                          &amp;min_width,
5140    *                                          &amp;natural_width);
5141    *     }
5142    * ]|
5143    *
5144    * will retrieve the minimum and natural width and height depending on the
5145    * preferred request mode of the #ClutterActor "child".
5146    *
5147    * The clutter_actor_get_preferred_size() function will implement this
5148    * check for you.
5149    *
5150    * Since: 0.8
5151    */
5152   obj_props[PROP_REQUEST_MODE] =
5153     g_param_spec_enum ("request-mode",
5154                        P_("Request Mode"),
5155                        P_("The actor's request mode"),
5156                        CLUTTER_TYPE_REQUEST_MODE,
5157                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5158                        CLUTTER_PARAM_READWRITE);
5159
5160   /**
5161    * ClutterActor:depth:
5162    *
5163    * The position of the actor on the Z axis
5164    *
5165    * Since: 0.6
5166    */
5167   obj_props[PROP_DEPTH] =
5168     g_param_spec_float ("depth",
5169                         P_("Depth"),
5170                         P_("Position on the Z axis"),
5171                         -G_MAXFLOAT, G_MAXFLOAT,
5172                         0.0,
5173                         CLUTTER_PARAM_READWRITE);
5174
5175   /**
5176    * ClutterActor:opacity:
5177    *
5178    * Opacity of an actor, between 0 (fully transparent) and
5179    * 255 (fully opaque)
5180    */
5181   obj_props[PROP_OPACITY] =
5182     g_param_spec_uint ("opacity",
5183                        P_("Opacity"),
5184                        P_("Opacity of an actor"),
5185                        0, 255,
5186                        255,
5187                        CLUTTER_PARAM_READWRITE);
5188
5189   /**
5190    * ClutterActor:offscreen-redirect:
5191    *
5192    * Determines the conditions in which the actor will be redirected
5193    * to an offscreen framebuffer while being painted. For example this
5194    * can be used to cache an actor in a framebuffer or for improved
5195    * handling of transparent actors. See
5196    * clutter_actor_set_offscreen_redirect() for details.
5197    *
5198    * Since: 1.8
5199    */
5200   obj_props[PROP_OFFSCREEN_REDIRECT] =
5201     g_param_spec_flags ("offscreen-redirect",
5202                         P_("Offscreen redirect"),
5203                         P_("Flags controlling when to flatten the actor into a single image"),
5204                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5205                         0,
5206                         CLUTTER_PARAM_READWRITE);
5207
5208   /**
5209    * ClutterActor:visible:
5210    *
5211    * Whether the actor is set to be visible or not
5212    *
5213    * See also #ClutterActor:mapped
5214    */
5215   obj_props[PROP_VISIBLE] =
5216     g_param_spec_boolean ("visible",
5217                           P_("Visible"),
5218                           P_("Whether the actor is visible or not"),
5219                           FALSE,
5220                           CLUTTER_PARAM_READWRITE);
5221
5222   /**
5223    * ClutterActor:mapped:
5224    *
5225    * Whether the actor is mapped (will be painted when the stage
5226    * to which it belongs is mapped)
5227    *
5228    * Since: 1.0
5229    */
5230   obj_props[PROP_MAPPED] =
5231     g_param_spec_boolean ("mapped",
5232                           P_("Mapped"),
5233                           P_("Whether the actor will be painted"),
5234                           FALSE,
5235                           CLUTTER_PARAM_READABLE);
5236
5237   /**
5238    * ClutterActor:realized:
5239    *
5240    * Whether the actor has been realized
5241    *
5242    * Since: 1.0
5243    */
5244   obj_props[PROP_REALIZED] =
5245     g_param_spec_boolean ("realized",
5246                           P_("Realized"),
5247                           P_("Whether the actor has been realized"),
5248                           FALSE,
5249                           CLUTTER_PARAM_READABLE);
5250
5251   /**
5252    * ClutterActor:reactive:
5253    *
5254    * Whether the actor is reactive to events or not
5255    *
5256    * Only reactive actors will emit event-related signals
5257    *
5258    * Since: 0.6
5259    */
5260   obj_props[PROP_REACTIVE] =
5261     g_param_spec_boolean ("reactive",
5262                           P_("Reactive"),
5263                           P_("Whether the actor is reactive to events"),
5264                           FALSE,
5265                           CLUTTER_PARAM_READWRITE);
5266
5267   /**
5268    * ClutterActor:has-clip:
5269    *
5270    * Whether the actor has the #ClutterActor:clip property set or not
5271    */
5272   obj_props[PROP_HAS_CLIP] =
5273     g_param_spec_boolean ("has-clip",
5274                           P_("Has Clip"),
5275                           P_("Whether the actor has a clip set"),
5276                           FALSE,
5277                           CLUTTER_PARAM_READABLE);
5278
5279   /**
5280    * ClutterActor:clip:
5281    *
5282    * The clip region for the actor, in actor-relative coordinates
5283    *
5284    * Every part of the actor outside the clip region will not be
5285    * painted
5286    */
5287   obj_props[PROP_CLIP] =
5288     g_param_spec_boxed ("clip",
5289                         P_("Clip"),
5290                         P_("The clip region for the actor"),
5291                         CLUTTER_TYPE_GEOMETRY,
5292                         CLUTTER_PARAM_READWRITE);
5293
5294   /**
5295    * ClutterActor:name:
5296    *
5297    * The name of the actor
5298    *
5299    * Since: 0.2
5300    */
5301   obj_props[PROP_NAME] =
5302     g_param_spec_string ("name",
5303                          P_("Name"),
5304                          P_("Name of the actor"),
5305                          NULL,
5306                          CLUTTER_PARAM_READWRITE);
5307
5308   /**
5309    * ClutterActor:scale-x:
5310    *
5311    * The horizontal scale of the actor
5312    *
5313    * Since: 0.6
5314    */
5315   obj_props[PROP_SCALE_X] =
5316     g_param_spec_double ("scale-x",
5317                          P_("Scale X"),
5318                          P_("Scale factor on the X axis"),
5319                          0.0, G_MAXDOUBLE,
5320                          1.0,
5321                          CLUTTER_PARAM_READWRITE);
5322
5323   /**
5324    * ClutterActor:scale-y:
5325    *
5326    * The vertical scale of the actor
5327    *
5328    * Since: 0.6
5329    */
5330   obj_props[PROP_SCALE_Y] =
5331     g_param_spec_double ("scale-y",
5332                          P_("Scale Y"),
5333                          P_("Scale factor on the Y axis"),
5334                          0.0, G_MAXDOUBLE,
5335                          1.0,
5336                          CLUTTER_PARAM_READWRITE);
5337
5338   /**
5339    * ClutterActor:scale-center-x:
5340    *
5341    * The horizontal center point for scaling
5342    *
5343    * Since: 1.0
5344    */
5345   obj_props[PROP_SCALE_CENTER_X] =
5346     g_param_spec_float ("scale-center-x",
5347                         P_("Scale Center X"),
5348                         P_("Horizontal scale center"),
5349                         -G_MAXFLOAT, G_MAXFLOAT,
5350                         0.0,
5351                         CLUTTER_PARAM_READWRITE);
5352
5353   /**
5354    * ClutterActor:scale-center-y:
5355    *
5356    * The vertical center point for scaling
5357    *
5358    * Since: 1.0
5359    */
5360   obj_props[PROP_SCALE_CENTER_Y] =
5361     g_param_spec_float ("scale-center-y",
5362                         P_("Scale Center Y"),
5363                         P_("Vertical scale center"),
5364                         -G_MAXFLOAT, G_MAXFLOAT,
5365                         0.0,
5366                         CLUTTER_PARAM_READWRITE);
5367
5368   /**
5369    * ClutterActor:scale-gravity:
5370    *
5371    * The center point for scaling expressed as a #ClutterGravity
5372    *
5373    * Since: 1.0
5374    */
5375   obj_props[PROP_SCALE_GRAVITY] =
5376     g_param_spec_enum ("scale-gravity",
5377                        P_("Scale Gravity"),
5378                        P_("The center of scaling"),
5379                        CLUTTER_TYPE_GRAVITY,
5380                        CLUTTER_GRAVITY_NONE,
5381                        CLUTTER_PARAM_READWRITE);
5382
5383   /**
5384    * ClutterActor:rotation-angle-x:
5385    *
5386    * The rotation angle on the X axis
5387    *
5388    * Since: 0.6
5389    */
5390   obj_props[PROP_ROTATION_ANGLE_X] =
5391     g_param_spec_double ("rotation-angle-x",
5392                          P_("Rotation Angle X"),
5393                          P_("The rotation angle on the X axis"),
5394                          -G_MAXDOUBLE, G_MAXDOUBLE,
5395                          0.0,
5396                          CLUTTER_PARAM_READWRITE);
5397
5398   /**
5399    * ClutterActor:rotation-angle-y:
5400    *
5401    * The rotation angle on the Y axis
5402    *
5403    * Since: 0.6
5404    */
5405   obj_props[PROP_ROTATION_ANGLE_Y] =
5406     g_param_spec_double ("rotation-angle-y",
5407                          P_("Rotation Angle Y"),
5408                          P_("The rotation angle on the Y axis"),
5409                          -G_MAXDOUBLE, G_MAXDOUBLE,
5410                          0.0,
5411                          CLUTTER_PARAM_READWRITE);
5412
5413   /**
5414    * ClutterActor:rotation-angle-z:
5415    *
5416    * The rotation angle on the Z axis
5417    *
5418    * Since: 0.6
5419    */
5420   obj_props[PROP_ROTATION_ANGLE_Z] =
5421     g_param_spec_double ("rotation-angle-z",
5422                          P_("Rotation Angle Z"),
5423                          P_("The rotation angle on the Z axis"),
5424                          -G_MAXDOUBLE, G_MAXDOUBLE,
5425                          0.0,
5426                          CLUTTER_PARAM_READWRITE);
5427
5428   /**
5429    * ClutterActor:rotation-center-x:
5430    *
5431    * The rotation center on the X axis.
5432    *
5433    * Since: 0.6
5434    */
5435   obj_props[PROP_ROTATION_CENTER_X] =
5436     g_param_spec_boxed ("rotation-center-x",
5437                         P_("Rotation Center X"),
5438                         P_("The rotation center on the X axis"),
5439                         CLUTTER_TYPE_VERTEX,
5440                         CLUTTER_PARAM_READWRITE);
5441
5442   /**
5443    * ClutterActor:rotation-center-y:
5444    *
5445    * The rotation center on the Y axis.
5446    *
5447    * Since: 0.6
5448    */
5449   obj_props[PROP_ROTATION_CENTER_Y] =
5450     g_param_spec_boxed ("rotation-center-y",
5451                         P_("Rotation Center Y"),
5452                         P_("The rotation center on the Y axis"),
5453                         CLUTTER_TYPE_VERTEX,
5454                         CLUTTER_PARAM_READWRITE);
5455
5456   /**
5457    * ClutterActor:rotation-center-z:
5458    *
5459    * The rotation center on the Z axis.
5460    *
5461    * Since: 0.6
5462    */
5463   obj_props[PROP_ROTATION_CENTER_Z] =
5464     g_param_spec_boxed ("rotation-center-z",
5465                         P_("Rotation Center Z"),
5466                         P_("The rotation center on the Z axis"),
5467                         CLUTTER_TYPE_VERTEX,
5468                         CLUTTER_PARAM_READWRITE);
5469
5470   /**
5471    * ClutterActor:rotation-center-z-gravity:
5472    *
5473    * The rotation center on the Z axis expressed as a #ClutterGravity.
5474    *
5475    * Since: 1.0
5476    */
5477   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5478     g_param_spec_enum ("rotation-center-z-gravity",
5479                        P_("Rotation Center Z Gravity"),
5480                        P_("Center point for rotation around the Z axis"),
5481                        CLUTTER_TYPE_GRAVITY,
5482                        CLUTTER_GRAVITY_NONE,
5483                        CLUTTER_PARAM_READWRITE);
5484
5485   /**
5486    * ClutterActor:anchor-x:
5487    *
5488    * The X coordinate of an actor's anchor point, relative to
5489    * the actor coordinate space, in pixels
5490    *
5491    * Since: 0.8
5492    */
5493   obj_props[PROP_ANCHOR_X] =
5494     g_param_spec_float ("anchor-x",
5495                         P_("Anchor X"),
5496                         P_("X coordinate of the anchor point"),
5497                         -G_MAXFLOAT, G_MAXFLOAT,
5498                         0,
5499                         CLUTTER_PARAM_READWRITE);
5500
5501   /**
5502    * ClutterActor:anchor-y:
5503    *
5504    * The Y coordinate of an actor's anchor point, relative to
5505    * the actor coordinate space, in pixels
5506    *
5507    * Since: 0.8
5508    */
5509   obj_props[PROP_ANCHOR_Y] =
5510     g_param_spec_float ("anchor-y",
5511                         P_("Anchor Y"),
5512                         P_("Y coordinate of the anchor point"),
5513                         -G_MAXFLOAT, G_MAXFLOAT,
5514                         0,
5515                         CLUTTER_PARAM_READWRITE);
5516
5517   /**
5518    * ClutterActor:anchor-gravity:
5519    *
5520    * The anchor point expressed as a #ClutterGravity
5521    *
5522    * Since: 1.0
5523    */
5524   obj_props[PROP_ANCHOR_GRAVITY] =
5525     g_param_spec_enum ("anchor-gravity",
5526                        P_("Anchor Gravity"),
5527                        P_("The anchor point as a ClutterGravity"),
5528                        CLUTTER_TYPE_GRAVITY,
5529                        CLUTTER_GRAVITY_NONE,
5530                        CLUTTER_PARAM_READWRITE);
5531
5532   /**
5533    * ClutterActor:show-on-set-parent:
5534    *
5535    * If %TRUE, the actor is automatically shown when parented.
5536    *
5537    * Calling clutter_actor_hide() on an actor which has not been
5538    * parented will set this property to %FALSE as a side effect.
5539    *
5540    * Since: 0.8
5541    */
5542   obj_props[PROP_SHOW_ON_SET_PARENT] =
5543     g_param_spec_boolean ("show-on-set-parent",
5544                           P_("Show on set parent"),
5545                           P_("Whether the actor is shown when parented"),
5546                           TRUE,
5547                           CLUTTER_PARAM_READWRITE);
5548
5549   /**
5550    * ClutterActor:clip-to-allocation:
5551    *
5552    * Whether the clip region should track the allocated area
5553    * of the actor.
5554    *
5555    * This property is ignored if a clip area has been explicitly
5556    * set using clutter_actor_set_clip().
5557    *
5558    * Since: 1.0
5559    */
5560   obj_props[PROP_CLIP_TO_ALLOCATION] =
5561     g_param_spec_boolean ("clip-to-allocation",
5562                           P_("Clip to Allocation"),
5563                           P_("Sets the clip region to track the actor's allocation"),
5564                           FALSE,
5565                           CLUTTER_PARAM_READWRITE);
5566
5567   /**
5568    * ClutterActor:text-direction:
5569    *
5570    * The direction of the text inside a #ClutterActor.
5571    *
5572    * Since: 1.0
5573    */
5574   obj_props[PROP_TEXT_DIRECTION] =
5575     g_param_spec_enum ("text-direction",
5576                        P_("Text Direction"),
5577                        P_("Direction of the text"),
5578                        CLUTTER_TYPE_TEXT_DIRECTION,
5579                        CLUTTER_TEXT_DIRECTION_LTR,
5580                        CLUTTER_PARAM_READWRITE);
5581
5582   /**
5583    * ClutterActor:has-pointer:
5584    *
5585    * Whether the actor contains the pointer of a #ClutterInputDevice
5586    * or not.
5587    *
5588    * Since: 1.2
5589    */
5590   obj_props[PROP_HAS_POINTER] =
5591     g_param_spec_boolean ("has-pointer",
5592                           P_("Has Pointer"),
5593                           P_("Whether the actor contains the pointer of an input device"),
5594                           FALSE,
5595                           CLUTTER_PARAM_READABLE);
5596
5597   /**
5598    * ClutterActor:actions:
5599    *
5600    * Adds a #ClutterAction to the actor
5601    *
5602    * Since: 1.4
5603    */
5604   obj_props[PROP_ACTIONS] =
5605     g_param_spec_object ("actions",
5606                          P_("Actions"),
5607                          P_("Adds an action to the actor"),
5608                          CLUTTER_TYPE_ACTION,
5609                          CLUTTER_PARAM_WRITABLE);
5610
5611   /**
5612    * ClutterActor:constraints:
5613    *
5614    * Adds a #ClutterConstraint to the actor
5615    *
5616    * Since: 1.4
5617    */
5618   obj_props[PROP_CONSTRAINTS] =
5619     g_param_spec_object ("constraints",
5620                          P_("Constraints"),
5621                          P_("Adds a constraint to the actor"),
5622                          CLUTTER_TYPE_CONSTRAINT,
5623                          CLUTTER_PARAM_WRITABLE);
5624
5625   /**
5626    * ClutterActor:effect:
5627    *
5628    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5629    *
5630    * Since: 1.4
5631    */
5632   obj_props[PROP_EFFECT] =
5633     g_param_spec_object ("effect",
5634                          P_("Effect"),
5635                          P_("Add an effect to be applied on the actor"),
5636                          CLUTTER_TYPE_EFFECT,
5637                          CLUTTER_PARAM_WRITABLE);
5638
5639   /**
5640    * ClutterActor:layout-manager:
5641    *
5642    * A delegate object for controlling the layout of the children of
5643    * an actor.
5644    *
5645    * Since: 1.10
5646    */
5647   obj_props[PROP_LAYOUT_MANAGER] =
5648     g_param_spec_object ("layout-manager",
5649                          P_("Layout Manager"),
5650                          P_("The object controlling the layout of an actor's children"),
5651                          CLUTTER_TYPE_LAYOUT_MANAGER,
5652                          CLUTTER_PARAM_READWRITE);
5653
5654
5655   /**
5656    * ClutterActor:x-align:
5657    *
5658    * The alignment of an actor on the X axis, if the actor has been given
5659    * extra space for its allocation.
5660    *
5661    * Since: 1.10
5662    */
5663   obj_props[PROP_X_ALIGN] =
5664     g_param_spec_enum ("x-align",
5665                        P_("X Alignment"),
5666                        P_("The alignment of the actor on the X axis within its allocation"),
5667                        CLUTTER_TYPE_ACTOR_ALIGN,
5668                        CLUTTER_ACTOR_ALIGN_FILL,
5669                        CLUTTER_PARAM_READWRITE);
5670
5671   /**
5672    * ClutterActor:y-align:
5673    *
5674    * The alignment of an actor on the Y axis, if the actor has been given
5675    * extra space for its allocation.
5676    *
5677    * Since: 1.10
5678    */
5679   obj_props[PROP_Y_ALIGN] =
5680     g_param_spec_enum ("y-align",
5681                        P_("Y Alignment"),
5682                        P_("The alignment of the actor on the Y axis within its allocation"),
5683                        CLUTTER_TYPE_ACTOR_ALIGN,
5684                        CLUTTER_ACTOR_ALIGN_FILL,
5685                        CLUTTER_PARAM_READWRITE);
5686
5687   /**
5688    * ClutterActor:margin-top:
5689    *
5690    * The margin (in pixels) from the top of the actor.
5691    *
5692    * This property adds a margin to the actor's preferred size; the margin
5693    * will be automatically taken into account when allocating the actor.
5694    *
5695    * Since: 1.10
5696    */
5697   obj_props[PROP_MARGIN_TOP] =
5698     g_param_spec_float ("margin-top",
5699                         P_("Margin Top"),
5700                         P_("Extra space at the top"),
5701                         0.0, G_MAXFLOAT,
5702                         0.0,
5703                         CLUTTER_PARAM_READWRITE);
5704
5705   /**
5706    * ClutterActor:margin-bottom:
5707    *
5708    * The margin (in pixels) from the bottom of the actor.
5709    *
5710    * This property adds a margin to the actor's preferred size; the margin
5711    * will be automatically taken into account when allocating the actor.
5712    *
5713    * Since: 1.10
5714    */
5715   obj_props[PROP_MARGIN_BOTTOM] =
5716     g_param_spec_float ("margin-bottom",
5717                         P_("Margin Bottom"),
5718                         P_("Extra space at the bottom"),
5719                         0.0, G_MAXFLOAT,
5720                         0.0,
5721                         CLUTTER_PARAM_READWRITE);
5722
5723   /**
5724    * ClutterActor:margin-left:
5725    *
5726    * The margin (in pixels) from the left of the actor.
5727    *
5728    * This property adds a margin to the actor's preferred size; the margin
5729    * will be automatically taken into account when allocating the actor.
5730    *
5731    * Since: 1.10
5732    */
5733   obj_props[PROP_MARGIN_LEFT] =
5734     g_param_spec_float ("margin-left",
5735                         P_("Margin Left"),
5736                         P_("Extra space at the left"),
5737                         0.0, G_MAXFLOAT,
5738                         0.0,
5739                         CLUTTER_PARAM_READWRITE);
5740
5741   /**
5742    * ClutterActor:margin-right:
5743    *
5744    * The margin (in pixels) from the right of the actor.
5745    *
5746    * This property adds a margin to the actor's preferred size; the margin
5747    * will be automatically taken into account when allocating the actor.
5748    *
5749    * Since: 1.10
5750    */
5751   obj_props[PROP_MARGIN_RIGHT] =
5752     g_param_spec_float ("margin-right",
5753                         P_("Margin Right"),
5754                         P_("Extra space at the right"),
5755                         0.0, G_MAXFLOAT,
5756                         0.0,
5757                         CLUTTER_PARAM_READWRITE);
5758
5759   /**
5760    * ClutterActor:background-color-set:
5761    *
5762    * Whether the #ClutterActor:background-color property has been set.
5763    *
5764    * Since: 1.10
5765    */
5766   obj_props[PROP_BACKGROUND_COLOR_SET] =
5767     g_param_spec_boolean ("background-color-set",
5768                           P_("Background Color Set"),
5769                           P_("Whether the background color is set"),
5770                           FALSE,
5771                           CLUTTER_PARAM_READABLE);
5772
5773   /**
5774    * ClutterActor:background-color:
5775    *
5776    * Paints a solid fill of the actor's allocation using the specified
5777    * color.
5778    *
5779    * Since: 1.10
5780    */
5781   obj_props[PROP_BACKGROUND_COLOR] =
5782     clutter_param_spec_color ("background-color",
5783                               P_("Background color"),
5784                               P_("The actor's background color"),
5785                               CLUTTER_COLOR_Transparent,
5786                               CLUTTER_PARAM_READWRITE);
5787
5788   /**
5789    * ClutterActor:first-child:
5790    *
5791    * The actor's first child.
5792    *
5793    * Since: 1.10
5794    */
5795   obj_props[PROP_FIRST_CHILD] =
5796     g_param_spec_object ("first-child",
5797                          P_("First Child"),
5798                          P_("The actor's first child"),
5799                          CLUTTER_TYPE_ACTOR,
5800                          CLUTTER_PARAM_READABLE);
5801
5802   /**
5803    * ClutterActor:last-child:
5804    *
5805    * The actor's last child.
5806    *
5807    * Since: 1.10
5808    */
5809   obj_props[PROP_LAST_CHILD] =
5810     g_param_spec_object ("last-child",
5811                          P_("Last Child"),
5812                          P_("The actor's last child"),
5813                          CLUTTER_TYPE_ACTOR,
5814                          CLUTTER_PARAM_READABLE);
5815
5816   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5817
5818   /**
5819    * ClutterActor::destroy:
5820    * @actor: the #ClutterActor which emitted the signal
5821    *
5822    * The ::destroy signal notifies that all references held on the
5823    * actor which emitted it should be released.
5824    *
5825    * The ::destroy signal should be used by all holders of a reference
5826    * on @actor.
5827    *
5828    * This signal might result in the finalization of the #ClutterActor
5829    * if all references are released.
5830    *
5831    * Composite actors and actors implementing the #ClutterContainer
5832    * interface should override the default implementation of the
5833    * class handler of this signal and call clutter_actor_destroy() on
5834    * their children. When overriding the default class handler, it is
5835    * required to chain up to the parent's implementation.
5836    *
5837    * Since: 0.2
5838    */
5839   actor_signals[DESTROY] =
5840     g_signal_new (I_("destroy"),
5841                   G_TYPE_FROM_CLASS (object_class),
5842                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5843                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5844                   NULL, NULL,
5845                   _clutter_marshal_VOID__VOID,
5846                   G_TYPE_NONE, 0);
5847   /**
5848    * ClutterActor::show:
5849    * @actor: the object which received the signal
5850    *
5851    * The ::show signal is emitted when an actor is visible and
5852    * rendered on the stage.
5853    *
5854    * Since: 0.2
5855    */
5856   actor_signals[SHOW] =
5857     g_signal_new (I_("show"),
5858                   G_TYPE_FROM_CLASS (object_class),
5859                   G_SIGNAL_RUN_FIRST,
5860                   G_STRUCT_OFFSET (ClutterActorClass, show),
5861                   NULL, NULL,
5862                   _clutter_marshal_VOID__VOID,
5863                   G_TYPE_NONE, 0);
5864   /**
5865    * ClutterActor::hide:
5866    * @actor: the object which received the signal
5867    *
5868    * The ::hide signal is emitted when an actor is no longer rendered
5869    * on the stage.
5870    *
5871    * Since: 0.2
5872    */
5873   actor_signals[HIDE] =
5874     g_signal_new (I_("hide"),
5875                   G_TYPE_FROM_CLASS (object_class),
5876                   G_SIGNAL_RUN_FIRST,
5877                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5878                   NULL, NULL,
5879                   _clutter_marshal_VOID__VOID,
5880                   G_TYPE_NONE, 0);
5881   /**
5882    * ClutterActor::parent-set:
5883    * @actor: the object which received the signal
5884    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5885    *
5886    * This signal is emitted when the parent of the actor changes.
5887    *
5888    * Since: 0.2
5889    */
5890   actor_signals[PARENT_SET] =
5891     g_signal_new (I_("parent-set"),
5892                   G_TYPE_FROM_CLASS (object_class),
5893                   G_SIGNAL_RUN_LAST,
5894                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5895                   NULL, NULL,
5896                   _clutter_marshal_VOID__OBJECT,
5897                   G_TYPE_NONE, 1,
5898                   CLUTTER_TYPE_ACTOR);
5899
5900   /**
5901    * ClutterActor::queue-redraw:
5902    * @actor: the actor we're bubbling the redraw request through
5903    * @origin: the actor which initiated the redraw request
5904    *
5905    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5906    * is called on @origin.
5907    *
5908    * The default implementation for #ClutterActor chains up to the
5909    * parent actor and queues a redraw on the parent, thus "bubbling"
5910    * the redraw queue up through the actor graph. The default
5911    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5912    * in a main loop idle handler.
5913    *
5914    * Note that the @origin actor may be the stage, or a container; it
5915    * does not have to be a leaf node in the actor graph.
5916    *
5917    * Toolkits embedding a #ClutterStage which require a redraw and
5918    * relayout cycle can stop the emission of this signal using the
5919    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
5920    * themselves, like:
5921    *
5922    * |[
5923    *   static void
5924    *   on_redraw_complete (gpointer data)
5925    *   {
5926    *     ClutterStage *stage = data;
5927    *
5928    *     /&ast; execute the Clutter drawing pipeline &ast;/
5929    *     clutter_stage_ensure_redraw (stage);
5930    *   }
5931    *
5932    *   static void
5933    *   on_stage_queue_redraw (ClutterStage *stage)
5934    *   {
5935    *     /&ast; this prevents the default handler to run &ast;/
5936    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
5937    *
5938    *     /&ast; queue a redraw with the host toolkit and call
5939    *      &ast; a function when the redraw has been completed
5940    *      &ast;/
5941    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
5942    *   }
5943    * ]|
5944    *
5945    * <note><para>This signal is emitted before the Clutter paint
5946    * pipeline is executed. If you want to know when the pipeline has
5947    * been completed you should connect to the ::paint signal on the
5948    * Stage with g_signal_connect_after().</para></note>
5949    *
5950    * Since: 1.0
5951    */
5952   actor_signals[QUEUE_REDRAW] =
5953     g_signal_new (I_("queue-redraw"),
5954                   G_TYPE_FROM_CLASS (object_class),
5955                   G_SIGNAL_RUN_LAST,
5956                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
5957                   NULL, NULL,
5958                   _clutter_marshal_VOID__OBJECT,
5959                   G_TYPE_NONE, 1,
5960                   CLUTTER_TYPE_ACTOR);
5961
5962   /**
5963    * ClutterActor::queue-relayout
5964    * @actor: the actor being queued for relayout
5965    *
5966    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
5967    * is called on an actor.
5968    *
5969    * The default implementation for #ClutterActor chains up to the
5970    * parent actor and queues a relayout on the parent, thus "bubbling"
5971    * the relayout queue up through the actor graph.
5972    *
5973    * The main purpose of this signal is to allow relayout to be propagated
5974    * properly in the procense of #ClutterClone actors. Applications will
5975    * not normally need to connect to this signal.
5976    *
5977    * Since: 1.2
5978    */
5979   actor_signals[QUEUE_RELAYOUT] =
5980     g_signal_new (I_("queue-relayout"),
5981                   G_TYPE_FROM_CLASS (object_class),
5982                   G_SIGNAL_RUN_LAST,
5983                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
5984                   NULL, NULL,
5985                   _clutter_marshal_VOID__VOID,
5986                   G_TYPE_NONE, 0);
5987
5988   /**
5989    * ClutterActor::event:
5990    * @actor: the actor which received the event
5991    * @event: a #ClutterEvent
5992    *
5993    * The ::event signal is emitted each time an event is received
5994    * by the @actor. This signal will be emitted on every actor,
5995    * following the hierarchy chain, until it reaches the top-level
5996    * container (the #ClutterStage).
5997    *
5998    * Return value: %TRUE if the event has been handled by the actor,
5999    *   or %FALSE to continue the emission.
6000    *
6001    * Since: 0.6
6002    */
6003   actor_signals[EVENT] =
6004     g_signal_new (I_("event"),
6005                   G_TYPE_FROM_CLASS (object_class),
6006                   G_SIGNAL_RUN_LAST,
6007                   G_STRUCT_OFFSET (ClutterActorClass, event),
6008                   _clutter_boolean_handled_accumulator, NULL,
6009                   _clutter_marshal_BOOLEAN__BOXED,
6010                   G_TYPE_BOOLEAN, 1,
6011                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6012   /**
6013    * ClutterActor::button-press-event:
6014    * @actor: the actor which received the event
6015    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6016    *
6017    * The ::button-press-event signal is emitted each time a mouse button
6018    * is pressed on @actor.
6019    *
6020    * Return value: %TRUE if the event has been handled by the actor,
6021    *   or %FALSE to continue the emission.
6022    *
6023    * Since: 0.6
6024    */
6025   actor_signals[BUTTON_PRESS_EVENT] =
6026     g_signal_new (I_("button-press-event"),
6027                   G_TYPE_FROM_CLASS (object_class),
6028                   G_SIGNAL_RUN_LAST,
6029                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6030                   _clutter_boolean_handled_accumulator, NULL,
6031                   _clutter_marshal_BOOLEAN__BOXED,
6032                   G_TYPE_BOOLEAN, 1,
6033                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6034   /**
6035    * ClutterActor::button-release-event:
6036    * @actor: the actor which received the event
6037    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6038    *
6039    * The ::button-release-event signal is emitted each time a mouse button
6040    * is released on @actor.
6041    *
6042    * Return value: %TRUE if the event has been handled by the actor,
6043    *   or %FALSE to continue the emission.
6044    *
6045    * Since: 0.6
6046    */
6047   actor_signals[BUTTON_RELEASE_EVENT] =
6048     g_signal_new (I_("button-release-event"),
6049                   G_TYPE_FROM_CLASS (object_class),
6050                   G_SIGNAL_RUN_LAST,
6051                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6052                   _clutter_boolean_handled_accumulator, NULL,
6053                   _clutter_marshal_BOOLEAN__BOXED,
6054                   G_TYPE_BOOLEAN, 1,
6055                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6056   /**
6057    * ClutterActor::scroll-event:
6058    * @actor: the actor which received the event
6059    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6060    *
6061    * The ::scroll-event signal is emitted each time the mouse is
6062    * scrolled on @actor
6063    *
6064    * Return value: %TRUE if the event has been handled by the actor,
6065    *   or %FALSE to continue the emission.
6066    *
6067    * Since: 0.6
6068    */
6069   actor_signals[SCROLL_EVENT] =
6070     g_signal_new (I_("scroll-event"),
6071                   G_TYPE_FROM_CLASS (object_class),
6072                   G_SIGNAL_RUN_LAST,
6073                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6074                   _clutter_boolean_handled_accumulator, NULL,
6075                   _clutter_marshal_BOOLEAN__BOXED,
6076                   G_TYPE_BOOLEAN, 1,
6077                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6078   /**
6079    * ClutterActor::key-press-event:
6080    * @actor: the actor which received the event
6081    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6082    *
6083    * The ::key-press-event signal is emitted each time a keyboard button
6084    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6085    *
6086    * Return value: %TRUE if the event has been handled by the actor,
6087    *   or %FALSE to continue the emission.
6088    *
6089    * Since: 0.6
6090    */
6091   actor_signals[KEY_PRESS_EVENT] =
6092     g_signal_new (I_("key-press-event"),
6093                   G_TYPE_FROM_CLASS (object_class),
6094                   G_SIGNAL_RUN_LAST,
6095                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6096                   _clutter_boolean_handled_accumulator, NULL,
6097                   _clutter_marshal_BOOLEAN__BOXED,
6098                   G_TYPE_BOOLEAN, 1,
6099                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6100   /**
6101    * ClutterActor::key-release-event:
6102    * @actor: the actor which received the event
6103    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6104    *
6105    * The ::key-release-event signal is emitted each time a keyboard button
6106    * is released while @actor has key focus (see
6107    * clutter_stage_set_key_focus()).
6108    *
6109    * Return value: %TRUE if the event has been handled by the actor,
6110    *   or %FALSE to continue the emission.
6111    *
6112    * Since: 0.6
6113    */
6114   actor_signals[KEY_RELEASE_EVENT] =
6115     g_signal_new (I_("key-release-event"),
6116                   G_TYPE_FROM_CLASS (object_class),
6117                   G_SIGNAL_RUN_LAST,
6118                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6119                   _clutter_boolean_handled_accumulator, NULL,
6120                   _clutter_marshal_BOOLEAN__BOXED,
6121                   G_TYPE_BOOLEAN, 1,
6122                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6123   /**
6124    * ClutterActor::motion-event:
6125    * @actor: the actor which received the event
6126    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6127    *
6128    * The ::motion-event signal is emitted each time the mouse pointer is
6129    * moved over @actor.
6130    *
6131    * Return value: %TRUE if the event has been handled by the actor,
6132    *   or %FALSE to continue the emission.
6133    *
6134    * Since: 0.6
6135    */
6136   actor_signals[MOTION_EVENT] =
6137     g_signal_new (I_("motion-event"),
6138                   G_TYPE_FROM_CLASS (object_class),
6139                   G_SIGNAL_RUN_LAST,
6140                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6141                   _clutter_boolean_handled_accumulator, NULL,
6142                   _clutter_marshal_BOOLEAN__BOXED,
6143                   G_TYPE_BOOLEAN, 1,
6144                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6145
6146   /**
6147    * ClutterActor::key-focus-in:
6148    * @actor: the actor which now has key focus
6149    *
6150    * The ::key-focus-in signal is emitted when @actor receives key focus.
6151    *
6152    * Since: 0.6
6153    */
6154   actor_signals[KEY_FOCUS_IN] =
6155     g_signal_new (I_("key-focus-in"),
6156                   G_TYPE_FROM_CLASS (object_class),
6157                   G_SIGNAL_RUN_LAST,
6158                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6159                   NULL, NULL,
6160                   _clutter_marshal_VOID__VOID,
6161                   G_TYPE_NONE, 0);
6162
6163   /**
6164    * ClutterActor::key-focus-out:
6165    * @actor: the actor which now has key focus
6166    *
6167    * The ::key-focus-out signal is emitted when @actor loses key focus.
6168    *
6169    * Since: 0.6
6170    */
6171   actor_signals[KEY_FOCUS_OUT] =
6172     g_signal_new (I_("key-focus-out"),
6173                   G_TYPE_FROM_CLASS (object_class),
6174                   G_SIGNAL_RUN_LAST,
6175                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6176                   NULL, NULL,
6177                   _clutter_marshal_VOID__VOID,
6178                   G_TYPE_NONE, 0);
6179
6180   /**
6181    * ClutterActor::enter-event:
6182    * @actor: the actor which the pointer has entered.
6183    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6184    *
6185    * The ::enter-event signal is emitted when the pointer enters the @actor
6186    *
6187    * Return value: %TRUE if the event has been handled by the actor,
6188    *   or %FALSE to continue the emission.
6189    *
6190    * Since: 0.6
6191    */
6192   actor_signals[ENTER_EVENT] =
6193     g_signal_new (I_("enter-event"),
6194                   G_TYPE_FROM_CLASS (object_class),
6195                   G_SIGNAL_RUN_LAST,
6196                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6197                   _clutter_boolean_handled_accumulator, NULL,
6198                   _clutter_marshal_BOOLEAN__BOXED,
6199                   G_TYPE_BOOLEAN, 1,
6200                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6201
6202   /**
6203    * ClutterActor::leave-event:
6204    * @actor: the actor which the pointer has left
6205    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6206    *
6207    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6208    *
6209    * Return value: %TRUE if the event has been handled by the actor,
6210    *   or %FALSE to continue the emission.
6211    *
6212    * Since: 0.6
6213    */
6214   actor_signals[LEAVE_EVENT] =
6215     g_signal_new (I_("leave-event"),
6216                   G_TYPE_FROM_CLASS (object_class),
6217                   G_SIGNAL_RUN_LAST,
6218                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6219                   _clutter_boolean_handled_accumulator, NULL,
6220                   _clutter_marshal_BOOLEAN__BOXED,
6221                   G_TYPE_BOOLEAN, 1,
6222                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6223
6224   /**
6225    * ClutterActor::captured-event:
6226    * @actor: the actor which received the signal
6227    * @event: a #ClutterEvent
6228    *
6229    * The ::captured-event signal is emitted when an event is captured
6230    * by Clutter. This signal will be emitted starting from the top-level
6231    * container (the #ClutterStage) to the actor which received the event
6232    * going down the hierarchy. This signal can be used to intercept every
6233    * event before the specialized events (like
6234    * ClutterActor::button-press-event or ::key-released-event) are
6235    * emitted.
6236    *
6237    * Return value: %TRUE if the event has been handled by the actor,
6238    *   or %FALSE to continue the emission.
6239    *
6240    * Since: 0.6
6241    */
6242   actor_signals[CAPTURED_EVENT] =
6243     g_signal_new (I_("captured-event"),
6244                   G_TYPE_FROM_CLASS (object_class),
6245                   G_SIGNAL_RUN_LAST,
6246                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6247                   _clutter_boolean_handled_accumulator, NULL,
6248                   _clutter_marshal_BOOLEAN__BOXED,
6249                   G_TYPE_BOOLEAN, 1,
6250                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6251
6252   /**
6253    * ClutterActor::paint:
6254    * @actor: the #ClutterActor that received the signal
6255    *
6256    * The ::paint signal is emitted each time an actor is being painted.
6257    *
6258    * Subclasses of #ClutterActor should override the class signal handler
6259    * and paint themselves in that function.
6260    *
6261    * It is possible to connect a handler to the ::paint signal in order
6262    * to set up some custom aspect of a paint.
6263    *
6264    * Since: 0.8
6265    */
6266   actor_signals[PAINT] =
6267     g_signal_new (I_("paint"),
6268                   G_TYPE_FROM_CLASS (object_class),
6269                   G_SIGNAL_RUN_LAST,
6270                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6271                   NULL, NULL,
6272                   _clutter_marshal_VOID__VOID,
6273                   G_TYPE_NONE, 0);
6274   /**
6275    * ClutterActor::realize:
6276    * @actor: the #ClutterActor that received the signal
6277    *
6278    * The ::realize signal is emitted each time an actor is being
6279    * realized.
6280    *
6281    * Since: 0.8
6282    */
6283   actor_signals[REALIZE] =
6284     g_signal_new (I_("realize"),
6285                   G_TYPE_FROM_CLASS (object_class),
6286                   G_SIGNAL_RUN_LAST,
6287                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6288                   NULL, NULL,
6289                   _clutter_marshal_VOID__VOID,
6290                   G_TYPE_NONE, 0);
6291   /**
6292    * ClutterActor::unrealize:
6293    * @actor: the #ClutterActor that received the signal
6294    *
6295    * The ::unrealize signal is emitted each time an actor is being
6296    * unrealized.
6297    *
6298    * Since: 0.8
6299    */
6300   actor_signals[UNREALIZE] =
6301     g_signal_new (I_("unrealize"),
6302                   G_TYPE_FROM_CLASS (object_class),
6303                   G_SIGNAL_RUN_LAST,
6304                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6305                   NULL, NULL,
6306                   _clutter_marshal_VOID__VOID,
6307                   G_TYPE_NONE, 0);
6308
6309   /**
6310    * ClutterActor::pick:
6311    * @actor: the #ClutterActor that received the signal
6312    * @color: the #ClutterColor to be used when picking
6313    *
6314    * The ::pick signal is emitted each time an actor is being painted
6315    * in "pick mode". The pick mode is used to identify the actor during
6316    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6317    * The actor should paint its shape using the passed @pick_color.
6318    *
6319    * Subclasses of #ClutterActor should override the class signal handler
6320    * and paint themselves in that function.
6321    *
6322    * It is possible to connect a handler to the ::pick signal in order
6323    * to set up some custom aspect of a paint in pick mode.
6324    *
6325    * Since: 1.0
6326    */
6327   actor_signals[PICK] =
6328     g_signal_new (I_("pick"),
6329                   G_TYPE_FROM_CLASS (object_class),
6330                   G_SIGNAL_RUN_LAST,
6331                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6332                   NULL, NULL,
6333                   _clutter_marshal_VOID__BOXED,
6334                   G_TYPE_NONE, 1,
6335                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6336
6337   /**
6338    * ClutterActor::allocation-changed:
6339    * @actor: the #ClutterActor that emitted the signal
6340    * @box: a #ClutterActorBox with the new allocation
6341    * @flags: #ClutterAllocationFlags for the allocation
6342    *
6343    * The ::allocation-changed signal is emitted when the
6344    * #ClutterActor:allocation property changes. Usually, application
6345    * code should just use the notifications for the :allocation property
6346    * but if you want to track the allocation flags as well, for instance
6347    * to know whether the absolute origin of @actor changed, then you might
6348    * want use this signal instead.
6349    *
6350    * Since: 1.0
6351    */
6352   actor_signals[ALLOCATION_CHANGED] =
6353     g_signal_new (I_("allocation-changed"),
6354                   G_TYPE_FROM_CLASS (object_class),
6355                   G_SIGNAL_RUN_LAST,
6356                   0,
6357                   NULL, NULL,
6358                   _clutter_marshal_VOID__BOXED_FLAGS,
6359                   G_TYPE_NONE, 2,
6360                   CLUTTER_TYPE_ACTOR_BOX,
6361                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6362 }
6363
6364 static void
6365 clutter_actor_init (ClutterActor *self)
6366 {
6367   ClutterActorPrivate *priv;
6368
6369   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6370
6371   priv->id = _clutter_context_acquire_id (self);
6372   priv->pick_id = -1;
6373
6374   priv->opacity = 0xff;
6375   priv->show_on_set_parent = TRUE;
6376
6377   priv->needs_width_request = TRUE;
6378   priv->needs_height_request = TRUE;
6379   priv->needs_allocation = TRUE;
6380
6381   priv->cached_width_age = 1;
6382   priv->cached_height_age = 1;
6383
6384   priv->opacity_override = -1;
6385   priv->enable_model_view_transform = TRUE;
6386
6387   /* Initialize an empty paint volume to start with */
6388   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6389   priv->last_paint_volume_valid = TRUE;
6390
6391   priv->transform_valid = FALSE;
6392 }
6393
6394 /**
6395  * clutter_actor_new:
6396  *
6397  * Creates a new #ClutterActor.
6398  *
6399  * A newly created actor has a floating reference, which will be sunk
6400  * when it is added to another actor.
6401  *
6402  * Return value: (transfer full): the newly created #ClutterActor
6403  *
6404  * Since: 1.10
6405  */
6406 ClutterActor *
6407 clutter_actor_new (void)
6408 {
6409   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6410 }
6411
6412 /**
6413  * clutter_actor_destroy:
6414  * @self: a #ClutterActor
6415  *
6416  * Destroys an actor.  When an actor is destroyed, it will break any
6417  * references it holds to other objects.  If the actor is inside a
6418  * container, the actor will be removed.
6419  *
6420  * When you destroy a container, its children will be destroyed as well.
6421  *
6422  * Note: you cannot destroy the #ClutterStage returned by
6423  * clutter_stage_get_default().
6424  */
6425 void
6426 clutter_actor_destroy (ClutterActor *self)
6427 {
6428   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6429
6430   g_object_ref (self);
6431
6432   /* avoid recursion while destroying */
6433   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6434     {
6435       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6436
6437       g_object_run_dispose (G_OBJECT (self));
6438
6439       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6440     }
6441
6442   g_object_unref (self);
6443 }
6444
6445 void
6446 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6447                                     ClutterPaintVolume *clip)
6448 {
6449   ClutterActorPrivate *priv = self->priv;
6450   ClutterPaintVolume *pv;
6451   gboolean clipped;
6452
6453   /* If we've been explicitly passed a clip volume then there's
6454    * nothing more to calculate, but otherwise the only thing we know
6455    * is that the change is constrained to the given actor.
6456    *
6457    * The idea is that if we know the paint volume for where the actor
6458    * was last drawn (in eye coordinates) and we also have the paint
6459    * volume for where it will be drawn next (in actor coordinates)
6460    * then if we queue a redraw for both these volumes that will cover
6461    * everything that needs to be redrawn to clear the old view and
6462    * show the latest view of the actor.
6463    *
6464    * Don't clip this redraw if we don't know what position we had for
6465    * the previous redraw since we don't know where to set the clip so
6466    * it will clear the actor as it is currently.
6467    */
6468   if (clip)
6469     {
6470       _clutter_actor_set_queue_redraw_clip (self, clip);
6471       clipped = TRUE;
6472     }
6473   else if (G_LIKELY (priv->last_paint_volume_valid))
6474     {
6475       pv = _clutter_actor_get_paint_volume_mutable (self);
6476       if (pv)
6477         {
6478           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6479
6480           /* make sure we redraw the actors old position... */
6481           _clutter_actor_set_queue_redraw_clip (stage,
6482                                                 &priv->last_paint_volume);
6483           _clutter_actor_signal_queue_redraw (stage, stage);
6484           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6485
6486           /* XXX: Ideally the redraw signal would take a clip volume
6487            * argument, but that would be an ABI break. Until we can
6488            * break the ABI we pass the argument out-of-band
6489            */
6490
6491           /* setup the clip for the actors new position... */
6492           _clutter_actor_set_queue_redraw_clip (self, pv);
6493           clipped = TRUE;
6494         }
6495       else
6496         clipped = FALSE;
6497     }
6498   else
6499     clipped = FALSE;
6500
6501   _clutter_actor_signal_queue_redraw (self, self);
6502
6503   /* Just in case anyone is manually firing redraw signals without
6504    * using the public queue_redraw() API we are careful to ensure that
6505    * our out-of-band clip member is cleared before returning...
6506    *
6507    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6508    */
6509   if (G_LIKELY (clipped))
6510     _clutter_actor_set_queue_redraw_clip (self, NULL);
6511
6512   priv->queue_redraw_entry = NULL;
6513 }
6514
6515 static void
6516 _clutter_actor_get_allocation_clip (ClutterActor *self,
6517                                     ClutterActorBox *clip)
6518 {
6519   ClutterActorBox allocation;
6520
6521   /* XXX: we don't care if we get an out of date allocation here
6522    * because clutter_actor_queue_redraw_with_clip knows to ignore
6523    * the clip if the actor's allocation is invalid.
6524    *
6525    * This is noted because clutter_actor_get_allocation_box does some
6526    * unnecessary work to support buggy code with a comment suggesting
6527    * that it could be changed later which would be good for this use
6528    * case!
6529    */
6530   clutter_actor_get_allocation_box (self, &allocation);
6531
6532   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6533    * actor's own coordinate space but the allocation is in parent
6534    * coordinates */
6535   clip->x1 = 0;
6536   clip->y1 = 0;
6537   clip->x2 = allocation.x2 - allocation.x1;
6538   clip->y2 = allocation.y2 - allocation.y1;
6539 }
6540
6541 void
6542 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6543                                   ClutterRedrawFlags  flags,
6544                                   ClutterPaintVolume *volume,
6545                                   ClutterEffect      *effect)
6546 {
6547   ClutterActorPrivate *priv = self->priv;
6548   ClutterPaintVolume allocation_pv;
6549   ClutterPaintVolume *pv;
6550   gboolean should_free_pv;
6551   ClutterActor *stage;
6552
6553   /* Here's an outline of the actor queue redraw mechanism:
6554    *
6555    * The process starts in one of the following two functions which
6556    * are wrappers for this function:
6557    * clutter_actor_queue_redraw
6558    * _clutter_actor_queue_redraw_with_clip
6559    *
6560    * additionally, an effect can queue a redraw by wrapping this
6561    * function in clutter_effect_queue_rerun
6562    *
6563    * This functions queues an entry in a list associated with the
6564    * stage which is a list of actors that queued a redraw while
6565    * updating the timelines, performing layouting and processing other
6566    * mainloop sources before the next paint starts.
6567    *
6568    * We aim to minimize the processing done at this point because
6569    * there is a good chance other events will happen while updating
6570    * the scenegraph that would invalidate any expensive work we might
6571    * otherwise try to do here. For example we don't try and resolve
6572    * the screen space bounding box of an actor at this stage so as to
6573    * minimize how much of the screen redraw because it's possible
6574    * something else will happen which will force a full redraw anyway.
6575    *
6576    * When all updates are complete and we come to paint the stage then
6577    * we iterate this list and actually emit the "queue-redraw" signals
6578    * for each of the listed actors which will bubble up to the stage
6579    * for each actor and at that point we will transform the actors
6580    * paint volume into screen coordinates to determine the clip region
6581    * for what needs to be redrawn in the next paint.
6582    *
6583    * Besides minimizing redundant work another reason for this
6584    * deferred design is that it's more likely we will be able to
6585    * determine the paint volume of an actor once we've finished
6586    * updating the scenegraph because its allocation should be up to
6587    * date. NB: If we can't determine an actors paint volume then we
6588    * can't automatically queue a clipped redraw which can make a big
6589    * difference to performance.
6590    *
6591    * So the control flow goes like this:
6592    * One of clutter_actor_queue_redraw,
6593    *        _clutter_actor_queue_redraw_with_clip
6594    *     or clutter_effect_queue_rerun
6595    *
6596    * then control moves to:
6597    *   _clutter_stage_queue_actor_redraw
6598    *
6599    * later during _clutter_stage_do_update, once relayouting is done
6600    * and the scenegraph has been updated we will call:
6601    * _clutter_stage_finish_queue_redraws
6602    *
6603    * _clutter_stage_finish_queue_redraws will call
6604    * _clutter_actor_finish_queue_redraw for each listed actor.
6605    * Note: actors *are* allowed to queue further redraws during this
6606    * process (considering clone actors or texture_new_from_actor which
6607    * respond to their source queueing a redraw by queuing a redraw
6608    * themselves). We repeat the process until the list is empty.
6609    *
6610    * This will result in the "queue-redraw" signal being fired for
6611    * each actor which will pass control to the default signal handler:
6612    * clutter_actor_real_queue_redraw
6613    *
6614    * This will bubble up to the stages handler:
6615    * clutter_stage_real_queue_redraw
6616    *
6617    * clutter_stage_real_queue_redraw will transform the actors paint
6618    * volume into screen space and add it as a clip region for the next
6619    * paint.
6620    */
6621
6622   /* ignore queueing a redraw for actors being destroyed */
6623   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6624     return;
6625
6626   stage = _clutter_actor_get_stage_internal (self);
6627
6628   /* Ignore queueing a redraw for actors not descended from a stage */
6629   if (stage == NULL)
6630     return;
6631
6632   /* ignore queueing a redraw on stages that are being destroyed */
6633   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6634     return;
6635
6636   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6637     {
6638       ClutterActorBox allocation_clip;
6639       ClutterVertex origin;
6640
6641       /* If the actor doesn't have a valid allocation then we will
6642        * queue a full stage redraw. */
6643       if (priv->needs_allocation)
6644         {
6645           /* NB: NULL denotes an undefined clip which will result in a
6646            * full redraw... */
6647           _clutter_actor_set_queue_redraw_clip (self, NULL);
6648           _clutter_actor_signal_queue_redraw (self, self);
6649           return;
6650         }
6651
6652       _clutter_paint_volume_init_static (&allocation_pv, self);
6653       pv = &allocation_pv;
6654
6655       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6656
6657       origin.x = allocation_clip.x1;
6658       origin.y = allocation_clip.y1;
6659       origin.z = 0;
6660       clutter_paint_volume_set_origin (pv, &origin);
6661       clutter_paint_volume_set_width (pv,
6662                                       allocation_clip.x2 - allocation_clip.x1);
6663       clutter_paint_volume_set_height (pv,
6664                                        allocation_clip.y2 -
6665                                        allocation_clip.y1);
6666       should_free_pv = TRUE;
6667     }
6668   else
6669     {
6670       pv = volume;
6671       should_free_pv = FALSE;
6672     }
6673
6674   self->priv->queue_redraw_entry =
6675     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6676                                        priv->queue_redraw_entry,
6677                                        self,
6678                                        pv);
6679
6680   if (should_free_pv)
6681     clutter_paint_volume_free (pv);
6682
6683   /* If this is the first redraw queued then we can directly use the
6684      effect parameter */
6685   if (!priv->is_dirty)
6686     priv->effect_to_redraw = effect;
6687   /* Otherwise we need to merge it with the existing effect parameter */
6688   else if (effect != NULL)
6689     {
6690       /* If there's already an effect then we need to use whichever is
6691          later in the chain of actors. Otherwise a full redraw has
6692          already been queued on the actor so we need to ignore the
6693          effect parameter */
6694       if (priv->effect_to_redraw != NULL)
6695         {
6696           if (priv->effects == NULL)
6697             g_warning ("Redraw queued with an effect that is "
6698                        "not applied to the actor");
6699           else
6700             {
6701               const GList *l;
6702
6703               for (l = _clutter_meta_group_peek_metas (priv->effects);
6704                    l != NULL;
6705                    l = l->next)
6706                 {
6707                   if (l->data == priv->effect_to_redraw ||
6708                       l->data == effect)
6709                     priv->effect_to_redraw = l->data;
6710                 }
6711             }
6712         }
6713     }
6714   else
6715     {
6716       /* If no effect is specified then we need to redraw the whole
6717          actor */
6718       priv->effect_to_redraw = NULL;
6719     }
6720
6721   priv->is_dirty = TRUE;
6722 }
6723
6724 /**
6725  * clutter_actor_queue_redraw:
6726  * @self: A #ClutterActor
6727  *
6728  * Queues up a redraw of an actor and any children. The redraw occurs
6729  * once the main loop becomes idle (after the current batch of events
6730  * has been processed, roughly).
6731  *
6732  * Applications rarely need to call this, as redraws are handled
6733  * automatically by modification functions.
6734  *
6735  * This function will not do anything if @self is not visible, or
6736  * if the actor is inside an invisible part of the scenegraph.
6737  *
6738  * Also be aware that painting is a NOP for actors with an opacity of
6739  * 0
6740  *
6741  * When you are implementing a custom actor you must queue a redraw
6742  * whenever some private state changes that will affect painting or
6743  * picking of your actor.
6744  */
6745 void
6746 clutter_actor_queue_redraw (ClutterActor *self)
6747 {
6748   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6749
6750   _clutter_actor_queue_redraw_full (self,
6751                                     0, /* flags */
6752                                     NULL, /* clip volume */
6753                                     NULL /* effect */);
6754 }
6755
6756 /*< private >
6757  * _clutter_actor_queue_redraw_with_clip:
6758  * @self: A #ClutterActor
6759  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6760  *   this queue redraw.
6761  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6762  *   redrawn or %NULL if you are just using a @flag to state your
6763  *   desired clipping.
6764  *
6765  * Queues up a clipped redraw of an actor and any children. The redraw
6766  * occurs once the main loop becomes idle (after the current batch of
6767  * events has been processed, roughly).
6768  *
6769  * If no flags are given the clip volume is defined by @volume
6770  * specified in actor coordinates and tells Clutter that only content
6771  * within this volume has been changed so Clutter can optionally
6772  * optimize the redraw.
6773  *
6774  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6775  * should be %NULL and this tells Clutter to use the actor's current
6776  * allocation as a clip box. This flag can only be used for 2D actors,
6777  * because any actor with depth may be projected outside its
6778  * allocation.
6779  *
6780  * Applications rarely need to call this, as redraws are handled
6781  * automatically by modification functions.
6782  *
6783  * This function will not do anything if @self is not visible, or if
6784  * the actor is inside an invisible part of the scenegraph.
6785  *
6786  * Also be aware that painting is a NOP for actors with an opacity of
6787  * 0
6788  *
6789  * When you are implementing a custom actor you must queue a redraw
6790  * whenever some private state changes that will affect painting or
6791  * picking of your actor.
6792  */
6793 void
6794 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6795                                        ClutterRedrawFlags  flags,
6796                                        ClutterPaintVolume *volume)
6797 {
6798   _clutter_actor_queue_redraw_full (self,
6799                                     flags, /* flags */
6800                                     volume, /* clip volume */
6801                                     NULL /* effect */);
6802 }
6803
6804 static void
6805 _clutter_actor_queue_only_relayout (ClutterActor *self)
6806 {
6807   ClutterActorPrivate *priv = self->priv;
6808
6809   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6810     return;
6811
6812   if (priv->needs_width_request &&
6813       priv->needs_height_request &&
6814       priv->needs_allocation)
6815     return; /* save some cpu cycles */
6816
6817 #if CLUTTER_ENABLE_DEBUG
6818   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6819     {
6820       g_warning ("The actor '%s' is currently inside an allocation "
6821                  "cycle; calling clutter_actor_queue_relayout() is "
6822                  "not recommended",
6823                  _clutter_actor_get_debug_name (self));
6824     }
6825 #endif /* CLUTTER_ENABLE_DEBUG */
6826
6827   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6828 }
6829
6830 /**
6831  * clutter_actor_queue_redraw_with_clip:
6832  * @self: a #ClutterActor
6833  * @clip: (allow-none): a rectangular clip region, or %NULL
6834  *
6835  * Queues a redraw on @self limited to a specific, actor-relative
6836  * rectangular area.
6837  *
6838  * If @clip is %NULL this function is equivalent to
6839  * clutter_actor_queue_redraw().
6840  *
6841  * Since: 1.10
6842  */
6843 void
6844 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6845                                       const cairo_rectangle_int_t *clip)
6846 {
6847   ClutterPaintVolume volume;
6848   ClutterVertex origin;
6849
6850   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6851
6852   if (clip == NULL)
6853     {
6854       clutter_actor_queue_redraw (self);
6855       return;
6856     }
6857
6858   _clutter_paint_volume_init_static (&volume, self);
6859
6860   origin.x = clip->x;
6861   origin.y = clip->y;
6862   origin.z = 0.0f;
6863
6864   clutter_paint_volume_set_origin (&volume, &origin);
6865   clutter_paint_volume_set_width (&volume, clip->width);
6866   clutter_paint_volume_set_height (&volume, clip->height);
6867
6868   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6869
6870   clutter_paint_volume_free (&volume);
6871 }
6872
6873 /**
6874  * clutter_actor_queue_relayout:
6875  * @self: A #ClutterActor
6876  *
6877  * Indicates that the actor's size request or other layout-affecting
6878  * properties may have changed. This function is used inside #ClutterActor
6879  * subclass implementations, not by applications directly.
6880  *
6881  * Queueing a new layout automatically queues a redraw as well.
6882  *
6883  * Since: 0.8
6884  */
6885 void
6886 clutter_actor_queue_relayout (ClutterActor *self)
6887 {
6888   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6889
6890   _clutter_actor_queue_only_relayout (self);
6891   clutter_actor_queue_redraw (self);
6892 }
6893
6894 /**
6895  * clutter_actor_get_preferred_size:
6896  * @self: a #ClutterActor
6897  * @min_width_p: (out) (allow-none): return location for the minimum
6898  *   width, or %NULL
6899  * @min_height_p: (out) (allow-none): return location for the minimum
6900  *   height, or %NULL
6901  * @natural_width_p: (out) (allow-none): return location for the natural
6902  *   width, or %NULL
6903  * @natural_height_p: (out) (allow-none): return location for the natural
6904  *   height, or %NULL
6905  *
6906  * Computes the preferred minimum and natural size of an actor, taking into
6907  * account the actor's geometry management (either height-for-width
6908  * or width-for-height).
6909  *
6910  * The width and height used to compute the preferred height and preferred
6911  * width are the actor's natural ones.
6912  *
6913  * If you need to control the height for the preferred width, or the width for
6914  * the preferred height, you should use clutter_actor_get_preferred_width()
6915  * and clutter_actor_get_preferred_height(), and check the actor's preferred
6916  * geometry management using the #ClutterActor:request-mode property.
6917  *
6918  * Since: 0.8
6919  */
6920 void
6921 clutter_actor_get_preferred_size (ClutterActor *self,
6922                                   gfloat       *min_width_p,
6923                                   gfloat       *min_height_p,
6924                                   gfloat       *natural_width_p,
6925                                   gfloat       *natural_height_p)
6926 {
6927   ClutterActorPrivate *priv;
6928   gfloat min_width, min_height;
6929   gfloat natural_width, natural_height;
6930
6931   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6932
6933   priv = self->priv;
6934
6935   min_width = min_height = 0;
6936   natural_width = natural_height = 0;
6937
6938   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
6939     {
6940       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
6941       clutter_actor_get_preferred_width (self, -1,
6942                                          &min_width,
6943                                          &natural_width);
6944       clutter_actor_get_preferred_height (self, natural_width,
6945                                           &min_height,
6946                                           &natural_height);
6947     }
6948   else
6949     {
6950       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
6951       clutter_actor_get_preferred_height (self, -1,
6952                                           &min_height,
6953                                           &natural_height);
6954       clutter_actor_get_preferred_width (self, natural_height,
6955                                          &min_width,
6956                                          &natural_width);
6957     }
6958
6959   if (min_width_p)
6960     *min_width_p = min_width;
6961
6962   if (min_height_p)
6963     *min_height_p = min_height;
6964
6965   if (natural_width_p)
6966     *natural_width_p = natural_width;
6967
6968   if (natural_height_p)
6969     *natural_height_p = natural_height;
6970 }
6971
6972 /*< private >
6973  * effective_align:
6974  * @align: a #ClutterActorAlign
6975  * @direction: a #ClutterTextDirection
6976  *
6977  * Retrieves the correct alignment depending on the text direction
6978  *
6979  * Return value: the effective alignment
6980  */
6981 static ClutterActorAlign
6982 effective_align (ClutterActorAlign    align,
6983                  ClutterTextDirection direction)
6984 {
6985   ClutterActorAlign res;
6986
6987   switch (align)
6988     {
6989     case CLUTTER_ACTOR_ALIGN_START:
6990       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
6991           ? CLUTTER_ACTOR_ALIGN_END
6992           : CLUTTER_ACTOR_ALIGN_START;
6993       break;
6994
6995     case CLUTTER_ACTOR_ALIGN_END:
6996       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
6997           ? CLUTTER_ACTOR_ALIGN_START
6998           : CLUTTER_ACTOR_ALIGN_END;
6999       break;
7000
7001     default:
7002       res = align;
7003       break;
7004     }
7005
7006   return res;
7007 }
7008
7009 static inline void
7010 adjust_for_margin (float  margin_start,
7011                    float  margin_end,
7012                    float *minimum_size,
7013                    float *natural_size,
7014                    float *allocated_start,
7015                    float *allocated_end)
7016 {
7017   *minimum_size -= (margin_start + margin_end);
7018   *natural_size -= (margin_start + margin_end);
7019   *allocated_start += margin_start;
7020   *allocated_end -= margin_end;
7021 }
7022
7023 static inline void
7024 adjust_for_alignment (ClutterActorAlign  alignment,
7025                       float              natural_size,
7026                       float             *allocated_start,
7027                       float             *allocated_end)
7028 {
7029   float allocated_size = *allocated_end - *allocated_start;
7030
7031   switch (alignment)
7032     {
7033     case CLUTTER_ACTOR_ALIGN_FILL:
7034       /* do nothing */
7035       break;
7036
7037     case CLUTTER_ACTOR_ALIGN_START:
7038       /* keep start */
7039       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7040       break;
7041
7042     case CLUTTER_ACTOR_ALIGN_END:
7043       if (allocated_size > natural_size)
7044         {
7045           *allocated_start += (allocated_size - natural_size);
7046           *allocated_end = *allocated_start + natural_size;
7047         }
7048       break;
7049
7050     case CLUTTER_ACTOR_ALIGN_CENTER:
7051       if (allocated_size > natural_size)
7052         {
7053           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7054           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7055         }
7056       break;
7057     }
7058 }
7059
7060 /*< private >
7061  * clutter_actor_adjust_width:
7062  * @self: a #ClutterActor
7063  * @minimum_width: (inout): the actor's preferred minimum width, which
7064  *   will be adjusted depending on the margin
7065  * @natural_width: (inout): the actor's preferred natural width, which
7066  *   will be adjusted depending on the margin
7067  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7068  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7069  *
7070  * Adjusts the preferred and allocated position and size of an actor,
7071  * depending on the margin and alignment properties.
7072  */
7073 static void
7074 clutter_actor_adjust_width (ClutterActor *self,
7075                             gfloat       *minimum_width,
7076                             gfloat       *natural_width,
7077                             gfloat       *adjusted_x1,
7078                             gfloat       *adjusted_x2)
7079 {
7080   ClutterTextDirection text_dir;
7081   const ClutterLayoutInfo *info;
7082
7083   info = _clutter_actor_get_layout_info_or_defaults (self);
7084   text_dir = clutter_actor_get_text_direction (self);
7085
7086   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7087
7088   /* this will tweak natural_width to remove the margin, so that
7089    * adjust_for_alignment() will use the correct size
7090    */
7091   adjust_for_margin (info->margin.left, info->margin.right,
7092                      minimum_width, natural_width,
7093                      adjusted_x1, adjusted_x2);
7094
7095   adjust_for_alignment (effective_align (info->x_align, text_dir),
7096                         *natural_width,
7097                         adjusted_x1, adjusted_x2);
7098 }
7099
7100 /*< private >
7101  * clutter_actor_adjust_height:
7102  * @self: a #ClutterActor
7103  * @minimum_height: (inout): the actor's preferred minimum height, which
7104  *   will be adjusted depending on the margin
7105  * @natural_height: (inout): the actor's preferred natural height, which
7106  *   will be adjusted depending on the margin
7107  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7108  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7109  *
7110  * Adjusts the preferred and allocated position and size of an actor,
7111  * depending on the margin and alignment properties.
7112  */
7113 static void
7114 clutter_actor_adjust_height (ClutterActor *self,
7115                              gfloat       *minimum_height,
7116                              gfloat       *natural_height,
7117                              gfloat       *adjusted_y1,
7118                              gfloat       *adjusted_y2)
7119 {
7120   const ClutterLayoutInfo *info;
7121
7122   info = _clutter_actor_get_layout_info_or_defaults (self);
7123
7124   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7125
7126   /* this will tweak natural_height to remove the margin, so that
7127    * adjust_for_alignment() will use the correct size
7128    */
7129   adjust_for_margin (info->margin.top, info->margin.bottom,
7130                      minimum_height, natural_height,
7131                      adjusted_y1,
7132                      adjusted_y2);
7133
7134   /* we don't use effective_align() here, because text direction
7135    * only affects the horizontal axis
7136    */
7137   adjust_for_alignment (info->y_align,
7138                         *natural_height,
7139                         adjusted_y1,
7140                         adjusted_y2);
7141
7142 }
7143
7144 /* looks for a cached size request for this for_size. If not
7145  * found, returns the oldest entry so it can be overwritten */
7146 static gboolean
7147 _clutter_actor_get_cached_size_request (gfloat         for_size,
7148                                         SizeRequest   *cached_size_requests,
7149                                         SizeRequest  **result)
7150 {
7151   guint i;
7152
7153   *result = &cached_size_requests[0];
7154
7155   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7156     {
7157       SizeRequest *sr;
7158
7159       sr = &cached_size_requests[i];
7160
7161       if (sr->age > 0 &&
7162           sr->for_size == for_size)
7163         {
7164           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7165           *result = sr;
7166           return TRUE;
7167         }
7168       else if (sr->age < (*result)->age)
7169         {
7170           *result = sr;
7171         }
7172     }
7173
7174   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7175
7176   return FALSE;
7177 }
7178
7179 /**
7180  * clutter_actor_get_preferred_width:
7181  * @self: A #ClutterActor
7182  * @for_height: available height when computing the preferred width,
7183  *   or a negative value to indicate that no height is defined
7184  * @min_width_p: (out) (allow-none): return location for minimum width,
7185  *   or %NULL
7186  * @natural_width_p: (out) (allow-none): return location for the natural
7187  *   width, or %NULL
7188  *
7189  * Computes the requested minimum and natural widths for an actor,
7190  * optionally depending on the specified height, or if they are
7191  * already computed, returns the cached values.
7192  *
7193  * An actor may not get its request - depending on the layout
7194  * manager that's in effect.
7195  *
7196  * A request should not incorporate the actor's scale or anchor point;
7197  * those transformations do not affect layout, only rendering.
7198  *
7199  * Since: 0.8
7200  */
7201 void
7202 clutter_actor_get_preferred_width (ClutterActor *self,
7203                                    gfloat        for_height,
7204                                    gfloat       *min_width_p,
7205                                    gfloat       *natural_width_p)
7206 {
7207   float request_min_width, request_natural_width;
7208   SizeRequest *cached_size_request;
7209   const ClutterLayoutInfo *info;
7210   ClutterActorPrivate *priv;
7211   gboolean found_in_cache;
7212
7213   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7214
7215   priv = self->priv;
7216
7217   info = _clutter_actor_get_layout_info_or_defaults (self);
7218
7219   /* we shortcircuit the case of a fixed size set using set_width() */
7220   if (priv->min_width_set && priv->natural_width_set)
7221     {
7222       if (min_width_p != NULL)
7223         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7224
7225       if (natural_width_p != NULL)
7226         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7227
7228       return;
7229     }
7230
7231   /* the remaining cases are:
7232    *
7233    *   - either min_width or natural_width have been set
7234    *   - neither min_width or natural_width have been set
7235    *
7236    * in both cases, we go through the cache (and through the actor in case
7237    * of cache misses) and determine the authoritative value depending on
7238    * the *_set flags.
7239    */
7240
7241   if (!priv->needs_width_request)
7242     {
7243       found_in_cache =
7244         _clutter_actor_get_cached_size_request (for_height,
7245                                                 priv->width_requests,
7246                                                 &cached_size_request);
7247     }
7248   else
7249     {
7250       /* if the actor needs a width request we use the first slot */
7251       found_in_cache = FALSE;
7252       cached_size_request = &priv->width_requests[0];
7253     }
7254
7255   if (!found_in_cache)
7256     {
7257       gfloat minimum_width, natural_width;
7258       ClutterActorClass *klass;
7259
7260       minimum_width = natural_width = 0;
7261
7262       /* adjust for the margin */
7263       if (for_height >= 0)
7264         {
7265           for_height -= (info->margin.top + info->margin.bottom);
7266           if (for_height < 0)
7267             for_height = 0;
7268         }
7269
7270       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7271
7272       klass = CLUTTER_ACTOR_GET_CLASS (self);
7273       klass->get_preferred_width (self, for_height,
7274                                   &minimum_width,
7275                                   &natural_width);
7276
7277       /* adjust for the margin */
7278       minimum_width += (info->margin.left + info->margin.right);
7279       natural_width += (info->margin.left + info->margin.right);
7280
7281       /* Due to accumulated float errors, it's better not to warn
7282        * on this, but just fix it.
7283        */
7284       if (natural_width < minimum_width)
7285         natural_width = minimum_width;
7286
7287       cached_size_request->min_size = minimum_width;
7288       cached_size_request->natural_size = natural_width;
7289       cached_size_request->for_size = for_height;
7290       cached_size_request->age = priv->cached_width_age;
7291
7292       priv->cached_width_age += 1;
7293       priv->needs_width_request = FALSE;
7294     }
7295
7296   if (!priv->min_width_set)
7297     request_min_width = cached_size_request->min_size;
7298   else
7299     request_min_width = info->min_width;
7300
7301   if (!priv->natural_width_set)
7302     request_natural_width = cached_size_request->natural_size;
7303   else
7304     request_natural_width = info->natural_width;
7305
7306   if (min_width_p)
7307     *min_width_p = request_min_width;
7308
7309   if (natural_width_p)
7310     *natural_width_p = request_natural_width;
7311 }
7312
7313 /**
7314  * clutter_actor_get_preferred_height:
7315  * @self: A #ClutterActor
7316  * @for_width: available width to assume in computing desired height,
7317  *   or a negative value to indicate that no width is defined
7318  * @min_height_p: (out) (allow-none): return location for minimum height,
7319  *   or %NULL
7320  * @natural_height_p: (out) (allow-none): return location for natural
7321  *   height, or %NULL
7322  *
7323  * Computes the requested minimum and natural heights for an actor,
7324  * or if they are already computed, returns the cached values.
7325  *
7326  * An actor may not get its request - depending on the layout
7327  * manager that's in effect.
7328  *
7329  * A request should not incorporate the actor's scale or anchor point;
7330  * those transformations do not affect layout, only rendering.
7331  *
7332  * Since: 0.8
7333  */
7334 void
7335 clutter_actor_get_preferred_height (ClutterActor *self,
7336                                     gfloat        for_width,
7337                                     gfloat       *min_height_p,
7338                                     gfloat       *natural_height_p)
7339 {
7340   float request_min_height, request_natural_height;
7341   SizeRequest *cached_size_request;
7342   const ClutterLayoutInfo *info;
7343   ClutterActorPrivate *priv;
7344   gboolean found_in_cache;
7345
7346   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7347
7348   priv = self->priv;
7349
7350   info = _clutter_actor_get_layout_info_or_defaults (self);
7351
7352   /* we shortcircuit the case of a fixed size set using set_height() */
7353   if (priv->min_height_set && priv->natural_height_set)
7354     {
7355       if (min_height_p != NULL)
7356         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7357
7358       if (natural_height_p != NULL)
7359         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7360
7361       return;
7362     }
7363
7364   /* the remaining cases are:
7365    *
7366    *   - either min_height or natural_height have been set
7367    *   - neither min_height or natural_height have been set
7368    *
7369    * in both cases, we go through the cache (and through the actor in case
7370    * of cache misses) and determine the authoritative value depending on
7371    * the *_set flags.
7372    */
7373
7374   if (!priv->needs_height_request)
7375     {
7376       found_in_cache =
7377         _clutter_actor_get_cached_size_request (for_width,
7378                                                 priv->height_requests,
7379                                                 &cached_size_request);
7380     }
7381   else
7382     {
7383       found_in_cache = FALSE;
7384       cached_size_request = &priv->height_requests[0];
7385     }
7386
7387   if (!found_in_cache)
7388     {
7389       gfloat minimum_height, natural_height;
7390       ClutterActorClass *klass;
7391
7392       minimum_height = natural_height = 0;
7393
7394       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7395
7396       /* adjust for margin */
7397       if (for_width >= 0)
7398         {
7399           for_width -= (info->margin.left + info->margin.right);
7400           if (for_width < 0)
7401             for_width = 0;
7402         }
7403
7404       klass = CLUTTER_ACTOR_GET_CLASS (self);
7405       klass->get_preferred_height (self, for_width,
7406                                    &minimum_height,
7407                                    &natural_height);
7408
7409       /* adjust for margin */
7410       minimum_height += (info->margin.top + info->margin.bottom);
7411       natural_height += (info->margin.top + info->margin.bottom);
7412
7413       /* Due to accumulated float errors, it's better not to warn
7414        * on this, but just fix it.
7415        */
7416       if (natural_height < minimum_height)
7417         natural_height = minimum_height;
7418
7419       cached_size_request->min_size = minimum_height;
7420       cached_size_request->natural_size = natural_height;
7421       cached_size_request->for_size = for_width;
7422       cached_size_request->age = priv->cached_height_age;
7423
7424       priv->cached_height_age += 1;
7425       priv->needs_height_request = FALSE;
7426     }
7427
7428   if (!priv->min_height_set)
7429     request_min_height = cached_size_request->min_size;
7430   else
7431     request_min_height = info->min_height;
7432
7433   if (!priv->natural_height_set)
7434     request_natural_height = cached_size_request->natural_size;
7435   else
7436     request_natural_height = info->natural_height;
7437
7438   if (min_height_p)
7439     *min_height_p = request_min_height;
7440
7441   if (natural_height_p)
7442     *natural_height_p = request_natural_height;
7443 }
7444
7445 /**
7446  * clutter_actor_get_allocation_box:
7447  * @self: A #ClutterActor
7448  * @box: (out): the function fills this in with the actor's allocation
7449  *
7450  * Gets the layout box an actor has been assigned. The allocation can
7451  * only be assumed valid inside a paint() method; anywhere else, it
7452  * may be out-of-date.
7453  *
7454  * An allocation does not incorporate the actor's scale or anchor point;
7455  * those transformations do not affect layout, only rendering.
7456  *
7457  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7458  * of functions inside the implementation of the get_preferred_width()
7459  * or get_preferred_height() virtual functions.</note>
7460  *
7461  * Since: 0.8
7462  */
7463 void
7464 clutter_actor_get_allocation_box (ClutterActor    *self,
7465                                   ClutterActorBox *box)
7466 {
7467   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7468
7469   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7470    * which limits calling get_allocation to inside paint() basically; or
7471    * we can 2) force a layout, which could be expensive if someone calls
7472    * get_allocation somewhere silly; or we can 3) just return the latest
7473    * value, allowing it to be out-of-date, and assume people know what
7474    * they are doing.
7475    *
7476    * The least-surprises approach that keeps existing code working is
7477    * likely to be 2). People can end up doing some inefficient things,
7478    * though, and in general code that requires 2) is probably broken.
7479    */
7480
7481   /* this implements 2) */
7482   if (G_UNLIKELY (self->priv->needs_allocation))
7483     {
7484       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7485
7486       /* do not queue a relayout on an unparented actor */
7487       if (stage)
7488         _clutter_stage_maybe_relayout (stage);
7489     }
7490
7491   /* commenting out the code above and just keeping this assigment
7492    * implements 3)
7493    */
7494   *box = self->priv->allocation;
7495 }
7496
7497 /**
7498  * clutter_actor_get_allocation_geometry:
7499  * @self: A #ClutterActor
7500  * @geom: (out): allocation geometry in pixels
7501  *
7502  * Gets the layout box an actor has been assigned.  The allocation can
7503  * only be assumed valid inside a paint() method; anywhere else, it
7504  * may be out-of-date.
7505  *
7506  * An allocation does not incorporate the actor's scale or anchor point;
7507  * those transformations do not affect layout, only rendering.
7508  *
7509  * The returned rectangle is in pixels.
7510  *
7511  * Since: 0.8
7512  */
7513 void
7514 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7515                                        ClutterGeometry *geom)
7516 {
7517   ClutterActorBox box;
7518
7519   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7520   g_return_if_fail (geom != NULL);
7521
7522   clutter_actor_get_allocation_box (self, &box);
7523
7524   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7525   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7526   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7527   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7528 }
7529
7530 static void
7531 clutter_actor_update_constraints (ClutterActor    *self,
7532                                   ClutterActorBox *allocation)
7533 {
7534   ClutterActorPrivate *priv = self->priv;
7535   const GList *constraints, *l;
7536
7537   if (priv->constraints == NULL)
7538     return;
7539
7540   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7541   for (l = constraints; l != NULL; l = l->next)
7542     {
7543       ClutterConstraint *constraint = l->data;
7544       ClutterActorMeta *meta = l->data;
7545
7546       if (clutter_actor_meta_get_enabled (meta))
7547         {
7548           _clutter_constraint_update_allocation (constraint,
7549                                                  self,
7550                                                  allocation);
7551         }
7552     }
7553 }
7554
7555 /*< private >
7556  * clutter_actor_adjust_allocation:
7557  * @self: a #ClutterActor
7558  * @allocation: (inout): the allocation to adjust
7559  *
7560  * Adjusts the passed allocation box taking into account the actor's
7561  * layout information, like alignment, expansion, and margin.
7562  */
7563 static void
7564 clutter_actor_adjust_allocation (ClutterActor    *self,
7565                                  ClutterActorBox *allocation)
7566 {
7567   ClutterActorBox adj_allocation;
7568   float alloc_width, alloc_height;
7569   float min_width, min_height;
7570   float nat_width, nat_height;
7571   ClutterRequestMode req_mode;
7572
7573   adj_allocation = *allocation;
7574
7575   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7576
7577   /* we want to hit the cache, so we use the public API */
7578   req_mode = clutter_actor_get_request_mode (self);
7579
7580   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7581     {
7582       clutter_actor_get_preferred_width (self, -1,
7583                                          &min_width,
7584                                          &nat_width);
7585       clutter_actor_get_preferred_height (self, alloc_width,
7586                                           &min_height,
7587                                           &nat_height);
7588     }
7589   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7590     {
7591       clutter_actor_get_preferred_height (self, -1,
7592                                           &min_height,
7593                                           &nat_height);
7594       clutter_actor_get_preferred_height (self, alloc_height,
7595                                           &min_width,
7596                                           &nat_width);
7597     }
7598
7599 #ifdef CLUTTER_ENABLE_DEBUG
7600   /* warn about underallocations */
7601   if (_clutter_diagnostic_enabled () &&
7602       (floorf (min_width - alloc_width) > 0 ||
7603        floorf (min_height - alloc_height) > 0))
7604     {
7605       ClutterActor *parent = clutter_actor_get_parent (self);
7606
7607       /* the only actors that are allowed to be underallocated are the Stage,
7608        * as it doesn't have an implicit size, and Actors that specifically
7609        * told us that they want to opt-out from layout control mechanisms
7610        * through the NO_LAYOUT escape hatch.
7611        */
7612       if (parent != NULL &&
7613           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7614         {
7615           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7616                      "of %.2f x %.2f from its parent actor '%s', but its "
7617                      "requested minimum size is of %.2f x %.2f",
7618                      _clutter_actor_get_debug_name (self),
7619                      alloc_width, alloc_height,
7620                      _clutter_actor_get_debug_name (parent),
7621                      min_width, min_height);
7622         }
7623     }
7624 #endif
7625
7626   clutter_actor_adjust_width (self,
7627                               &min_width,
7628                               &nat_width,
7629                               &adj_allocation.x1,
7630                               &adj_allocation.x2);
7631
7632   clutter_actor_adjust_height (self,
7633                                &min_height,
7634                                &nat_height,
7635                                &adj_allocation.y1,
7636                                &adj_allocation.y2);
7637
7638   /* we maintain the invariant that an allocation cannot be adjusted
7639    * to be outside the parent-given box
7640    */
7641   if (adj_allocation.x1 < allocation->x1 ||
7642       adj_allocation.y1 < allocation->y1 ||
7643       adj_allocation.x2 > allocation->x2 ||
7644       adj_allocation.y2 > allocation->y2)
7645     {
7646       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7647                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7648                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7649                  _clutter_actor_get_debug_name (self),
7650                  adj_allocation.x1, adj_allocation.y1,
7651                  adj_allocation.x2 - adj_allocation.x1,
7652                  adj_allocation.y2 - adj_allocation.y1,
7653                  allocation->x1, allocation->y1,
7654                  allocation->x2 - allocation->x1,
7655                  allocation->y2 - allocation->y1);
7656       return;
7657     }
7658
7659   *allocation = adj_allocation;
7660 }
7661
7662 /**
7663  * clutter_actor_allocate:
7664  * @self: A #ClutterActor
7665  * @box: new allocation of the actor, in parent-relative coordinates
7666  * @flags: flags that control the allocation
7667  *
7668  * Called by the parent of an actor to assign the actor its size.
7669  * Should never be called by applications (except when implementing
7670  * a container or layout manager).
7671  *
7672  * Actors can know from their allocation box whether they have moved
7673  * with respect to their parent actor. The @flags parameter describes
7674  * additional information about the allocation, for instance whether
7675  * the parent has moved with respect to the stage, for example because
7676  * a grandparent's origin has moved.
7677  *
7678  * Since: 0.8
7679  */
7680 void
7681 clutter_actor_allocate (ClutterActor           *self,
7682                         const ClutterActorBox  *box,
7683                         ClutterAllocationFlags  flags)
7684 {
7685   ClutterActorPrivate *priv;
7686   ClutterActorClass *klass;
7687   ClutterActorBox old_allocation, real_allocation;
7688   gboolean origin_changed, child_moved, size_changed;
7689   gboolean stage_allocation_changed;
7690
7691   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7692   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7693     {
7694       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7695                  "which isn't a descendent of the stage!\n",
7696                  self, _clutter_actor_get_debug_name (self));
7697       return;
7698     }
7699
7700   priv = self->priv;
7701
7702   old_allocation = priv->allocation;
7703   real_allocation = *box;
7704
7705   /* constraints are allowed to modify the allocation only here; we do
7706    * this prior to all the other checks so that we can bail out if the
7707    * allocation did not change
7708    */
7709   clutter_actor_update_constraints (self, &real_allocation);
7710
7711   /* adjust the allocation depending on the align/margin properties */
7712   clutter_actor_adjust_allocation (self, &real_allocation);
7713
7714   if (real_allocation.x2 < real_allocation.x1 ||
7715       real_allocation.y2 < real_allocation.y1)
7716     {
7717       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7718                  _clutter_actor_get_debug_name (self),
7719                  real_allocation.x2 - real_allocation.x1,
7720                  real_allocation.y2 - real_allocation.y1);
7721     }
7722
7723   /* we allow 0-sized actors, but not negative-sized ones */
7724   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7725   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7726
7727   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7728
7729   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7730                  real_allocation.y1 != old_allocation.y1);
7731
7732   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7733                   real_allocation.y2 != old_allocation.y2);
7734
7735   if (origin_changed || child_moved || size_changed)
7736     stage_allocation_changed = TRUE;
7737   else
7738     stage_allocation_changed = FALSE;
7739
7740   /* If we get an allocation "out of the blue"
7741    * (we did not queue relayout), then we want to
7742    * ignore it. But if we have needs_allocation set,
7743    * we want to guarantee that allocate() virtual
7744    * method is always called, i.e. that queue_relayout()
7745    * always results in an allocate() invocation on
7746    * an actor.
7747    *
7748    * The optimization here is to avoid re-allocating
7749    * actors that did not queue relayout and were
7750    * not moved.
7751    */
7752   if (!priv->needs_allocation && !stage_allocation_changed)
7753     {
7754       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7755       return;
7756     }
7757
7758   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7759    * clutter_actor_allocate(), it indicates whether the parent has its
7760    * absolute origin moved; when passed in to ClutterActor::allocate()
7761    * virtual method though, it indicates whether the child has its
7762    * absolute origin moved.  So we set it when child_moved is TRUE
7763    */
7764   if (child_moved)
7765     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7766
7767   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7768
7769   klass = CLUTTER_ACTOR_GET_CLASS (self);
7770   klass->allocate (self, &real_allocation, flags);
7771
7772   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7773
7774   if (stage_allocation_changed)
7775     clutter_actor_queue_redraw (self);
7776 }
7777
7778 /**
7779  * clutter_actor_set_allocation:
7780  * @self: a #ClutterActor
7781  * @box: a #ClutterActorBox
7782  * @flags: allocation flags
7783  *
7784  * Stores the allocation of @self as defined by @box.
7785  *
7786  * This function can only be called from within the implementation of
7787  * the #ClutterActorClass.allocate() virtual function.
7788  *
7789  * The allocation should have been adjusted to take into account constraints,
7790  * alignment, and margin properties. If you are implementing a #ClutterActor
7791  * subclass that provides its own layout management policy for its children
7792  * instead of using a #ClutterLayoutManager delegate, you should not call
7793  * this function on the children of @self; instead, you should call
7794  * clutter_actor_allocate(), which will adjust the allocation box for
7795  * you.
7796  *
7797  * This function should only be used by subclasses of #ClutterActor
7798  * that wish to store their allocation but cannot chain up to the
7799  * parent's implementation; the default implementation of the
7800  * #ClutterActorClass.allocate() virtual function will call this
7801  * function.
7802  *
7803  * It is important to note that, while chaining up was the recommended
7804  * behaviour for #ClutterActor subclasses prior to the introduction of
7805  * this function, it is recommended to call clutter_actor_set_allocation()
7806  * instead.
7807  *
7808  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7809  * to handle the allocation of its children, this function will call
7810  * the clutter_layout_manager_allocate() function only if the
7811  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7812  * expected that the subclass will call clutter_layout_manager_allocate()
7813  * by itself. For instance, the following code:
7814  *
7815  * |[
7816  * static void
7817  * my_actor_allocate (ClutterActor *actor,
7818  *                    const ClutterActorBox *allocation,
7819  *                    ClutterAllocationFlags flags)
7820  * {
7821  *   ClutterActorBox new_alloc;
7822  *   ClutterAllocationFlags new_flags;
7823  *
7824  *   adjust_allocation (allocation, &amp;new_alloc);
7825  *
7826  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7827  *
7828  *   /&ast; this will use the layout manager set on the actor &ast;/
7829  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7830  * }
7831  * ]|
7832  *
7833  * is equivalent to this:
7834  *
7835  * |[
7836  * static void
7837  * my_actor_allocate (ClutterActor *actor,
7838  *                    const ClutterActorBox *allocation,
7839  *                    ClutterAllocationFlags flags)
7840  * {
7841  *   ClutterLayoutManager *layout;
7842  *   ClutterActorBox new_alloc;
7843  *
7844  *   adjust_allocation (allocation, &amp;new_alloc);
7845  *
7846  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7847  *
7848  *   layout = clutter_actor_get_layout_manager (actor);
7849  *   clutter_layout_manager_allocate (layout,
7850  *                                    CLUTTER_CONTAINER (actor),
7851  *                                    &amp;new_alloc,
7852  *                                    flags);
7853  * }
7854  * ]|
7855  *
7856  * Since: 1.10
7857  */
7858 void
7859 clutter_actor_set_allocation (ClutterActor           *self,
7860                               const ClutterActorBox  *box,
7861                               ClutterAllocationFlags  flags)
7862 {
7863   ClutterActorPrivate *priv;
7864   gboolean changed;
7865
7866   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7867   g_return_if_fail (box != NULL);
7868
7869   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7870     {
7871       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7872                   "can only be called from within the implementation of "
7873                   "the ClutterActor::allocate() virtual function.");
7874       return;
7875     }
7876
7877   priv = self->priv;
7878
7879   g_object_freeze_notify (G_OBJECT (self));
7880
7881   changed = clutter_actor_set_allocation_internal (self, box, flags);
7882
7883   /* we allocate our children before we notify changes in our geometry,
7884    * so that people connecting to properties will be able to get valid
7885    * data out of the sub-tree of the scene graph that has this actor at
7886    * the root.
7887    */
7888   clutter_actor_maybe_layout_children (self, box, flags);
7889
7890   if (changed)
7891     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7892                    &priv->allocation,
7893                    priv->allocation_flags);
7894
7895   g_object_thaw_notify (G_OBJECT (self));
7896 }
7897
7898 /**
7899  * clutter_actor_set_geometry:
7900  * @self: A #ClutterActor
7901  * @geometry: A #ClutterGeometry
7902  *
7903  * Sets the actor's fixed position and forces its minimum and natural
7904  * size, in pixels. This means the untransformed actor will have the
7905  * given geometry. This is the same as calling clutter_actor_set_position()
7906  * and clutter_actor_set_size().
7907  *
7908  * Deprecated: 1.10: Use clutter_actor_set_position() and
7909  *   clutter_actor_set_size() instead.
7910  */
7911 void
7912 clutter_actor_set_geometry (ClutterActor          *self,
7913                             const ClutterGeometry *geometry)
7914 {
7915   g_object_freeze_notify (G_OBJECT (self));
7916
7917   clutter_actor_set_position (self, geometry->x, geometry->y);
7918   clutter_actor_set_size (self, geometry->width, geometry->height);
7919
7920   g_object_thaw_notify (G_OBJECT (self));
7921 }
7922
7923 /**
7924  * clutter_actor_get_geometry:
7925  * @self: A #ClutterActor
7926  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
7927  *
7928  * Gets the size and position of an actor relative to its parent
7929  * actor. This is the same as calling clutter_actor_get_position() and
7930  * clutter_actor_get_size(). It tries to "do what you mean" and get the
7931  * requested size and position if the actor's allocation is invalid.
7932  *
7933  * Deprecated: 1.10: Use clutter_actor_get_position() and
7934  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
7935  *   instead.
7936  */
7937 void
7938 clutter_actor_get_geometry (ClutterActor    *self,
7939                             ClutterGeometry *geometry)
7940 {
7941   gfloat x, y, width, height;
7942
7943   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7944   g_return_if_fail (geometry != NULL);
7945
7946   clutter_actor_get_position (self, &x, &y);
7947   clutter_actor_get_size (self, &width, &height);
7948
7949   geometry->x = (int) x;
7950   geometry->y = (int) y;
7951   geometry->width = (int) width;
7952   geometry->height = (int) height;
7953 }
7954
7955 /**
7956  * clutter_actor_set_position:
7957  * @self: A #ClutterActor
7958  * @x: New left position of actor in pixels.
7959  * @y: New top position of actor in pixels.
7960  *
7961  * Sets the actor's fixed position in pixels relative to any parent
7962  * actor.
7963  *
7964  * If a layout manager is in use, this position will override the
7965  * layout manager and force a fixed position.
7966  */
7967 void
7968 clutter_actor_set_position (ClutterActor *self,
7969                             gfloat        x,
7970                             gfloat        y)
7971 {
7972   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7973
7974   g_object_freeze_notify (G_OBJECT (self));
7975
7976   clutter_actor_set_x (self, x);
7977   clutter_actor_set_y (self, y);
7978
7979   g_object_thaw_notify (G_OBJECT (self));
7980 }
7981
7982 /**
7983  * clutter_actor_get_fixed_position_set:
7984  * @self: A #ClutterActor
7985  *
7986  * Checks whether an actor has a fixed position set (and will thus be
7987  * unaffected by any layout manager).
7988  *
7989  * Return value: %TRUE if the fixed position is set on the actor
7990  *
7991  * Since: 0.8
7992  */
7993 gboolean
7994 clutter_actor_get_fixed_position_set (ClutterActor *self)
7995 {
7996   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
7997
7998   return self->priv->position_set;
7999 }
8000
8001 /**
8002  * clutter_actor_set_fixed_position_set:
8003  * @self: A #ClutterActor
8004  * @is_set: whether to use fixed position
8005  *
8006  * Sets whether an actor has a fixed position set (and will thus be
8007  * unaffected by any layout manager).
8008  *
8009  * Since: 0.8
8010  */
8011 void
8012 clutter_actor_set_fixed_position_set (ClutterActor *self,
8013                                       gboolean      is_set)
8014 {
8015   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8016
8017   if (self->priv->position_set == (is_set != FALSE))
8018     return;
8019
8020   self->priv->position_set = is_set != FALSE;
8021   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8022
8023   clutter_actor_queue_relayout (self);
8024 }
8025
8026 /**
8027  * clutter_actor_move_by:
8028  * @self: A #ClutterActor
8029  * @dx: Distance to move Actor on X axis.
8030  * @dy: Distance to move Actor on Y axis.
8031  *
8032  * Moves an actor by the specified distance relative to its current
8033  * position in pixels.
8034  *
8035  * This function modifies the fixed position of an actor and thus removes
8036  * it from any layout management. Another way to move an actor is with an
8037  * anchor point, see clutter_actor_set_anchor_point().
8038  *
8039  * Since: 0.2
8040  */
8041 void
8042 clutter_actor_move_by (ClutterActor *self,
8043                        gfloat        dx,
8044                        gfloat        dy)
8045 {
8046   const ClutterLayoutInfo *info;
8047   gfloat x, y;
8048
8049   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8050
8051   info = _clutter_actor_get_layout_info_or_defaults (self);
8052   x = info->fixed_x;
8053   y = info->fixed_y;
8054
8055   clutter_actor_set_position (self, x + dx, y + dy);
8056 }
8057
8058 static void
8059 clutter_actor_set_min_width (ClutterActor *self,
8060                              gfloat        min_width)
8061 {
8062   ClutterActorPrivate *priv = self->priv;
8063   ClutterActorBox old = { 0, };
8064   ClutterLayoutInfo *info;
8065
8066   /* if we are setting the size on a top-level actor and the
8067    * backend only supports static top-levels (e.g. framebuffers)
8068    * then we ignore the passed value and we override it with
8069    * the stage implementation's preferred size.
8070    */
8071   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8072       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8073     return;
8074
8075   info = _clutter_actor_get_layout_info (self);
8076
8077   if (priv->min_width_set && min_width == info->min_width)
8078     return;
8079
8080   g_object_freeze_notify (G_OBJECT (self));
8081
8082   clutter_actor_store_old_geometry (self, &old);
8083
8084   info->min_width = min_width;
8085   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8086   clutter_actor_set_min_width_set (self, TRUE);
8087
8088   clutter_actor_notify_if_geometry_changed (self, &old);
8089
8090   g_object_thaw_notify (G_OBJECT (self));
8091
8092   clutter_actor_queue_relayout (self);
8093 }
8094
8095 static void
8096 clutter_actor_set_min_height (ClutterActor *self,
8097                               gfloat        min_height)
8098
8099 {
8100   ClutterActorPrivate *priv = self->priv;
8101   ClutterActorBox old = { 0, };
8102   ClutterLayoutInfo *info;
8103
8104   /* if we are setting the size on a top-level actor and the
8105    * backend only supports static top-levels (e.g. framebuffers)
8106    * then we ignore the passed value and we override it with
8107    * the stage implementation's preferred size.
8108    */
8109   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8110       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8111     return;
8112
8113   info = _clutter_actor_get_layout_info (self);
8114
8115   if (priv->min_height_set && min_height == info->min_height)
8116     return;
8117
8118   g_object_freeze_notify (G_OBJECT (self));
8119
8120   clutter_actor_store_old_geometry (self, &old);
8121
8122   info->min_height = min_height;
8123   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8124   clutter_actor_set_min_height_set (self, TRUE);
8125
8126   clutter_actor_notify_if_geometry_changed (self, &old);
8127
8128   g_object_thaw_notify (G_OBJECT (self));
8129
8130   clutter_actor_queue_relayout (self);
8131 }
8132
8133 static void
8134 clutter_actor_set_natural_width (ClutterActor *self,
8135                                  gfloat        natural_width)
8136 {
8137   ClutterActorPrivate *priv = self->priv;
8138   ClutterActorBox old = { 0, };
8139   ClutterLayoutInfo *info;
8140
8141   /* if we are setting the size on a top-level actor and the
8142    * backend only supports static top-levels (e.g. framebuffers)
8143    * then we ignore the passed value and we override it with
8144    * the stage implementation's preferred size.
8145    */
8146   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8147       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8148     return;
8149
8150   info = _clutter_actor_get_layout_info (self);
8151
8152   if (priv->natural_width_set && natural_width == info->natural_width)
8153     return;
8154
8155   g_object_freeze_notify (G_OBJECT (self));
8156
8157   clutter_actor_store_old_geometry (self, &old);
8158
8159   info->natural_width = natural_width;
8160   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8161   clutter_actor_set_natural_width_set (self, TRUE);
8162
8163   clutter_actor_notify_if_geometry_changed (self, &old);
8164
8165   g_object_thaw_notify (G_OBJECT (self));
8166
8167   clutter_actor_queue_relayout (self);
8168 }
8169
8170 static void
8171 clutter_actor_set_natural_height (ClutterActor *self,
8172                                   gfloat        natural_height)
8173 {
8174   ClutterActorPrivate *priv = self->priv;
8175   ClutterActorBox old = { 0, };
8176   ClutterLayoutInfo *info;
8177
8178   /* if we are setting the size on a top-level actor and the
8179    * backend only supports static top-levels (e.g. framebuffers)
8180    * then we ignore the passed value and we override it with
8181    * the stage implementation's preferred size.
8182    */
8183   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8184       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8185     return;
8186
8187   info = _clutter_actor_get_layout_info (self);
8188
8189   if (priv->natural_height_set && natural_height == info->natural_height)
8190     return;
8191
8192   g_object_freeze_notify (G_OBJECT (self));
8193
8194   clutter_actor_store_old_geometry (self, &old);
8195
8196   info->natural_height = natural_height;
8197   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8198   clutter_actor_set_natural_height_set (self, TRUE);
8199
8200   clutter_actor_notify_if_geometry_changed (self, &old);
8201
8202   g_object_thaw_notify (G_OBJECT (self));
8203
8204   clutter_actor_queue_relayout (self);
8205 }
8206
8207 static void
8208 clutter_actor_set_min_width_set (ClutterActor *self,
8209                                  gboolean      use_min_width)
8210 {
8211   ClutterActorPrivate *priv = self->priv;
8212   ClutterActorBox old = { 0, };
8213
8214   if (priv->min_width_set == (use_min_width != FALSE))
8215     return;
8216
8217   clutter_actor_store_old_geometry (self, &old);
8218
8219   priv->min_width_set = use_min_width != FALSE;
8220   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8221
8222   clutter_actor_notify_if_geometry_changed (self, &old);
8223
8224   clutter_actor_queue_relayout (self);
8225 }
8226
8227 static void
8228 clutter_actor_set_min_height_set (ClutterActor *self,
8229                                   gboolean      use_min_height)
8230 {
8231   ClutterActorPrivate *priv = self->priv;
8232   ClutterActorBox old = { 0, };
8233
8234   if (priv->min_height_set == (use_min_height != FALSE))
8235     return;
8236
8237   clutter_actor_store_old_geometry (self, &old);
8238
8239   priv->min_height_set = use_min_height != FALSE;
8240   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8241
8242   clutter_actor_notify_if_geometry_changed (self, &old);
8243
8244   clutter_actor_queue_relayout (self);
8245 }
8246
8247 static void
8248 clutter_actor_set_natural_width_set (ClutterActor *self,
8249                                      gboolean      use_natural_width)
8250 {
8251   ClutterActorPrivate *priv = self->priv;
8252   ClutterActorBox old = { 0, };
8253
8254   if (priv->natural_width_set == (use_natural_width != FALSE))
8255     return;
8256
8257   clutter_actor_store_old_geometry (self, &old);
8258
8259   priv->natural_width_set = use_natural_width != FALSE;
8260   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8261
8262   clutter_actor_notify_if_geometry_changed (self, &old);
8263
8264   clutter_actor_queue_relayout (self);
8265 }
8266
8267 static void
8268 clutter_actor_set_natural_height_set (ClutterActor *self,
8269                                       gboolean      use_natural_height)
8270 {
8271   ClutterActorPrivate *priv = self->priv;
8272   ClutterActorBox old = { 0, };
8273
8274   if (priv->natural_height_set == (use_natural_height != FALSE))
8275     return;
8276
8277   clutter_actor_store_old_geometry (self, &old);
8278
8279   priv->natural_height_set = use_natural_height != FALSE;
8280   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8281
8282   clutter_actor_notify_if_geometry_changed (self, &old);
8283
8284   clutter_actor_queue_relayout (self);
8285 }
8286
8287 /**
8288  * clutter_actor_set_request_mode:
8289  * @self: a #ClutterActor
8290  * @mode: the request mode
8291  *
8292  * Sets the geometry request mode of @self.
8293  *
8294  * The @mode determines the order for invoking
8295  * clutter_actor_get_preferred_width() and
8296  * clutter_actor_get_preferred_height()
8297  *
8298  * Since: 1.2
8299  */
8300 void
8301 clutter_actor_set_request_mode (ClutterActor       *self,
8302                                 ClutterRequestMode  mode)
8303 {
8304   ClutterActorPrivate *priv;
8305
8306   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8307
8308   priv = self->priv;
8309
8310   if (priv->request_mode == mode)
8311     return;
8312
8313   priv->request_mode = mode;
8314
8315   priv->needs_width_request = TRUE;
8316   priv->needs_height_request = TRUE;
8317
8318   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8319
8320   clutter_actor_queue_relayout (self);
8321 }
8322
8323 /**
8324  * clutter_actor_get_request_mode:
8325  * @self: a #ClutterActor
8326  *
8327  * Retrieves the geometry request mode of @self
8328  *
8329  * Return value: the request mode for the actor
8330  *
8331  * Since: 1.2
8332  */
8333 ClutterRequestMode
8334 clutter_actor_get_request_mode (ClutterActor *self)
8335 {
8336   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8337                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8338
8339   return self->priv->request_mode;
8340 }
8341
8342 /* variant of set_width() without checks and without notification
8343  * freeze+thaw, for internal usage only
8344  */
8345 static inline void
8346 clutter_actor_set_width_internal (ClutterActor *self,
8347                                   gfloat        width)
8348 {
8349   if (width >= 0)
8350     {
8351       /* the Stage will use the :min-width to control the minimum
8352        * width to be resized to, so we should not be setting it
8353        * along with the :natural-width
8354        */
8355       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8356         clutter_actor_set_min_width (self, width);
8357
8358       clutter_actor_set_natural_width (self, width);
8359     }
8360   else
8361     {
8362       /* we only unset the :natural-width for the Stage */
8363       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8364         clutter_actor_set_min_width_set (self, FALSE);
8365
8366       clutter_actor_set_natural_width_set (self, FALSE);
8367     }
8368 }
8369
8370 /* variant of set_height() without checks and without notification
8371  * freeze+thaw, for internal usage only
8372  */
8373 static inline void
8374 clutter_actor_set_height_internal (ClutterActor *self,
8375                                    gfloat        height)
8376 {
8377   if (height >= 0)
8378     {
8379       /* see the comment above in set_width_internal() */
8380       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8381         clutter_actor_set_min_height (self, height);
8382
8383       clutter_actor_set_natural_height (self, height);
8384     }
8385   else
8386     {
8387       /* see the comment above in set_width_internal() */
8388       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8389         clutter_actor_set_min_height_set (self, FALSE);
8390
8391       clutter_actor_set_natural_height_set (self, FALSE);
8392     }
8393 }
8394
8395 /**
8396  * clutter_actor_set_size:
8397  * @self: A #ClutterActor
8398  * @width: New width of actor in pixels, or -1
8399  * @height: New height of actor in pixels, or -1
8400  *
8401  * Sets the actor's size request in pixels. This overrides any
8402  * "normal" size request the actor would have. For example
8403  * a text actor might normally request the size of the text;
8404  * this function would force a specific size instead.
8405  *
8406  * If @width and/or @height are -1 the actor will use its
8407  * "normal" size request instead of overriding it, i.e.
8408  * you can "unset" the size with -1.
8409  *
8410  * This function sets or unsets both the minimum and natural size.
8411  */
8412 void
8413 clutter_actor_set_size (ClutterActor *self,
8414                         gfloat        width,
8415                         gfloat        height)
8416 {
8417   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8418
8419   g_object_freeze_notify (G_OBJECT (self));
8420
8421   clutter_actor_set_width_internal (self, width);
8422   clutter_actor_set_height_internal (self, height);
8423
8424   g_object_thaw_notify (G_OBJECT (self));
8425 }
8426
8427 /**
8428  * clutter_actor_get_size:
8429  * @self: A #ClutterActor
8430  * @width: (out) (allow-none): return location for the width, or %NULL.
8431  * @height: (out) (allow-none): return location for the height, or %NULL.
8432  *
8433  * This function tries to "do what you mean" and return
8434  * the size an actor will have. If the actor has a valid
8435  * allocation, the allocation will be returned; otherwise,
8436  * the actors natural size request will be returned.
8437  *
8438  * If you care whether you get the request vs. the allocation, you
8439  * should probably call a different function like
8440  * clutter_actor_get_allocation_box() or
8441  * clutter_actor_get_preferred_width().
8442  *
8443  * Since: 0.2
8444  */
8445 void
8446 clutter_actor_get_size (ClutterActor *self,
8447                         gfloat       *width,
8448                         gfloat       *height)
8449 {
8450   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8451
8452   if (width)
8453     *width = clutter_actor_get_width (self);
8454
8455   if (height)
8456     *height = clutter_actor_get_height (self);
8457 }
8458
8459 /**
8460  * clutter_actor_get_position:
8461  * @self: a #ClutterActor
8462  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8463  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8464  *
8465  * This function tries to "do what you mean" and tell you where the
8466  * actor is, prior to any transformations. Retrieves the fixed
8467  * position of an actor in pixels, if one has been set; otherwise, if
8468  * the allocation is valid, returns the actor's allocated position;
8469  * otherwise, returns 0,0.
8470  *
8471  * The returned position is in pixels.
8472  *
8473  * Since: 0.6
8474  */
8475 void
8476 clutter_actor_get_position (ClutterActor *self,
8477                             gfloat       *x,
8478                             gfloat       *y)
8479 {
8480   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8481
8482   if (x)
8483     *x = clutter_actor_get_x (self);
8484
8485   if (y)
8486     *y = clutter_actor_get_y (self);
8487 }
8488
8489 /**
8490  * clutter_actor_get_transformed_position:
8491  * @self: A #ClutterActor
8492  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8493  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8494  *
8495  * Gets the absolute position of an actor, in pixels relative to the stage.
8496  *
8497  * Since: 0.8
8498  */
8499 void
8500 clutter_actor_get_transformed_position (ClutterActor *self,
8501                                         gfloat       *x,
8502                                         gfloat       *y)
8503 {
8504   ClutterVertex v1;
8505   ClutterVertex v2;
8506
8507   v1.x = v1.y = v1.z = 0;
8508   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8509
8510   if (x)
8511     *x = v2.x;
8512
8513   if (y)
8514     *y = v2.y;
8515 }
8516
8517 /**
8518  * clutter_actor_get_transformed_size:
8519  * @self: A #ClutterActor
8520  * @width: (out) (allow-none): return location for the width, or %NULL
8521  * @height: (out) (allow-none): return location for the height, or %NULL
8522  *
8523  * Gets the absolute size of an actor in pixels, taking into account the
8524  * scaling factors.
8525  *
8526  * If the actor has a valid allocation, the allocated size will be used.
8527  * If the actor has not a valid allocation then the preferred size will
8528  * be transformed and returned.
8529  *
8530  * If you want the transformed allocation, see
8531  * clutter_actor_get_abs_allocation_vertices() instead.
8532  *
8533  * <note>When the actor (or one of its ancestors) is rotated around the
8534  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8535  * as a generic quadrangle; in that case this function returns the size
8536  * of the smallest rectangle that encapsulates the entire quad. Please
8537  * note that in this case no assumptions can be made about the relative
8538  * position of this envelope to the absolute position of the actor, as
8539  * returned by clutter_actor_get_transformed_position(); if you need this
8540  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8541  * to get the coords of the actual quadrangle.</note>
8542  *
8543  * Since: 0.8
8544  */
8545 void
8546 clutter_actor_get_transformed_size (ClutterActor *self,
8547                                     gfloat       *width,
8548                                     gfloat       *height)
8549 {
8550   ClutterActorPrivate *priv;
8551   ClutterVertex v[4];
8552   gfloat x_min, x_max, y_min, y_max;
8553   gint i;
8554
8555   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8556
8557   priv = self->priv;
8558
8559   /* if the actor hasn't been allocated yet, get the preferred
8560    * size and transform that
8561    */
8562   if (priv->needs_allocation)
8563     {
8564       gfloat natural_width, natural_height;
8565       ClutterActorBox box;
8566
8567       /* Make a fake allocation to transform.
8568        *
8569        * NB: _clutter_actor_transform_and_project_box expects a box in
8570        * the actor's coordinate space... */
8571
8572       box.x1 = 0;
8573       box.y1 = 0;
8574
8575       natural_width = natural_height = 0;
8576       clutter_actor_get_preferred_size (self, NULL, NULL,
8577                                         &natural_width,
8578                                         &natural_height);
8579
8580       box.x2 = natural_width;
8581       box.y2 = natural_height;
8582
8583       _clutter_actor_transform_and_project_box (self, &box, v);
8584     }
8585   else
8586     clutter_actor_get_abs_allocation_vertices (self, v);
8587
8588   x_min = x_max = v[0].x;
8589   y_min = y_max = v[0].y;
8590
8591   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8592     {
8593       if (v[i].x < x_min)
8594         x_min = v[i].x;
8595
8596       if (v[i].x > x_max)
8597         x_max = v[i].x;
8598
8599       if (v[i].y < y_min)
8600         y_min = v[i].y;
8601
8602       if (v[i].y > y_max)
8603         y_max = v[i].y;
8604     }
8605
8606   if (width)
8607     *width  = x_max - x_min;
8608
8609   if (height)
8610     *height = y_max - y_min;
8611 }
8612
8613 /**
8614  * clutter_actor_get_width:
8615  * @self: A #ClutterActor
8616  *
8617  * Retrieves the width of a #ClutterActor.
8618  *
8619  * If the actor has a valid allocation, this function will return the
8620  * width of the allocated area given to the actor.
8621  *
8622  * If the actor does not have a valid allocation, this function will
8623  * return the actor's natural width, that is the preferred width of
8624  * the actor.
8625  *
8626  * If you care whether you get the preferred width or the width that
8627  * has been assigned to the actor, you should probably call a different
8628  * function like clutter_actor_get_allocation_box() to retrieve the
8629  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8630  * preferred width.
8631  *
8632  * If an actor has a fixed width, for instance a width that has been
8633  * assigned using clutter_actor_set_width(), the width returned will
8634  * be the same value.
8635  *
8636  * Return value: the width of the actor, in pixels
8637  */
8638 gfloat
8639 clutter_actor_get_width (ClutterActor *self)
8640 {
8641   ClutterActorPrivate *priv;
8642
8643   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8644
8645   priv = self->priv;
8646
8647   if (priv->needs_allocation)
8648     {
8649       gfloat natural_width = 0;
8650
8651       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8652         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8653       else
8654         {
8655           gfloat natural_height = 0;
8656
8657           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8658           clutter_actor_get_preferred_width (self, natural_height,
8659                                              NULL,
8660                                              &natural_width);
8661         }
8662
8663       return natural_width;
8664     }
8665   else
8666     return priv->allocation.x2 - priv->allocation.x1;
8667 }
8668
8669 /**
8670  * clutter_actor_get_height:
8671  * @self: A #ClutterActor
8672  *
8673  * Retrieves the height of a #ClutterActor.
8674  *
8675  * If the actor has a valid allocation, this function will return the
8676  * height of the allocated area given to the actor.
8677  *
8678  * If the actor does not have a valid allocation, this function will
8679  * return the actor's natural height, that is the preferred height of
8680  * the actor.
8681  *
8682  * If you care whether you get the preferred height or the height that
8683  * has been assigned to the actor, you should probably call a different
8684  * function like clutter_actor_get_allocation_box() to retrieve the
8685  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8686  * preferred height.
8687  *
8688  * If an actor has a fixed height, for instance a height that has been
8689  * assigned using clutter_actor_set_height(), the height returned will
8690  * be the same value.
8691  *
8692  * Return value: the height of the actor, in pixels
8693  */
8694 gfloat
8695 clutter_actor_get_height (ClutterActor *self)
8696 {
8697   ClutterActorPrivate *priv;
8698
8699   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8700
8701   priv = self->priv;
8702
8703   if (priv->needs_allocation)
8704     {
8705       gfloat natural_height = 0;
8706
8707       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8708         {
8709           gfloat natural_width = 0;
8710
8711           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8712           clutter_actor_get_preferred_height (self, natural_width,
8713                                               NULL, &natural_height);
8714         }
8715       else
8716         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8717
8718       return natural_height;
8719     }
8720   else
8721     return priv->allocation.y2 - priv->allocation.y1;
8722 }
8723
8724 /**
8725  * clutter_actor_set_width:
8726  * @self: A #ClutterActor
8727  * @width: Requested new width for the actor, in pixels, or -1
8728  *
8729  * Forces a width on an actor, causing the actor's preferred width
8730  * and height (if any) to be ignored.
8731  *
8732  * If @width is -1 the actor will use its preferred width request
8733  * instead of overriding it, i.e. you can "unset" the width with -1.
8734  *
8735  * This function sets both the minimum and natural size of the actor.
8736  *
8737  * since: 0.2
8738  */
8739 void
8740 clutter_actor_set_width (ClutterActor *self,
8741                          gfloat        width)
8742 {
8743   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8744
8745   g_object_freeze_notify (G_OBJECT (self));
8746
8747   clutter_actor_set_width_internal (self, width);
8748
8749   g_object_thaw_notify (G_OBJECT (self));
8750 }
8751
8752 /**
8753  * clutter_actor_set_height:
8754  * @self: A #ClutterActor
8755  * @height: Requested new height for the actor, in pixels, or -1
8756  *
8757  * Forces a height on an actor, causing the actor's preferred width
8758  * and height (if any) to be ignored.
8759  *
8760  * If @height is -1 the actor will use its preferred height instead of
8761  * overriding it, i.e. you can "unset" the height with -1.
8762  *
8763  * This function sets both the minimum and natural size of the actor.
8764  *
8765  * since: 0.2
8766  */
8767 void
8768 clutter_actor_set_height (ClutterActor *self,
8769                           gfloat        height)
8770 {
8771   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8772
8773   g_object_freeze_notify (G_OBJECT (self));
8774
8775   clutter_actor_set_height_internal (self, height);
8776
8777   g_object_thaw_notify (G_OBJECT (self));
8778 }
8779
8780 /**
8781  * clutter_actor_set_x:
8782  * @self: a #ClutterActor
8783  * @x: the actor's position on the X axis
8784  *
8785  * Sets the actor's X coordinate, relative to its parent, in pixels.
8786  *
8787  * Overrides any layout manager and forces a fixed position for
8788  * the actor.
8789  *
8790  * Since: 0.6
8791  */
8792 void
8793 clutter_actor_set_x (ClutterActor *self,
8794                      gfloat        x)
8795 {
8796   ClutterActorBox old = { 0, };
8797   ClutterActorPrivate *priv;
8798   ClutterLayoutInfo *info;
8799
8800   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8801
8802   priv = self->priv;
8803
8804   info = _clutter_actor_get_layout_info (self);
8805
8806   if (priv->position_set && info->fixed_x == x)
8807     return;
8808
8809   clutter_actor_store_old_geometry (self, &old);
8810
8811   info->fixed_x = x;
8812   clutter_actor_set_fixed_position_set (self, TRUE);
8813
8814   clutter_actor_notify_if_geometry_changed (self, &old);
8815
8816   clutter_actor_queue_relayout (self);
8817 }
8818
8819 /**
8820  * clutter_actor_set_y:
8821  * @self: a #ClutterActor
8822  * @y: the actor's position on the Y axis
8823  *
8824  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8825  *
8826  * Overrides any layout manager and forces a fixed position for
8827  * the actor.
8828  *
8829  * Since: 0.6
8830  */
8831 void
8832 clutter_actor_set_y (ClutterActor *self,
8833                      gfloat        y)
8834 {
8835   ClutterActorBox old = { 0, };
8836   ClutterActorPrivate *priv;
8837   ClutterLayoutInfo *info;
8838
8839   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8840
8841   priv = self->priv;
8842
8843   info = _clutter_actor_get_layout_info (self);
8844
8845   if (priv->position_set && info->fixed_y == y)
8846     return;
8847
8848   clutter_actor_store_old_geometry (self, &old);
8849
8850   info->fixed_y = y;
8851   clutter_actor_set_fixed_position_set (self, TRUE);
8852
8853   clutter_actor_notify_if_geometry_changed (self, &old);
8854
8855   clutter_actor_queue_relayout (self);
8856 }
8857
8858 /**
8859  * clutter_actor_get_x:
8860  * @self: A #ClutterActor
8861  *
8862  * Retrieves the X coordinate of a #ClutterActor.
8863  *
8864  * This function tries to "do what you mean", by returning the
8865  * correct value depending on the actor's state.
8866  *
8867  * If the actor has a valid allocation, this function will return
8868  * the X coordinate of the origin of the allocation box.
8869  *
8870  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8871  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8872  * function will return that coordinate.
8873  *
8874  * If both the allocation and a fixed position are missing, this function
8875  * will return 0.
8876  *
8877  * Return value: the X coordinate, in pixels, ignoring any
8878  *   transformation (i.e. scaling, rotation)
8879  */
8880 gfloat
8881 clutter_actor_get_x (ClutterActor *self)
8882 {
8883   ClutterActorPrivate *priv;
8884
8885   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8886
8887   priv = self->priv;
8888
8889   if (priv->needs_allocation)
8890     {
8891       if (priv->position_set)
8892         {
8893           const ClutterLayoutInfo *info;
8894
8895           info = _clutter_actor_get_layout_info_or_defaults (self);
8896
8897           return info->fixed_x;
8898         }
8899       else
8900         return 0;
8901     }
8902   else
8903     return priv->allocation.x1;
8904 }
8905
8906 /**
8907  * clutter_actor_get_y:
8908  * @self: A #ClutterActor
8909  *
8910  * Retrieves the Y coordinate of a #ClutterActor.
8911  *
8912  * This function tries to "do what you mean", by returning the
8913  * correct value depending on the actor's state.
8914  *
8915  * If the actor has a valid allocation, this function will return
8916  * the Y coordinate of the origin of the allocation box.
8917  *
8918  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
8919  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8920  * function will return that coordinate.
8921  *
8922  * If both the allocation and a fixed position are missing, this function
8923  * will return 0.
8924  *
8925  * Return value: the Y coordinate, in pixels, ignoring any
8926  *   transformation (i.e. scaling, rotation)
8927  */
8928 gfloat
8929 clutter_actor_get_y (ClutterActor *self)
8930 {
8931   ClutterActorPrivate *priv;
8932
8933   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8934
8935   priv = self->priv;
8936
8937   if (priv->needs_allocation)
8938     {
8939       if (priv->position_set)
8940         {
8941           const ClutterLayoutInfo *info;
8942
8943           info = _clutter_actor_get_layout_info_or_defaults (self);
8944
8945           return info->fixed_y;
8946         }
8947       else
8948         return 0;
8949     }
8950   else
8951     return priv->allocation.y1;
8952 }
8953
8954 /**
8955  * clutter_actor_set_scale:
8956  * @self: A #ClutterActor
8957  * @scale_x: double factor to scale actor by horizontally.
8958  * @scale_y: double factor to scale actor by vertically.
8959  *
8960  * Scales an actor with the given factors. The scaling is relative to
8961  * the scale center and the anchor point. The scale center is
8962  * unchanged by this function and defaults to 0,0.
8963  *
8964  * Since: 0.2
8965  */
8966 void
8967 clutter_actor_set_scale (ClutterActor *self,
8968                          gdouble       scale_x,
8969                          gdouble       scale_y)
8970 {
8971   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8972
8973   g_object_freeze_notify (G_OBJECT (self));
8974
8975   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
8976   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
8977
8978   g_object_thaw_notify (G_OBJECT (self));
8979 }
8980
8981 /**
8982  * clutter_actor_set_scale_full:
8983  * @self: A #ClutterActor
8984  * @scale_x: double factor to scale actor by horizontally.
8985  * @scale_y: double factor to scale actor by vertically.
8986  * @center_x: X coordinate of the center of the scale.
8987  * @center_y: Y coordinate of the center of the scale
8988  *
8989  * Scales an actor with the given factors around the given center
8990  * point. The center point is specified in pixels relative to the
8991  * anchor point (usually the top left corner of the actor).
8992  *
8993  * Since: 1.0
8994  */
8995 void
8996 clutter_actor_set_scale_full (ClutterActor *self,
8997                               gdouble       scale_x,
8998                               gdouble       scale_y,
8999                               gfloat        center_x,
9000                               gfloat        center_y)
9001 {
9002   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9003
9004   g_object_freeze_notify (G_OBJECT (self));
9005
9006   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9007   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9008   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9009   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9010
9011   g_object_thaw_notify (G_OBJECT (self));
9012 }
9013
9014 /**
9015  * clutter_actor_set_scale_with_gravity:
9016  * @self: A #ClutterActor
9017  * @scale_x: double factor to scale actor by horizontally.
9018  * @scale_y: double factor to scale actor by vertically.
9019  * @gravity: the location of the scale center expressed as a compass
9020  * direction.
9021  *
9022  * Scales an actor with the given factors around the given
9023  * center point. The center point is specified as one of the compass
9024  * directions in #ClutterGravity. For example, setting it to north
9025  * will cause the top of the actor to remain unchanged and the rest of
9026  * the actor to expand left, right and downwards.
9027  *
9028  * Since: 1.0
9029  */
9030 void
9031 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9032                                       gdouble         scale_x,
9033                                       gdouble         scale_y,
9034                                       ClutterGravity  gravity)
9035 {
9036   ClutterTransformInfo *info;
9037   GObject *obj;
9038
9039   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9040
9041   obj = G_OBJECT (self);
9042
9043   g_object_freeze_notify (obj);
9044
9045   info = _clutter_actor_get_transform_info (self);
9046   info->scale_x = scale_x;
9047   info->scale_y = scale_y;
9048
9049   if (gravity == CLUTTER_GRAVITY_NONE)
9050     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9051   else
9052     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9053
9054   self->priv->transform_valid = FALSE;
9055
9056   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9057   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9058   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9059   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9060   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9061
9062   clutter_actor_queue_redraw (self);
9063
9064   g_object_thaw_notify (obj);
9065 }
9066
9067 /**
9068  * clutter_actor_get_scale:
9069  * @self: A #ClutterActor
9070  * @scale_x: (out) (allow-none): Location to store horizonal
9071  *   scale factor, or %NULL.
9072  * @scale_y: (out) (allow-none): Location to store vertical
9073  *   scale factor, or %NULL.
9074  *
9075  * Retrieves an actors scale factors.
9076  *
9077  * Since: 0.2
9078  */
9079 void
9080 clutter_actor_get_scale (ClutterActor *self,
9081                          gdouble      *scale_x,
9082                          gdouble      *scale_y)
9083 {
9084   const ClutterTransformInfo *info;
9085
9086   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9087
9088   info = _clutter_actor_get_transform_info_or_defaults (self);
9089
9090   if (scale_x)
9091     *scale_x = info->scale_x;
9092
9093   if (scale_y)
9094     *scale_y = info->scale_y;
9095 }
9096
9097 /**
9098  * clutter_actor_get_scale_center:
9099  * @self: A #ClutterActor
9100  * @center_x: (out) (allow-none): Location to store the X position
9101  *   of the scale center, or %NULL.
9102  * @center_y: (out) (allow-none): Location to store the Y position
9103  *   of the scale center, or %NULL.
9104  *
9105  * Retrieves the scale center coordinate in pixels relative to the top
9106  * left corner of the actor. If the scale center was specified using a
9107  * #ClutterGravity this will calculate the pixel offset using the
9108  * current size of the actor.
9109  *
9110  * Since: 1.0
9111  */
9112 void
9113 clutter_actor_get_scale_center (ClutterActor *self,
9114                                 gfloat       *center_x,
9115                                 gfloat       *center_y)
9116 {
9117   const ClutterTransformInfo *info;
9118
9119   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9120
9121   info = _clutter_actor_get_transform_info_or_defaults (self);
9122
9123   clutter_anchor_coord_get_units (self, &info->scale_center,
9124                                   center_x,
9125                                   center_y,
9126                                   NULL);
9127 }
9128
9129 /**
9130  * clutter_actor_get_scale_gravity:
9131  * @self: A #ClutterActor
9132  *
9133  * Retrieves the scale center as a compass direction. If the scale
9134  * center was specified in pixels or units this will return
9135  * %CLUTTER_GRAVITY_NONE.
9136  *
9137  * Return value: the scale gravity
9138  *
9139  * Since: 1.0
9140  */
9141 ClutterGravity
9142 clutter_actor_get_scale_gravity (ClutterActor *self)
9143 {
9144   const ClutterTransformInfo *info;
9145
9146   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9147
9148   info = _clutter_actor_get_transform_info_or_defaults (self);
9149
9150   return clutter_anchor_coord_get_gravity (&info->scale_center);
9151 }
9152
9153 /**
9154  * clutter_actor_set_opacity:
9155  * @self: A #ClutterActor
9156  * @opacity: New opacity value for the actor.
9157  *
9158  * Sets the actor's opacity, with zero being completely transparent and
9159  * 255 (0xff) being fully opaque.
9160  */
9161 void
9162 clutter_actor_set_opacity (ClutterActor *self,
9163                            guint8        opacity)
9164 {
9165   ClutterActorPrivate *priv;
9166
9167   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9168
9169   priv = self->priv;
9170
9171   if (priv->opacity != opacity)
9172     {
9173       priv->opacity = opacity;
9174
9175       /* Queue a redraw from the flatten effect so that it can use
9176          its cached image if available instead of having to redraw the
9177          actual actor. If it doesn't end up using the FBO then the
9178          effect is still able to continue the paint anyway. If there
9179          is no flatten effect yet then this is equivalent to queueing
9180          a full redraw */
9181       _clutter_actor_queue_redraw_full (self,
9182                                         0, /* flags */
9183                                         NULL, /* clip */
9184                                         priv->flatten_effect);
9185
9186       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9187     }
9188 }
9189
9190 /*
9191  * clutter_actor_get_paint_opacity_internal:
9192  * @self: a #ClutterActor
9193  *
9194  * Retrieves the absolute opacity of the actor, as it appears on the stage
9195  *
9196  * This function does not do type checks
9197  *
9198  * Return value: the absolute opacity of the actor
9199  */
9200 static guint8
9201 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9202 {
9203   ClutterActorPrivate *priv = self->priv;
9204   ClutterActor *parent;
9205
9206   /* override the top-level opacity to always be 255; even in
9207    * case of ClutterStage:use-alpha being TRUE we want the rest
9208    * of the scene to be painted
9209    */
9210   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9211     return 255;
9212
9213   if (priv->opacity_override >= 0)
9214     return priv->opacity_override;
9215
9216   parent = priv->parent;
9217
9218   /* Factor in the actual actors opacity with parents */
9219   if (parent != NULL)
9220     {
9221       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9222
9223       if (opacity != 0xff)
9224         return (opacity * priv->opacity) / 0xff;
9225     }
9226
9227   return priv->opacity;
9228
9229 }
9230
9231 /**
9232  * clutter_actor_get_paint_opacity:
9233  * @self: A #ClutterActor
9234  *
9235  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9236  *
9237  * This function traverses the hierarchy chain and composites the opacity of
9238  * the actor with that of its parents.
9239  *
9240  * This function is intended for subclasses to use in the paint virtual
9241  * function, to paint themselves with the correct opacity.
9242  *
9243  * Return value: The actor opacity value.
9244  *
9245  * Since: 0.8
9246  */
9247 guint8
9248 clutter_actor_get_paint_opacity (ClutterActor *self)
9249 {
9250   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9251
9252   return clutter_actor_get_paint_opacity_internal (self);
9253 }
9254
9255 /**
9256  * clutter_actor_get_opacity:
9257  * @self: a #ClutterActor
9258  *
9259  * Retrieves the opacity value of an actor, as set by
9260  * clutter_actor_set_opacity().
9261  *
9262  * For retrieving the absolute opacity of the actor inside a paint
9263  * virtual function, see clutter_actor_get_paint_opacity().
9264  *
9265  * Return value: the opacity of the actor
9266  */
9267 guint8
9268 clutter_actor_get_opacity (ClutterActor *self)
9269 {
9270   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9271
9272   return self->priv->opacity;
9273 }
9274
9275 /**
9276  * clutter_actor_set_offscreen_redirect:
9277  * @self: A #ClutterActor
9278  * @redirect: New offscreen redirect flags for the actor.
9279  *
9280  * Defines the circumstances where the actor should be redirected into
9281  * an offscreen image. The offscreen image is used to flatten the
9282  * actor into a single image while painting for two main reasons.
9283  * Firstly, when the actor is painted a second time without any of its
9284  * contents changing it can simply repaint the cached image without
9285  * descending further down the actor hierarchy. Secondly, it will make
9286  * the opacity look correct even if there are overlapping primitives
9287  * in the actor.
9288  *
9289  * Caching the actor could in some cases be a performance win and in
9290  * some cases be a performance lose so it is important to determine
9291  * which value is right for an actor before modifying this value. For
9292  * example, there is never any reason to flatten an actor that is just
9293  * a single texture (such as a #ClutterTexture) because it is
9294  * effectively already cached in an image so the offscreen would be
9295  * redundant. Also if the actor contains primitives that are far apart
9296  * with a large transparent area in the middle (such as a large
9297  * CluterGroup with a small actor in the top left and a small actor in
9298  * the bottom right) then the cached image will contain the entire
9299  * image of the large area and the paint will waste time blending all
9300  * of the transparent pixels in the middle.
9301  *
9302  * The default method of implementing opacity on a container simply
9303  * forwards on the opacity to all of the children. If the children are
9304  * overlapping then it will appear as if they are two separate glassy
9305  * objects and there will be a break in the color where they
9306  * overlap. By redirecting to an offscreen buffer it will be as if the
9307  * two opaque objects are combined into one and then made transparent
9308  * which is usually what is expected.
9309  *
9310  * The image below demonstrates the difference between redirecting and
9311  * not. The image shows two Clutter groups, each containing a red and
9312  * a green rectangle which overlap. The opacity on the group is set to
9313  * 128 (which is 50%). When the offscreen redirect is not used, the
9314  * red rectangle can be seen through the blue rectangle as if the two
9315  * rectangles were separately transparent. When the redirect is used
9316  * the group as a whole is transparent instead so the red rectangle is
9317  * not visible where they overlap.
9318  *
9319  * <figure id="offscreen-redirect">
9320  *   <title>Sample of using an offscreen redirect for transparency</title>
9321  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9322  * </figure>
9323  *
9324  * The default value for this property is 0, so we effectively will
9325  * never redirect an actor offscreen by default. This means that there
9326  * are times that transparent actors may look glassy as described
9327  * above. The reason this is the default is because there is a
9328  * performance trade off between quality and performance here. In many
9329  * cases the default form of glassy opacity looks good enough, but if
9330  * it's not you will need to set the
9331  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9332  * redirection for opacity.
9333  *
9334  * Custom actors that don't contain any overlapping primitives are
9335  * recommended to override the has_overlaps() virtual to return %FALSE
9336  * for maximum efficiency.
9337  *
9338  * Since: 1.8
9339  */
9340 void
9341 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9342                                       ClutterOffscreenRedirect redirect)
9343 {
9344   ClutterActorPrivate *priv;
9345
9346   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9347
9348   priv = self->priv;
9349
9350   if (priv->offscreen_redirect != redirect)
9351     {
9352       priv->offscreen_redirect = redirect;
9353
9354       /* Queue a redraw from the effect so that it can use its cached
9355          image if available instead of having to redraw the actual
9356          actor. If it doesn't end up using the FBO then the effect is
9357          still able to continue the paint anyway. If there is no
9358          effect then this is equivalent to queuing a full redraw */
9359       _clutter_actor_queue_redraw_full (self,
9360                                         0, /* flags */
9361                                         NULL, /* clip */
9362                                         priv->flatten_effect);
9363
9364       g_object_notify_by_pspec (G_OBJECT (self),
9365                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9366     }
9367 }
9368
9369 /**
9370  * clutter_actor_get_offscreen_redirect:
9371  * @self: a #ClutterActor
9372  *
9373  * Retrieves whether to redirect the actor to an offscreen buffer, as
9374  * set by clutter_actor_set_offscreen_redirect().
9375  *
9376  * Return value: the value of the offscreen-redirect property of the actor
9377  *
9378  * Since: 1.8
9379  */
9380 ClutterOffscreenRedirect
9381 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9382 {
9383   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9384
9385   return self->priv->offscreen_redirect;
9386 }
9387
9388 /**
9389  * clutter_actor_set_name:
9390  * @self: A #ClutterActor
9391  * @name: Textual tag to apply to actor
9392  *
9393  * Sets the given name to @self. The name can be used to identify
9394  * a #ClutterActor.
9395  */
9396 void
9397 clutter_actor_set_name (ClutterActor *self,
9398                         const gchar  *name)
9399 {
9400   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9401
9402   g_free (self->priv->name);
9403   self->priv->name = g_strdup (name);
9404
9405   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9406 }
9407
9408 /**
9409  * clutter_actor_get_name:
9410  * @self: A #ClutterActor
9411  *
9412  * Retrieves the name of @self.
9413  *
9414  * Return value: the name of the actor, or %NULL. The returned string is
9415  *   owned by the actor and should not be modified or freed.
9416  */
9417 const gchar *
9418 clutter_actor_get_name (ClutterActor *self)
9419 {
9420   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9421
9422   return self->priv->name;
9423 }
9424
9425 /**
9426  * clutter_actor_get_gid:
9427  * @self: A #ClutterActor
9428  *
9429  * Retrieves the unique id for @self.
9430  *
9431  * Return value: Globally unique value for this object instance.
9432  *
9433  * Since: 0.6
9434  *
9435  * Deprecated: 1.8: The id is not used any longer.
9436  */
9437 guint32
9438 clutter_actor_get_gid (ClutterActor *self)
9439 {
9440   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9441
9442   return self->priv->id;
9443 }
9444
9445 /**
9446  * clutter_actor_set_depth:
9447  * @self: a #ClutterActor
9448  * @depth: Z co-ord
9449  *
9450  * Sets the Z coordinate of @self to @depth.
9451  *
9452  * The unit used by @depth is dependant on the perspective setup. See
9453  * also clutter_stage_set_perspective().
9454  */
9455 void
9456 clutter_actor_set_depth (ClutterActor *self,
9457                          gfloat        depth)
9458 {
9459   ClutterActorPrivate *priv;
9460
9461   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9462
9463   priv = self->priv;
9464
9465   if (priv->z != depth)
9466     {
9467       /* Sets Z value - XXX 2.0: should we invert? */
9468       priv->z = depth;
9469
9470       priv->transform_valid = FALSE;
9471
9472       /* FIXME - remove this crap; sadly, there are still containers
9473        * in Clutter that depend on this utter brain damage
9474        */
9475       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9476
9477       clutter_actor_queue_redraw (self);
9478
9479       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9480     }
9481 }
9482
9483 /**
9484  * clutter_actor_get_depth:
9485  * @self: a #ClutterActor
9486  *
9487  * Retrieves the depth of @self.
9488  *
9489  * Return value: the depth of the actor
9490  */
9491 gfloat
9492 clutter_actor_get_depth (ClutterActor *self)
9493 {
9494   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9495
9496   return self->priv->z;
9497 }
9498
9499 /**
9500  * clutter_actor_set_rotation:
9501  * @self: a #ClutterActor
9502  * @axis: the axis of rotation
9503  * @angle: the angle of rotation
9504  * @x: X coordinate of the rotation center
9505  * @y: Y coordinate of the rotation center
9506  * @z: Z coordinate of the rotation center
9507  *
9508  * Sets the rotation angle of @self around the given axis.
9509  *
9510  * The rotation center coordinates used depend on the value of @axis:
9511  * <itemizedlist>
9512  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9513  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9514  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9515  * </itemizedlist>
9516  *
9517  * The rotation coordinates are relative to the anchor point of the
9518  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9519  * point is set, the upper left corner is assumed as the origin.
9520  *
9521  * Since: 0.8
9522  */
9523 void
9524 clutter_actor_set_rotation (ClutterActor      *self,
9525                             ClutterRotateAxis  axis,
9526                             gdouble            angle,
9527                             gfloat             x,
9528                             gfloat             y,
9529                             gfloat             z)
9530 {
9531   ClutterVertex v;
9532
9533   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9534
9535   v.x = x;
9536   v.y = y;
9537   v.z = z;
9538
9539   g_object_freeze_notify (G_OBJECT (self));
9540
9541   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9542   clutter_actor_set_rotation_center_internal (self, axis, &v);
9543
9544   g_object_thaw_notify (G_OBJECT (self));
9545 }
9546
9547 /**
9548  * clutter_actor_set_z_rotation_from_gravity:
9549  * @self: a #ClutterActor
9550  * @angle: the angle of rotation
9551  * @gravity: the center point of the rotation
9552  *
9553  * Sets the rotation angle of @self around the Z axis using the center
9554  * point specified as a compass point. For example to rotate such that
9555  * the center of the actor remains static you can use
9556  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9557  * will move accordingly.
9558  *
9559  * Since: 1.0
9560  */
9561 void
9562 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9563                                            gdouble         angle,
9564                                            ClutterGravity  gravity)
9565 {
9566   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9567
9568   if (gravity == CLUTTER_GRAVITY_NONE)
9569     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9570   else
9571     {
9572       GObject *obj = G_OBJECT (self);
9573       ClutterTransformInfo *info;
9574
9575       info = _clutter_actor_get_transform_info (self);
9576
9577       g_object_freeze_notify (obj);
9578
9579       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9580
9581       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9582       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9583       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9584
9585       g_object_thaw_notify (obj);
9586     }
9587 }
9588
9589 /**
9590  * clutter_actor_get_rotation:
9591  * @self: a #ClutterActor
9592  * @axis: the axis of rotation
9593  * @x: (out): return value for the X coordinate of the center of rotation
9594  * @y: (out): return value for the Y coordinate of the center of rotation
9595  * @z: (out): return value for the Z coordinate of the center of rotation
9596  *
9597  * Retrieves the angle and center of rotation on the given axis,
9598  * set using clutter_actor_set_rotation().
9599  *
9600  * Return value: the angle of rotation
9601  *
9602  * Since: 0.8
9603  */
9604 gdouble
9605 clutter_actor_get_rotation (ClutterActor      *self,
9606                             ClutterRotateAxis  axis,
9607                             gfloat            *x,
9608                             gfloat            *y,
9609                             gfloat            *z)
9610 {
9611   const ClutterTransformInfo *info;
9612   const AnchorCoord *anchor_coord;
9613   gdouble retval = 0;
9614
9615   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9616
9617   info = _clutter_actor_get_transform_info_or_defaults (self);
9618
9619   switch (axis)
9620     {
9621     case CLUTTER_X_AXIS:
9622       anchor_coord = &info->rx_center;
9623       retval = info->rx_angle;
9624       break;
9625
9626     case CLUTTER_Y_AXIS:
9627       anchor_coord = &info->ry_center;
9628       retval = info->ry_angle;
9629       break;
9630
9631     case CLUTTER_Z_AXIS:
9632       anchor_coord = &info->rz_center;
9633       retval = info->rz_angle;
9634       break;
9635
9636     default:
9637       anchor_coord = NULL;
9638       retval = 0.0;
9639       break;
9640     }
9641
9642   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9643
9644   return retval;
9645 }
9646
9647 /**
9648  * clutter_actor_get_z_rotation_gravity:
9649  * @self: A #ClutterActor
9650  *
9651  * Retrieves the center for the rotation around the Z axis as a
9652  * compass direction. If the center was specified in pixels or units
9653  * this will return %CLUTTER_GRAVITY_NONE.
9654  *
9655  * Return value: the Z rotation center
9656  *
9657  * Since: 1.0
9658  */
9659 ClutterGravity
9660 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9661 {
9662   const ClutterTransformInfo *info;
9663
9664   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9665
9666   info = _clutter_actor_get_transform_info_or_defaults (self);
9667
9668   return clutter_anchor_coord_get_gravity (&info->rz_center);
9669 }
9670
9671 /**
9672  * clutter_actor_set_clip:
9673  * @self: A #ClutterActor
9674  * @xoff: X offset of the clip rectangle
9675  * @yoff: Y offset of the clip rectangle
9676  * @width: Width of the clip rectangle
9677  * @height: Height of the clip rectangle
9678  *
9679  * Sets clip area for @self. The clip area is always computed from the
9680  * upper left corner of the actor, even if the anchor point is set
9681  * otherwise.
9682  *
9683  * Since: 0.6
9684  */
9685 void
9686 clutter_actor_set_clip (ClutterActor *self,
9687                         gfloat        xoff,
9688                         gfloat        yoff,
9689                         gfloat        width,
9690                         gfloat        height)
9691 {
9692   ClutterActorPrivate *priv;
9693
9694   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9695
9696   priv = self->priv;
9697
9698   if (priv->has_clip &&
9699       priv->clip.x == xoff &&
9700       priv->clip.y == yoff &&
9701       priv->clip.width == width &&
9702       priv->clip.height == height)
9703     return;
9704
9705   priv->clip.x = xoff;
9706   priv->clip.y = yoff;
9707   priv->clip.width = width;
9708   priv->clip.height = height;
9709
9710   priv->has_clip = TRUE;
9711
9712   clutter_actor_queue_redraw (self);
9713
9714   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9715   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9716 }
9717
9718 /**
9719  * clutter_actor_remove_clip:
9720  * @self: A #ClutterActor
9721  *
9722  * Removes clip area from @self.
9723  */
9724 void
9725 clutter_actor_remove_clip (ClutterActor *self)
9726 {
9727   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9728
9729   if (!self->priv->has_clip)
9730     return;
9731
9732   self->priv->has_clip = FALSE;
9733
9734   clutter_actor_queue_redraw (self);
9735
9736   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9737 }
9738
9739 /**
9740  * clutter_actor_has_clip:
9741  * @self: a #ClutterActor
9742  *
9743  * Determines whether the actor has a clip area set or not.
9744  *
9745  * Return value: %TRUE if the actor has a clip area set.
9746  *
9747  * Since: 0.1.1
9748  */
9749 gboolean
9750 clutter_actor_has_clip (ClutterActor *self)
9751 {
9752   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9753
9754   return self->priv->has_clip;
9755 }
9756
9757 /**
9758  * clutter_actor_get_clip:
9759  * @self: a #ClutterActor
9760  * @xoff: (out) (allow-none): return location for the X offset of
9761  *   the clip rectangle, or %NULL
9762  * @yoff: (out) (allow-none): return location for the Y offset of
9763  *   the clip rectangle, or %NULL
9764  * @width: (out) (allow-none): return location for the width of
9765  *   the clip rectangle, or %NULL
9766  * @height: (out) (allow-none): return location for the height of
9767  *   the clip rectangle, or %NULL
9768  *
9769  * Gets the clip area for @self, if any is set
9770  *
9771  * Since: 0.6
9772  */
9773 void
9774 clutter_actor_get_clip (ClutterActor *self,
9775                         gfloat       *xoff,
9776                         gfloat       *yoff,
9777                         gfloat       *width,
9778                         gfloat       *height)
9779 {
9780   ClutterActorPrivate *priv;
9781
9782   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9783
9784   priv = self->priv;
9785
9786   if (!priv->has_clip)
9787     return;
9788
9789   if (xoff != NULL)
9790     *xoff = priv->clip.x;
9791
9792   if (yoff != NULL)
9793     *yoff = priv->clip.y;
9794
9795   if (width != NULL)
9796     *width = priv->clip.width;
9797
9798   if (height != NULL)
9799     *height = priv->clip.height;
9800 }
9801
9802 /**
9803  * clutter_actor_get_children:
9804  * @self: a #ClutterActor
9805  *
9806  * Retrieves the list of children of @self.
9807  *
9808  * Return value: (transfer container) (element-type ClutterActor): A newly
9809  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9810  *   done.
9811  *
9812  * Since: 1.10
9813  */
9814 GList *
9815 clutter_actor_get_children (ClutterActor *self)
9816 {
9817   ClutterActor *iter;
9818   GList *res;
9819
9820   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9821
9822   /* we walk the list backward so that we can use prepend(),
9823    * which is O(1)
9824    */
9825   for (iter = self->priv->last_child, res = NULL;
9826        iter != NULL;
9827        iter = iter->priv->prev_sibling)
9828     {
9829       res = g_list_prepend (res, iter);
9830     }
9831
9832   return res;
9833 }
9834
9835 /*< private >
9836  * insert_child_at_depth:
9837  * @self: a #ClutterActor
9838  * @child: a #ClutterActor
9839  *
9840  * Inserts @child inside the list of children held by @self, using
9841  * the depth as the insertion criteria.
9842  *
9843  * This sadly makes the insertion not O(1), but we can keep the
9844  * list sorted so that the painters algorithm we use for painting
9845  * the children will work correctly.
9846  */
9847 static void
9848 insert_child_at_depth (ClutterActor *self,
9849                        ClutterActor *child,
9850                        gpointer      dummy G_GNUC_UNUSED)
9851 {
9852   ClutterActor *iter;
9853
9854   child->priv->parent = self;
9855
9856   /* special-case the first child */
9857   if (self->priv->n_children == 0)
9858     {
9859       self->priv->first_child = child;
9860       self->priv->last_child = child;
9861
9862       child->priv->next_sibling = NULL;
9863       child->priv->prev_sibling = NULL;
9864
9865       return;
9866     }
9867
9868   /* Find the right place to insert the child so that it will still be
9869      sorted and the child will be after all of the actors at the same
9870      dept */
9871   for (iter = self->priv->first_child;
9872        iter != NULL;
9873        iter = iter->priv->next_sibling)
9874     {
9875       if (iter->priv->z > child->priv->z)
9876         break;
9877     }
9878
9879   if (iter != NULL)
9880     {
9881       ClutterActor *tmp = iter->priv->prev_sibling;
9882
9883       if (tmp != NULL)
9884         tmp->priv->next_sibling = child;
9885
9886       /* Insert the node before the found one */
9887       child->priv->prev_sibling = iter->priv->prev_sibling;
9888       child->priv->next_sibling = iter;
9889       iter->priv->prev_sibling = child;
9890     }
9891   else
9892     {
9893       ClutterActor *tmp = self->priv->last_child;
9894
9895       if (tmp != NULL)
9896         tmp->priv->next_sibling = child;
9897
9898       /* insert the node at the end of the list */
9899       child->priv->prev_sibling = self->priv->last_child;
9900       child->priv->next_sibling = NULL;
9901     }
9902
9903   if (child->priv->prev_sibling == NULL)
9904     self->priv->first_child = child;
9905
9906   if (child->priv->next_sibling == NULL)
9907     self->priv->last_child = child;
9908 }
9909
9910 static void
9911 insert_child_at_index (ClutterActor *self,
9912                        ClutterActor *child,
9913                        gpointer      data_)
9914 {
9915   gint index_ = GPOINTER_TO_INT (data_);
9916
9917   child->priv->parent = self;
9918
9919   if (index_ == 0)
9920     {
9921       ClutterActor *tmp = self->priv->first_child;
9922
9923       if (tmp != NULL)
9924         tmp->priv->prev_sibling = child;
9925
9926       child->priv->prev_sibling = NULL;
9927       child->priv->next_sibling = tmp;
9928     }
9929   else if (index_ < 0)
9930     {
9931       ClutterActor *tmp = self->priv->last_child;
9932
9933       if (tmp != NULL)
9934         tmp->priv->next_sibling = child;
9935
9936       child->priv->prev_sibling = tmp;
9937       child->priv->next_sibling = NULL;
9938     }
9939   else
9940     {
9941       ClutterActor *iter;
9942       int i;
9943
9944       for (iter = self->priv->first_child, i = 0;
9945            iter != NULL;
9946            iter = iter->priv->next_sibling, i += 1)
9947         {
9948           if (index_ == i)
9949             {
9950               ClutterActor *tmp = iter->priv->prev_sibling;
9951
9952               child->priv->prev_sibling = tmp;
9953               child->priv->next_sibling = iter;
9954
9955               iter->priv->prev_sibling = child;
9956
9957               if (tmp != NULL)
9958                 tmp->priv->next_sibling = child;
9959
9960               break;
9961             }
9962         }
9963     }
9964
9965   if (child->priv->prev_sibling == NULL)
9966     self->priv->first_child = child;
9967
9968   if (child->priv->next_sibling == NULL)
9969     self->priv->last_child = child;
9970 }
9971
9972 static void
9973 insert_child_above (ClutterActor *self,
9974                     ClutterActor *child,
9975                     gpointer      data)
9976 {
9977   ClutterActor *sibling = data;
9978
9979   child->priv->parent = self;
9980
9981   if (sibling == NULL)
9982     sibling = self->priv->last_child;
9983
9984   child->priv->prev_sibling = sibling;
9985
9986   if (sibling != NULL)
9987     {
9988       ClutterActor *tmp = sibling->priv->next_sibling;
9989
9990       child->priv->next_sibling = tmp;
9991
9992       if (tmp != NULL)
9993         tmp->priv->prev_sibling = child;
9994
9995       sibling->priv->next_sibling = child;
9996     }
9997   else
9998     child->priv->next_sibling = NULL;
9999
10000   if (child->priv->prev_sibling == NULL)
10001     self->priv->first_child = child;
10002
10003   if (child->priv->next_sibling == NULL)
10004     self->priv->last_child = child;
10005 }
10006
10007 static void
10008 insert_child_below (ClutterActor *self,
10009                     ClutterActor *child,
10010                     gpointer      data)
10011 {
10012   ClutterActor *sibling = data;
10013
10014   child->priv->parent = self;
10015
10016   if (sibling == NULL)
10017     sibling = self->priv->first_child;
10018
10019   child->priv->next_sibling = sibling;
10020
10021   if (sibling != NULL)
10022     {
10023       ClutterActor *tmp = sibling->priv->prev_sibling;
10024
10025       child->priv->prev_sibling = tmp;
10026
10027       if (tmp != NULL)
10028         tmp->priv->next_sibling = child;
10029
10030       sibling->priv->prev_sibling = child;
10031     }
10032   else
10033     child->priv->prev_sibling = NULL;
10034
10035   if (child->priv->prev_sibling == NULL)
10036     self->priv->first_child = child;
10037
10038   if (child->priv->next_sibling == NULL)
10039     self->priv->last_child = child;
10040 }
10041
10042 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10043                                            ClutterActor *child,
10044                                            gpointer      data);
10045
10046 typedef enum {
10047   ADD_CHILD_CREATE_META       = 1 << 0,
10048   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10049   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10050   ADD_CHILD_CHECK_STATE       = 1 << 3,
10051   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10052
10053   /* default flags for public API */
10054   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10055                                ADD_CHILD_EMIT_PARENT_SET |
10056                                ADD_CHILD_EMIT_ACTOR_ADDED |
10057                                ADD_CHILD_CHECK_STATE |
10058                                ADD_CHILD_NOTIFY_FIRST_LAST,
10059
10060   /* flags for legacy/deprecated API */
10061   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10062                                ADD_CHILD_CHECK_STATE |
10063                                ADD_CHILD_NOTIFY_FIRST_LAST
10064 } ClutterActorAddChildFlags;
10065
10066 /*< private >
10067  * clutter_actor_add_child_internal:
10068  * @self: a #ClutterActor
10069  * @child: a #ClutterActor
10070  * @flags: control flags for actions
10071  * @add_func: delegate function
10072  * @data: (closure): data to pass to @add_func
10073  *
10074  * Adds @child to the list of children of @self.
10075  *
10076  * The actual insertion inside the list is delegated to @add_func: this
10077  * function will just set up the state, perform basic checks, and emit
10078  * signals.
10079  *
10080  * The @flags argument is used to perform additional operations.
10081  */
10082 static inline void
10083 clutter_actor_add_child_internal (ClutterActor              *self,
10084                                   ClutterActor              *child,
10085                                   ClutterActorAddChildFlags  flags,
10086                                   ClutterActorAddChildFunc   add_func,
10087                                   gpointer                   data)
10088 {
10089   ClutterTextDirection text_dir;
10090   gboolean create_meta;
10091   gboolean emit_parent_set, emit_actor_added;
10092   gboolean check_state;
10093   gboolean notify_first_last;
10094   ClutterActor *old_first_child, *old_last_child;
10095
10096   if (child->priv->parent != NULL)
10097     {
10098       g_warning ("Cannot set a parent on an actor which has a parent. "
10099                  "You must use clutter_actor_remove_child() first.");
10100       return;
10101     }
10102
10103   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10104     {
10105       g_warning ("Cannot set a parent on a toplevel actor\n");
10106       return;
10107     }
10108
10109   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10110     {
10111       g_warning ("Cannot set a parent currently being destroyed");
10112       return;
10113     }
10114
10115   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10116   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10117   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10118   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10119   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10120
10121   old_first_child = self->priv->first_child;
10122   old_last_child = self->priv->last_child;
10123
10124   if (create_meta)
10125     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10126
10127   g_object_ref_sink (child);
10128   child->priv->parent = NULL;
10129   child->priv->next_sibling = NULL;
10130   child->priv->prev_sibling = NULL;
10131
10132   /* delegate the actual insertion */
10133   add_func (self, child, data);
10134
10135   g_assert (child->priv->parent == self);
10136
10137   self->priv->n_children += 1;
10138
10139   self->priv->age += 1;
10140
10141   /* if push_internal() has been called then we automatically set
10142    * the flag on the actor
10143    */
10144   if (self->priv->internal_child)
10145     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10146
10147   /* clutter_actor_reparent() will emit ::parent-set for us */
10148   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10149     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10150
10151   if (check_state)
10152     {
10153       /* If parent is mapped or realized, we need to also be mapped or
10154        * realized once we're inside the parent.
10155        */
10156       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10157
10158       /* propagate the parent's text direction to the child */
10159       text_dir = clutter_actor_get_text_direction (self);
10160       clutter_actor_set_text_direction (child, text_dir);
10161     }
10162
10163   if (child->priv->show_on_set_parent)
10164     clutter_actor_show (child);
10165
10166   if (CLUTTER_ACTOR_IS_MAPPED (child))
10167     clutter_actor_queue_redraw (child);
10168
10169   /* maintain the invariant that if an actor needs layout,
10170    * its parents do as well
10171    */
10172   if (child->priv->needs_width_request ||
10173       child->priv->needs_height_request ||
10174       child->priv->needs_allocation)
10175     {
10176       /* we work around the short-circuiting we do
10177        * in clutter_actor_queue_relayout() since we
10178        * want to force a relayout
10179        */
10180       child->priv->needs_width_request = TRUE;
10181       child->priv->needs_height_request = TRUE;
10182       child->priv->needs_allocation = TRUE;
10183
10184       clutter_actor_queue_relayout (child->priv->parent);
10185     }
10186
10187   if (emit_actor_added)
10188     g_signal_emit_by_name (self, "actor-added", child);
10189
10190   if (notify_first_last)
10191     {
10192       if (old_first_child != self->priv->first_child)
10193         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10194
10195       if (old_last_child != self->priv->last_child)
10196         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10197     }
10198 }
10199
10200 /**
10201  * clutter_actor_add_child:
10202  * @self: a #ClutterActor
10203  * @child: a #ClutterActor
10204  *
10205  * Adds @child to the children of @self.
10206  *
10207  * This function will acquire a reference on @child that will only
10208  * be released when calling clutter_actor_remove_child().
10209  *
10210  * This function will take into consideration the #ClutterActor:depth
10211  * of @child, and will keep the list of children sorted.
10212  *
10213  * This function will emit the #ClutterContainer::actor-added signal
10214  * on @self.
10215  *
10216  * Since: 1.10
10217  */
10218 void
10219 clutter_actor_add_child (ClutterActor *self,
10220                          ClutterActor *child)
10221 {
10222   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10223   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10224   g_return_if_fail (self != child);
10225   g_return_if_fail (child->priv->parent == NULL);
10226
10227   clutter_actor_add_child_internal (self, child,
10228                                     ADD_CHILD_DEFAULT_FLAGS,
10229                                     insert_child_at_depth,
10230                                     NULL);
10231 }
10232
10233 /**
10234  * clutter_actor_insert_child_at_index:
10235  * @self: a #ClutterActor
10236  * @child: a #ClutterActor
10237  * @index_: the index
10238  *
10239  * Inserts @child into the list of children of @self, using the
10240  * given @index_.
10241  *
10242  * This function will acquire a reference on @child that will only
10243  * be released when calling clutter_actor_remove_child().
10244  *
10245  * This function will not take into consideration the #ClutterActor:depth
10246  * of @child.
10247  *
10248  * This function will emit the #ClutterContainer::actor-added signal
10249  * on @self.
10250  *
10251  * Since: 1.10
10252  */
10253 void
10254 clutter_actor_insert_child_at_index (ClutterActor *self,
10255                                      ClutterActor *child,
10256                                      gint          index_)
10257 {
10258   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10259   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10260   g_return_if_fail (self != child);
10261   g_return_if_fail (child->priv->parent == NULL);
10262
10263   clutter_actor_add_child_internal (self, child,
10264                                     ADD_CHILD_DEFAULT_FLAGS,
10265                                     insert_child_at_index,
10266                                     GINT_TO_POINTER (index_));
10267 }
10268
10269 /**
10270  * clutter_actor_insert_child_above:
10271  * @self: a #ClutterActor
10272  * @child: a #ClutterActor
10273  * @sibling: (allow-none): a child of @self, or %NULL
10274  *
10275  * Inserts @child into the list of children of @self, above another
10276  * child of @self or, if @sibling is %NULL, above all the children
10277  * of @self.
10278  *
10279  * This function will acquire a reference on @child that will only
10280  * be released when calling clutter_actor_remove_child().
10281  *
10282  * This function will not take into consideration the #ClutterActor:depth
10283  * of @child.
10284  *
10285  * This function will emit the #ClutterContainer::actor-added signal
10286  * on @self.
10287  *
10288  * Since: 1.10
10289  */
10290 void
10291 clutter_actor_insert_child_above (ClutterActor *self,
10292                                   ClutterActor *child,
10293                                   ClutterActor *sibling)
10294 {
10295   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10296   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10297   g_return_if_fail (self != child);
10298   g_return_if_fail (child != sibling);
10299   g_return_if_fail (child->priv->parent == NULL);
10300   g_return_if_fail (sibling == NULL ||
10301                     (CLUTTER_IS_ACTOR (sibling) &&
10302                      sibling->priv->parent == self));
10303
10304   clutter_actor_add_child_internal (self, child,
10305                                     ADD_CHILD_DEFAULT_FLAGS,
10306                                     insert_child_above,
10307                                     sibling);
10308 }
10309
10310 /**
10311  * clutter_actor_insert_child_below:
10312  * @self: a #ClutterActor
10313  * @child: a #ClutterActor
10314  * @sibling: (allow-none): a child of @self, or %NULL
10315  *
10316  * Inserts @child into the list of children of @self, below another
10317  * child of @self or, if @sibling is %NULL, below all the children
10318  * of @self.
10319  *
10320  * This function will acquire a reference on @child that will only
10321  * be released when calling clutter_actor_remove_child().
10322  *
10323  * This function will not take into consideration the #ClutterActor:depth
10324  * of @child.
10325  *
10326  * This function will emit the #ClutterContainer::actor-added signal
10327  * on @self.
10328  *
10329  * Since: 1.10
10330  */
10331 void
10332 clutter_actor_insert_child_below (ClutterActor *self,
10333                                   ClutterActor *child,
10334                                   ClutterActor *sibling)
10335 {
10336   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10337   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10338   g_return_if_fail (self != child);
10339   g_return_if_fail (child != sibling);
10340   g_return_if_fail (child->priv->parent == NULL);
10341   g_return_if_fail (sibling == NULL ||
10342                     (CLUTTER_IS_ACTOR (sibling) &&
10343                      sibling->priv->parent == self));
10344
10345   clutter_actor_add_child_internal (self, child,
10346                                     ADD_CHILD_DEFAULT_FLAGS,
10347                                     insert_child_below,
10348                                     sibling);
10349 }
10350
10351 /**
10352  * clutter_actor_set_parent:
10353  * @self: A #ClutterActor
10354  * @parent: A new #ClutterActor parent
10355  *
10356  * Sets the parent of @self to @parent.
10357  *
10358  * This function will result in @parent acquiring a reference on @self,
10359  * eventually by sinking its floating reference first. The reference
10360  * will be released by clutter_actor_unparent().
10361  *
10362  * This function should only be called by legacy #ClutterActor<!-- -->s
10363  * implementing the #ClutterContainer interface.
10364  *
10365  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10366  */
10367 void
10368 clutter_actor_set_parent (ClutterActor *self,
10369                           ClutterActor *parent)
10370 {
10371   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10372   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10373   g_return_if_fail (self != parent);
10374   g_return_if_fail (self->priv->parent == NULL);
10375
10376   /* as this function will be called inside ClutterContainer::add
10377    * implementations or when building up a composite actor, we have
10378    * to preserve the old behaviour, and not create child meta or
10379    * emit the ::actor-added signal, to avoid recursion or double
10380    * emissions
10381    */
10382   clutter_actor_add_child_internal (parent, self,
10383                                     ADD_CHILD_LEGACY_FLAGS,
10384                                     insert_child_at_depth,
10385                                     NULL);
10386 }
10387
10388 /**
10389  * clutter_actor_get_parent:
10390  * @self: A #ClutterActor
10391  *
10392  * Retrieves the parent of @self.
10393  *
10394  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10395  *  if no parent is set
10396  */
10397 ClutterActor *
10398 clutter_actor_get_parent (ClutterActor *self)
10399 {
10400   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10401
10402   return self->priv->parent;
10403 }
10404
10405 /**
10406  * clutter_actor_get_paint_visibility:
10407  * @self: A #ClutterActor
10408  *
10409  * Retrieves the 'paint' visibility of an actor recursively checking for non
10410  * visible parents.
10411  *
10412  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10413  *
10414  * Return Value: %TRUE if the actor is visibile and will be painted.
10415  *
10416  * Since: 0.8.4
10417  */
10418 gboolean
10419 clutter_actor_get_paint_visibility (ClutterActor *actor)
10420 {
10421   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10422
10423   return CLUTTER_ACTOR_IS_MAPPED (actor);
10424 }
10425
10426 /**
10427  * clutter_actor_remove_child:
10428  * @self: a #ClutterActor
10429  * @child: a #ClutterActor
10430  *
10431  * Removes @child from the children of @self.
10432  *
10433  * This function will release the reference added by
10434  * clutter_actor_add_child(), so if you want to keep using @child
10435  * you will have to acquire a referenced on it before calling this
10436  * function.
10437  *
10438  * This function will emit the #ClutterContainer::actor-removed
10439  * signal on @self.
10440  *
10441  * Since: 1.10
10442  */
10443 void
10444 clutter_actor_remove_child (ClutterActor *self,
10445                             ClutterActor *child)
10446 {
10447   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10448   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10449   g_return_if_fail (self != child);
10450   g_return_if_fail (child->priv->parent != NULL);
10451   g_return_if_fail (child->priv->parent == self);
10452
10453   clutter_actor_remove_child_internal (self, child,
10454                                        REMOVE_CHILD_DEFAULT_FLAGS);
10455 }
10456
10457 /**
10458  * clutter_actor_remove_all_children:
10459  * @self: a #ClutterActor
10460  *
10461  * Removes all children of @self.
10462  *
10463  * This function releases the reference added by inserting a child actor
10464  * in the list of children of @self.
10465  *
10466  * If the reference count of a child drops to zero, the child will be
10467  * destroyed. If you want to ensure the destruction of all the children
10468  * of @self, use clutter_actor_destroy_all_children().
10469  *
10470  * Since: 1.10
10471  */
10472 void
10473 clutter_actor_remove_all_children (ClutterActor *self)
10474 {
10475   ClutterActorIter iter;
10476
10477   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10478
10479   if (self->priv->n_children == 0)
10480     return;
10481
10482   clutter_actor_iter_init (&iter, self);
10483   while (clutter_actor_iter_next (&iter, NULL))
10484     clutter_actor_iter_remove (&iter);
10485
10486   /* sanity check */
10487   g_assert (self->priv->first_child == NULL);
10488   g_assert (self->priv->last_child == NULL);
10489   g_assert (self->priv->n_children == 0);
10490 }
10491
10492 /**
10493  * clutter_actor_destroy_all_children:
10494  * @self: a #ClutterActor
10495  *
10496  * Destroys all children of @self.
10497  *
10498  * This function releases the reference added by inserting a child
10499  * actor in the list of children of @self, and ensures that the
10500  * #ClutterActor::destroy signal is emitted on each child of the
10501  * actor.
10502  *
10503  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10504  * when its reference count drops to 0; the default handler of the
10505  * #ClutterActor::destroy signal will destroy all the children of an
10506  * actor. This function ensures that all children are destroyed, instead
10507  * of just removed from @self, unlike clutter_actor_remove_all_children()
10508  * which will merely release the reference and remove each child.
10509  *
10510  * Unless you acquired an additional reference on each child of @self
10511  * prior to calling clutter_actor_remove_all_children() and want to reuse
10512  * the actors, you should use clutter_actor_destroy_all_children() in
10513  * order to make sure that children are destroyed and signal handlers
10514  * are disconnected even in cases where circular references prevent this
10515  * from automatically happening through reference counting alone.
10516  *
10517  * Since: 1.10
10518  */
10519 void
10520 clutter_actor_destroy_all_children (ClutterActor *self)
10521 {
10522   ClutterActorIter iter;
10523
10524   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10525
10526   if (self->priv->n_children == 0)
10527     return;
10528
10529   clutter_actor_iter_init (&iter, self);
10530   while (clutter_actor_iter_next (&iter, NULL))
10531     clutter_actor_iter_destroy (&iter);
10532
10533   /* sanity check */
10534   g_assert (self->priv->first_child == NULL);
10535   g_assert (self->priv->last_child == NULL);
10536   g_assert (self->priv->n_children == 0);
10537 }
10538
10539 typedef struct _InsertBetweenData {
10540   ClutterActor *prev_sibling;
10541   ClutterActor *next_sibling;
10542 } InsertBetweenData;
10543
10544 static void
10545 insert_child_between (ClutterActor *self,
10546                       ClutterActor *child,
10547                       gpointer      data_)
10548 {
10549   InsertBetweenData *data = data_;
10550   ClutterActor *prev_sibling = data->prev_sibling;
10551   ClutterActor *next_sibling = data->next_sibling;
10552
10553   child->priv->parent = self;
10554   child->priv->prev_sibling = prev_sibling;
10555   child->priv->next_sibling = next_sibling;
10556
10557   if (prev_sibling != NULL)
10558     prev_sibling->priv->next_sibling = child;
10559
10560   if (next_sibling != NULL)
10561     next_sibling->priv->prev_sibling = child;
10562
10563   if (child->priv->prev_sibling == NULL)
10564     self->priv->first_child = child;
10565
10566   if (child->priv->next_sibling == NULL)
10567     self->priv->last_child = child;
10568 }
10569
10570 /**
10571  * clutter_actor_replace_child:
10572  * @self: a #ClutterActor
10573  * @old_child: the child of @self to replace
10574  * @new_child: the #ClutterActor to replace @old_child
10575  *
10576  * Replaces @old_child with @new_child in the list of children of @self.
10577  *
10578  * Since: 1.10
10579  */
10580 void
10581 clutter_actor_replace_child (ClutterActor *self,
10582                              ClutterActor *old_child,
10583                              ClutterActor *new_child)
10584 {
10585   ClutterActor *prev_sibling, *next_sibling;
10586   InsertBetweenData clos;
10587
10588   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10589   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10590   g_return_if_fail (old_child->priv->parent == self);
10591   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10592   g_return_if_fail (old_child != new_child);
10593   g_return_if_fail (new_child != self);
10594   g_return_if_fail (new_child->priv->parent == NULL);
10595
10596   prev_sibling = old_child->priv->prev_sibling;
10597   next_sibling = old_child->priv->next_sibling;
10598   clutter_actor_remove_child_internal (self, old_child,
10599                                        REMOVE_CHILD_DEFAULT_FLAGS);
10600
10601   clos.prev_sibling = prev_sibling;
10602   clos.next_sibling = next_sibling;
10603   clutter_actor_add_child_internal (self, new_child,
10604                                     ADD_CHILD_DEFAULT_FLAGS,
10605                                     insert_child_between,
10606                                     &clos);
10607 }
10608
10609 /**
10610  * clutter_actor_unparent:
10611  * @self: a #ClutterActor
10612  *
10613  * Removes the parent of @self.
10614  *
10615  * This will cause the parent of @self to release the reference
10616  * acquired when calling clutter_actor_set_parent(), so if you
10617  * want to keep @self you will have to acquire a reference of
10618  * your own, through g_object_ref().
10619  *
10620  * This function should only be called by legacy #ClutterActor<!-- -->s
10621  * implementing the #ClutterContainer interface.
10622  *
10623  * Since: 0.1.1
10624  *
10625  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10626  */
10627 void
10628 clutter_actor_unparent (ClutterActor *self)
10629 {
10630   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10631
10632   if (self->priv->parent == NULL)
10633     return;
10634
10635   clutter_actor_remove_child_internal (self->priv->parent, self,
10636                                        REMOVE_CHILD_LEGACY_FLAGS);
10637 }
10638
10639 /**
10640  * clutter_actor_reparent:
10641  * @self: a #ClutterActor
10642  * @new_parent: the new #ClutterActor parent
10643  *
10644  * Resets the parent actor of @self.
10645  *
10646  * This function is logically equivalent to calling clutter_actor_unparent()
10647  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10648  * ensures the child is not finalized when unparented, and emits the
10649  * #ClutterActor::parent-set signal only once.
10650  *
10651  * In reality, calling this function is less useful than it sounds, as some
10652  * application code may rely on changes in the intermediate state between
10653  * removal and addition of the actor from its old parent to the @new_parent.
10654  * Thus, it is strongly encouraged to avoid using this function in application
10655  * code.
10656  *
10657  * Since: 0.2
10658  *
10659  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10660  *   clutter_actor_add_child() instead; remember to take a reference on
10661  *   the actor being removed before calling clutter_actor_remove_child()
10662  *   to avoid the reference count dropping to zero and the actor being
10663  *   destroyed.
10664  */
10665 void
10666 clutter_actor_reparent (ClutterActor *self,
10667                         ClutterActor *new_parent)
10668 {
10669   ClutterActorPrivate *priv;
10670
10671   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10672   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10673   g_return_if_fail (self != new_parent);
10674
10675   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10676     {
10677       g_warning ("Cannot set a parent on a toplevel actor");
10678       return;
10679     }
10680
10681   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10682     {
10683       g_warning ("Cannot set a parent currently being destroyed");
10684       return;
10685     }
10686
10687   priv = self->priv;
10688
10689   if (priv->parent != new_parent)
10690     {
10691       ClutterActor *old_parent;
10692
10693       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10694
10695       old_parent = priv->parent;
10696
10697       g_object_ref (self);
10698
10699       if (old_parent != NULL)
10700         {
10701          /* go through the Container implementation if this is a regular
10702           * child and not an internal one
10703           */
10704          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10705            {
10706              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10707
10708              /* this will have to call unparent() */
10709              clutter_container_remove_actor (parent, self);
10710            }
10711          else
10712            clutter_actor_remove_child_internal (old_parent, self,
10713                                                 REMOVE_CHILD_LEGACY_FLAGS);
10714         }
10715
10716       /* Note, will call set_parent() */
10717       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10718         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10719       else
10720         clutter_actor_add_child_internal (new_parent, self,
10721                                           ADD_CHILD_LEGACY_FLAGS,
10722                                           insert_child_at_depth,
10723                                           NULL);
10724
10725       /* we emit the ::parent-set signal once */
10726       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10727
10728       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10729
10730       /* the IN_REPARENT flag suspends state updates */
10731       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10732
10733       g_object_unref (self);
10734    }
10735 }
10736
10737 /**
10738  * clutter_actor_contains:
10739  * @self: A #ClutterActor
10740  * @descendant: A #ClutterActor, possibly contained in @self
10741  *
10742  * Determines if @descendant is contained inside @self (either as an
10743  * immediate child, or as a deeper descendant). If @self and
10744  * @descendant point to the same actor then it will also return %TRUE.
10745  *
10746  * Return value: whether @descendent is contained within @self
10747  *
10748  * Since: 1.4
10749  */
10750 gboolean
10751 clutter_actor_contains (ClutterActor *self,
10752                         ClutterActor *descendant)
10753 {
10754   ClutterActor *actor;
10755
10756   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10757   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10758
10759   for (actor = descendant; actor; actor = actor->priv->parent)
10760     if (actor == self)
10761       return TRUE;
10762
10763   return FALSE;
10764 }
10765
10766 /**
10767  * clutter_actor_set_child_above_sibling:
10768  * @self: a #ClutterActor
10769  * @child: a #ClutterActor child of @self
10770  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10771  *
10772  * Sets @child to be above @sibling in the list of children of @self.
10773  *
10774  * If @sibling is %NULL, @child will be the new last child of @self.
10775  *
10776  * This function is logically equivalent to removing @child and using
10777  * clutter_actor_insert_child_above(), but it will not emit signals
10778  * or change state on @child.
10779  *
10780  * Since: 1.10
10781  */
10782 void
10783 clutter_actor_set_child_above_sibling (ClutterActor *self,
10784                                        ClutterActor *child,
10785                                        ClutterActor *sibling)
10786 {
10787   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10788   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10789   g_return_if_fail (child->priv->parent == self);
10790   g_return_if_fail (child != sibling);
10791   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10792
10793   if (sibling != NULL)
10794     g_return_if_fail (sibling->priv->parent == self);
10795
10796   /* we don't want to change the state of child, or emit signals, or
10797    * regenerate ChildMeta instances here, but we still want to follow
10798    * the correct sequence of steps encoded in remove_child() and
10799    * add_child(), so that correctness is ensured, and we only go
10800    * through one known code path.
10801    */
10802   g_object_ref (child);
10803   clutter_actor_remove_child_internal (self, child, 0);
10804   clutter_actor_add_child_internal (self, child,
10805                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10806                                     insert_child_above,
10807                                     sibling);
10808
10809   clutter_actor_queue_relayout (self);
10810 }
10811
10812 /**
10813  * clutter_actor_set_child_below_sibling:
10814  * @self: a #ClutterActor
10815  * @child: a #ClutterActor child of @self
10816  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10817  *
10818  * Sets @child to be below @sibling in the list of children of @self.
10819  *
10820  * If @sibling is %NULL, @child will be the new first child of @self.
10821  *
10822  * This function is logically equivalent to removing @self and using
10823  * clutter_actor_insert_child_below(), but it will not emit signals
10824  * or change state on @child.
10825  *
10826  * Since: 1.10
10827  */
10828 void
10829 clutter_actor_set_child_below_sibling (ClutterActor *self,
10830                                        ClutterActor *child,
10831                                        ClutterActor *sibling)
10832 {
10833   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10834   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10835   g_return_if_fail (child->priv->parent == self);
10836   g_return_if_fail (child != sibling);
10837   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10838
10839   if (sibling != NULL)
10840     g_return_if_fail (sibling->priv->parent == self);
10841
10842   /* see the comment in set_child_above_sibling() */
10843   g_object_ref (child);
10844   clutter_actor_remove_child_internal (self, child, 0);
10845   clutter_actor_add_child_internal (self, child,
10846                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10847                                     insert_child_below,
10848                                     sibling);
10849
10850   clutter_actor_queue_relayout (self);
10851 }
10852
10853 /**
10854  * clutter_actor_set_child_at_index:
10855  * @self: a #ClutterActor
10856  * @child: a #ClutterActor child of @self
10857  * @index_: the new index for @child
10858  *
10859  * Changes the index of @child in the list of children of @self.
10860  *
10861  * This function is logically equivalent to removing @child and
10862  * calling clutter_actor_insert_child_at_index(), but it will not
10863  * emit signals or change state on @child.
10864  *
10865  * Since: 1.10
10866  */
10867 void
10868 clutter_actor_set_child_at_index (ClutterActor *self,
10869                                   ClutterActor *child,
10870                                   gint          index_)
10871 {
10872   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10873   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10874   g_return_if_fail (child->priv->parent == self);
10875   g_return_if_fail (index_ <= self->priv->n_children);
10876
10877   g_object_ref (child);
10878   clutter_actor_remove_child_internal (self, child, 0);
10879   clutter_actor_add_child_internal (self, child,
10880                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10881                                     insert_child_at_index,
10882                                     GINT_TO_POINTER (index_));
10883
10884   clutter_actor_queue_relayout (self);
10885 }
10886
10887 /**
10888  * clutter_actor_raise:
10889  * @self: A #ClutterActor
10890  * @below: (allow-none): A #ClutterActor to raise above.
10891  *
10892  * Puts @self above @below.
10893  *
10894  * Both actors must have the same parent, and the parent must implement
10895  * the #ClutterContainer interface
10896  *
10897  * This function calls clutter_container_raise_child() internally.
10898  *
10899  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
10900  */
10901 void
10902 clutter_actor_raise (ClutterActor *self,
10903                      ClutterActor *below)
10904 {
10905   ClutterActor *parent;
10906
10907   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10908
10909   parent = clutter_actor_get_parent (self);
10910   if (parent == NULL)
10911     {
10912       g_warning ("%s: Actor '%s' is not inside a container",
10913                  G_STRFUNC,
10914                  _clutter_actor_get_debug_name (self));
10915       return;
10916     }
10917
10918   if (below != NULL)
10919     {
10920       if (parent != clutter_actor_get_parent (below))
10921         {
10922           g_warning ("%s Actor '%s' is not in the same container as "
10923                      "actor '%s'",
10924                      G_STRFUNC,
10925                      _clutter_actor_get_debug_name (self),
10926                      _clutter_actor_get_debug_name (below));
10927           return;
10928         }
10929     }
10930
10931   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
10932 }
10933
10934 /**
10935  * clutter_actor_lower:
10936  * @self: A #ClutterActor
10937  * @above: (allow-none): A #ClutterActor to lower below
10938  *
10939  * Puts @self below @above.
10940  *
10941  * Both actors must have the same parent, and the parent must implement
10942  * the #ClutterContainer interface.
10943  *
10944  * This function calls clutter_container_lower_child() internally.
10945  *
10946  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
10947  */
10948 void
10949 clutter_actor_lower (ClutterActor *self,
10950                      ClutterActor *above)
10951 {
10952   ClutterActor *parent;
10953
10954   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10955
10956   parent = clutter_actor_get_parent (self);
10957   if (parent == NULL)
10958     {
10959       g_warning ("%s: Actor of type %s is not inside a container",
10960                  G_STRFUNC,
10961                  _clutter_actor_get_debug_name (self));
10962       return;
10963     }
10964
10965   if (above)
10966     {
10967       if (parent != clutter_actor_get_parent (above))
10968         {
10969           g_warning ("%s: Actor '%s' is not in the same container as "
10970                      "actor '%s'",
10971                      G_STRFUNC,
10972                      _clutter_actor_get_debug_name (self),
10973                      _clutter_actor_get_debug_name (above));
10974           return;
10975         }
10976     }
10977
10978   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
10979 }
10980
10981 /**
10982  * clutter_actor_raise_top:
10983  * @self: A #ClutterActor
10984  *
10985  * Raises @self to the top.
10986  *
10987  * This function calls clutter_actor_raise() internally.
10988  *
10989  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
10990  *   a %NULL sibling, instead.
10991  */
10992 void
10993 clutter_actor_raise_top (ClutterActor *self)
10994 {
10995   clutter_actor_raise (self, NULL);
10996 }
10997
10998 /**
10999  * clutter_actor_lower_bottom:
11000  * @self: A #ClutterActor
11001  *
11002  * Lowers @self to the bottom.
11003  *
11004  * This function calls clutter_actor_lower() internally.
11005  *
11006  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11007  *   a %NULL sibling, instead.
11008  */
11009 void
11010 clutter_actor_lower_bottom (ClutterActor *self)
11011 {
11012   clutter_actor_lower (self, NULL);
11013 }
11014
11015 /*
11016  * Event handling
11017  */
11018
11019 /**
11020  * clutter_actor_event:
11021  * @actor: a #ClutterActor
11022  * @event: a #ClutterEvent
11023  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11024  *
11025  * This function is used to emit an event on the main stage.
11026  * You should rarely need to use this function, except for
11027  * synthetising events.
11028  *
11029  * Return value: the return value from the signal emission: %TRUE
11030  *   if the actor handled the event, or %FALSE if the event was
11031  *   not handled
11032  *
11033  * Since: 0.6
11034  */
11035 gboolean
11036 clutter_actor_event (ClutterActor *actor,
11037                      ClutterEvent *event,
11038                      gboolean      capture)
11039 {
11040   gboolean retval = FALSE;
11041   gint signal_num = -1;
11042
11043   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11044   g_return_val_if_fail (event != NULL, FALSE);
11045
11046   g_object_ref (actor);
11047
11048   if (capture)
11049     {
11050       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11051                      event,
11052                      &retval);
11053       goto out;
11054     }
11055
11056   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11057
11058   if (!retval)
11059     {
11060       switch (event->type)
11061         {
11062         case CLUTTER_NOTHING:
11063           break;
11064         case CLUTTER_BUTTON_PRESS:
11065           signal_num = BUTTON_PRESS_EVENT;
11066           break;
11067         case CLUTTER_BUTTON_RELEASE:
11068           signal_num = BUTTON_RELEASE_EVENT;
11069           break;
11070         case CLUTTER_SCROLL:
11071           signal_num = SCROLL_EVENT;
11072           break;
11073         case CLUTTER_KEY_PRESS:
11074           signal_num = KEY_PRESS_EVENT;
11075           break;
11076         case CLUTTER_KEY_RELEASE:
11077           signal_num = KEY_RELEASE_EVENT;
11078           break;
11079         case CLUTTER_MOTION:
11080           signal_num = MOTION_EVENT;
11081           break;
11082         case CLUTTER_ENTER:
11083           signal_num = ENTER_EVENT;
11084           break;
11085         case CLUTTER_LEAVE:
11086           signal_num = LEAVE_EVENT;
11087           break;
11088         case CLUTTER_DELETE:
11089         case CLUTTER_DESTROY_NOTIFY:
11090         case CLUTTER_CLIENT_MESSAGE:
11091         default:
11092           signal_num = -1;
11093           break;
11094         }
11095
11096       if (signal_num != -1)
11097         g_signal_emit (actor, actor_signals[signal_num], 0,
11098                        event, &retval);
11099     }
11100
11101 out:
11102   g_object_unref (actor);
11103
11104   return retval;
11105 }
11106
11107 /**
11108  * clutter_actor_set_reactive:
11109  * @actor: a #ClutterActor
11110  * @reactive: whether the actor should be reactive to events
11111  *
11112  * Sets @actor as reactive. Reactive actors will receive events.
11113  *
11114  * Since: 0.6
11115  */
11116 void
11117 clutter_actor_set_reactive (ClutterActor *actor,
11118                             gboolean      reactive)
11119 {
11120   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11121
11122   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11123     return;
11124
11125   if (reactive)
11126     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11127   else
11128     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11129
11130   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11131 }
11132
11133 /**
11134  * clutter_actor_get_reactive:
11135  * @actor: a #ClutterActor
11136  *
11137  * Checks whether @actor is marked as reactive.
11138  *
11139  * Return value: %TRUE if the actor is reactive
11140  *
11141  * Since: 0.6
11142  */
11143 gboolean
11144 clutter_actor_get_reactive (ClutterActor *actor)
11145 {
11146   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11147
11148   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11149 }
11150
11151 /**
11152  * clutter_actor_get_anchor_point:
11153  * @self: a #ClutterActor
11154  * @anchor_x: (out): return location for the X coordinate of the anchor point
11155  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11156  *
11157  * Gets the current anchor point of the @actor in pixels.
11158  *
11159  * Since: 0.6
11160  */
11161 void
11162 clutter_actor_get_anchor_point (ClutterActor *self,
11163                                 gfloat       *anchor_x,
11164                                 gfloat       *anchor_y)
11165 {
11166   const ClutterTransformInfo *info;
11167
11168   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11169
11170   info = _clutter_actor_get_transform_info_or_defaults (self);
11171   clutter_anchor_coord_get_units (self, &info->anchor,
11172                                   anchor_x,
11173                                   anchor_y,
11174                                   NULL);
11175 }
11176
11177 /**
11178  * clutter_actor_set_anchor_point:
11179  * @self: a #ClutterActor
11180  * @anchor_x: X coordinate of the anchor point
11181  * @anchor_y: Y coordinate of the anchor point
11182  *
11183  * Sets an anchor point for @self. The anchor point is a point in the
11184  * coordinate space of an actor to which the actor position within its
11185  * parent is relative; the default is (0, 0), i.e. the top-left corner
11186  * of the actor.
11187  *
11188  * Since: 0.6
11189  */
11190 void
11191 clutter_actor_set_anchor_point (ClutterActor *self,
11192                                 gfloat        anchor_x,
11193                                 gfloat        anchor_y)
11194 {
11195   ClutterTransformInfo *info;
11196   ClutterActorPrivate *priv;
11197   gboolean changed = FALSE;
11198   gfloat old_anchor_x, old_anchor_y;
11199   GObject *obj;
11200
11201   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11202
11203   obj = G_OBJECT (self);
11204   priv = self->priv;
11205   info = _clutter_actor_get_transform_info (self);
11206
11207   g_object_freeze_notify (obj);
11208
11209   clutter_anchor_coord_get_units (self, &info->anchor,
11210                                   &old_anchor_x,
11211                                   &old_anchor_y,
11212                                   NULL);
11213
11214   if (info->anchor.is_fractional)
11215     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11216
11217   if (old_anchor_x != anchor_x)
11218     {
11219       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11220       changed = TRUE;
11221     }
11222
11223   if (old_anchor_y != anchor_y)
11224     {
11225       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11226       changed = TRUE;
11227     }
11228
11229   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11230
11231   if (changed)
11232     {
11233       priv->transform_valid = FALSE;
11234       clutter_actor_queue_redraw (self);
11235     }
11236
11237   g_object_thaw_notify (obj);
11238 }
11239
11240 /**
11241  * clutter_actor_get_anchor_point_gravity:
11242  * @self: a #ClutterActor
11243  *
11244  * Retrieves the anchor position expressed as a #ClutterGravity. If
11245  * the anchor point was specified using pixels or units this will
11246  * return %CLUTTER_GRAVITY_NONE.
11247  *
11248  * Return value: the #ClutterGravity used by the anchor point
11249  *
11250  * Since: 1.0
11251  */
11252 ClutterGravity
11253 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11254 {
11255   const ClutterTransformInfo *info;
11256
11257   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11258
11259   info = _clutter_actor_get_transform_info_or_defaults (self);
11260
11261   return clutter_anchor_coord_get_gravity (&info->anchor);
11262 }
11263
11264 /**
11265  * clutter_actor_move_anchor_point:
11266  * @self: a #ClutterActor
11267  * @anchor_x: X coordinate of the anchor point
11268  * @anchor_y: Y coordinate of the anchor point
11269  *
11270  * Sets an anchor point for the actor, and adjusts the actor postion so that
11271  * the relative position of the actor toward its parent remains the same.
11272  *
11273  * Since: 0.6
11274  */
11275 void
11276 clutter_actor_move_anchor_point (ClutterActor *self,
11277                                  gfloat        anchor_x,
11278                                  gfloat        anchor_y)
11279 {
11280   gfloat old_anchor_x, old_anchor_y;
11281   const ClutterTransformInfo *info;
11282
11283   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11284
11285   info = _clutter_actor_get_transform_info (self);
11286   clutter_anchor_coord_get_units (self, &info->anchor,
11287                                   &old_anchor_x,
11288                                   &old_anchor_y,
11289                                   NULL);
11290
11291   g_object_freeze_notify (G_OBJECT (self));
11292
11293   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11294
11295   if (self->priv->position_set)
11296     clutter_actor_move_by (self,
11297                            anchor_x - old_anchor_x,
11298                            anchor_y - old_anchor_y);
11299
11300   g_object_thaw_notify (G_OBJECT (self));
11301 }
11302
11303 /**
11304  * clutter_actor_move_anchor_point_from_gravity:
11305  * @self: a #ClutterActor
11306  * @gravity: #ClutterGravity.
11307  *
11308  * Sets an anchor point on the actor based on the given gravity, adjusting the
11309  * actor postion so that its relative position within its parent remains
11310  * unchanged.
11311  *
11312  * Since version 1.0 the anchor point will be stored as a gravity so
11313  * that if the actor changes size then the anchor point will move. For
11314  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11315  * and later double the size of the actor, the anchor point will move
11316  * to the bottom right.
11317  *
11318  * Since: 0.6
11319  */
11320 void
11321 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11322                                               ClutterGravity  gravity)
11323 {
11324   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11325   const ClutterTransformInfo *info;
11326   ClutterActorPrivate *priv;
11327
11328   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11329
11330   priv = self->priv;
11331   info = _clutter_actor_get_transform_info (self);
11332
11333   g_object_freeze_notify (G_OBJECT (self));
11334
11335   clutter_anchor_coord_get_units (self, &info->anchor,
11336                                   &old_anchor_x,
11337                                   &old_anchor_y,
11338                                   NULL);
11339   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11340   clutter_anchor_coord_get_units (self, &info->anchor,
11341                                   &new_anchor_x,
11342                                   &new_anchor_y,
11343                                   NULL);
11344
11345   if (priv->position_set)
11346     clutter_actor_move_by (self,
11347                            new_anchor_x - old_anchor_x,
11348                            new_anchor_y - old_anchor_y);
11349
11350   g_object_thaw_notify (G_OBJECT (self));
11351 }
11352
11353 /**
11354  * clutter_actor_set_anchor_point_from_gravity:
11355  * @self: a #ClutterActor
11356  * @gravity: #ClutterGravity.
11357  *
11358  * Sets an anchor point on the actor, based on the given gravity (this is a
11359  * convenience function wrapping clutter_actor_set_anchor_point()).
11360  *
11361  * Since version 1.0 the anchor point will be stored as a gravity so
11362  * that if the actor changes size then the anchor point will move. For
11363  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11364  * and later double the size of the actor, the anchor point will move
11365  * to the bottom right.
11366  *
11367  * Since: 0.6
11368  */
11369 void
11370 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11371                                              ClutterGravity  gravity)
11372 {
11373   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11374
11375   if (gravity == CLUTTER_GRAVITY_NONE)
11376     clutter_actor_set_anchor_point (self, 0, 0);
11377   else
11378     {
11379       GObject *obj = G_OBJECT (self);
11380       ClutterTransformInfo *info;
11381
11382       g_object_freeze_notify (obj);
11383
11384       info = _clutter_actor_get_transform_info (self);
11385       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11386
11387       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11388       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11389       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11390
11391       self->priv->transform_valid = FALSE;
11392
11393       clutter_actor_queue_redraw (self);
11394
11395       g_object_thaw_notify (obj);
11396     }
11397 }
11398
11399 static void
11400 clutter_container_iface_init (ClutterContainerIface *iface)
11401 {
11402   /* we don't override anything, as ClutterContainer already has a default
11403    * implementation that we can use, and which calls into our own API.
11404    */
11405 }
11406
11407 typedef enum
11408 {
11409   PARSE_X,
11410   PARSE_Y,
11411   PARSE_WIDTH,
11412   PARSE_HEIGHT,
11413   PARSE_ANCHOR_X,
11414   PARSE_ANCHOR_Y
11415 } ParseDimension;
11416
11417 static gfloat
11418 parse_units (ClutterActor   *self,
11419              ParseDimension  dimension,
11420              JsonNode       *node)
11421 {
11422   GValue value = { 0, };
11423   gfloat retval = 0;
11424
11425   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11426     return 0;
11427
11428   json_node_get_value (node, &value);
11429
11430   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11431     {
11432       retval = (gfloat) g_value_get_int64 (&value);
11433     }
11434   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11435     {
11436       retval = g_value_get_double (&value);
11437     }
11438   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11439     {
11440       ClutterUnits units;
11441       gboolean res;
11442
11443       res = clutter_units_from_string (&units, g_value_get_string (&value));
11444       if (res)
11445         retval = clutter_units_to_pixels (&units);
11446       else
11447         {
11448           g_warning ("Invalid value '%s': integers, strings or floating point "
11449                      "values can be used for the x, y, width and height "
11450                      "properties. Valid modifiers for strings are 'px', 'mm', "
11451                      "'pt' and 'em'.",
11452                      g_value_get_string (&value));
11453           retval = 0;
11454         }
11455     }
11456   else
11457     {
11458       g_warning ("Invalid value of type '%s': integers, strings of floating "
11459                  "point values can be used for the x, y, width, height "
11460                  "anchor-x and anchor-y properties.",
11461                  g_type_name (G_VALUE_TYPE (&value)));
11462     }
11463
11464   g_value_unset (&value);
11465
11466   return retval;
11467 }
11468
11469 typedef struct {
11470   ClutterRotateAxis axis;
11471
11472   gdouble angle;
11473
11474   gfloat center_x;
11475   gfloat center_y;
11476   gfloat center_z;
11477 } RotationInfo;
11478
11479 static inline gboolean
11480 parse_rotation_array (ClutterActor *actor,
11481                       JsonArray    *array,
11482                       RotationInfo *info)
11483 {
11484   JsonNode *element;
11485
11486   if (json_array_get_length (array) != 2)
11487     return FALSE;
11488
11489   /* angle */
11490   element = json_array_get_element (array, 0);
11491   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11492     info->angle = json_node_get_double (element);
11493   else
11494     return FALSE;
11495
11496   /* center */
11497   element = json_array_get_element (array, 1);
11498   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11499     {
11500       JsonArray *center = json_node_get_array (element);
11501
11502       if (json_array_get_length (center) != 2)
11503         return FALSE;
11504
11505       switch (info->axis)
11506         {
11507         case CLUTTER_X_AXIS:
11508           info->center_y = parse_units (actor, PARSE_Y,
11509                                         json_array_get_element (center, 0));
11510           info->center_z = parse_units (actor, PARSE_Y,
11511                                         json_array_get_element (center, 1));
11512           return TRUE;
11513
11514         case CLUTTER_Y_AXIS:
11515           info->center_x = parse_units (actor, PARSE_X,
11516                                         json_array_get_element (center, 0));
11517           info->center_z = parse_units (actor, PARSE_X,
11518                                         json_array_get_element (center, 1));
11519           return TRUE;
11520
11521         case CLUTTER_Z_AXIS:
11522           info->center_x = parse_units (actor, PARSE_X,
11523                                         json_array_get_element (center, 0));
11524           info->center_y = parse_units (actor, PARSE_Y,
11525                                         json_array_get_element (center, 1));
11526           return TRUE;
11527         }
11528     }
11529
11530   return FALSE;
11531 }
11532
11533 static gboolean
11534 parse_rotation (ClutterActor *actor,
11535                 JsonNode     *node,
11536                 RotationInfo *info)
11537 {
11538   JsonArray *array;
11539   guint len, i;
11540   gboolean retval = FALSE;
11541
11542   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11543     {
11544       g_warning ("Invalid node of type '%s' found, expecting an array",
11545                  json_node_type_name (node));
11546       return FALSE;
11547     }
11548
11549   array = json_node_get_array (node);
11550   len = json_array_get_length (array);
11551
11552   for (i = 0; i < len; i++)
11553     {
11554       JsonNode *element = json_array_get_element (array, i);
11555       JsonObject *object;
11556       JsonNode *member;
11557
11558       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11559         {
11560           g_warning ("Invalid node of type '%s' found, expecting an object",
11561                      json_node_type_name (element));
11562           return FALSE;
11563         }
11564
11565       object = json_node_get_object (element);
11566
11567       if (json_object_has_member (object, "x-axis"))
11568         {
11569           member = json_object_get_member (object, "x-axis");
11570
11571           info->axis = CLUTTER_X_AXIS;
11572
11573           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11574             {
11575               info->angle = json_node_get_double (member);
11576               retval = TRUE;
11577             }
11578           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11579             retval = parse_rotation_array (actor,
11580                                            json_node_get_array (member),
11581                                            info);
11582           else
11583             retval = FALSE;
11584         }
11585       else if (json_object_has_member (object, "y-axis"))
11586         {
11587           member = json_object_get_member (object, "y-axis");
11588
11589           info->axis = CLUTTER_Y_AXIS;
11590
11591           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11592             {
11593               info->angle = json_node_get_double (member);
11594               retval = TRUE;
11595             }
11596           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11597             retval = parse_rotation_array (actor,
11598                                            json_node_get_array (member),
11599                                            info);
11600           else
11601             retval = FALSE;
11602         }
11603       else if (json_object_has_member (object, "z-axis"))
11604         {
11605           member = json_object_get_member (object, "z-axis");
11606
11607           info->axis = CLUTTER_Z_AXIS;
11608
11609           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11610             {
11611               info->angle = json_node_get_double (member);
11612               retval = TRUE;
11613             }
11614           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11615             retval = parse_rotation_array (actor,
11616                                            json_node_get_array (member),
11617                                            info);
11618           else
11619             retval = FALSE;
11620         }
11621     }
11622
11623   return retval;
11624 }
11625
11626 static GSList *
11627 parse_actor_metas (ClutterScript *script,
11628                    ClutterActor  *actor,
11629                    JsonNode      *node)
11630 {
11631   GList *elements, *l;
11632   GSList *retval = NULL;
11633
11634   if (!JSON_NODE_HOLDS_ARRAY (node))
11635     return NULL;
11636
11637   elements = json_array_get_elements (json_node_get_array (node));
11638
11639   for (l = elements; l != NULL; l = l->next)
11640     {
11641       JsonNode *element = l->data;
11642       const gchar *id_ = _clutter_script_get_id_from_node (element);
11643       GObject *meta;
11644
11645       if (id_ == NULL || *id_ == '\0')
11646         continue;
11647
11648       meta = clutter_script_get_object (script, id_);
11649       if (meta == NULL)
11650         continue;
11651
11652       retval = g_slist_prepend (retval, meta);
11653     }
11654
11655   g_list_free (elements);
11656
11657   return g_slist_reverse (retval);
11658 }
11659
11660 static GSList *
11661 parse_behaviours (ClutterScript *script,
11662                   ClutterActor  *actor,
11663                   JsonNode      *node)
11664 {
11665   GList *elements, *l;
11666   GSList *retval = NULL;
11667
11668   if (!JSON_NODE_HOLDS_ARRAY (node))
11669     return NULL;
11670
11671   elements = json_array_get_elements (json_node_get_array (node));
11672
11673   for (l = elements; l != NULL; l = l->next)
11674     {
11675       JsonNode *element = l->data;
11676       const gchar *id_ = _clutter_script_get_id_from_node (element);
11677       GObject *behaviour;
11678
11679       if (id_ == NULL || *id_ == '\0')
11680         continue;
11681
11682       behaviour = clutter_script_get_object (script, id_);
11683       if (behaviour == NULL)
11684         continue;
11685
11686       retval = g_slist_prepend (retval, behaviour);
11687     }
11688
11689   g_list_free (elements);
11690
11691   return g_slist_reverse (retval);
11692 }
11693
11694 static gboolean
11695 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11696                                  ClutterScript     *script,
11697                                  GValue            *value,
11698                                  const gchar       *name,
11699                                  JsonNode          *node)
11700 {
11701   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11702   gboolean retval = FALSE;
11703
11704   if ((name[0] == 'x' && name[1] == '\0') ||
11705       (name[0] == 'y' && name[1] == '\0') ||
11706       (strcmp (name, "width") == 0) ||
11707       (strcmp (name, "height") == 0) ||
11708       (strcmp (name, "anchor_x") == 0) ||
11709       (strcmp (name, "anchor_y") == 0))
11710     {
11711       ParseDimension dimension;
11712       gfloat units;
11713
11714       if (name[0] == 'x')
11715         dimension = PARSE_X;
11716       else if (name[0] == 'y')
11717         dimension = PARSE_Y;
11718       else if (name[0] == 'w')
11719         dimension = PARSE_WIDTH;
11720       else if (name[0] == 'h')
11721         dimension = PARSE_HEIGHT;
11722       else if (name[0] == 'a' && name[7] == 'x')
11723         dimension = PARSE_ANCHOR_X;
11724       else if (name[0] == 'a' && name[7] == 'y')
11725         dimension = PARSE_ANCHOR_Y;
11726       else
11727         return FALSE;
11728
11729       units = parse_units (actor, dimension, node);
11730
11731       /* convert back to pixels: all properties are pixel-based */
11732       g_value_init (value, G_TYPE_FLOAT);
11733       g_value_set_float (value, units);
11734
11735       retval = TRUE;
11736     }
11737   else if (strcmp (name, "rotation") == 0)
11738     {
11739       RotationInfo *info;
11740
11741       info = g_slice_new0 (RotationInfo);
11742       retval = parse_rotation (actor, node, info);
11743
11744       if (retval)
11745         {
11746           g_value_init (value, G_TYPE_POINTER);
11747           g_value_set_pointer (value, info);
11748         }
11749       else
11750         g_slice_free (RotationInfo, info);
11751     }
11752   else if (strcmp (name, "behaviours") == 0)
11753     {
11754       GSList *l;
11755
11756 #ifdef CLUTTER_ENABLE_DEBUG
11757       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11758         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11759                                      "and it should not be used in newly "
11760                                      "written ClutterScript definitions.");
11761 #endif
11762
11763       l = parse_behaviours (script, actor, node);
11764
11765       g_value_init (value, G_TYPE_POINTER);
11766       g_value_set_pointer (value, l);
11767
11768       retval = TRUE;
11769     }
11770   else if (strcmp (name, "actions") == 0 ||
11771            strcmp (name, "constraints") == 0 ||
11772            strcmp (name, "effects") == 0)
11773     {
11774       GSList *l;
11775
11776       l = parse_actor_metas (script, actor, node);
11777
11778       g_value_init (value, G_TYPE_POINTER);
11779       g_value_set_pointer (value, l);
11780
11781       retval = TRUE;
11782     }
11783
11784   return retval;
11785 }
11786
11787 static void
11788 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11789                                    ClutterScript     *script,
11790                                    const gchar       *name,
11791                                    const GValue      *value)
11792 {
11793   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11794
11795 #ifdef CLUTTER_ENABLE_DEBUG
11796   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11797     {
11798       gchar *tmp = g_strdup_value_contents (value);
11799
11800       CLUTTER_NOTE (SCRIPT,
11801                     "in ClutterActor::set_custom_property('%s') = %s",
11802                     name,
11803                     tmp);
11804
11805       g_free (tmp);
11806     }
11807 #endif /* CLUTTER_ENABLE_DEBUG */
11808
11809   if (strcmp (name, "rotation") == 0)
11810     {
11811       RotationInfo *info;
11812
11813       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11814         return;
11815
11816       info = g_value_get_pointer (value);
11817
11818       clutter_actor_set_rotation (actor,
11819                                   info->axis, info->angle,
11820                                   info->center_x,
11821                                   info->center_y,
11822                                   info->center_z);
11823
11824       g_slice_free (RotationInfo, info);
11825
11826       return;
11827     }
11828
11829   if (strcmp (name, "behaviours") == 0)
11830     {
11831       GSList *behaviours, *l;
11832
11833       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11834         return;
11835
11836       behaviours = g_value_get_pointer (value);
11837       for (l = behaviours; l != NULL; l = l->next)
11838         {
11839           ClutterBehaviour *behaviour = l->data;
11840
11841           clutter_behaviour_apply (behaviour, actor);
11842         }
11843
11844       g_slist_free (behaviours);
11845
11846       return;
11847     }
11848
11849   if (strcmp (name, "actions") == 0 ||
11850       strcmp (name, "constraints") == 0 ||
11851       strcmp (name, "effects") == 0)
11852     {
11853       GSList *metas, *l;
11854
11855       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11856         return;
11857
11858       metas = g_value_get_pointer (value);
11859       for (l = metas; l != NULL; l = l->next)
11860         {
11861           if (name[0] == 'a')
11862             clutter_actor_add_action (actor, l->data);
11863
11864           if (name[0] == 'c')
11865             clutter_actor_add_constraint (actor, l->data);
11866
11867           if (name[0] == 'e')
11868             clutter_actor_add_effect (actor, l->data);
11869         }
11870
11871       g_slist_free (metas);
11872
11873       return;
11874     }
11875
11876   g_object_set_property (G_OBJECT (scriptable), name, value);
11877 }
11878
11879 static void
11880 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
11881 {
11882   iface->parse_custom_node = clutter_actor_parse_custom_node;
11883   iface->set_custom_property = clutter_actor_set_custom_property;
11884 }
11885
11886 static ClutterActorMeta *
11887 get_meta_from_animation_property (ClutterActor  *actor,
11888                                   const gchar   *name,
11889                                   gchar        **name_p)
11890 {
11891   ClutterActorPrivate *priv = actor->priv;
11892   ClutterActorMeta *meta = NULL;
11893   gchar **tokens;
11894
11895   /* if this is not a special property, fall through */
11896   if (name[0] != '@')
11897     return NULL;
11898
11899   /* detect the properties named using the following spec:
11900    *
11901    *   @<section>.<meta-name>.<property-name>
11902    *
11903    * where <section> can be one of the following:
11904    *
11905    *   - actions
11906    *   - constraints
11907    *   - effects
11908    *
11909    * and <meta-name> is the name set on a specific ActorMeta
11910    */
11911
11912   tokens = g_strsplit (name + 1, ".", -1);
11913   if (tokens == NULL || g_strv_length (tokens) != 3)
11914     {
11915       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
11916                     name + 1);
11917       g_strfreev (tokens);
11918       return NULL;
11919     }
11920
11921   if (strcmp (tokens[0], "actions") == 0)
11922     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
11923
11924   if (strcmp (tokens[0], "constraints") == 0)
11925     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
11926
11927   if (strcmp (tokens[0], "effects") == 0)
11928     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
11929
11930   if (name_p != NULL)
11931     *name_p = g_strdup (tokens[2]);
11932
11933   CLUTTER_NOTE (ANIMATION,
11934                 "Looking for property '%s' of object '%s' in section '%s'",
11935                 tokens[2],
11936                 tokens[1],
11937                 tokens[0]);
11938
11939   g_strfreev (tokens);
11940
11941   return meta;
11942 }
11943
11944 static GParamSpec *
11945 clutter_actor_find_property (ClutterAnimatable *animatable,
11946                              const gchar       *property_name)
11947 {
11948   ClutterActorMeta *meta = NULL;
11949   GObjectClass *klass = NULL;
11950   GParamSpec *pspec = NULL;
11951   gchar *p_name = NULL;
11952
11953   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11954                                            property_name,
11955                                            &p_name);
11956
11957   if (meta != NULL)
11958     {
11959       klass = G_OBJECT_GET_CLASS (meta);
11960
11961       pspec = g_object_class_find_property (klass, p_name);
11962     }
11963   else
11964     {
11965       klass = G_OBJECT_GET_CLASS (animatable);
11966
11967       pspec = g_object_class_find_property (klass, property_name);
11968     }
11969
11970   g_free (p_name);
11971
11972   return pspec;
11973 }
11974
11975 static void
11976 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
11977                                  const gchar       *property_name,
11978                                  GValue            *initial)
11979 {
11980   ClutterActorMeta *meta = NULL;
11981   gchar *p_name = NULL;
11982
11983   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11984                                            property_name,
11985                                            &p_name);
11986
11987   if (meta != NULL)
11988     g_object_get_property (G_OBJECT (meta), p_name, initial);
11989   else
11990     g_object_get_property (G_OBJECT (animatable), property_name, initial);
11991
11992   g_free (p_name);
11993 }
11994
11995 static void
11996 clutter_actor_set_final_state (ClutterAnimatable *animatable,
11997                                const gchar       *property_name,
11998                                const GValue      *final)
11999 {
12000   ClutterActorMeta *meta = NULL;
12001   gchar *p_name = NULL;
12002
12003   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12004                                            property_name,
12005                                            &p_name);
12006   if (meta != NULL)
12007     g_object_set_property (G_OBJECT (meta), p_name, final);
12008   else
12009     g_object_set_property (G_OBJECT (animatable), property_name, final);
12010
12011   g_free (p_name);
12012 }
12013
12014 static void
12015 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12016 {
12017   iface->find_property = clutter_actor_find_property;
12018   iface->get_initial_state = clutter_actor_get_initial_state;
12019   iface->set_final_state = clutter_actor_set_final_state;
12020 }
12021
12022 /**
12023  * clutter_actor_transform_stage_point:
12024  * @self: A #ClutterActor
12025  * @x: (in): x screen coordinate of the point to unproject
12026  * @y: (in): y screen coordinate of the point to unproject
12027  * @x_out: (out): return location for the unprojected x coordinance
12028  * @y_out: (out): return location for the unprojected y coordinance
12029  *
12030  * This function translates screen coordinates (@x, @y) to
12031  * coordinates relative to the actor. For example, it can be used to translate
12032  * screen events from global screen coordinates into actor-local coordinates.
12033  *
12034  * The conversion can fail, notably if the transform stack results in the
12035  * actor being projected on the screen as a mere line.
12036  *
12037  * The conversion should not be expected to be pixel-perfect due to the
12038  * nature of the operation. In general the error grows when the skewing
12039  * of the actor rectangle on screen increases.
12040  *
12041  * <note><para>This function can be computationally intensive.</para></note>
12042  *
12043  * <note><para>This function only works when the allocation is up-to-date,
12044  * i.e. inside of paint().</para></note>
12045  *
12046  * Return value: %TRUE if conversion was successful.
12047  *
12048  * Since: 0.6
12049  */
12050 gboolean
12051 clutter_actor_transform_stage_point (ClutterActor *self,
12052                                      gfloat        x,
12053                                      gfloat        y,
12054                                      gfloat       *x_out,
12055                                      gfloat       *y_out)
12056 {
12057   ClutterVertex v[4];
12058   float ST[3][3];
12059   float RQ[3][3];
12060   int du, dv, xi, yi;
12061   float px, py;
12062   float xf, yf, wf, det;
12063   ClutterActorPrivate *priv;
12064
12065   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12066
12067   priv = self->priv;
12068
12069   /* This implementation is based on the quad -> quad projection algorithm
12070    * described by Paul Heckbert in:
12071    *
12072    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12073    *
12074    * and the sample implementation at:
12075    *
12076    *   http://www.cs.cmu.edu/~ph/src/texfund/
12077    *
12078    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12079    * quad to rectangle only, which significantly simplifies things; the
12080    * function calls have been unrolled, and most of the math is done in fixed
12081    * point.
12082    */
12083
12084   clutter_actor_get_abs_allocation_vertices (self, v);
12085
12086   /* Keeping these as ints simplifies the multiplication (no significant
12087    * loss of precision here).
12088    */
12089   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12090   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12091
12092   if (!du || !dv)
12093     return FALSE;
12094
12095 #define UX2FP(x)        (x)
12096 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12097
12098   /* First, find mapping from unit uv square to xy quadrilateral; this
12099    * equivalent to the pmap_square_quad() functions in the sample
12100    * implementation, which we can simplify, since our target is always
12101    * a rectangle.
12102    */
12103   px = v[0].x - v[1].x + v[3].x - v[2].x;
12104   py = v[0].y - v[1].y + v[3].y - v[2].y;
12105
12106   if (!px && !py)
12107     {
12108       /* affine transform */
12109       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12110       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12111       RQ[2][0] = UX2FP (v[0].x);
12112       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12113       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12114       RQ[2][1] = UX2FP (v[0].y);
12115       RQ[0][2] = 0;
12116       RQ[1][2] = 0;
12117       RQ[2][2] = 1.0;
12118     }
12119   else
12120     {
12121       /* projective transform */
12122       double dx1, dx2, dy1, dy2, del;
12123
12124       dx1 = UX2FP (v[1].x - v[3].x);
12125       dx2 = UX2FP (v[2].x - v[3].x);
12126       dy1 = UX2FP (v[1].y - v[3].y);
12127       dy2 = UX2FP (v[2].y - v[3].y);
12128
12129       del = DET2FP (dx1, dx2, dy1, dy2);
12130       if (!del)
12131         return FALSE;
12132
12133       /*
12134        * The division here needs to be done in floating point for
12135        * precisions reasons.
12136        */
12137       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12138       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12139       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12140       RQ[2][2] = 1.0;
12141       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12142       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12143       RQ[2][0] = UX2FP (v[0].x);
12144       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12145       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12146       RQ[2][1] = UX2FP (v[0].y);
12147     }
12148
12149   /*
12150    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12151    * square. Since our rectangle is based at 0,0 we only need to scale.
12152    */
12153   RQ[0][0] /= du;
12154   RQ[1][0] /= dv;
12155   RQ[0][1] /= du;
12156   RQ[1][1] /= dv;
12157   RQ[0][2] /= du;
12158   RQ[1][2] /= dv;
12159
12160   /*
12161    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12162    * inverse of that.
12163    */
12164   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12165   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12166   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12167   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12168   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12169   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12170   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12171   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12172   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12173
12174   /*
12175    * Check the resulting matrix is OK.
12176    */
12177   det = (RQ[0][0] * ST[0][0])
12178       + (RQ[0][1] * ST[0][1])
12179       + (RQ[0][2] * ST[0][2]);
12180   if (!det)
12181     return FALSE;
12182
12183   /*
12184    * Now transform our point with the ST matrix; the notional w
12185    * coordinate is 1, hence the last part is simply added.
12186    */
12187   xi = (int) x;
12188   yi = (int) y;
12189
12190   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12191   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12192   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12193
12194   if (x_out)
12195     *x_out = xf / wf;
12196
12197   if (y_out)
12198     *y_out = yf / wf;
12199
12200 #undef UX2FP
12201 #undef DET2FP
12202
12203   return TRUE;
12204 }
12205
12206 /*
12207  * ClutterGeometry
12208  */
12209
12210 static ClutterGeometry*
12211 clutter_geometry_copy (const ClutterGeometry *geometry)
12212 {
12213   return g_slice_dup (ClutterGeometry, geometry);
12214 }
12215
12216 static void
12217 clutter_geometry_free (ClutterGeometry *geometry)
12218 {
12219   if (G_LIKELY (geometry != NULL))
12220     g_slice_free (ClutterGeometry, geometry);
12221 }
12222
12223 /**
12224  * clutter_geometry_union:
12225  * @geometry_a: a #ClutterGeometry
12226  * @geometry_b: another #ClutterGeometry
12227  * @result: (out): location to store the result
12228  *
12229  * Find the union of two rectangles represented as #ClutterGeometry.
12230  *
12231  * Since: 1.4
12232  */
12233 void
12234 clutter_geometry_union (const ClutterGeometry *geometry_a,
12235                         const ClutterGeometry *geometry_b,
12236                         ClutterGeometry       *result)
12237 {
12238   /* We don't try to handle rectangles that can't be represented
12239    * as a signed integer box */
12240   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12241   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12242   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12243                   geometry_b->x + (gint)geometry_b->width);
12244   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12245                   geometry_b->y + (gint)geometry_b->height);
12246   result->x = x_1;
12247   result->y = y_1;
12248   result->width = x_2 - x_1;
12249   result->height = y_2 - y_1;
12250 }
12251
12252 /**
12253  * clutter_geometry_intersects:
12254  * @geometry0: The first geometry to test
12255  * @geometry1: The second geometry to test
12256  *
12257  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12258  * they do else %FALSE.
12259  *
12260  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12261  * %FALSE.
12262  *
12263  * Since: 1.4
12264  */
12265 gboolean
12266 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12267                              const ClutterGeometry *geometry1)
12268 {
12269   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12270       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12271       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12272       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12273     return FALSE;
12274   else
12275     return TRUE;
12276 }
12277
12278 static gboolean
12279 clutter_geometry_progress (const GValue *a,
12280                            const GValue *b,
12281                            gdouble       progress,
12282                            GValue       *retval)
12283 {
12284   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12285   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12286   ClutterGeometry res = { 0, };
12287   gint a_width = a_geom->width;
12288   gint b_width = b_geom->width;
12289   gint a_height = a_geom->height;
12290   gint b_height = b_geom->height;
12291
12292   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12293   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12294
12295   res.width = a_width + (b_width - a_width) * progress;
12296   res.height = a_height + (b_height - a_height) * progress;
12297
12298   g_value_set_boxed (retval, &res);
12299
12300   return TRUE;
12301 }
12302
12303 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12304                                clutter_geometry_copy,
12305                                clutter_geometry_free,
12306                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12307
12308 /*
12309  * ClutterVertices
12310  */
12311
12312 /**
12313  * clutter_vertex_new:
12314  * @x: X coordinate
12315  * @y: Y coordinate
12316  * @z: Z coordinate
12317  *
12318  * Creates a new #ClutterVertex for the point in 3D space
12319  * identified by the 3 coordinates @x, @y, @z
12320  *
12321  * Return value: the newly allocate #ClutterVertex. Use
12322  *   clutter_vertex_free() to free the resources
12323  *
12324  * Since: 1.0
12325  */
12326 ClutterVertex *
12327 clutter_vertex_new (gfloat x,
12328                     gfloat y,
12329                     gfloat z)
12330 {
12331   ClutterVertex *vertex;
12332
12333   vertex = g_slice_new (ClutterVertex);
12334   vertex->x = x;
12335   vertex->y = y;
12336   vertex->z = z;
12337
12338   return vertex;
12339 }
12340
12341 /**
12342  * clutter_vertex_copy:
12343  * @vertex: a #ClutterVertex
12344  *
12345  * Copies @vertex
12346  *
12347  * Return value: a newly allocated copy of #ClutterVertex. Use
12348  *   clutter_vertex_free() to free the allocated resources
12349  *
12350  * Since: 1.0
12351  */
12352 ClutterVertex *
12353 clutter_vertex_copy (const ClutterVertex *vertex)
12354 {
12355   if (G_LIKELY (vertex != NULL))
12356     return g_slice_dup (ClutterVertex, vertex);
12357
12358   return NULL;
12359 }
12360
12361 /**
12362  * clutter_vertex_free:
12363  * @vertex: a #ClutterVertex
12364  *
12365  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12366  *
12367  * Since: 1.0
12368  */
12369 void
12370 clutter_vertex_free (ClutterVertex *vertex)
12371 {
12372   if (G_UNLIKELY (vertex != NULL))
12373     g_slice_free (ClutterVertex, vertex);
12374 }
12375
12376 /**
12377  * clutter_vertex_equal:
12378  * @vertex_a: a #ClutterVertex
12379  * @vertex_b: a #ClutterVertex
12380  *
12381  * Compares @vertex_a and @vertex_b for equality
12382  *
12383  * Return value: %TRUE if the passed #ClutterVertex are equal
12384  *
12385  * Since: 1.0
12386  */
12387 gboolean
12388 clutter_vertex_equal (const ClutterVertex *vertex_a,
12389                       const ClutterVertex *vertex_b)
12390 {
12391   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12392
12393   if (vertex_a == vertex_b)
12394     return TRUE;
12395
12396   return vertex_a->x == vertex_b->x &&
12397          vertex_a->y == vertex_b->y &&
12398          vertex_a->z == vertex_b->z;
12399 }
12400
12401 static gboolean
12402 clutter_vertex_progress (const GValue *a,
12403                          const GValue *b,
12404                          gdouble       progress,
12405                          GValue       *retval)
12406 {
12407   const ClutterVertex *av = g_value_get_boxed (a);
12408   const ClutterVertex *bv = g_value_get_boxed (b);
12409   ClutterVertex res = { 0, };
12410
12411   res.x = av->x + (bv->x - av->x) * progress;
12412   res.y = av->y + (bv->y - av->y) * progress;
12413   res.z = av->z + (bv->z - av->z) * progress;
12414
12415   g_value_set_boxed (retval, &res);
12416
12417   return TRUE;
12418 }
12419
12420 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12421                                clutter_vertex_copy,
12422                                clutter_vertex_free,
12423                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12424
12425 /**
12426  * clutter_actor_is_rotated:
12427  * @self: a #ClutterActor
12428  *
12429  * Checks whether any rotation is applied to the actor.
12430  *
12431  * Return value: %TRUE if the actor is rotated.
12432  *
12433  * Since: 0.6
12434  */
12435 gboolean
12436 clutter_actor_is_rotated (ClutterActor *self)
12437 {
12438   const ClutterTransformInfo *info;
12439
12440   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12441
12442   info = _clutter_actor_get_transform_info_or_defaults (self);
12443
12444   if (info->rx_angle || info->ry_angle || info->rz_angle)
12445     return TRUE;
12446
12447   return FALSE;
12448 }
12449
12450 /**
12451  * clutter_actor_is_scaled:
12452  * @self: a #ClutterActor
12453  *
12454  * Checks whether the actor is scaled in either dimension.
12455  *
12456  * Return value: %TRUE if the actor is scaled.
12457  *
12458  * Since: 0.6
12459  */
12460 gboolean
12461 clutter_actor_is_scaled (ClutterActor *self)
12462 {
12463   const ClutterTransformInfo *info;
12464
12465   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12466
12467   info = _clutter_actor_get_transform_info_or_defaults (self);
12468
12469   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12470     return TRUE;
12471
12472   return FALSE;
12473 }
12474
12475 ClutterActor *
12476 _clutter_actor_get_stage_internal (ClutterActor *actor)
12477 {
12478   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12479     actor = actor->priv->parent;
12480
12481   return actor;
12482 }
12483
12484 /**
12485  * clutter_actor_get_stage:
12486  * @actor: a #ClutterActor
12487  *
12488  * Retrieves the #ClutterStage where @actor is contained.
12489  *
12490  * Return value: (transfer none) (type Clutter.Stage): the stage
12491  *   containing the actor, or %NULL
12492  *
12493  * Since: 0.8
12494  */
12495 ClutterActor *
12496 clutter_actor_get_stage (ClutterActor *actor)
12497 {
12498   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12499
12500   return _clutter_actor_get_stage_internal (actor);
12501 }
12502
12503 /**
12504  * clutter_actor_allocate_available_size:
12505  * @self: a #ClutterActor
12506  * @x: the actor's X coordinate
12507  * @y: the actor's Y coordinate
12508  * @available_width: the maximum available width, or -1 to use the
12509  *   actor's natural width
12510  * @available_height: the maximum available height, or -1 to use the
12511  *   actor's natural height
12512  * @flags: flags controlling the allocation
12513  *
12514  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12515  * preferred size, but limiting it to the maximum available width
12516  * and height provided.
12517  *
12518  * This function will do the right thing when dealing with the
12519  * actor's request mode.
12520  *
12521  * The implementation of this function is equivalent to:
12522  *
12523  * |[
12524  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12525  *     {
12526  *       clutter_actor_get_preferred_width (self, available_height,
12527  *                                          &amp;min_width,
12528  *                                          &amp;natural_width);
12529  *       width = CLAMP (natural_width, min_width, available_width);
12530  *
12531  *       clutter_actor_get_preferred_height (self, width,
12532  *                                           &amp;min_height,
12533  *                                           &amp;natural_height);
12534  *       height = CLAMP (natural_height, min_height, available_height);
12535  *     }
12536  *   else
12537  *     {
12538  *       clutter_actor_get_preferred_height (self, available_width,
12539  *                                           &amp;min_height,
12540  *                                           &amp;natural_height);
12541  *       height = CLAMP (natural_height, min_height, available_height);
12542  *
12543  *       clutter_actor_get_preferred_width (self, height,
12544  *                                          &amp;min_width,
12545  *                                          &amp;natural_width);
12546  *       width = CLAMP (natural_width, min_width, available_width);
12547  *     }
12548  *
12549  *   box.x1 = x; box.y1 = y;
12550  *   box.x2 = box.x1 + available_width;
12551  *   box.y2 = box.y1 + available_height;
12552  *   clutter_actor_allocate (self, &amp;box, flags);
12553  * ]|
12554  *
12555  * This function can be used by fluid layout managers to allocate
12556  * an actor's preferred size without making it bigger than the area
12557  * available for the container.
12558  *
12559  * Since: 1.0
12560  */
12561 void
12562 clutter_actor_allocate_available_size (ClutterActor           *self,
12563                                        gfloat                  x,
12564                                        gfloat                  y,
12565                                        gfloat                  available_width,
12566                                        gfloat                  available_height,
12567                                        ClutterAllocationFlags  flags)
12568 {
12569   ClutterActorPrivate *priv;
12570   gfloat width, height;
12571   gfloat min_width, min_height;
12572   gfloat natural_width, natural_height;
12573   ClutterActorBox box;
12574
12575   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12576
12577   priv = self->priv;
12578
12579   width = height = 0.0;
12580
12581   switch (priv->request_mode)
12582     {
12583     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12584       clutter_actor_get_preferred_width (self, available_height,
12585                                          &min_width,
12586                                          &natural_width);
12587       width  = CLAMP (natural_width, min_width, available_width);
12588
12589       clutter_actor_get_preferred_height (self, width,
12590                                           &min_height,
12591                                           &natural_height);
12592       height = CLAMP (natural_height, min_height, available_height);
12593       break;
12594
12595     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12596       clutter_actor_get_preferred_height (self, available_width,
12597                                           &min_height,
12598                                           &natural_height);
12599       height = CLAMP (natural_height, min_height, available_height);
12600
12601       clutter_actor_get_preferred_width (self, height,
12602                                          &min_width,
12603                                          &natural_width);
12604       width  = CLAMP (natural_width, min_width, available_width);
12605       break;
12606     }
12607
12608
12609   box.x1 = x;
12610   box.y1 = y;
12611   box.x2 = box.x1 + width;
12612   box.y2 = box.y1 + height;
12613   clutter_actor_allocate (self, &box, flags);
12614 }
12615
12616 /**
12617  * clutter_actor_allocate_preferred_size:
12618  * @self: a #ClutterActor
12619  * @flags: flags controlling the allocation
12620  *
12621  * Allocates the natural size of @self.
12622  *
12623  * This function is a utility call for #ClutterActor implementations
12624  * that allocates the actor's preferred natural size. It can be used
12625  * by fixed layout managers (like #ClutterGroup or so called
12626  * 'composite actors') inside the ClutterActor::allocate
12627  * implementation to give each child exactly how much space it
12628  * requires.
12629  *
12630  * This function is not meant to be used by applications. It is also
12631  * not meant to be used outside the implementation of the
12632  * ClutterActor::allocate virtual function.
12633  *
12634  * Since: 0.8
12635  */
12636 void
12637 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12638                                        ClutterAllocationFlags  flags)
12639 {
12640   gfloat actor_x, actor_y;
12641   gfloat natural_width, natural_height;
12642   ClutterActorBox actor_box;
12643
12644   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12645
12646   actor_x = clutter_actor_get_x (self);
12647   actor_y = clutter_actor_get_y (self);
12648
12649   clutter_actor_get_preferred_size (self,
12650                                     NULL, NULL,
12651                                     &natural_width,
12652                                     &natural_height);
12653
12654   actor_box.x1 = actor_x;
12655   actor_box.y1 = actor_y;
12656   actor_box.x2 = actor_box.x1 + natural_width;
12657   actor_box.y2 = actor_box.y1 + natural_height;
12658
12659   clutter_actor_allocate (self, &actor_box, flags);
12660 }
12661
12662 /**
12663  * clutter_actor_allocate_align_fill:
12664  * @self: a #ClutterActor
12665  * @box: a #ClutterActorBox, containing the available width and height
12666  * @x_align: the horizontal alignment, between 0 and 1
12667  * @y_align: the vertical alignment, between 0 and 1
12668  * @x_fill: whether the actor should fill horizontally
12669  * @y_fill: whether the actor should fill vertically
12670  * @flags: allocation flags to be passed to clutter_actor_allocate()
12671  *
12672  * Allocates @self by taking into consideration the available allocation
12673  * area; an alignment factor on either axis; and whether the actor should
12674  * fill the allocation on either axis.
12675  *
12676  * The @box should contain the available allocation width and height;
12677  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12678  * allocation will be offset by their value.
12679  *
12680  * This function takes into consideration the geometry request specified by
12681  * the #ClutterActor:request-mode property, and the text direction.
12682  *
12683  * This function is useful for fluid layout managers, like #ClutterBinLayout
12684  * or #ClutterTableLayout
12685  *
12686  * Since: 1.4
12687  */
12688 void
12689 clutter_actor_allocate_align_fill (ClutterActor           *self,
12690                                    const ClutterActorBox  *box,
12691                                    gdouble                 x_align,
12692                                    gdouble                 y_align,
12693                                    gboolean                x_fill,
12694                                    gboolean                y_fill,
12695                                    ClutterAllocationFlags  flags)
12696 {
12697   ClutterActorPrivate *priv;
12698   ClutterActorBox allocation = { 0, };
12699   gfloat x_offset, y_offset;
12700   gfloat available_width, available_height;
12701   gfloat child_width, child_height;
12702
12703   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12704   g_return_if_fail (box != NULL);
12705   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12706   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12707
12708   priv = self->priv;
12709
12710   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12711   clutter_actor_box_get_size (box, &available_width, &available_height);
12712
12713   if (available_width < 0)
12714     available_width = 0;
12715
12716   if (available_height < 0)
12717     available_height = 0;
12718
12719   if (x_fill)
12720     {
12721       allocation.x1 = x_offset;
12722       allocation.x2 = allocation.x1 + available_width;
12723     }
12724
12725   if (y_fill)
12726     {
12727       allocation.y1 = y_offset;
12728       allocation.y2 = allocation.y1 + available_height;
12729     }
12730
12731   /* if we are filling horizontally and vertically then we're done */
12732   if (x_fill && y_fill)
12733     goto out;
12734
12735   child_width = child_height = 0.0f;
12736
12737   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12738     {
12739       gfloat min_width, natural_width;
12740       gfloat min_height, natural_height;
12741
12742       clutter_actor_get_preferred_width (self, available_height,
12743                                          &min_width,
12744                                          &natural_width);
12745
12746       child_width = CLAMP (natural_width, min_width, available_width);
12747
12748       if (!y_fill)
12749         {
12750           clutter_actor_get_preferred_height (self, child_width,
12751                                               &min_height,
12752                                               &natural_height);
12753
12754           child_height = CLAMP (natural_height, min_height, available_height);
12755         }
12756     }
12757   else
12758     {
12759       gfloat min_width, natural_width;
12760       gfloat min_height, natural_height;
12761
12762       clutter_actor_get_preferred_height (self, available_width,
12763                                           &min_height,
12764                                           &natural_height);
12765
12766       child_height = CLAMP (natural_height, min_height, available_height);
12767
12768       if (!x_fill)
12769         {
12770           clutter_actor_get_preferred_width (self, child_height,
12771                                              &min_width,
12772                                              &natural_width);
12773
12774           child_width = CLAMP (natural_width, min_width, available_width);
12775         }
12776     }
12777
12778   /* invert the horizontal alignment for RTL languages */
12779   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12780     x_align = 1.0 - x_align;
12781
12782   if (!x_fill)
12783     {
12784       allocation.x1 = x_offset
12785                     + ((available_width - child_width) * x_align);
12786       allocation.x2 = allocation.x1 + child_width;
12787     }
12788
12789   if (!y_fill)
12790     {
12791       allocation.y1 = y_offset
12792                     + ((available_height - child_height) * y_align);
12793       allocation.y2 = allocation.y1 + child_height;
12794     }
12795
12796 out:
12797   clutter_actor_box_clamp_to_pixel (&allocation);
12798   clutter_actor_allocate (self, &allocation, flags);
12799 }
12800
12801 /**
12802  * clutter_actor_grab_key_focus:
12803  * @self: a #ClutterActor
12804  *
12805  * Sets the key focus of the #ClutterStage including @self
12806  * to this #ClutterActor.
12807  *
12808  * Since: 1.0
12809  */
12810 void
12811 clutter_actor_grab_key_focus (ClutterActor *self)
12812 {
12813   ClutterActor *stage;
12814
12815   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12816
12817   stage = _clutter_actor_get_stage_internal (self);
12818   if (stage != NULL)
12819     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12820 }
12821
12822 /**
12823  * clutter_actor_get_pango_context:
12824  * @self: a #ClutterActor
12825  *
12826  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12827  * is already configured using the appropriate font map, resolution
12828  * and font options.
12829  *
12830  * Unlike clutter_actor_create_pango_context(), this context is owend
12831  * by the #ClutterActor and it will be updated each time the options
12832  * stored by the #ClutterBackend change.
12833  *
12834  * You can use the returned #PangoContext to create a #PangoLayout
12835  * and render text using cogl_pango_render_layout() to reuse the
12836  * glyphs cache also used by Clutter.
12837  *
12838  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12839  *   The returned #PangoContext is owned by the actor and should not be
12840  *   unreferenced by the application code
12841  *
12842  * Since: 1.0
12843  */
12844 PangoContext *
12845 clutter_actor_get_pango_context (ClutterActor *self)
12846 {
12847   ClutterActorPrivate *priv;
12848
12849   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12850
12851   priv = self->priv;
12852
12853   if (priv->pango_context != NULL)
12854     return priv->pango_context;
12855
12856   priv->pango_context = _clutter_context_get_pango_context ();
12857   g_object_ref (priv->pango_context);
12858
12859   return priv->pango_context;
12860 }
12861
12862 /**
12863  * clutter_actor_create_pango_context:
12864  * @self: a #ClutterActor
12865  *
12866  * Creates a #PangoContext for the given actor. The #PangoContext
12867  * is already configured using the appropriate font map, resolution
12868  * and font options.
12869  *
12870  * See also clutter_actor_get_pango_context().
12871  *
12872  * Return value: (transfer full): the newly created #PangoContext.
12873  *   Use g_object_unref() on the returned value to deallocate its
12874  *   resources
12875  *
12876  * Since: 1.0
12877  */
12878 PangoContext *
12879 clutter_actor_create_pango_context (ClutterActor *self)
12880 {
12881   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12882
12883   return _clutter_context_create_pango_context ();
12884 }
12885
12886 /**
12887  * clutter_actor_create_pango_layout:
12888  * @self: a #ClutterActor
12889  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
12890  *
12891  * Creates a new #PangoLayout from the same #PangoContext used
12892  * by the #ClutterActor. The #PangoLayout is already configured
12893  * with the font map, resolution and font options, and the
12894  * given @text.
12895  *
12896  * If you want to keep around a #PangoLayout created by this
12897  * function you will have to connect to the #ClutterBackend::font-changed
12898  * and #ClutterBackend::resolution-changed signals, and call
12899  * pango_layout_context_changed() in response to them.
12900  *
12901  * Return value: (transfer full): the newly created #PangoLayout.
12902  *   Use g_object_unref() when done
12903  *
12904  * Since: 1.0
12905  */
12906 PangoLayout *
12907 clutter_actor_create_pango_layout (ClutterActor *self,
12908                                    const gchar  *text)
12909 {
12910   PangoContext *context;
12911   PangoLayout *layout;
12912
12913   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12914
12915   context = clutter_actor_get_pango_context (self);
12916   layout = pango_layout_new (context);
12917
12918   if (text)
12919     pango_layout_set_text (layout, text, -1);
12920
12921   return layout;
12922 }
12923
12924 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
12925  * ClutterOffscreenEffect.
12926  */
12927 void
12928 _clutter_actor_set_opacity_override (ClutterActor *self,
12929                                      gint          opacity)
12930 {
12931   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12932
12933   self->priv->opacity_override = opacity;
12934 }
12935
12936 gint
12937 _clutter_actor_get_opacity_override (ClutterActor *self)
12938 {
12939   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
12940
12941   return self->priv->opacity_override;
12942 }
12943
12944 /* Allows you to disable applying the actors model view transform during
12945  * a paint. Used by ClutterClone. */
12946 void
12947 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
12948                                                 gboolean      enable)
12949 {
12950   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12951
12952   self->priv->enable_model_view_transform = enable;
12953 }
12954
12955 void
12956 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
12957                                           gboolean      enable)
12958 {
12959   ClutterActorPrivate *priv;
12960
12961   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12962
12963   priv = self->priv;
12964
12965   priv->enable_paint_unmapped = enable;
12966
12967   if (priv->enable_paint_unmapped)
12968     {
12969       /* Make sure that the parents of the widget are realized first;
12970        * otherwise checks in clutter_actor_update_map_state() will
12971        * fail.
12972        */
12973       clutter_actor_realize (self);
12974
12975       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
12976     }
12977   else
12978     {
12979       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
12980     }
12981 }
12982
12983 static void
12984 clutter_anchor_coord_get_units (ClutterActor      *self,
12985                                 const AnchorCoord *coord,
12986                                 gfloat            *x,
12987                                 gfloat            *y,
12988                                 gfloat            *z)
12989 {
12990   if (coord->is_fractional)
12991     {
12992       gfloat actor_width, actor_height;
12993
12994       clutter_actor_get_size (self, &actor_width, &actor_height);
12995
12996       if (x)
12997         *x = actor_width * coord->v.fraction.x;
12998
12999       if (y)
13000         *y = actor_height * coord->v.fraction.y;
13001
13002       if (z)
13003         *z = 0;
13004     }
13005   else
13006     {
13007       if (x)
13008         *x = coord->v.units.x;
13009
13010       if (y)
13011         *y = coord->v.units.y;
13012
13013       if (z)
13014         *z = coord->v.units.z;
13015     }
13016 }
13017
13018 static void
13019 clutter_anchor_coord_set_units (AnchorCoord *coord,
13020                                 gfloat       x,
13021                                 gfloat       y,
13022                                 gfloat       z)
13023 {
13024   coord->is_fractional = FALSE;
13025   coord->v.units.x = x;
13026   coord->v.units.y = y;
13027   coord->v.units.z = z;
13028 }
13029
13030 static ClutterGravity
13031 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13032 {
13033   if (coord->is_fractional)
13034     {
13035       if (coord->v.fraction.x == 0.0)
13036         {
13037           if (coord->v.fraction.y == 0.0)
13038             return CLUTTER_GRAVITY_NORTH_WEST;
13039           else if (coord->v.fraction.y == 0.5)
13040             return CLUTTER_GRAVITY_WEST;
13041           else if (coord->v.fraction.y == 1.0)
13042             return CLUTTER_GRAVITY_SOUTH_WEST;
13043           else
13044             return CLUTTER_GRAVITY_NONE;
13045         }
13046       else if (coord->v.fraction.x == 0.5)
13047         {
13048           if (coord->v.fraction.y == 0.0)
13049             return CLUTTER_GRAVITY_NORTH;
13050           else if (coord->v.fraction.y == 0.5)
13051             return CLUTTER_GRAVITY_CENTER;
13052           else if (coord->v.fraction.y == 1.0)
13053             return CLUTTER_GRAVITY_SOUTH;
13054           else
13055             return CLUTTER_GRAVITY_NONE;
13056         }
13057       else if (coord->v.fraction.x == 1.0)
13058         {
13059           if (coord->v.fraction.y == 0.0)
13060             return CLUTTER_GRAVITY_NORTH_EAST;
13061           else if (coord->v.fraction.y == 0.5)
13062             return CLUTTER_GRAVITY_EAST;
13063           else if (coord->v.fraction.y == 1.0)
13064             return CLUTTER_GRAVITY_SOUTH_EAST;
13065           else
13066             return CLUTTER_GRAVITY_NONE;
13067         }
13068       else
13069         return CLUTTER_GRAVITY_NONE;
13070     }
13071   else
13072     return CLUTTER_GRAVITY_NONE;
13073 }
13074
13075 static void
13076 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13077                                   ClutterGravity  gravity)
13078 {
13079   switch (gravity)
13080     {
13081     case CLUTTER_GRAVITY_NORTH:
13082       coord->v.fraction.x = 0.5;
13083       coord->v.fraction.y = 0.0;
13084       break;
13085
13086     case CLUTTER_GRAVITY_NORTH_EAST:
13087       coord->v.fraction.x = 1.0;
13088       coord->v.fraction.y = 0.0;
13089       break;
13090
13091     case CLUTTER_GRAVITY_EAST:
13092       coord->v.fraction.x = 1.0;
13093       coord->v.fraction.y = 0.5;
13094       break;
13095
13096     case CLUTTER_GRAVITY_SOUTH_EAST:
13097       coord->v.fraction.x = 1.0;
13098       coord->v.fraction.y = 1.0;
13099       break;
13100
13101     case CLUTTER_GRAVITY_SOUTH:
13102       coord->v.fraction.x = 0.5;
13103       coord->v.fraction.y = 1.0;
13104       break;
13105
13106     case CLUTTER_GRAVITY_SOUTH_WEST:
13107       coord->v.fraction.x = 0.0;
13108       coord->v.fraction.y = 1.0;
13109       break;
13110
13111     case CLUTTER_GRAVITY_WEST:
13112       coord->v.fraction.x = 0.0;
13113       coord->v.fraction.y = 0.5;
13114       break;
13115
13116     case CLUTTER_GRAVITY_NORTH_WEST:
13117       coord->v.fraction.x = 0.0;
13118       coord->v.fraction.y = 0.0;
13119       break;
13120
13121     case CLUTTER_GRAVITY_CENTER:
13122       coord->v.fraction.x = 0.5;
13123       coord->v.fraction.y = 0.5;
13124       break;
13125
13126     default:
13127       coord->v.fraction.x = 0.0;
13128       coord->v.fraction.y = 0.0;
13129       break;
13130     }
13131
13132   coord->is_fractional = TRUE;
13133 }
13134
13135 static gboolean
13136 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13137 {
13138   if (coord->is_fractional)
13139     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13140   else
13141     return (coord->v.units.x == 0.0
13142             && coord->v.units.y == 0.0
13143             && coord->v.units.z == 0.0);
13144 }
13145
13146 /**
13147  * clutter_actor_get_flags:
13148  * @self: a #ClutterActor
13149  *
13150  * Retrieves the flags set on @self
13151  *
13152  * Return value: a bitwise or of #ClutterActorFlags or 0
13153  *
13154  * Since: 1.0
13155  */
13156 ClutterActorFlags
13157 clutter_actor_get_flags (ClutterActor *self)
13158 {
13159   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13160
13161   return self->flags;
13162 }
13163
13164 /**
13165  * clutter_actor_set_flags:
13166  * @self: a #ClutterActor
13167  * @flags: the flags to set
13168  *
13169  * Sets @flags on @self
13170  *
13171  * This function will emit notifications for the changed properties
13172  *
13173  * Since: 1.0
13174  */
13175 void
13176 clutter_actor_set_flags (ClutterActor      *self,
13177                          ClutterActorFlags  flags)
13178 {
13179   ClutterActorFlags old_flags;
13180   GObject *obj;
13181   gboolean was_reactive_set, reactive_set;
13182   gboolean was_realized_set, realized_set;
13183   gboolean was_mapped_set, mapped_set;
13184   gboolean was_visible_set, visible_set;
13185
13186   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13187
13188   if (self->flags == flags)
13189     return;
13190
13191   obj = G_OBJECT (self);
13192   g_object_ref (obj);
13193   g_object_freeze_notify (obj);
13194
13195   old_flags = self->flags;
13196
13197   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13198   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13199   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13200   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13201
13202   self->flags |= flags;
13203
13204   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13205   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13206   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13207   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13208
13209   if (reactive_set != was_reactive_set)
13210     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13211
13212   if (realized_set != was_realized_set)
13213     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13214
13215   if (mapped_set != was_mapped_set)
13216     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13217
13218   if (visible_set != was_visible_set)
13219     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13220
13221   g_object_thaw_notify (obj);
13222   g_object_unref (obj);
13223 }
13224
13225 /**
13226  * clutter_actor_unset_flags:
13227  * @self: a #ClutterActor
13228  * @flags: the flags to unset
13229  *
13230  * Unsets @flags on @self
13231  *
13232  * This function will emit notifications for the changed properties
13233  *
13234  * Since: 1.0
13235  */
13236 void
13237 clutter_actor_unset_flags (ClutterActor      *self,
13238                            ClutterActorFlags  flags)
13239 {
13240   ClutterActorFlags old_flags;
13241   GObject *obj;
13242   gboolean was_reactive_set, reactive_set;
13243   gboolean was_realized_set, realized_set;
13244   gboolean was_mapped_set, mapped_set;
13245   gboolean was_visible_set, visible_set;
13246
13247   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13248
13249   obj = G_OBJECT (self);
13250   g_object_freeze_notify (obj);
13251
13252   old_flags = self->flags;
13253
13254   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13255   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13256   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13257   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13258
13259   self->flags &= ~flags;
13260
13261   if (self->flags == old_flags)
13262     return;
13263
13264   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13265   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13266   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13267   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13268
13269   if (reactive_set != was_reactive_set)
13270     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13271
13272   if (realized_set != was_realized_set)
13273     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13274
13275   if (mapped_set != was_mapped_set)
13276     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13277
13278   if (visible_set != was_visible_set)
13279     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13280
13281   g_object_thaw_notify (obj);
13282 }
13283
13284 /**
13285  * clutter_actor_get_transformation_matrix:
13286  * @self: a #ClutterActor
13287  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13288  *
13289  * Retrieves the transformations applied to @self relative to its
13290  * parent.
13291  *
13292  * Since: 1.0
13293  */
13294 void
13295 clutter_actor_get_transformation_matrix (ClutterActor *self,
13296                                          CoglMatrix   *matrix)
13297 {
13298   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13299
13300   cogl_matrix_init_identity (matrix);
13301
13302   _clutter_actor_apply_modelview_transform (self, matrix);
13303 }
13304
13305 void
13306 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13307                                    gboolean      is_in_clone_paint)
13308 {
13309   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13310   self->priv->in_clone_paint = is_in_clone_paint;
13311 }
13312
13313 /**
13314  * clutter_actor_is_in_clone_paint:
13315  * @self: a #ClutterActor
13316  *
13317  * Checks whether @self is being currently painted by a #ClutterClone
13318  *
13319  * This function is useful only inside the ::paint virtual function
13320  * implementations or within handlers for the #ClutterActor::paint
13321  * signal
13322  *
13323  * This function should not be used by applications
13324  *
13325  * Return value: %TRUE if the #ClutterActor is currently being painted
13326  *   by a #ClutterClone, and %FALSE otherwise
13327  *
13328  * Since: 1.0
13329  */
13330 gboolean
13331 clutter_actor_is_in_clone_paint (ClutterActor *self)
13332 {
13333   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13334
13335   return self->priv->in_clone_paint;
13336 }
13337
13338 static gboolean
13339 set_direction_recursive (ClutterActor *actor,
13340                          gpointer      user_data)
13341 {
13342   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13343
13344   clutter_actor_set_text_direction (actor, text_dir);
13345
13346   return TRUE;
13347 }
13348
13349 /**
13350  * clutter_actor_set_text_direction:
13351  * @self: a #ClutterActor
13352  * @text_dir: the text direction for @self
13353  *
13354  * Sets the #ClutterTextDirection for an actor
13355  *
13356  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13357  *
13358  * If @self implements #ClutterContainer then this function will recurse
13359  * inside all the children of @self (including the internal ones).
13360  *
13361  * Composite actors not implementing #ClutterContainer, or actors requiring
13362  * special handling when the text direction changes, should connect to
13363  * the #GObject::notify signal for the #ClutterActor:text-direction property
13364  *
13365  * Since: 1.2
13366  */
13367 void
13368 clutter_actor_set_text_direction (ClutterActor         *self,
13369                                   ClutterTextDirection  text_dir)
13370 {
13371   ClutterActorPrivate *priv;
13372
13373   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13374   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13375
13376   priv = self->priv;
13377
13378   if (priv->text_direction != text_dir)
13379     {
13380       priv->text_direction = text_dir;
13381
13382       /* we need to emit the notify::text-direction first, so that
13383        * the sub-classes can catch that and do specific handling of
13384        * the text direction; see clutter_text_direction_changed_cb()
13385        * inside clutter-text.c
13386        */
13387       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13388
13389       _clutter_actor_foreach_child (self, set_direction_recursive,
13390                                     GINT_TO_POINTER (text_dir));
13391
13392       clutter_actor_queue_relayout (self);
13393     }
13394 }
13395
13396 void
13397 _clutter_actor_set_has_pointer (ClutterActor *self,
13398                                 gboolean      has_pointer)
13399 {
13400   ClutterActorPrivate *priv = self->priv;
13401
13402   if (priv->has_pointer != has_pointer)
13403     {
13404       priv->has_pointer = has_pointer;
13405
13406       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13407     }
13408 }
13409
13410 /**
13411  * clutter_actor_get_text_direction:
13412  * @self: a #ClutterActor
13413  *
13414  * Retrieves the value set using clutter_actor_set_text_direction()
13415  *
13416  * If no text direction has been previously set, the default text
13417  * direction, as returned by clutter_get_default_text_direction(), will
13418  * be returned instead
13419  *
13420  * Return value: the #ClutterTextDirection for the actor
13421  *
13422  * Since: 1.2
13423  */
13424 ClutterTextDirection
13425 clutter_actor_get_text_direction (ClutterActor *self)
13426 {
13427   ClutterActorPrivate *priv;
13428
13429   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13430                         CLUTTER_TEXT_DIRECTION_LTR);
13431
13432   priv = self->priv;
13433
13434   /* if no direction has been set yet use the default */
13435   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13436     priv->text_direction = clutter_get_default_text_direction ();
13437
13438   return priv->text_direction;
13439 }
13440
13441 /**
13442  * clutter_actor_push_internal:
13443  * @self: a #ClutterActor
13444  *
13445  * Should be used by actors implementing the #ClutterContainer and with
13446  * internal children added through clutter_actor_set_parent(), for instance:
13447  *
13448  * |[
13449  *   static void
13450  *   my_actor_init (MyActor *self)
13451  *   {
13452  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13453  *
13454  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13455  *
13456  *     /&ast; calling clutter_actor_set_parent() now will result in
13457  *      &ast; the internal flag being set on a child of MyActor
13458  *      &ast;/
13459  *
13460  *     /&ast; internal child - a background texture &ast;/
13461  *     self->priv->background_tex = clutter_texture_new ();
13462  *     clutter_actor_set_parent (self->priv->background_tex,
13463  *                               CLUTTER_ACTOR (self));
13464  *
13465  *     /&ast; internal child - a label &ast;/
13466  *     self->priv->label = clutter_text_new ();
13467  *     clutter_actor_set_parent (self->priv->label,
13468  *                               CLUTTER_ACTOR (self));
13469  *
13470  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13471  *
13472  *     /&ast; calling clutter_actor_set_parent() now will not result in
13473  *      &ast; the internal flag being set on a child of MyActor
13474  *      &ast;/
13475  *   }
13476  * ]|
13477  *
13478  * This function will be used by Clutter to toggle an "internal child"
13479  * flag whenever clutter_actor_set_parent() is called; internal children
13480  * are handled differently by Clutter, specifically when destroying their
13481  * parent.
13482  *
13483  * Call clutter_actor_pop_internal() when you finished adding internal
13484  * children.
13485  *
13486  * Nested calls to clutter_actor_push_internal() are allowed, but each
13487  * one must by followed by a clutter_actor_pop_internal() call.
13488  *
13489  * Since: 1.2
13490  *
13491  * Deprecated: 1.10: All children of an actor are accessible through
13492  *   the #ClutterActor API, and #ClutterActor implements the
13493  *   #ClutterContainer interface, so this function is only useful
13494  *   for legacy containers overriding the default implementation.
13495  */
13496 void
13497 clutter_actor_push_internal (ClutterActor *self)
13498 {
13499   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13500
13501   self->priv->internal_child += 1;
13502 }
13503
13504 /**
13505  * clutter_actor_pop_internal:
13506  * @self: a #ClutterActor
13507  *
13508  * Disables the effects of clutter_actor_push_internal().
13509  *
13510  * Since: 1.2
13511  *
13512  * Deprecated: 1.10: All children of an actor are accessible through
13513  *   the #ClutterActor API. This function is only useful for legacy
13514  *   containers overriding the default implementation of the
13515  *   #ClutterContainer interface.
13516  */
13517 void
13518 clutter_actor_pop_internal (ClutterActor *self)
13519 {
13520   ClutterActorPrivate *priv;
13521
13522   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13523
13524   priv = self->priv;
13525
13526   if (priv->internal_child == 0)
13527     {
13528       g_warning ("Mismatched %s: you need to call "
13529                  "clutter_actor_push_composite() at least once before "
13530                  "calling this function", G_STRFUNC);
13531       return;
13532     }
13533
13534   priv->internal_child -= 1;
13535 }
13536
13537 /**
13538  * clutter_actor_has_pointer:
13539  * @self: a #ClutterActor
13540  *
13541  * Checks whether an actor contains the pointer of a
13542  * #ClutterInputDevice
13543  *
13544  * Return value: %TRUE if the actor contains the pointer, and
13545  *   %FALSE otherwise
13546  *
13547  * Since: 1.2
13548  */
13549 gboolean
13550 clutter_actor_has_pointer (ClutterActor *self)
13551 {
13552   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13553
13554   return self->priv->has_pointer;
13555 }
13556
13557 /* XXX: This is a workaround for not being able to break the ABI of
13558  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13559  * clutter_actor_queue_clipped_redraw() for details.
13560  */
13561 ClutterPaintVolume *
13562 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13563 {
13564   return g_object_get_data (G_OBJECT (self),
13565                             "-clutter-actor-queue-redraw-clip");
13566 }
13567
13568 void
13569 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13570                                       ClutterPaintVolume *clip)
13571 {
13572   g_object_set_data (G_OBJECT (self),
13573                      "-clutter-actor-queue-redraw-clip",
13574                      clip);
13575 }
13576
13577 /**
13578  * clutter_actor_has_allocation:
13579  * @self: a #ClutterActor
13580  *
13581  * Checks if the actor has an up-to-date allocation assigned to
13582  * it. This means that the actor should have an allocation: it's
13583  * visible and has a parent. It also means that there is no
13584  * outstanding relayout request in progress for the actor or its
13585  * children (There might be other outstanding layout requests in
13586  * progress that will cause the actor to get a new allocation
13587  * when the stage is laid out, however).
13588  *
13589  * If this function returns %FALSE, then the actor will normally
13590  * be allocated before it is next drawn on the screen.
13591  *
13592  * Return value: %TRUE if the actor has an up-to-date allocation
13593  *
13594  * Since: 1.4
13595  */
13596 gboolean
13597 clutter_actor_has_allocation (ClutterActor *self)
13598 {
13599   ClutterActorPrivate *priv;
13600
13601   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13602
13603   priv = self->priv;
13604
13605   return priv->parent != NULL &&
13606          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13607          !priv->needs_allocation;
13608 }
13609
13610 /**
13611  * clutter_actor_add_action:
13612  * @self: a #ClutterActor
13613  * @action: a #ClutterAction
13614  *
13615  * Adds @action to the list of actions applied to @self
13616  *
13617  * A #ClutterAction can only belong to one actor at a time
13618  *
13619  * The #ClutterActor will hold a reference on @action until either
13620  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13621  * is called
13622  *
13623  * Since: 1.4
13624  */
13625 void
13626 clutter_actor_add_action (ClutterActor  *self,
13627                           ClutterAction *action)
13628 {
13629   ClutterActorPrivate *priv;
13630
13631   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13632   g_return_if_fail (CLUTTER_IS_ACTION (action));
13633
13634   priv = self->priv;
13635
13636   if (priv->actions == NULL)
13637     {
13638       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13639       priv->actions->actor = self;
13640     }
13641
13642   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13643
13644   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13645 }
13646
13647 /**
13648  * clutter_actor_add_action_with_name:
13649  * @self: a #ClutterActor
13650  * @name: the name to set on the action
13651  * @action: a #ClutterAction
13652  *
13653  * A convenience function for setting the name of a #ClutterAction
13654  * while adding it to the list of actions applied to @self
13655  *
13656  * This function is the logical equivalent of:
13657  *
13658  * |[
13659  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13660  *   clutter_actor_add_action (self, action);
13661  * ]|
13662  *
13663  * Since: 1.4
13664  */
13665 void
13666 clutter_actor_add_action_with_name (ClutterActor  *self,
13667                                     const gchar   *name,
13668                                     ClutterAction *action)
13669 {
13670   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13671   g_return_if_fail (name != NULL);
13672   g_return_if_fail (CLUTTER_IS_ACTION (action));
13673
13674   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13675   clutter_actor_add_action (self, action);
13676 }
13677
13678 /**
13679  * clutter_actor_remove_action:
13680  * @self: a #ClutterActor
13681  * @action: a #ClutterAction
13682  *
13683  * Removes @action from the list of actions applied to @self
13684  *
13685  * The reference held by @self on the #ClutterAction will be released
13686  *
13687  * Since: 1.4
13688  */
13689 void
13690 clutter_actor_remove_action (ClutterActor  *self,
13691                              ClutterAction *action)
13692 {
13693   ClutterActorPrivate *priv;
13694
13695   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13696   g_return_if_fail (CLUTTER_IS_ACTION (action));
13697
13698   priv = self->priv;
13699
13700   if (priv->actions == NULL)
13701     return;
13702
13703   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13704
13705   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13706 }
13707
13708 /**
13709  * clutter_actor_remove_action_by_name:
13710  * @self: a #ClutterActor
13711  * @name: the name of the action to remove
13712  *
13713  * Removes the #ClutterAction with the given name from the list
13714  * of actions applied to @self
13715  *
13716  * Since: 1.4
13717  */
13718 void
13719 clutter_actor_remove_action_by_name (ClutterActor *self,
13720                                      const gchar  *name)
13721 {
13722   ClutterActorPrivate *priv;
13723   ClutterActorMeta *meta;
13724
13725   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13726   g_return_if_fail (name != NULL);
13727
13728   priv = self->priv;
13729
13730   if (priv->actions == NULL)
13731     return;
13732
13733   meta = _clutter_meta_group_get_meta (priv->actions, name);
13734   if (meta == NULL)
13735     return;
13736
13737   _clutter_meta_group_remove_meta (priv->actions, meta);
13738
13739   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13740 }
13741
13742 /**
13743  * clutter_actor_get_actions:
13744  * @self: a #ClutterActor
13745  *
13746  * Retrieves the list of actions applied to @self
13747  *
13748  * Return value: (transfer container) (element-type Clutter.Action): a copy
13749  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13750  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13751  *   allocated by the returned #GList
13752  *
13753  * Since: 1.4
13754  */
13755 GList *
13756 clutter_actor_get_actions (ClutterActor *self)
13757 {
13758   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13759
13760   if (self->priv->actions == NULL)
13761     return NULL;
13762
13763   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13764 }
13765
13766 /**
13767  * clutter_actor_get_action:
13768  * @self: a #ClutterActor
13769  * @name: the name of the action to retrieve
13770  *
13771  * Retrieves the #ClutterAction with the given name in the list
13772  * of actions applied to @self
13773  *
13774  * Return value: (transfer none): a #ClutterAction for the given
13775  *   name, or %NULL. The returned #ClutterAction is owned by the
13776  *   actor and it should not be unreferenced directly
13777  *
13778  * Since: 1.4
13779  */
13780 ClutterAction *
13781 clutter_actor_get_action (ClutterActor *self,
13782                           const gchar  *name)
13783 {
13784   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13785   g_return_val_if_fail (name != NULL, NULL);
13786
13787   if (self->priv->actions == NULL)
13788     return NULL;
13789
13790   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13791 }
13792
13793 /**
13794  * clutter_actor_clear_actions:
13795  * @self: a #ClutterActor
13796  *
13797  * Clears the list of actions applied to @self
13798  *
13799  * Since: 1.4
13800  */
13801 void
13802 clutter_actor_clear_actions (ClutterActor *self)
13803 {
13804   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13805
13806   if (self->priv->actions == NULL)
13807     return;
13808
13809   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13810 }
13811
13812 /**
13813  * clutter_actor_add_constraint:
13814  * @self: a #ClutterActor
13815  * @constraint: a #ClutterConstraint
13816  *
13817  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13818  * to @self
13819  *
13820  * The #ClutterActor will hold a reference on the @constraint until
13821  * either clutter_actor_remove_constraint() or
13822  * clutter_actor_clear_constraints() is called.
13823  *
13824  * Since: 1.4
13825  */
13826 void
13827 clutter_actor_add_constraint (ClutterActor      *self,
13828                               ClutterConstraint *constraint)
13829 {
13830   ClutterActorPrivate *priv;
13831
13832   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13833   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13834
13835   priv = self->priv;
13836
13837   if (priv->constraints == NULL)
13838     {
13839       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13840       priv->constraints->actor = self;
13841     }
13842
13843   _clutter_meta_group_add_meta (priv->constraints,
13844                                 CLUTTER_ACTOR_META (constraint));
13845   clutter_actor_queue_relayout (self);
13846
13847   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13848 }
13849
13850 /**
13851  * clutter_actor_add_constraint_with_name:
13852  * @self: a #ClutterActor
13853  * @name: the name to set on the constraint
13854  * @constraint: a #ClutterConstraint
13855  *
13856  * A convenience function for setting the name of a #ClutterConstraint
13857  * while adding it to the list of constraints applied to @self
13858  *
13859  * This function is the logical equivalent of:
13860  *
13861  * |[
13862  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13863  *   clutter_actor_add_constraint (self, constraint);
13864  * ]|
13865  *
13866  * Since: 1.4
13867  */
13868 void
13869 clutter_actor_add_constraint_with_name (ClutterActor      *self,
13870                                         const gchar       *name,
13871                                         ClutterConstraint *constraint)
13872 {
13873   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13874   g_return_if_fail (name != NULL);
13875   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13876
13877   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13878   clutter_actor_add_constraint (self, constraint);
13879 }
13880
13881 /**
13882  * clutter_actor_remove_constraint:
13883  * @self: a #ClutterActor
13884  * @constraint: a #ClutterConstraint
13885  *
13886  * Removes @constraint from the list of constraints applied to @self
13887  *
13888  * The reference held by @self on the #ClutterConstraint will be released
13889  *
13890  * Since: 1.4
13891  */
13892 void
13893 clutter_actor_remove_constraint (ClutterActor      *self,
13894                                  ClutterConstraint *constraint)
13895 {
13896   ClutterActorPrivate *priv;
13897
13898   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13899   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13900
13901   priv = self->priv;
13902
13903   if (priv->constraints == NULL)
13904     return;
13905
13906   _clutter_meta_group_remove_meta (priv->constraints,
13907                                    CLUTTER_ACTOR_META (constraint));
13908   clutter_actor_queue_relayout (self);
13909
13910   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13911 }
13912
13913 /**
13914  * clutter_actor_remove_constraint_by_name:
13915  * @self: a #ClutterActor
13916  * @name: the name of the constraint to remove
13917  *
13918  * Removes the #ClutterConstraint with the given name from the list
13919  * of constraints applied to @self
13920  *
13921  * Since: 1.4
13922  */
13923 void
13924 clutter_actor_remove_constraint_by_name (ClutterActor *self,
13925                                          const gchar  *name)
13926 {
13927   ClutterActorPrivate *priv;
13928   ClutterActorMeta *meta;
13929
13930   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13931   g_return_if_fail (name != NULL);
13932
13933   priv = self->priv;
13934
13935   if (priv->constraints == NULL)
13936     return;
13937
13938   meta = _clutter_meta_group_get_meta (priv->constraints, name);
13939   if (meta == NULL)
13940     return;
13941
13942   _clutter_meta_group_remove_meta (priv->constraints, meta);
13943   clutter_actor_queue_relayout (self);
13944 }
13945
13946 /**
13947  * clutter_actor_get_constraints:
13948  * @self: a #ClutterActor
13949  *
13950  * Retrieves the list of constraints applied to @self
13951  *
13952  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
13953  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
13954  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13955  *   allocated by the returned #GList
13956  *
13957  * Since: 1.4
13958  */
13959 GList *
13960 clutter_actor_get_constraints (ClutterActor *self)
13961 {
13962   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13963
13964   if (self->priv->constraints == NULL)
13965     return NULL;
13966
13967   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
13968 }
13969
13970 /**
13971  * clutter_actor_get_constraint:
13972  * @self: a #ClutterActor
13973  * @name: the name of the constraint to retrieve
13974  *
13975  * Retrieves the #ClutterConstraint with the given name in the list
13976  * of constraints applied to @self
13977  *
13978  * Return value: (transfer none): a #ClutterConstraint for the given
13979  *   name, or %NULL. The returned #ClutterConstraint is owned by the
13980  *   actor and it should not be unreferenced directly
13981  *
13982  * Since: 1.4
13983  */
13984 ClutterConstraint *
13985 clutter_actor_get_constraint (ClutterActor *self,
13986                               const gchar  *name)
13987 {
13988   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13989   g_return_val_if_fail (name != NULL, NULL);
13990
13991   if (self->priv->constraints == NULL)
13992     return NULL;
13993
13994   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
13995 }
13996
13997 /**
13998  * clutter_actor_clear_constraints:
13999  * @self: a #ClutterActor
14000  *
14001  * Clears the list of constraints applied to @self
14002  *
14003  * Since: 1.4
14004  */
14005 void
14006 clutter_actor_clear_constraints (ClutterActor *self)
14007 {
14008   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14009
14010   if (self->priv->constraints == NULL)
14011     return;
14012
14013   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14014
14015   clutter_actor_queue_relayout (self);
14016 }
14017
14018 /**
14019  * clutter_actor_set_clip_to_allocation:
14020  * @self: a #ClutterActor
14021  * @clip_set: %TRUE to apply a clip tracking the allocation
14022  *
14023  * Sets whether @self should be clipped to the same size as its
14024  * allocation
14025  *
14026  * Since: 1.4
14027  */
14028 void
14029 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14030                                       gboolean      clip_set)
14031 {
14032   ClutterActorPrivate *priv;
14033
14034   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14035
14036   clip_set = !!clip_set;
14037
14038   priv = self->priv;
14039
14040   if (priv->clip_to_allocation != clip_set)
14041     {
14042       priv->clip_to_allocation = clip_set;
14043
14044       clutter_actor_queue_redraw (self);
14045
14046       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14047     }
14048 }
14049
14050 /**
14051  * clutter_actor_get_clip_to_allocation:
14052  * @self: a #ClutterActor
14053  *
14054  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14055  *
14056  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14057  *
14058  * Since: 1.4
14059  */
14060 gboolean
14061 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14062 {
14063   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14064
14065   return self->priv->clip_to_allocation;
14066 }
14067
14068 /**
14069  * clutter_actor_add_effect:
14070  * @self: a #ClutterActor
14071  * @effect: a #ClutterEffect
14072  *
14073  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14074  *
14075  * The #ClutterActor will hold a reference on the @effect until either
14076  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14077  * called.
14078  *
14079  * Since: 1.4
14080  */
14081 void
14082 clutter_actor_add_effect (ClutterActor  *self,
14083                           ClutterEffect *effect)
14084 {
14085   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14086   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14087
14088   _clutter_actor_add_effect_internal (self, effect);
14089
14090   clutter_actor_queue_redraw (self);
14091
14092   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14093 }
14094
14095 /**
14096  * clutter_actor_add_effect_with_name:
14097  * @self: a #ClutterActor
14098  * @name: the name to set on the effect
14099  * @effect: a #ClutterEffect
14100  *
14101  * A convenience function for setting the name of a #ClutterEffect
14102  * while adding it to the list of effectss applied to @self
14103  *
14104  * This function is the logical equivalent of:
14105  *
14106  * |[
14107  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14108  *   clutter_actor_add_effect (self, effect);
14109  * ]|
14110  *
14111  * Since: 1.4
14112  */
14113 void
14114 clutter_actor_add_effect_with_name (ClutterActor  *self,
14115                                     const gchar   *name,
14116                                     ClutterEffect *effect)
14117 {
14118   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14119   g_return_if_fail (name != NULL);
14120   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14121
14122   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14123   clutter_actor_add_effect (self, effect);
14124 }
14125
14126 /**
14127  * clutter_actor_remove_effect:
14128  * @self: a #ClutterActor
14129  * @effect: a #ClutterEffect
14130  *
14131  * Removes @effect from the list of effects applied to @self
14132  *
14133  * The reference held by @self on the #ClutterEffect will be released
14134  *
14135  * Since: 1.4
14136  */
14137 void
14138 clutter_actor_remove_effect (ClutterActor  *self,
14139                              ClutterEffect *effect)
14140 {
14141   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14142   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14143
14144   _clutter_actor_remove_effect_internal (self, effect);
14145
14146   clutter_actor_queue_redraw (self);
14147
14148   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14149 }
14150
14151 /**
14152  * clutter_actor_remove_effect_by_name:
14153  * @self: a #ClutterActor
14154  * @name: the name of the effect to remove
14155  *
14156  * Removes the #ClutterEffect with the given name from the list
14157  * of effects applied to @self
14158  *
14159  * Since: 1.4
14160  */
14161 void
14162 clutter_actor_remove_effect_by_name (ClutterActor *self,
14163                                      const gchar  *name)
14164 {
14165   ClutterActorPrivate *priv;
14166   ClutterActorMeta *meta;
14167
14168   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14169   g_return_if_fail (name != NULL);
14170
14171   priv = self->priv;
14172
14173   if (priv->effects == NULL)
14174     return;
14175
14176   meta = _clutter_meta_group_get_meta (priv->effects, name);
14177   if (meta == NULL)
14178     return;
14179
14180   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14181 }
14182
14183 /**
14184  * clutter_actor_get_effects:
14185  * @self: a #ClutterActor
14186  *
14187  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14188  *
14189  * Return value: (transfer container) (element-type Clutter.Effect): a list
14190  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14191  *   list are owned by Clutter and they should not be freed. You should
14192  *   free the returned list using g_list_free() when done
14193  *
14194  * Since: 1.4
14195  */
14196 GList *
14197 clutter_actor_get_effects (ClutterActor *self)
14198 {
14199   ClutterActorPrivate *priv;
14200
14201   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14202
14203   priv = self->priv;
14204
14205   if (priv->effects == NULL)
14206     return NULL;
14207
14208   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14209 }
14210
14211 /**
14212  * clutter_actor_get_effect:
14213  * @self: a #ClutterActor
14214  * @name: the name of the effect to retrieve
14215  *
14216  * Retrieves the #ClutterEffect with the given name in the list
14217  * of effects applied to @self
14218  *
14219  * Return value: (transfer none): a #ClutterEffect for the given
14220  *   name, or %NULL. The returned #ClutterEffect is owned by the
14221  *   actor and it should not be unreferenced directly
14222  *
14223  * Since: 1.4
14224  */
14225 ClutterEffect *
14226 clutter_actor_get_effect (ClutterActor *self,
14227                           const gchar  *name)
14228 {
14229   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14230   g_return_val_if_fail (name != NULL, NULL);
14231
14232   if (self->priv->effects == NULL)
14233     return NULL;
14234
14235   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14236 }
14237
14238 /**
14239  * clutter_actor_clear_effects:
14240  * @self: a #ClutterActor
14241  *
14242  * Clears the list of effects applied to @self
14243  *
14244  * Since: 1.4
14245  */
14246 void
14247 clutter_actor_clear_effects (ClutterActor *self)
14248 {
14249   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14250
14251   if (self->priv->effects == NULL)
14252     return;
14253
14254   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14255
14256   clutter_actor_queue_redraw (self);
14257 }
14258
14259 /**
14260  * clutter_actor_has_key_focus:
14261  * @self: a #ClutterActor
14262  *
14263  * Checks whether @self is the #ClutterActor that has key focus
14264  *
14265  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14266  *
14267  * Since: 1.4
14268  */
14269 gboolean
14270 clutter_actor_has_key_focus (ClutterActor *self)
14271 {
14272   ClutterActor *stage;
14273
14274   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14275
14276   stage = _clutter_actor_get_stage_internal (self);
14277   if (stage == NULL)
14278     return FALSE;
14279
14280   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14281 }
14282
14283 static gboolean
14284 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14285                                       ClutterPaintVolume *pv)
14286 {
14287   ClutterActorPrivate *priv = self->priv;
14288
14289   /* Actors are only expected to report a valid paint volume
14290    * while they have a valid allocation. */
14291   if (G_UNLIKELY (priv->needs_allocation))
14292     {
14293       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14294                     "Actor needs allocation",
14295                     _clutter_actor_get_debug_name (self));
14296       return FALSE;
14297     }
14298
14299   /* Check if there are any handlers connected to the paint
14300    * signal. If there are then all bets are off for what the paint
14301    * volume for this actor might possibly be!
14302    *
14303    * XXX: It's expected that this is going to end up being quite a
14304    * costly check to have to do here, but we haven't come up with
14305    * another solution that can reliably catch paint signal handlers at
14306    * the right time to either avoid artefacts due to invalid stage
14307    * clipping or due to incorrect culling.
14308    *
14309    * Previously we checked in clutter_actor_paint(), but at that time
14310    * we may already be using a stage clip that could be derived from
14311    * an invalid paint-volume. We used to try and handle that by
14312    * queuing a follow up, unclipped, redraw but still the previous
14313    * checking wasn't enough to catch invalid volumes involved in
14314    * culling (considering that containers may derive their volume from
14315    * children that haven't yet been painted)
14316    *
14317    * Longer term, improved solutions could be:
14318    * - Disallow painting in the paint signal, only allow using it
14319    *   for tracking when paints happen. We can add another API that
14320    *   allows monkey patching the paint of arbitrary actors but in a
14321    *   more controlled way and that also supports modifying the
14322    *   paint-volume.
14323    * - If we could be notified somehow when signal handlers are
14324    *   connected we wouldn't have to poll for handlers like this.
14325    */
14326   if (g_signal_has_handler_pending (self,
14327                                     actor_signals[PAINT],
14328                                     0,
14329                                     TRUE))
14330     {
14331       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14332                     "Actor has \"paint\" signal handlers",
14333                     _clutter_actor_get_debug_name (self));
14334       return FALSE;
14335     }
14336
14337   _clutter_paint_volume_init_static (pv, self);
14338
14339   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14340     {
14341       clutter_paint_volume_free (pv);
14342       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14343                     "Actor failed to report a volume",
14344                     _clutter_actor_get_debug_name (self));
14345       return FALSE;
14346     }
14347
14348   /* since effects can modify the paint volume, we allow them to actually
14349    * do this by making get_paint_volume() "context sensitive"
14350    */
14351   if (priv->effects != NULL)
14352     {
14353       if (priv->current_effect != NULL)
14354         {
14355           const GList *effects, *l;
14356
14357           /* if we are being called from within the paint sequence of
14358            * an actor, get the paint volume up to the current effect
14359            */
14360           effects = _clutter_meta_group_peek_metas (priv->effects);
14361           for (l = effects;
14362                l != NULL || (l != NULL && l->data != priv->current_effect);
14363                l = l->next)
14364             {
14365               if (!_clutter_effect_get_paint_volume (l->data, pv))
14366                 {
14367                   clutter_paint_volume_free (pv);
14368                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14369                                 "Effect (%s) failed to report a volume",
14370                                 _clutter_actor_get_debug_name (self),
14371                                 _clutter_actor_meta_get_debug_name (l->data));
14372                   return FALSE;
14373                 }
14374             }
14375         }
14376       else
14377         {
14378           const GList *effects, *l;
14379
14380           /* otherwise, get the cumulative volume */
14381           effects = _clutter_meta_group_peek_metas (priv->effects);
14382           for (l = effects; l != NULL; l = l->next)
14383             if (!_clutter_effect_get_paint_volume (l->data, pv))
14384               {
14385                 clutter_paint_volume_free (pv);
14386                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14387                               "Effect (%s) failed to report a volume",
14388                               _clutter_actor_get_debug_name (self),
14389                               _clutter_actor_meta_get_debug_name (l->data));
14390                 return FALSE;
14391               }
14392         }
14393     }
14394
14395   return TRUE;
14396 }
14397
14398 /* The public clutter_actor_get_paint_volume API returns a const
14399  * pointer since we return a pointer directly to the cached
14400  * PaintVolume associated with the actor and don't want the user to
14401  * inadvertently modify it, but for internal uses we sometimes need
14402  * access to the same PaintVolume but need to apply some book-keeping
14403  * modifications to it so we don't want a const pointer.
14404  */
14405 static ClutterPaintVolume *
14406 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14407 {
14408   ClutterActorPrivate *priv;
14409
14410   priv = self->priv;
14411
14412   if (priv->paint_volume_valid)
14413     clutter_paint_volume_free (&priv->paint_volume);
14414
14415   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14416     {
14417       priv->paint_volume_valid = TRUE;
14418       return &priv->paint_volume;
14419     }
14420   else
14421     {
14422       priv->paint_volume_valid = FALSE;
14423       return NULL;
14424     }
14425 }
14426
14427 /**
14428  * clutter_actor_get_paint_volume:
14429  * @self: a #ClutterActor
14430  *
14431  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14432  * when a paint volume can't be determined.
14433  *
14434  * The paint volume is defined as the 3D space occupied by an actor
14435  * when being painted.
14436  *
14437  * This function will call the <function>get_paint_volume()</function>
14438  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14439  * should not usually care about overriding the default implementation,
14440  * unless they are, for instance: painting outside their allocation, or
14441  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14442  * 3D depth).
14443  *
14444  * <note>2D actors overriding <function>get_paint_volume()</function>
14445  * ensure their volume has a depth of 0. (This will be true so long as
14446  * you don't call clutter_paint_volume_set_depth().)</note>
14447  *
14448  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14449  *   or %NULL if no volume could be determined.
14450  *
14451  * Since: 1.6
14452  */
14453 const ClutterPaintVolume *
14454 clutter_actor_get_paint_volume (ClutterActor *self)
14455 {
14456   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14457
14458   return _clutter_actor_get_paint_volume_mutable (self);
14459 }
14460
14461 /**
14462  * clutter_actor_get_transformed_paint_volume:
14463  * @self: a #ClutterActor
14464  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14465  *    (or %NULL for the stage)
14466  *
14467  * Retrieves the 3D paint volume of an actor like
14468  * clutter_actor_get_paint_volume() does (Please refer to the
14469  * documentation of clutter_actor_get_paint_volume() for more
14470  * details.) and it additionally transforms the paint volume into the
14471  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14472  * is passed for @relative_to_ancestor)
14473  *
14474  * This can be used by containers that base their paint volume on
14475  * the volume of their children. Such containers can query the
14476  * transformed paint volume of all of its children and union them
14477  * together using clutter_paint_volume_union().
14478  *
14479  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14480  *   or %NULL if no volume could be determined.
14481  *
14482  * Since: 1.6
14483  */
14484 const ClutterPaintVolume *
14485 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14486                                             ClutterActor *relative_to_ancestor)
14487 {
14488   const ClutterPaintVolume *volume;
14489   ClutterActor *stage;
14490   ClutterPaintVolume *transformed_volume;
14491
14492   stage = _clutter_actor_get_stage_internal (self);
14493   if (G_UNLIKELY (stage == NULL))
14494     return NULL;
14495
14496   if (relative_to_ancestor == NULL)
14497     relative_to_ancestor = stage;
14498
14499   volume = clutter_actor_get_paint_volume (self);
14500   if (volume == NULL)
14501     return NULL;
14502
14503   transformed_volume =
14504     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14505
14506   _clutter_paint_volume_copy_static (volume, transformed_volume);
14507
14508   _clutter_paint_volume_transform_relative (transformed_volume,
14509                                             relative_to_ancestor);
14510
14511   return transformed_volume;
14512 }
14513
14514 /**
14515  * clutter_actor_get_paint_box:
14516  * @self: a #ClutterActor
14517  * @box: (out): return location for a #ClutterActorBox
14518  *
14519  * Retrieves the paint volume of the passed #ClutterActor, and
14520  * transforms it into a 2D bounding box in stage coordinates.
14521  *
14522  * This function is useful to determine the on screen area occupied by
14523  * the actor. The box is only an approximation and may often be
14524  * considerably larger due to the optimizations used to calculate the
14525  * box. The box is never smaller though, so it can reliably be used
14526  * for culling.
14527  *
14528  * There are times when a 2D paint box can't be determined, e.g.
14529  * because the actor isn't yet parented under a stage or because
14530  * the actor is unable to determine a paint volume.
14531  *
14532  * Return value: %TRUE if a 2D paint box could be determined, else
14533  * %FALSE.
14534  *
14535  * Since: 1.6
14536  */
14537 gboolean
14538 clutter_actor_get_paint_box (ClutterActor    *self,
14539                              ClutterActorBox *box)
14540 {
14541   ClutterActor *stage;
14542   ClutterPaintVolume *pv;
14543
14544   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14545   g_return_val_if_fail (box != NULL, FALSE);
14546
14547   stage = _clutter_actor_get_stage_internal (self);
14548   if (G_UNLIKELY (!stage))
14549     return FALSE;
14550
14551   pv = _clutter_actor_get_paint_volume_mutable (self);
14552   if (G_UNLIKELY (!pv))
14553     return FALSE;
14554
14555   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14556
14557   return TRUE;
14558 }
14559
14560 /**
14561  * clutter_actor_has_overlaps:
14562  * @self: A #ClutterActor
14563  *
14564  * Asks the actor's implementation whether it may contain overlapping
14565  * primitives.
14566  *
14567  * For example; Clutter may use this to determine whether the painting
14568  * should be redirected to an offscreen buffer to correctly implement
14569  * the opacity property.
14570  *
14571  * Custom actors can override the default response by implementing the
14572  * #ClutterActor <function>has_overlaps</function> virtual function. See
14573  * clutter_actor_set_offscreen_redirect() for more information.
14574  *
14575  * Return value: %TRUE if the actor may have overlapping primitives, and
14576  *   %FALSE otherwise
14577  *
14578  * Since: 1.8
14579  */
14580 gboolean
14581 clutter_actor_has_overlaps (ClutterActor *self)
14582 {
14583   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14584
14585   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14586 }
14587
14588 /**
14589  * clutter_actor_has_effects:
14590  * @self: A #ClutterActor
14591  *
14592  * Returns whether the actor has any effects applied.
14593  *
14594  * Return value: %TRUE if the actor has any effects,
14595  *   %FALSE otherwise
14596  *
14597  * Since: 1.10
14598  */
14599 gboolean
14600 clutter_actor_has_effects (ClutterActor *self)
14601 {
14602   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14603
14604   if (self->priv->effects == NULL)
14605     return FALSE;
14606
14607   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14608 }
14609
14610 /**
14611  * clutter_actor_has_constraints:
14612  * @self: A #ClutterActor
14613  *
14614  * Returns whether the actor has any constraints applied.
14615  *
14616  * Return value: %TRUE if the actor has any constraints,
14617  *   %FALSE otherwise
14618  *
14619  * Since: 1.10
14620  */
14621 gboolean
14622 clutter_actor_has_constraints (ClutterActor *self)
14623 {
14624   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14625
14626   return self->priv->constraints != NULL;
14627 }
14628
14629 /**
14630  * clutter_actor_has_actions:
14631  * @self: A #ClutterActor
14632  *
14633  * Returns whether the actor has any actions applied.
14634  *
14635  * Return value: %TRUE if the actor has any actions,
14636  *   %FALSE otherwise
14637  *
14638  * Since: 1.10
14639  */
14640 gboolean
14641 clutter_actor_has_actions (ClutterActor *self)
14642 {
14643   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14644
14645   return self->priv->actions != NULL;
14646 }
14647
14648 /**
14649  * clutter_actor_get_n_children:
14650  * @self: a #ClutterActor
14651  *
14652  * Retrieves the number of children of @self.
14653  *
14654  * Return value: the number of children of an actor
14655  *
14656  * Since: 1.10
14657  */
14658 gint
14659 clutter_actor_get_n_children (ClutterActor *self)
14660 {
14661   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14662
14663   return self->priv->n_children;
14664 }
14665
14666 /**
14667  * clutter_actor_get_child_at_index:
14668  * @self: a #ClutterActor
14669  * @index_: the position in the list of children
14670  *
14671  * Retrieves the actor at the given @index_ inside the list of
14672  * children of @self.
14673  *
14674  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14675  *
14676  * Since: 1.10
14677  */
14678 ClutterActor *
14679 clutter_actor_get_child_at_index (ClutterActor *self,
14680                                   gint          index_)
14681 {
14682   ClutterActor *iter;
14683   int i;
14684
14685   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14686   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14687
14688   for (iter = self->priv->first_child, i = 0;
14689        iter != NULL && i < index_;
14690        iter = iter->priv->next_sibling, i += 1)
14691     ;
14692
14693   return iter;
14694 }
14695
14696 /*< private >
14697  * _clutter_actor_foreach_child:
14698  * @actor: The actor whos children you want to iterate
14699  * @callback: The function to call for each child
14700  * @user_data: Private data to pass to @callback
14701  *
14702  * Calls a given @callback once for each child of the specified @actor and
14703  * passing the @user_data pointer each time.
14704  *
14705  * Return value: returns %TRUE if all children were iterated, else
14706  *    %FALSE if a callback broke out of iteration early.
14707  */
14708 gboolean
14709 _clutter_actor_foreach_child (ClutterActor           *self,
14710                               ClutterForeachCallback  callback,
14711                               gpointer                user_data)
14712 {
14713   ClutterActorPrivate *priv = self->priv;
14714   ClutterActor *iter;
14715   gboolean cont;
14716
14717   for (cont = TRUE, iter = priv->first_child;
14718        cont && iter != NULL;
14719        iter = iter->priv->next_sibling)
14720     {
14721       cont = callback (iter, user_data);
14722     }
14723
14724   return cont;
14725 }
14726
14727 /* For debugging purposes this gives us a simple way to print out
14728  * the scenegraph e.g in gdb using:
14729  * [|
14730  *   _clutter_actor_traverse (stage,
14731  *                            0,
14732  *                            _clutter_debug_print_actor_cb,
14733  *                            NULL,
14734  *                            NULL);
14735  * |]
14736  */
14737 ClutterActorTraverseVisitFlags
14738 _clutter_debug_print_actor_cb (ClutterActor *actor,
14739                                int depth,
14740                                void *user_data)
14741 {
14742   g_print ("%*s%s:%p\n",
14743            depth * 2, "",
14744            _clutter_actor_get_debug_name (actor),
14745            actor);
14746
14747   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14748 }
14749
14750 static void
14751 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14752                                  ClutterTraverseCallback callback,
14753                                  gpointer                user_data)
14754 {
14755   GQueue *queue = g_queue_new ();
14756   ClutterActor dummy;
14757   int current_depth = 0;
14758
14759   g_queue_push_tail (queue, actor);
14760   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14761
14762   while ((actor = g_queue_pop_head (queue)))
14763     {
14764       ClutterActorTraverseVisitFlags flags;
14765
14766       if (actor == &dummy)
14767         {
14768           current_depth++;
14769           g_queue_push_tail (queue, &dummy);
14770           continue;
14771         }
14772
14773       flags = callback (actor, current_depth, user_data);
14774       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14775         break;
14776       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14777         {
14778           ClutterActor *iter;
14779
14780           for (iter = actor->priv->first_child;
14781                iter != NULL;
14782                iter = iter->priv->next_sibling)
14783             {
14784               g_queue_push_tail (queue, iter);
14785             }
14786         }
14787     }
14788
14789   g_queue_free (queue);
14790 }
14791
14792 static ClutterActorTraverseVisitFlags
14793 _clutter_actor_traverse_depth (ClutterActor           *actor,
14794                                ClutterTraverseCallback before_children_callback,
14795                                ClutterTraverseCallback after_children_callback,
14796                                int                     current_depth,
14797                                gpointer                user_data)
14798 {
14799   ClutterActorTraverseVisitFlags flags;
14800
14801   flags = before_children_callback (actor, current_depth, user_data);
14802   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14803     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14804
14805   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14806     {
14807       ClutterActor *iter;
14808
14809       for (iter = actor->priv->first_child;
14810            iter != NULL;
14811            iter = iter->priv->next_sibling)
14812         {
14813           flags = _clutter_actor_traverse_depth (iter,
14814                                                  before_children_callback,
14815                                                  after_children_callback,
14816                                                  current_depth + 1,
14817                                                  user_data);
14818
14819           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14820             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14821         }
14822     }
14823
14824   if (after_children_callback)
14825     return after_children_callback (actor, current_depth, user_data);
14826   else
14827     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14828 }
14829
14830 /* _clutter_actor_traverse:
14831  * @actor: The actor to start traversing the graph from
14832  * @flags: These flags may affect how the traversal is done
14833  * @before_children_callback: A function to call before visiting the
14834  *   children of the current actor.
14835  * @after_children_callback: A function to call after visiting the
14836  *   children of the current actor. (Ignored if
14837  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14838  * @user_data: The private data to pass to the callbacks
14839  *
14840  * Traverses the scenegraph starting at the specified @actor and
14841  * descending through all its children and its children's children.
14842  * For each actor traversed @before_children_callback and
14843  * @after_children_callback are called with the specified
14844  * @user_data, before and after visiting that actor's children.
14845  *
14846  * The callbacks can return flags that affect the ongoing traversal
14847  * such as by skipping over an actors children or bailing out of
14848  * any further traversing.
14849  */
14850 void
14851 _clutter_actor_traverse (ClutterActor              *actor,
14852                          ClutterActorTraverseFlags  flags,
14853                          ClutterTraverseCallback    before_children_callback,
14854                          ClutterTraverseCallback    after_children_callback,
14855                          gpointer                   user_data)
14856 {
14857   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
14858     _clutter_actor_traverse_breadth (actor,
14859                                      before_children_callback,
14860                                      user_data);
14861   else /* DEPTH_FIRST */
14862     _clutter_actor_traverse_depth (actor,
14863                                    before_children_callback,
14864                                    after_children_callback,
14865                                    0, /* start depth */
14866                                    user_data);
14867 }
14868
14869 static void
14870 on_layout_manager_changed (ClutterLayoutManager *manager,
14871                            ClutterActor         *self)
14872 {
14873   clutter_actor_queue_relayout (self);
14874 }
14875
14876 /**
14877  * clutter_actor_set_layout_manager:
14878  * @self: a #ClutterActor
14879  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
14880  *
14881  * Sets the #ClutterLayoutManager delegate object that will be used to
14882  * lay out the children of @self.
14883  *
14884  * The #ClutterActor will take a reference on the passed @manager which
14885  * will be released either when the layout manager is removed, or when
14886  * the actor is destroyed.
14887  *
14888  * Since: 1.10
14889  */
14890 void
14891 clutter_actor_set_layout_manager (ClutterActor         *self,
14892                                   ClutterLayoutManager *manager)
14893 {
14894   ClutterActorPrivate *priv;
14895
14896   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14897   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
14898
14899   priv = self->priv;
14900
14901   if (priv->layout_manager != NULL)
14902     {
14903       g_signal_handlers_disconnect_by_func (priv->layout_manager,
14904                                             G_CALLBACK (on_layout_manager_changed),
14905                                             self);
14906       clutter_layout_manager_set_container (priv->layout_manager, NULL);
14907       g_object_unref (priv->layout_manager);
14908     }
14909
14910   priv->layout_manager = manager;
14911
14912   if (priv->layout_manager != NULL)
14913     {
14914       g_object_ref_sink (priv->layout_manager);
14915       clutter_layout_manager_set_container (priv->layout_manager,
14916                                             CLUTTER_CONTAINER (self));
14917       g_signal_connect (priv->layout_manager, "layout-changed",
14918                         G_CALLBACK (on_layout_manager_changed),
14919                         self);
14920     }
14921
14922   clutter_actor_queue_relayout (self);
14923
14924   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
14925 }
14926
14927 /**
14928  * clutter_actor_get_layout_manager:
14929  * @self: a #ClutterActor
14930  *
14931  * Retrieves the #ClutterLayoutManager used by @self.
14932  *
14933  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
14934  *   or %NULL
14935  *
14936  * Since: 1.10
14937  */
14938 ClutterLayoutManager *
14939 clutter_actor_get_layout_manager (ClutterActor *self)
14940 {
14941   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14942
14943   return self->priv->layout_manager;
14944 }
14945
14946 static const ClutterLayoutInfo default_layout_info = {
14947   0.f,                          /* fixed-x */
14948   0.f,                          /* fixed-y */
14949   { 0, 0, 0, 0 },               /* margin */
14950   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
14951   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
14952   0.f, 0.f,                     /* min_width, natural_width */
14953   0.f, 0.f,                     /* natual_width, natural_height */
14954 };
14955
14956 static void
14957 layout_info_free (gpointer data)
14958 {
14959   if (G_LIKELY (data != NULL))
14960     g_slice_free (ClutterLayoutInfo, data);
14961 }
14962
14963 /*< private >
14964  * _clutter_actor_get_layout_info:
14965  * @self: a #ClutterActor
14966  *
14967  * Retrieves a pointer to the ClutterLayoutInfo structure.
14968  *
14969  * If the actor does not have a ClutterLayoutInfo associated to it, one
14970  * will be created and initialized to the default values.
14971  *
14972  * This function should be used for setters.
14973  *
14974  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
14975  * instead.
14976  *
14977  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
14978  */
14979 ClutterLayoutInfo *
14980 _clutter_actor_get_layout_info (ClutterActor *self)
14981 {
14982   ClutterLayoutInfo *retval;
14983
14984   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
14985   if (retval == NULL)
14986     {
14987       retval = g_slice_new (ClutterLayoutInfo);
14988
14989       *retval = default_layout_info;
14990
14991       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
14992                                retval,
14993                                layout_info_free);
14994     }
14995
14996   return retval;
14997 }
14998
14999 /*< private >
15000  * _clutter_actor_get_layout_info_or_defaults:
15001  * @self: a #ClutterActor
15002  *
15003  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15004  *
15005  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15006  * then the default structure will be returned.
15007  *
15008  * This function should only be used for getters.
15009  *
15010  * Return value: a const pointer to the ClutterLayoutInfo structure
15011  */
15012 const ClutterLayoutInfo *
15013 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15014 {
15015   const ClutterLayoutInfo *info;
15016
15017   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15018   if (info == NULL)
15019     return &default_layout_info;
15020
15021   return info;
15022 }
15023
15024 /**
15025  * clutter_actor_set_x_align:
15026  * @self: a #ClutterActor
15027  * @x_align: the horizontal alignment policy
15028  *
15029  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15030  * actor received extra horizontal space.
15031  *
15032  * See also the #ClutterActor:x-align property.
15033  *
15034  * Since: 1.10
15035  */
15036 void
15037 clutter_actor_set_x_align (ClutterActor      *self,
15038                            ClutterActorAlign  x_align)
15039 {
15040   ClutterLayoutInfo *info;
15041
15042   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15043
15044   info = _clutter_actor_get_layout_info (self);
15045
15046   if (info->x_align != x_align)
15047     {
15048       info->x_align = x_align;
15049
15050       clutter_actor_queue_relayout (self);
15051
15052       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15053     }
15054 }
15055
15056 /**
15057  * clutter_actor_get_x_align:
15058  * @self: a #ClutterActor
15059  *
15060  * Retrieves the horizontal alignment policy set using
15061  * clutter_actor_set_x_align().
15062  *
15063  * Return value: the horizontal alignment policy.
15064  *
15065  * Since: 1.10
15066  */
15067 ClutterActorAlign
15068 clutter_actor_get_x_align (ClutterActor *self)
15069 {
15070   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15071
15072   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15073 }
15074
15075 /**
15076  * clutter_actor_set_y_align:
15077  * @self: a #ClutterActor
15078  * @y_align: the vertical alignment policy
15079  *
15080  * Sets the vertical alignment policy of a #ClutterActor, in case the
15081  * actor received extra vertical space.
15082  *
15083  * See also the #ClutterActor:y-align property.
15084  *
15085  * Since: 1.10
15086  */
15087 void
15088 clutter_actor_set_y_align (ClutterActor      *self,
15089                            ClutterActorAlign  y_align)
15090 {
15091   ClutterLayoutInfo *info;
15092
15093   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15094
15095   info = _clutter_actor_get_layout_info (self);
15096
15097   if (info->y_align != y_align)
15098     {
15099       info->y_align = y_align;
15100
15101       clutter_actor_queue_relayout (self);
15102
15103       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15104     }
15105 }
15106
15107 /**
15108  * clutter_actor_get_y_align:
15109  * @self: a #ClutterActor
15110  *
15111  * Retrieves the vertical alignment policy set using
15112  * clutter_actor_set_y_align().
15113  *
15114  * Return value: the vertical alignment policy.
15115  *
15116  * Since: 1.10
15117  */
15118 ClutterActorAlign
15119 clutter_actor_get_y_align (ClutterActor *self)
15120 {
15121   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15122
15123   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15124 }
15125
15126
15127 /**
15128  * clutter_margin_new:
15129  *
15130  * Creates a new #ClutterMargin.
15131  *
15132  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15133  *   clutter_margin_free() to free the resources associated with it when
15134  *   done.
15135  *
15136  * Since: 1.10
15137  */
15138 ClutterMargin *
15139 clutter_margin_new (void)
15140 {
15141   return g_slice_new0 (ClutterMargin);
15142 }
15143
15144 /**
15145  * clutter_margin_copy:
15146  * @margin_: a #ClutterMargin
15147  *
15148  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15149  * the newly created structure.
15150  *
15151  * Return value: (transfer full): a copy of the #ClutterMargin.
15152  *
15153  * Since: 1.10
15154  */
15155 ClutterMargin *
15156 clutter_margin_copy (const ClutterMargin *margin_)
15157 {
15158   if (G_LIKELY (margin_ != NULL))
15159     return g_slice_dup (ClutterMargin, margin_);
15160
15161   return NULL;
15162 }
15163
15164 /**
15165  * clutter_margin_free:
15166  * @margin_: a #ClutterMargin
15167  *
15168  * Frees the resources allocated by clutter_margin_new() and
15169  * clutter_margin_copy().
15170  *
15171  * Since: 1.10
15172  */
15173 void
15174 clutter_margin_free (ClutterMargin *margin_)
15175 {
15176   if (G_LIKELY (margin_ != NULL))
15177     g_slice_free (ClutterMargin, margin_);
15178 }
15179
15180 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15181                      clutter_margin_copy,
15182                      clutter_margin_free)
15183
15184 /**
15185  * clutter_actor_set_margin:
15186  * @self: a #ClutterActor
15187  * @margin: a #ClutterMargin
15188  *
15189  * Sets all the components of the margin of a #ClutterActor.
15190  *
15191  * Since: 1.10
15192  */
15193 void
15194 clutter_actor_set_margin (ClutterActor        *self,
15195                           const ClutterMargin *margin)
15196 {
15197   ClutterLayoutInfo *info;
15198   gboolean changed;
15199   GObject *obj;
15200
15201   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15202   g_return_if_fail (margin != NULL);
15203
15204   obj = G_OBJECT (self);
15205   changed = FALSE;
15206
15207   g_object_freeze_notify (obj);
15208
15209   info = _clutter_actor_get_layout_info (self);
15210
15211   if (info->margin.top != margin->top)
15212     {
15213       info->margin.top = margin->top;
15214       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15215       changed = TRUE;
15216     }
15217
15218   if (info->margin.right != margin->right)
15219     {
15220       info->margin.right = margin->right;
15221       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15222       changed = TRUE;
15223     }
15224
15225   if (info->margin.bottom != margin->bottom)
15226     {
15227       info->margin.bottom = margin->bottom;
15228       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15229       changed = TRUE;
15230     }
15231
15232   if (info->margin.left != margin->left)
15233     {
15234       info->margin.left = margin->left;
15235       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15236       changed = TRUE;
15237     }
15238
15239   if (changed)
15240     clutter_actor_queue_relayout (self);
15241
15242   g_object_thaw_notify (obj);
15243 }
15244
15245 /**
15246  * clutter_actor_get_margin:
15247  * @self: a #ClutterActor
15248  * @margin: (out caller-allocates): return location for a #ClutterMargin
15249  *
15250  * Retrieves all the components of the margin of a #ClutterActor.
15251  *
15252  * Since: 1.10
15253  */
15254 void
15255 clutter_actor_get_margin (ClutterActor  *self,
15256                           ClutterMargin *margin)
15257 {
15258   const ClutterLayoutInfo *info;
15259
15260   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15261   g_return_if_fail (margin != NULL);
15262
15263   info = _clutter_actor_get_layout_info_or_defaults (self);
15264
15265   *margin = info->margin;
15266 }
15267
15268 /**
15269  * clutter_actor_set_margin_top:
15270  * @self: a #ClutterActor
15271  * @margin: the top margin
15272  *
15273  * Sets the margin from the top of a #ClutterActor.
15274  *
15275  * Since: 1.10
15276  */
15277 void
15278 clutter_actor_set_margin_top (ClutterActor *self,
15279                               gfloat        margin)
15280 {
15281   ClutterLayoutInfo *info;
15282
15283   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15284   g_return_if_fail (margin >= 0.f);
15285
15286   info = _clutter_actor_get_layout_info (self);
15287
15288   if (info->margin.top == margin)
15289     return;
15290
15291   info->margin.top = margin;
15292
15293   clutter_actor_queue_relayout (self);
15294
15295   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15296 }
15297
15298 /**
15299  * clutter_actor_get_margin_top:
15300  * @self: a #ClutterActor
15301  *
15302  * Retrieves the top margin of a #ClutterActor.
15303  *
15304  * Return value: the top margin
15305  *
15306  * Since: 1.10
15307  */
15308 gfloat
15309 clutter_actor_get_margin_top (ClutterActor *self)
15310 {
15311   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15312
15313   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15314 }
15315
15316 /**
15317  * clutter_actor_set_margin_bottom:
15318  * @self: a #ClutterActor
15319  * @margin: the bottom margin
15320  *
15321  * Sets the margin from the bottom of a #ClutterActor.
15322  *
15323  * Since: 1.10
15324  */
15325 void
15326 clutter_actor_set_margin_bottom (ClutterActor *self,
15327                                  gfloat        margin)
15328 {
15329   ClutterLayoutInfo *info;
15330
15331   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15332   g_return_if_fail (margin >= 0.f);
15333
15334   info = _clutter_actor_get_layout_info (self);
15335
15336   if (info->margin.bottom == margin)
15337     return;
15338
15339   info->margin.bottom = margin;
15340
15341   clutter_actor_queue_relayout (self);
15342
15343   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15344 }
15345
15346 /**
15347  * clutter_actor_get_margin_bottom:
15348  * @self: a #ClutterActor
15349  *
15350  * Retrieves the bottom margin of a #ClutterActor.
15351  *
15352  * Return value: the bottom margin
15353  *
15354  * Since: 1.10
15355  */
15356 gfloat
15357 clutter_actor_get_margin_bottom (ClutterActor *self)
15358 {
15359   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15360
15361   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15362 }
15363
15364 /**
15365  * clutter_actor_set_margin_left:
15366  * @self: a #ClutterActor
15367  * @margin: the left margin
15368  *
15369  * Sets the margin from the left of a #ClutterActor.
15370  *
15371  * Since: 1.10
15372  */
15373 void
15374 clutter_actor_set_margin_left (ClutterActor *self,
15375                                gfloat        margin)
15376 {
15377   ClutterLayoutInfo *info;
15378
15379   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15380   g_return_if_fail (margin >= 0.f);
15381
15382   info = _clutter_actor_get_layout_info (self);
15383
15384   if (info->margin.left == margin)
15385     return;
15386
15387   info->margin.left = margin;
15388
15389   clutter_actor_queue_relayout (self);
15390
15391   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15392 }
15393
15394 /**
15395  * clutter_actor_get_margin_left:
15396  * @self: a #ClutterActor
15397  *
15398  * Retrieves the left margin of a #ClutterActor.
15399  *
15400  * Return value: the left margin
15401  *
15402  * Since: 1.10
15403  */
15404 gfloat
15405 clutter_actor_get_margin_left (ClutterActor *self)
15406 {
15407   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15408
15409   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15410 }
15411
15412 /**
15413  * clutter_actor_set_margin_right:
15414  * @self: a #ClutterActor
15415  * @margin: the right margin
15416  *
15417  * Sets the margin from the right of a #ClutterActor.
15418  *
15419  * Since: 1.10
15420  */
15421 void
15422 clutter_actor_set_margin_right (ClutterActor *self,
15423                                 gfloat        margin)
15424 {
15425   ClutterLayoutInfo *info;
15426
15427   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15428   g_return_if_fail (margin >= 0.f);
15429
15430   info = _clutter_actor_get_layout_info (self);
15431
15432   if (info->margin.right == margin)
15433     return;
15434
15435   info->margin.right = margin;
15436
15437   clutter_actor_queue_relayout (self);
15438
15439   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15440 }
15441
15442 /**
15443  * clutter_actor_get_margin_right:
15444  * @self: a #ClutterActor
15445  *
15446  * Retrieves the right margin of a #ClutterActor.
15447  *
15448  * Return value: the right margin
15449  *
15450  * Since: 1.10
15451  */
15452 gfloat
15453 clutter_actor_get_margin_right (ClutterActor *self)
15454 {
15455   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15456
15457   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15458 }
15459
15460 /**
15461  * clutter_actor_set_background_color:
15462  * @self: a #ClutterActor
15463  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15464  *  set color
15465  *
15466  * Sets the background color of a #ClutterActor.
15467  *
15468  * The background color will be used to cover the whole allocation of the
15469  * actor. The default background color of an actor is transparent.
15470  *
15471  * To check whether an actor has a background color, you can use the
15472  * #ClutterActor:background-color-set actor property.
15473  *
15474  * Since: 1.10
15475  */
15476 void
15477 clutter_actor_set_background_color (ClutterActor       *self,
15478                                     const ClutterColor *color)
15479 {
15480   ClutterActorPrivate *priv;
15481
15482   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15483
15484   priv = self->priv;
15485
15486   if (color == NULL)
15487     {
15488       priv->bg_color_set = FALSE;
15489       g_object_notify_by_pspec (G_OBJECT (self),
15490                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15491       return;
15492     }
15493
15494   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15495     return;
15496
15497   priv->bg_color = *color;
15498   priv->bg_color_set = TRUE;
15499
15500   clutter_actor_queue_redraw (self);
15501
15502   g_object_notify_by_pspec (G_OBJECT (self),
15503                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15504   g_object_notify_by_pspec (G_OBJECT (self),
15505                             obj_props[PROP_BACKGROUND_COLOR]);
15506 }
15507
15508 /**
15509  * clutter_actor_get_background_color:
15510  * @self: a #ClutterActor
15511  * @color: (out caller-allocates): return location for a #ClutterColor
15512  *
15513  * Retrieves the color set using clutter_actor_set_background_color().
15514  *
15515  * Since: 1.10
15516  */
15517 void
15518 clutter_actor_get_background_color (ClutterActor *self,
15519                                     ClutterColor *color)
15520 {
15521   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15522   g_return_if_fail (color != NULL);
15523
15524   *color = self->priv->bg_color;
15525 }
15526
15527 /**
15528  * clutter_actor_get_previous_sibling:
15529  * @self: a #ClutterActor
15530  *
15531  * Retrieves the sibling of @self that comes before it in the list
15532  * of children of @self's parent.
15533  *
15534  * The returned pointer is only valid until the scene graph changes; it
15535  * is not safe to modify the list of children of @self while iterating
15536  * it.
15537  *
15538  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15539  *
15540  * Since: 1.10
15541  */
15542 ClutterActor *
15543 clutter_actor_get_previous_sibling (ClutterActor *self)
15544 {
15545   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15546
15547   return self->priv->prev_sibling;
15548 }
15549
15550 /**
15551  * clutter_actor_get_next_sibling:
15552  * @self: a #ClutterActor
15553  *
15554  * Retrieves the sibling of @self that comes after it in the list
15555  * of children of @self's parent.
15556  *
15557  * The returned pointer is only valid until the scene graph changes; it
15558  * is not safe to modify the list of children of @self while iterating
15559  * it.
15560  *
15561  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15562  *
15563  * Since: 1.10
15564  */
15565 ClutterActor *
15566 clutter_actor_get_next_sibling (ClutterActor *self)
15567 {
15568   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15569
15570   return self->priv->next_sibling;
15571 }
15572
15573 /**
15574  * clutter_actor_get_first_child:
15575  * @self: a #ClutterActor
15576  *
15577  * Retrieves the first child of @self.
15578  *
15579  * The returned pointer is only valid until the scene graph changes; it
15580  * is not safe to modify the list of children of @self while iterating
15581  * it.
15582  *
15583  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15584  *
15585  * Since: 1.10
15586  */
15587 ClutterActor *
15588 clutter_actor_get_first_child (ClutterActor *self)
15589 {
15590   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15591
15592   return self->priv->first_child;
15593 }
15594
15595 /**
15596  * clutter_actor_get_last_child:
15597  * @self: a #ClutterActor
15598  *
15599  * Retrieves the last child of @self.
15600  *
15601  * The returned pointer is only valid until the scene graph changes; it
15602  * is not safe to modify the list of children of @self while iterating
15603  * it.
15604  *
15605  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15606  *
15607  * Since: 1.10
15608  */
15609 ClutterActor *
15610 clutter_actor_get_last_child (ClutterActor *self)
15611 {
15612   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15613
15614   return self->priv->last_child;
15615 }
15616
15617 /* easy way to have properly named fields instead of the dummy ones
15618  * we use in the public structure
15619  */
15620 typedef struct _RealActorIter
15621 {
15622   ClutterActor *root;           /* dummy1 */
15623   ClutterActor *current;        /* dummy2 */
15624   gpointer padding_1;           /* dummy3 */
15625   gint age;                     /* dummy4 */
15626   gpointer padding_2;           /* dummy5 */
15627 } RealActorIter;
15628
15629 /**
15630  * clutter_actor_iter_init:
15631  * @iter: a #ClutterActorIter
15632  * @root: a #ClutterActor
15633  *
15634  * Initializes a #ClutterActorIter, which can then be used to iterate
15635  * efficiently over a section of the scene graph, and associates it
15636  * with @root.
15637  *
15638  * Modifying the scene graph section that contains @root will invalidate
15639  * the iterator.
15640  *
15641  * |[
15642  *   ClutterActorIter iter;
15643  *   ClutterActor *child;
15644  *
15645  *   clutter_actor_iter_init (&iter, container);
15646  *   while (clutter_actor_iter_next (&iter, &child))
15647  *     {
15648  *       /&ast; do something with child &ast;/
15649  *     }
15650  * ]|
15651  *
15652  * Since: 1.10
15653  */
15654 void
15655 clutter_actor_iter_init (ClutterActorIter *iter,
15656                          ClutterActor     *root)
15657 {
15658   RealActorIter *ri = (RealActorIter *) iter;
15659
15660   g_return_if_fail (iter != NULL);
15661   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15662
15663   ri->root = root;
15664   ri->current = NULL;
15665   ri->age = root->priv->age;
15666 }
15667
15668 /**
15669  * clutter_actor_iter_next:
15670  * @iter: a #ClutterActorIter
15671  * @child: (out): return location for a #ClutterActor
15672  *
15673  * Advances the @iter and retrieves the next child of the root #ClutterActor
15674  * that was used to initialize the #ClutterActorIterator.
15675  *
15676  * If the iterator can advance, this function returns %TRUE and sets the
15677  * @child argument.
15678  *
15679  * If the iterator cannot advance, this function returns %FALSE, and
15680  * the contents of @child are undefined.
15681  *
15682  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15683  *
15684  * Since: 1.10
15685  */
15686 gboolean
15687 clutter_actor_iter_next (ClutterActorIter  *iter,
15688                          ClutterActor     **child)
15689 {
15690   RealActorIter *ri = (RealActorIter *) iter;
15691
15692   g_return_val_if_fail (iter != NULL, FALSE);
15693   g_return_val_if_fail (ri->root != NULL, FALSE);
15694 #ifndef G_DISABLE_ASSERT
15695   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15696 #endif
15697
15698   if (ri->current == NULL)
15699     ri->current = ri->root->priv->first_child;
15700   else
15701     ri->current = ri->current->priv->next_sibling;
15702
15703   if (child != NULL)
15704     *child = ri->current;
15705
15706   return ri->current != NULL;
15707 }
15708
15709 /**
15710  * clutter_actor_iter_next:
15711  * @iter: a #ClutterActorIter
15712  * @child: (out): return location for a #ClutterActor
15713  *
15714  * Advances the @iter and retrieves the previous child of the root
15715  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15716  *
15717  * If the iterator can advance, this function returns %TRUE and sets the
15718  * @child argument.
15719  *
15720  * If the iterator cannot advance, this function returns %FALSE, and
15721  * the contents of @child are undefined.
15722  *
15723  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15724  *
15725  * Since: 1.10
15726  */
15727 gboolean
15728 clutter_actor_iter_prev (ClutterActorIter  *iter,
15729                          ClutterActor     **child)
15730 {
15731   RealActorIter *ri = (RealActorIter *) iter;
15732
15733   g_return_val_if_fail (iter != NULL, FALSE);
15734   g_return_val_if_fail (ri->root != NULL, FALSE);
15735 #ifndef G_DISABLE_ASSERT
15736   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15737 #endif
15738
15739   if (ri->current == NULL)
15740     ri->current = ri->root->priv->last_child;
15741   else
15742     ri->current = ri->current->priv->prev_sibling;
15743
15744   if (child != NULL)
15745     *child = ri->current;
15746
15747   return ri->current != NULL;
15748 }
15749
15750 /**
15751  * clutter_actor_iter_remove:
15752  * @iter: a #ClutterActorIter
15753  *
15754  * Safely removes the #ClutterActor currently pointer to by the iterator
15755  * from its parent.
15756  *
15757  * This function can only be called after clutter_actor_iter_next() or
15758  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15759  * than once for the same actor.
15760  *
15761  * This function will call clutter_actor_remove_child() internally.
15762  *
15763  * Since: 1.10
15764  */
15765 void
15766 clutter_actor_iter_remove (ClutterActorIter *iter)
15767 {
15768   RealActorIter *ri = (RealActorIter *) iter;
15769   ClutterActor *cur;
15770
15771   g_return_if_fail (iter != NULL);
15772   g_return_if_fail (ri->root != NULL);
15773 #ifndef G_DISABLE_ASSERT
15774   g_return_if_fail (ri->age == ri->root->priv->age);
15775 #endif
15776   g_return_if_fail (ri->current != NULL);
15777
15778   cur = ri->current;
15779
15780   if (cur != NULL)
15781     {
15782       ri->current = cur->priv->prev_sibling;
15783
15784       clutter_actor_remove_child_internal (ri->root, cur,
15785                                            REMOVE_CHILD_DEFAULT_FLAGS);
15786
15787       ri->age += 1;
15788     }
15789 }
15790
15791 /**
15792  * clutter_actor_iter_destroy:
15793  * @iter: a #ClutterActorIter
15794  *
15795  * Safely destroys the #ClutterActor currently pointer to by the iterator
15796  * from its parent.
15797  *
15798  * This function can only be called after clutter_actor_iter_next() or
15799  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15800  * than once for the same actor.
15801  *
15802  * This function will call clutter_actor_destroy() internally.
15803  *
15804  * Since: 1.10
15805  */
15806 void
15807 clutter_actor_iter_destroy (ClutterActorIter *iter)
15808 {
15809   RealActorIter *ri = (RealActorIter *) iter;
15810   ClutterActor *cur;
15811
15812   g_return_if_fail (iter != NULL);
15813   g_return_if_fail (ri->root != NULL);
15814 #ifndef G_DISABLE_ASSERT
15815   g_return_if_fail (ri->age == ri->root->priv->age);
15816 #endif
15817   g_return_if_fail (ri->current != NULL);
15818
15819   cur = ri->current;
15820
15821   if (cur != NULL)
15822     {
15823       ri->current = cur->priv->prev_sibling;
15824
15825       clutter_actor_destroy (cur);
15826
15827       ri->age += 1;
15828     }
15829 }