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