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