actor: Minor optimization to avoid get_preferred_*
[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, 2011, 2012 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: The basic element of the scene graph 
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="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-animation">
217  *   <title>Animation</title>
218  *   <para>Animation is a core concept of modern user interfaces; Clutter
219  *   provides a complete and powerful animation framework that automatically
220  *   tweens the actor's state without requiring direct, frame by frame
221  *   manipulation from your application code.</para>
222  *   <formalpara>
223  *     <title>Implicit animations</title>
224  *     <para>The implicit animation model of Clutter assumes that all the
225  *     changes in an actor state should be gradual and asynchronous; Clutter
226  *     will automatically transition an actor's property change between the
227  *     current state and the desired one without manual intervention.</para>
228  *     <para>By default, in the 1.0 API series, the transition happens with
229  *     a duration of zero milliseconds, and the implicit animation is an
230  *     opt in feature to retain backwards compatibility. In order to enable
231  *     implicit animations, it is necessary to change the easing state of
232  *     an actor by using clutter_actor_save_easing_state():</para>
233  *     <informalexample><programlisting>
234  * /&ast; assume that the actor is currently positioned at (100, 100) &ast;/
235  * clutter_actor_save_easing_state (actor);
236  * clutter_actor_set_position (actor, 500, 500);
237  * clutter_actor_restore_easing_state (actor);
238  *     </programlisting></informalexample>
239  *     <para>The example above will trigger an implicit animation of the
240  *     actor between its current position to a new position.</para>
241  *     <para>It is possible to animate multiple properties of an actor
242  *     at the same time, and you can animate multiple actors at the same
243  *     time as well, for instance:</para>
244  *     <informalexample><programlisting>
245  * /&ast; animate the actor's opacity and depth &ast;/
246  * clutter_actor_save_easing_state (actor);
247  * clutter_actor_set_opacity (actor, 0);
248  * clutter_actor_set_depth (actor, -100);
249  * clutter_actor_restore_easing_state (actor);
250  *
251  * /&ast; animate another actor's opacity &ast;/
252  * clutter_actor_save_easing_state (another_actor);
253  * clutter_actor_set_opacity (another_actor, 255);
254  * clutter_actor_set_depth (another_actor, 100);
255  * clutter_actor_restore_easing_state (another_actor);
256  *     </programlisting></informalexample>
257  *     <para>Implicit animations use a default duration of 250 milliseconds,
258  *     and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259  *     clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260  *     after changing the easing state of the actor.</para>
261  *     <para>It is important to note that if you modify the state on an
262  *     animatable property while a transition is in flight, the transition's
263  *     final value will be updated, as well as its duration and progress
264  *     mode by using the current easing state; for instance, in the following
265  *     example:</para>
266  *     <informalexample><programlisting>
267  * clutter_actor_save_easing_state (actor);
268  * clutter_actor_set_x (actor, 200);
269  * clutter_actor_restore_easing_state (actor);
270  *
271  * clutter_actor_save_easing_state (actor);
272  * clutter_actor_set_x (actor, 100);
273  * clutter_actor_restore_easing_state (actor);
274  *     </programlisting></informalexample>
275  *     <para>the first call to clutter_actor_set_x() will begin a transition
276  *     of the #ClutterActor:x property to the value of 200; the second call
277  *     to clutter_actor_set_x() will change the transition's final value to
278  *     100.</para>
279  *     <para>It is possible to retrieve the #ClutterTransition used by the
280  *     animatable properties by using clutter_actor_get_transition() and using
281  *     the property name as the transition name.</para>
282  *   </formalpara>
283  *   <formalpara>
284  *     <title>Explicit animations</title>
285  *     <para>The explicit animation model supported by Clutter requires that
286  *     you create a #ClutterTransition object, and set the initial and
287  *     final values. The transition will not start unless you add it to the
288  *     #ClutterActor.</para>
289  *     <informalexample><programlisting>
290  * ClutterTransition *transition;
291  *
292  * transition = clutter_property_transition_new ("opacity");
293  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296  * clutter_transition_set_interval (transition, clutter_interval_new (G_TYPE_UINT, 255, 0));
297  *
298  * clutter_actor_add_transition (actor, "animate-opacity", transition);
299  *     </programlisting></informalexample>
300  *     <para>The example above will animate the #ClutterActor:opacity property
301  *     of an actor between fully opaque and fully transparent, and back, over
302  *     a span of 3 seconds. The animation does not begin until it is added to
303  *     the actor.</para>
304  *     <para>The explicit animation API should also be used when using custom
305  *     animatable properties for #ClutterAction, #ClutterConstraint, and
306  *     #ClutterEffect instances associated to an actor; see the section on
307  *     <ulink linkend="ClutterActor-custom-animatable-properties">custom
308  *     animatable properties below</ulink> for an example.</para>
309  *     <para>Finally, explicit animations are useful for creating animations
310  *     that run continuously, for instance:</para>
311  *     <informalexample><programlisting>
312  * /&ast; this animation will pulse the actor's opacity continuously &ast;/
313  * ClutterTransition *transition;
314  * ClutterInterval *interval;
315  *
316  * transition = clutter_property_transition_new ("opacity");
317  *
318  * /&ast; we want to animate the opacity between 0 and 255 &ast;/
319  * internal = clutter_interval_new (G_TYPE_UINT, 0, 255);
320  * clutter_transition_set_interval (transition, interval);
321  *
322  * /&ast; over a one second duration, running an infinite amount of times &ast;/
323  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
324  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
325  *
326  * /&ast; we want to fade in and out, so we need to auto-reverse the transition &ast;/
327  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
328  *
329  * /&ast; and we want to use an easing function that eases both in and out &ast;/
330  * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
331  *                                     CLUTTER_EASE_IN_OUT_CUBIC);
332  *
333  * /&ast; add the transition to the desired actor; this will
334  *  &ast; start the animation.
335  *  &ast;/
336  * clutter_actor_add_transition (actor, "opacityAnimation", transition);
337  *     </programlisting></informalexample>
338  *   </formalpara>
339  * </refsect2>
340  *
341  * <refsect2 id="ClutterActor-subclassing">
342  *   <title>Implementing an actor</title>
343  *   <para>Careful consideration should be given when deciding to implement
344  *   a #ClutterActor sub-class. It is generally recommended to implement a
345  *   sub-class of #ClutterActor only for actors that should be used as leaf
346  *   nodes of a scene graph.</para>
347  *   <para>If your actor should be painted in a custom way, you should
348  *   override the #ClutterActor::paint signal class handler. You can either
349  *   opt to chain up to the parent class implementation or decide to fully
350  *   override the default paint implementation; Clutter will set up the
351  *   transformations and clip regions prior to emitting the #ClutterActor::paint
352  *   signal.</para>
353  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
354  *   #ClutterActorClass.get_preferred_height() virtual functions it is
355  *   possible to change or provide the preferred size of an actor; similarly,
356  *   by overriding the #ClutterActorClass.allocate() virtual function it is
357  *   possible to control the layout of the children of an actor. Make sure to
358  *   always chain up to the parent implementation of the
359  *   #ClutterActorClass.allocate() virtual function.</para>
360  *   <para>In general, it is strongly encouraged to use delegation and
361  *   composition instead of direct subclassing.</para>
362  * </refsect2>
363  *
364  * <refsect2 id="ClutterActor-script">
365  *   <title>ClutterActor custom properties for #ClutterScript</title>
366  *   <para>#ClutterActor defines a custom "rotation" property which
367  *   allows a short-hand description of the rotations to be applied
368  *   to an actor.</para>
369  *   <para>The syntax of the "rotation" property is the following:</para>
370  *   <informalexample>
371  *     <programlisting>
372  * "rotation" : [
373  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
374  * ]
375  *     </programlisting>
376  *   </informalexample>
377  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
378  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
379  *   floating point value representing the rotation angle on the given axis,
380  *   in degrees.</para>
381  *   <para>The <emphasis>center</emphasis> array is optional, and if present
382  *   it must contain the center of rotation as described by two coordinates:
383  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
384  *   "z-axis".</para>
385  *   <para>#ClutterActor will also parse every positional and dimensional
386  *   property defined as a string through clutter_units_from_string(); you
387  *   should read the documentation for the #ClutterUnits parser format for
388  *   the valid units and syntax.</para>
389  * </refsect2>
390  *
391  * <refsect2 id="ClutterActor-custom-animatable-properties">
392  *   <title>Custom animatable properties</title>
393  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
394  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
395  *   instance for animation purposes.</para>
396  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
397  *   property it is necessary to set the #ClutterActorMeta:name property on the
398  *   given action or constraint.</para>
399  *   <para>The property can be accessed using the following syntax:</para>
400  *   <informalexample>
401  *     <programlisting>
402  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
403  *     </programlisting>
404  *   </informalexample>
405  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
406  *   <para>The <emphasis>section</emphasis> fragment can be one between
407  *   "actions", "constraints" and "effects".</para>
408  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
409  *   action or constraint, as specified by the #ClutterActorMeta:name
410  *   property.</para>
411  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
412  *   action or constraint property to be animated.</para>
413  *   <para>The example below animates a #ClutterBindConstraint applied to an
414  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
415  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
416  *   its initial state is overlapping the actor to which is bound to.</para>
417  *   <informalexample><programlisting>
418  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
419  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
420  * clutter_actor_add_constraint (rect, constraint);
421  *
422  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
423  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
424  * clutter_actor_add_constraint (rect, constraint);
425  *
426  * clutter_actor_set_reactive (origin, TRUE);
427  *
428  * g_signal_connect (origin, "button-press-event",
429  *                   G_CALLBACK (on_button_press),
430  *                   rect);
431  *   </programlisting></informalexample>
432  *   <para>On button press, the rectangle "slides" from behind the actor to
433  *   which is bound to, using the #ClutterBindConstraint:offset property to
434  *   achieve the effect:</para>
435  *   <informalexample><programlisting>
436  * gboolean
437  * on_button_press (ClutterActor *origin,
438  *                  ClutterEvent *event,
439  *                  ClutterActor *rect)
440  * {
441  *   ClutterTransition *transition;
442  *   ClutterInterval *interval;
443  *
444  *   /&ast; the offset that we want to apply; this will make the actor
445  *    &ast; slide in from behind the origin and rest at the right of
446  *    &ast; the origin, plus a padding value.
447  *    &ast;/
448  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
449  *
450  *   /&ast; the property we wish to animate; the "@constraints" section
451  *    &ast; tells Clutter to check inside the constraints associated
452  *    &ast; with the actor; the "bind-x" section is the name of the
453  *    &ast; constraint; and the "offset" is the name of the property
454  *    &ast; on the constraint.
455  *    &ast;/
456  *   const char *prop = "@constraints.bind-x.offset";
457  *
458  *   /&ast; create a new transition for the given property &ast;/
459  *   transition = clutter_property_transition_new (prop);
460  *
461  *   /&ast; set the easing mode and duration &ast;/
462  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
463  *                                       CLUTTER_EASE_OUT_CUBIC);
464  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
465  *
466  *   /&ast; create the interval with the initial and final values &ast;/
467  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
468  *   clutter_transition_set_interval (transition, interval);
469  *
470  *   /&ast; add the transition to the actor; this causes the animation
471  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
472  *    &ast; the transition later.
473  *    &ast;/
474  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
475  *
476  *   /&ast; we handled the event &ast;/
477  *   return CLUTTER_EVENT_STOP;
478  * }
479  *   </programlisting></informalexample>
480  * </refsect2>
481  */
482
483 /**
484  * CLUTTER_ACTOR_IS_MAPPED:
485  * @a: a #ClutterActor
486  *
487  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
488  *
489  * The mapped state is set when the actor is visible and all its parents up
490  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
491  *
492  * This check can be used to see if an actor is going to be painted, as only
493  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
494  *
495  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
496  * not be checked directly; instead, the recommended usage is to connect a
497  * handler on the #GObject::notify signal for the #ClutterActor:mapped
498  * property of #ClutterActor, and check the presence of
499  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
500  *
501  * It is also important to note that Clutter may delay the changes of
502  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
503  * limitations, or during the reparenting of an actor, to optimize
504  * unnecessary (and potentially expensive) state changes.
505  *
506  * Since: 0.2
507  */
508
509 /**
510  * CLUTTER_ACTOR_IS_REALIZED:
511  * @a: a #ClutterActor
512  *
513  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
514  *
515  * The realized state has an actor-dependant interpretation. If an
516  * actor wants to delay allocating resources until it is attached to a
517  * stage, it may use the realize state to do so. However it is
518  * perfectly acceptable for an actor to allocate Cogl resources before
519  * being realized because there is only one drawing context used by Clutter
520  * so any resources will work on any stage.  If an actor is mapped it
521  * must also be realized, but an actor can be realized and unmapped
522  * (this is so hiding an actor temporarily doesn't do an expensive
523  * unrealize/realize).
524  *
525  * To be realized an actor must be inside a stage, and all its parents
526  * must be realized.
527  *
528  * Since: 0.2
529  */
530
531 /**
532  * CLUTTER_ACTOR_IS_VISIBLE:
533  * @a: a #ClutterActor
534  *
535  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
536  * Equivalent to the ClutterActor::visible object property.
537  *
538  * Note that an actor is only painted onscreen if it's mapped, which
539  * means it's visible, and all its parents are visible, and one of the
540  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
541  *
542  * Since: 0.2
543  */
544
545 /**
546  * CLUTTER_ACTOR_IS_REACTIVE:
547  * @a: a #ClutterActor
548  *
549  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
550  *
551  * Only reactive actors will receive event-related signals.
552  *
553  * Since: 0.6
554  */
555
556 #ifdef HAVE_CONFIG_H
557 #include "config.h"
558 #endif
559
560 #include <math.h>
561
562 #include <gobject/gvaluecollector.h>
563
564 #include <cogl/cogl.h>
565
566 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
567 #define CLUTTER_ENABLE_EXPERIMENTAL_API
568
569 #include "clutter-actor-private.h"
570
571 #include "clutter-action.h"
572 #include "clutter-actor-meta-private.h"
573 #include "clutter-animatable.h"
574 #include "clutter-color-static.h"
575 #include "clutter-color.h"
576 #include "clutter-constraint.h"
577 #include "clutter-container.h"
578 #include "clutter-content-private.h"
579 #include "clutter-debug.h"
580 #include "clutter-effect-private.h"
581 #include "clutter-enum-types.h"
582 #include "clutter-fixed-layout.h"
583 #include "clutter-flatten-effect.h"
584 #include "clutter-interval.h"
585 #include "clutter-main.h"
586 #include "clutter-marshal.h"
587 #include "clutter-paint-nodes.h"
588 #include "clutter-paint-node-private.h"
589 #include "clutter-paint-volume-private.h"
590 #include "clutter-private.h"
591 #include "clutter-profile.h"
592 #include "clutter-property-transition.h"
593 #include "clutter-scriptable.h"
594 #include "clutter-script-private.h"
595 #include "clutter-stage-private.h"
596 #include "clutter-timeline.h"
597 #include "clutter-transition.h"
598 #include "clutter-units.h"
599
600 #include "deprecated/clutter-actor.h"
601 #include "deprecated/clutter-behaviour.h"
602 #include "deprecated/clutter-container.h"
603
604 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
605 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
606
607 /* Internal enum used to control mapped state update.  This is a hint
608  * which indicates when to do something other than just enforce
609  * invariants.
610  */
611 typedef enum {
612   MAP_STATE_CHECK,           /* just enforce invariants. */
613   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
614                               * used when about to unparent.
615                               */
616   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
617                               * used to set mapped on toplevels.
618                               */
619   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
620                               * used just before unmapping parent.
621                               */
622 } MapStateChange;
623
624 /* 3 entries should be a good compromise, few layout managers
625  * will ask for 3 different preferred size in each allocation cycle */
626 #define N_CACHED_SIZE_REQUESTS 3
627
628 struct _ClutterActorPrivate
629 {
630   /* request mode */
631   ClutterRequestMode request_mode;
632
633   /* our cached size requests for different width / height */
634   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
635   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
636
637   /* An age of 0 means the entry is not set */
638   guint cached_height_age;
639   guint cached_width_age;
640
641   /* the bounding box of the actor, relative to the parent's
642    * allocation
643    */
644   ClutterActorBox allocation;
645   ClutterAllocationFlags allocation_flags;
646
647   /* clip, in actor coordinates */
648   cairo_rectangle_t clip;
649
650   /* the cached transformation matrix; see apply_transform() */
651   CoglMatrix transform;
652
653   guint8 opacity;
654   gint opacity_override;
655
656   ClutterOffscreenRedirect offscreen_redirect;
657
658   /* This is an internal effect used to implement the
659      offscreen-redirect property */
660   ClutterEffect *flatten_effect;
661
662   /* scene graph */
663   ClutterActor *parent;
664   ClutterActor *prev_sibling;
665   ClutterActor *next_sibling;
666   ClutterActor *first_child;
667   ClutterActor *last_child;
668
669   gint n_children;
670
671   /* tracks whenever the children of an actor are changed; the
672    * age is incremented by 1 whenever an actor is added or
673    * removed. the age is not incremented when the first or the
674    * last child pointers are changed, or when grandchildren of
675    * an actor are changed.
676    */
677   gint age;
678
679   gchar *name; /* a non-unique name, used for debugging */
680   guint32 id; /* unique id, used for backward compatibility */
681
682   gint32 pick_id; /* per-stage unique id, used for picking */
683
684   /* a back-pointer to the Pango context that we can use
685    * to create pre-configured PangoLayout
686    */
687   PangoContext *pango_context;
688
689   /* the text direction configured for this child - either by
690    * application code, or by the actor's parent
691    */
692   ClutterTextDirection text_direction;
693
694   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
695   gint internal_child;
696
697   /* meta classes */
698   ClutterMetaGroup *actions;
699   ClutterMetaGroup *constraints;
700   ClutterMetaGroup *effects;
701
702   /* delegate object used to allocate the children of this actor */
703   ClutterLayoutManager *layout_manager;
704
705   /* delegate object used to paint the contents of this actor */
706   ClutterContent *content;
707
708   ClutterContentGravity content_gravity;
709   ClutterScalingFilter min_filter;
710   ClutterScalingFilter mag_filter;
711
712   /* used when painting, to update the paint volume */
713   ClutterEffect *current_effect;
714
715   /* This is used to store an effect which needs to be redrawn. A
716      redraw can be queued to start from a particular effect. This is
717      used by parametrised effects that can cache an image of the
718      actor. If a parameter of the effect changes then it only needs to
719      redraw the cached image, not the actual actor. The pointer is
720      only valid if is_dirty == TRUE. If the pointer is NULL then the
721      whole actor is dirty. */
722   ClutterEffect *effect_to_redraw;
723
724   /* This is used when painting effects to implement the
725      clutter_actor_continue_paint() function. It points to the node in
726      the list of effects that is next in the chain */
727   const GList *next_effect_to_paint;
728
729   ClutterPaintVolume paint_volume;
730
731   /* NB: This volume isn't relative to this actor, it is in eye
732    * coordinates so that it can remain valid after the actor changes.
733    */
734   ClutterPaintVolume last_paint_volume;
735
736   ClutterStageQueueRedrawEntry *queue_redraw_entry;
737
738   ClutterColor bg_color;
739
740   /* bitfields */
741
742   /* fixed position and sizes */
743   guint position_set                : 1;
744   guint min_width_set               : 1;
745   guint min_height_set              : 1;
746   guint natural_width_set           : 1;
747   guint natural_height_set          : 1;
748   /* cached request is invalid (implies allocation is too) */
749   guint needs_width_request         : 1;
750   /* cached request is invalid (implies allocation is too) */
751   guint needs_height_request        : 1;
752   /* cached allocation is invalid (request has changed, probably) */
753   guint needs_allocation            : 1;
754   guint show_on_set_parent          : 1;
755   guint has_clip                    : 1;
756   guint clip_to_allocation          : 1;
757   guint enable_model_view_transform : 1;
758   guint enable_paint_unmapped       : 1;
759   guint has_pointer                 : 1;
760   guint propagated_one_redraw       : 1;
761   guint paint_volume_valid          : 1;
762   guint last_paint_volume_valid     : 1;
763   guint in_clone_paint              : 1;
764   guint transform_valid             : 1;
765   /* This is TRUE if anything has queued a redraw since we were last
766      painted. In this case effect_to_redraw will point to an effect
767      the redraw was queued from or it will be NULL if the redraw was
768      queued without an effect. */
769   guint is_dirty                    : 1;
770   guint bg_color_set                : 1;
771 };
772
773 enum
774 {
775   PROP_0,
776
777   PROP_NAME,
778
779   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
780    * when set they force a size request, when gotten they
781    * get the allocation if the allocation is valid, and the
782    * request otherwise
783    */
784   PROP_X,
785   PROP_Y,
786   PROP_WIDTH,
787   PROP_HEIGHT,
788
789   /* Then the rest of these size-related properties are the "actual"
790    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
791    */
792   PROP_FIXED_X,
793   PROP_FIXED_Y,
794
795   PROP_FIXED_POSITION_SET,
796
797   PROP_MIN_WIDTH,
798   PROP_MIN_WIDTH_SET,
799
800   PROP_MIN_HEIGHT,
801   PROP_MIN_HEIGHT_SET,
802
803   PROP_NATURAL_WIDTH,
804   PROP_NATURAL_WIDTH_SET,
805
806   PROP_NATURAL_HEIGHT,
807   PROP_NATURAL_HEIGHT_SET,
808
809   PROP_REQUEST_MODE,
810
811   /* Allocation properties are read-only */
812   PROP_ALLOCATION,
813
814   PROP_DEPTH,
815
816   PROP_CLIP,
817   PROP_HAS_CLIP,
818   PROP_CLIP_TO_ALLOCATION,
819
820   PROP_OPACITY,
821
822   PROP_OFFSCREEN_REDIRECT,
823
824   PROP_VISIBLE,
825   PROP_MAPPED,
826   PROP_REALIZED,
827   PROP_REACTIVE,
828
829   PROP_SCALE_X,
830   PROP_SCALE_Y,
831   PROP_SCALE_CENTER_X,
832   PROP_SCALE_CENTER_Y,
833   PROP_SCALE_GRAVITY,
834
835   PROP_ROTATION_ANGLE_X,
836   PROP_ROTATION_ANGLE_Y,
837   PROP_ROTATION_ANGLE_Z,
838   PROP_ROTATION_CENTER_X,
839   PROP_ROTATION_CENTER_Y,
840   PROP_ROTATION_CENTER_Z,
841   /* This property only makes sense for the z rotation because the
842      others would depend on the actor having a size along the
843      z-axis */
844   PROP_ROTATION_CENTER_Z_GRAVITY,
845
846   PROP_ANCHOR_X,
847   PROP_ANCHOR_Y,
848   PROP_ANCHOR_GRAVITY,
849
850   PROP_SHOW_ON_SET_PARENT,
851
852   PROP_TEXT_DIRECTION,
853   PROP_HAS_POINTER,
854
855   PROP_ACTIONS,
856   PROP_CONSTRAINTS,
857   PROP_EFFECT,
858
859   PROP_LAYOUT_MANAGER,
860
861   PROP_X_ALIGN,
862   PROP_Y_ALIGN,
863   PROP_MARGIN_TOP,
864   PROP_MARGIN_BOTTOM,
865   PROP_MARGIN_LEFT,
866   PROP_MARGIN_RIGHT,
867
868   PROP_BACKGROUND_COLOR,
869   PROP_BACKGROUND_COLOR_SET,
870
871   PROP_FIRST_CHILD,
872   PROP_LAST_CHILD,
873
874   PROP_CONTENT,
875   PROP_CONTENT_GRAVITY,
876   PROP_CONTENT_BOX,
877   PROP_MINIFICATION_FILTER,
878   PROP_MAGNIFICATION_FILTER,
879
880   PROP_LAST
881 };
882
883 static GParamSpec *obj_props[PROP_LAST];
884
885 enum
886 {
887   SHOW,
888   HIDE,
889   DESTROY,
890   PARENT_SET,
891   KEY_FOCUS_IN,
892   KEY_FOCUS_OUT,
893   PAINT,
894   PICK,
895   REALIZE,
896   UNREALIZE,
897   QUEUE_REDRAW,
898   QUEUE_RELAYOUT,
899   EVENT,
900   CAPTURED_EVENT,
901   BUTTON_PRESS_EVENT,
902   BUTTON_RELEASE_EVENT,
903   SCROLL_EVENT,
904   KEY_PRESS_EVENT,
905   KEY_RELEASE_EVENT,
906   MOTION_EVENT,
907   ENTER_EVENT,
908   LEAVE_EVENT,
909   ALLOCATION_CHANGED,
910   TRANSITIONS_COMPLETED,
911
912   LAST_SIGNAL
913 };
914
915 static guint actor_signals[LAST_SIGNAL] = { 0, };
916
917 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
918 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
919 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
920 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
921
922 /* These setters are all static for now, maybe they should be in the
923  * public API, but they are perhaps obscure enough to leave only as
924  * properties
925  */
926 static void clutter_actor_set_min_width          (ClutterActor *self,
927                                                   gfloat        min_width);
928 static void clutter_actor_set_min_height         (ClutterActor *self,
929                                                   gfloat        min_height);
930 static void clutter_actor_set_natural_width      (ClutterActor *self,
931                                                   gfloat        natural_width);
932 static void clutter_actor_set_natural_height     (ClutterActor *self,
933                                                   gfloat        natural_height);
934 static void clutter_actor_set_min_width_set      (ClutterActor *self,
935                                                   gboolean      use_min_width);
936 static void clutter_actor_set_min_height_set     (ClutterActor *self,
937                                                   gboolean      use_min_height);
938 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
939                                                   gboolean  use_natural_width);
940 static void clutter_actor_set_natural_height_set (ClutterActor *self,
941                                                   gboolean  use_natural_height);
942 static void clutter_actor_update_map_state       (ClutterActor  *self,
943                                                   MapStateChange change);
944 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
945
946 /* Helper routines for managing anchor coords */
947 static void clutter_anchor_coord_get_units (ClutterActor      *self,
948                                             const AnchorCoord *coord,
949                                             gfloat            *x,
950                                             gfloat            *y,
951                                             gfloat            *z);
952 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
953                                             gfloat             x,
954                                             gfloat             y,
955                                             gfloat             z);
956
957 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
958 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
959                                                         ClutterGravity     gravity);
960
961 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
962
963 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
964
965 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
966                                                                ClutterActor *ancestor,
967                                                                CoglMatrix *matrix);
968
969 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
970
971 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
972
973 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
974                                                                 const ClutterColor *color);
975
976 static void on_layout_manager_changed (ClutterLayoutManager *manager,
977                                        ClutterActor         *self);
978
979 /* Helper macro which translates by the anchor coord, applies the
980    given transformation and then translates back */
981 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
982   gfloat _tx, _ty, _tz;                                                \
983   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
984   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
985   { _transform; }                                                      \
986   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
987
988 static GQuark quark_shader_data = 0;
989 static GQuark quark_actor_layout_info = 0;
990 static GQuark quark_actor_transform_info = 0;
991 static GQuark quark_actor_animation_info = 0;
992
993 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
994                          clutter_actor,
995                          G_TYPE_INITIALLY_UNOWNED,
996                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
997                                                 clutter_container_iface_init)
998                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
999                                                 clutter_scriptable_iface_init)
1000                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1001                                                 clutter_animatable_iface_init)
1002                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1003                                                 atk_implementor_iface_init));
1004
1005 /*< private >
1006  * clutter_actor_get_debug_name:
1007  * @actor: a #ClutterActor
1008  *
1009  * Retrieves a printable name of @actor for debugging messages
1010  *
1011  * Return value: a string with a printable name
1012  */
1013 const gchar *
1014 _clutter_actor_get_debug_name (ClutterActor *actor)
1015 {
1016   return actor->priv->name != NULL ? actor->priv->name
1017                                    : G_OBJECT_TYPE_NAME (actor);
1018 }
1019
1020 #ifdef CLUTTER_ENABLE_DEBUG
1021 /* XXX - this is for debugging only, remove once working (or leave
1022  * in only in some debug mode). Should leave it for a little while
1023  * until we're confident in the new map/realize/visible handling.
1024  */
1025 static inline void
1026 clutter_actor_verify_map_state (ClutterActor *self)
1027 {
1028   ClutterActorPrivate *priv = self->priv;
1029
1030   if (CLUTTER_ACTOR_IS_REALIZED (self))
1031     {
1032       /* all bets are off during reparent when we're potentially realized,
1033        * but should not be according to invariants
1034        */
1035       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1036         {
1037           if (priv->parent == NULL)
1038             {
1039               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1040                 {
1041                 }
1042               else
1043                 g_warning ("Realized non-toplevel actor '%s' should "
1044                            "have a parent",
1045                            _clutter_actor_get_debug_name (self));
1046             }
1047           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1048             {
1049               g_warning ("Realized actor %s has an unrealized parent %s",
1050                          _clutter_actor_get_debug_name (self),
1051                          _clutter_actor_get_debug_name (priv->parent));
1052             }
1053         }
1054     }
1055
1056   if (CLUTTER_ACTOR_IS_MAPPED (self))
1057     {
1058       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1059         g_warning ("Actor '%s' is mapped but not realized",
1060                    _clutter_actor_get_debug_name (self));
1061
1062       /* remaining bets are off during reparent when we're potentially
1063        * mapped, but should not be according to invariants
1064        */
1065       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1066         {
1067           if (priv->parent == NULL)
1068             {
1069               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1070                 {
1071                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1072                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1073                     {
1074                       g_warning ("Toplevel actor '%s' is mapped "
1075                                  "but not visible",
1076                                  _clutter_actor_get_debug_name (self));
1077                     }
1078                 }
1079               else
1080                 {
1081                   g_warning ("Mapped actor '%s' should have a parent",
1082                              _clutter_actor_get_debug_name (self));
1083                 }
1084             }
1085           else
1086             {
1087               ClutterActor *iter = self;
1088
1089               /* check for the enable_paint_unmapped flag on the actor
1090                * and parents; if the flag is enabled at any point of this
1091                * branch of the scene graph then all the later checks
1092                * become pointless
1093                */
1094               while (iter != NULL)
1095                 {
1096                   if (iter->priv->enable_paint_unmapped)
1097                     return;
1098
1099                   iter = iter->priv->parent;
1100                 }
1101
1102               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1103                 {
1104                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1105                              "is not visible",
1106                              _clutter_actor_get_debug_name (self),
1107                              _clutter_actor_get_debug_name (priv->parent));
1108                 }
1109
1110               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1111                 {
1112                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1113                              "is not realized",
1114                              _clutter_actor_get_debug_name (self),
1115                              _clutter_actor_get_debug_name (priv->parent));
1116                 }
1117
1118               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1119                 {
1120                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1121                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1122                                "parent '%s' is not mapped",
1123                                _clutter_actor_get_debug_name (self),
1124                                _clutter_actor_get_debug_name (priv->parent));
1125                 }
1126             }
1127         }
1128     }
1129 }
1130
1131 #endif /* CLUTTER_ENABLE_DEBUG */
1132
1133 static void
1134 clutter_actor_set_mapped (ClutterActor *self,
1135                           gboolean      mapped)
1136 {
1137   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1138     return;
1139
1140   if (mapped)
1141     {
1142       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1143       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1144     }
1145   else
1146     {
1147       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1148       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1149     }
1150 }
1151
1152 /* this function updates the mapped and realized states according to
1153  * invariants, in the appropriate order.
1154  */
1155 static void
1156 clutter_actor_update_map_state (ClutterActor  *self,
1157                                 MapStateChange change)
1158 {
1159   gboolean was_mapped;
1160
1161   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1162
1163   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1164     {
1165       /* the mapped flag on top-level actors must be set by the
1166        * per-backend implementation because it might be asynchronous.
1167        *
1168        * That is, the MAPPED flag on toplevels currently tracks the X
1169        * server mapped-ness of the window, while the expected behavior
1170        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1171        * This creates some weird complexity by breaking the invariant
1172        * that if we're visible and all ancestors shown then we are
1173        * also mapped - instead, we are mapped if all ancestors
1174        * _possibly excepting_ the stage are mapped. The stage
1175        * will map/unmap for example when it is minimized or
1176        * moved to another workspace.
1177        *
1178        * So, the only invariant on the stage is that if visible it
1179        * should be realized, and that it has to be visible to be
1180        * mapped.
1181        */
1182       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1183         clutter_actor_realize (self);
1184
1185       switch (change)
1186         {
1187         case MAP_STATE_CHECK:
1188           break;
1189
1190         case MAP_STATE_MAKE_MAPPED:
1191           g_assert (!was_mapped);
1192           clutter_actor_set_mapped (self, TRUE);
1193           break;
1194
1195         case MAP_STATE_MAKE_UNMAPPED:
1196           g_assert (was_mapped);
1197           clutter_actor_set_mapped (self, FALSE);
1198           break;
1199
1200         case MAP_STATE_MAKE_UNREALIZED:
1201           /* we only use MAKE_UNREALIZED in unparent,
1202            * and unparenting a stage isn't possible.
1203            * If someone wants to just unrealize a stage
1204            * then clutter_actor_unrealize() doesn't
1205            * go through this codepath.
1206            */
1207           g_warning ("Trying to force unrealize stage is not allowed");
1208           break;
1209         }
1210
1211       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1212           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1213           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1214         {
1215           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1216                      "it is somehow still mapped",
1217                      _clutter_actor_get_debug_name (self));
1218         }
1219     }
1220   else
1221     {
1222       ClutterActorPrivate *priv = self->priv;
1223       ClutterActor *parent = priv->parent;
1224       gboolean should_be_mapped;
1225       gboolean may_be_realized;
1226       gboolean must_be_realized;
1227
1228       should_be_mapped = FALSE;
1229       may_be_realized = TRUE;
1230       must_be_realized = FALSE;
1231
1232       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1233         {
1234           may_be_realized = FALSE;
1235         }
1236       else
1237         {
1238           /* Maintain invariant that if parent is mapped, and we are
1239            * visible, then we are mapped ...  unless parent is a
1240            * stage, in which case we map regardless of parent's map
1241            * state but do require stage to be visible and realized.
1242            *
1243            * If parent is realized, that does not force us to be
1244            * realized; but if parent is unrealized, that does force
1245            * us to be unrealized.
1246            *
1247            * The reason we don't force children to realize with
1248            * parents is _clutter_actor_rerealize(); if we require that
1249            * a realized parent means children are realized, then to
1250            * unrealize an actor we would have to unrealize its
1251            * parents, which would end up meaning unrealizing and
1252            * hiding the entire stage. So we allow unrealizing a
1253            * child (as long as that child is not mapped) while that
1254            * child still has a realized parent.
1255            *
1256            * Also, if we unrealize from leaf nodes to root, and
1257            * realize from root to leaf, the invariants are never
1258            * violated if we allow children to be unrealized
1259            * while parents are realized.
1260            *
1261            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1262            * to force us to unmap, even though parent is still
1263            * mapped. This is because we're unmapping from leaf nodes
1264            * up to root nodes.
1265            */
1266           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1267               change != MAP_STATE_MAKE_UNMAPPED)
1268             {
1269               gboolean parent_is_visible_realized_toplevel;
1270
1271               parent_is_visible_realized_toplevel =
1272                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1273                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1274                  CLUTTER_ACTOR_IS_REALIZED (parent));
1275
1276               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1277                   parent_is_visible_realized_toplevel)
1278                 {
1279                   must_be_realized = TRUE;
1280                   should_be_mapped = TRUE;
1281                 }
1282             }
1283
1284           /* if the actor has been set to be painted even if unmapped
1285            * then we should map it and check for realization as well;
1286            * this is an override for the branch of the scene graph
1287            * which begins with this node
1288            */
1289           if (priv->enable_paint_unmapped)
1290             {
1291               if (priv->parent == NULL)
1292                 g_warning ("Attempting to map an unparented actor '%s'",
1293                            _clutter_actor_get_debug_name (self));
1294
1295               should_be_mapped = TRUE;
1296               must_be_realized = TRUE;
1297             }
1298
1299           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1300             may_be_realized = FALSE;
1301         }
1302
1303       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1304         {
1305           if (parent == NULL)
1306             g_warning ("Attempting to map a child that does not "
1307                        "meet the necessary invariants: the actor '%s' "
1308                        "has no parent",
1309                        _clutter_actor_get_debug_name (self));
1310           else
1311             g_warning ("Attempting to map a child that does not "
1312                        "meet the necessary invariants: the actor '%s' "
1313                        "is parented to an unmapped actor '%s'",
1314                        _clutter_actor_get_debug_name (self),
1315                        _clutter_actor_get_debug_name (priv->parent));
1316         }
1317
1318       /* If in reparent, we temporarily suspend unmap and unrealize.
1319        *
1320        * We want to go in the order "realize, map" and "unmap, unrealize"
1321        */
1322
1323       /* Unmap */
1324       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1325         clutter_actor_set_mapped (self, FALSE);
1326
1327       /* Realize */
1328       if (must_be_realized)
1329         clutter_actor_realize (self);
1330
1331       /* if we must be realized then we may be, presumably */
1332       g_assert (!(must_be_realized && !may_be_realized));
1333
1334       /* Unrealize */
1335       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1336         clutter_actor_unrealize_not_hiding (self);
1337
1338       /* Map */
1339       if (should_be_mapped)
1340         {
1341           if (!must_be_realized)
1342             g_warning ("Somehow we think actor '%s' should be mapped but "
1343                        "not realized, which isn't allowed",
1344                        _clutter_actor_get_debug_name (self));
1345
1346           /* realization is allowed to fail (though I don't know what
1347            * an app is supposed to do about that - shouldn't it just
1348            * be a g_error? anyway, we have to avoid mapping if this
1349            * happens)
1350            */
1351           if (CLUTTER_ACTOR_IS_REALIZED (self))
1352             clutter_actor_set_mapped (self, TRUE);
1353         }
1354     }
1355
1356 #ifdef CLUTTER_ENABLE_DEBUG
1357   /* check all invariants were kept */
1358   clutter_actor_verify_map_state (self);
1359 #endif
1360 }
1361
1362 static void
1363 clutter_actor_real_map (ClutterActor *self)
1364 {
1365   ClutterActorPrivate *priv = self->priv;
1366   ClutterActor *stage, *iter;
1367
1368   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1369
1370   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1371                 _clutter_actor_get_debug_name (self));
1372
1373   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1374
1375   stage = _clutter_actor_get_stage_internal (self);
1376   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1377
1378   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1379                 priv->pick_id,
1380                 _clutter_actor_get_debug_name (self));
1381
1382   /* notify on parent mapped before potentially mapping
1383    * children, so apps see a top-down notification.
1384    */
1385   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1386
1387   for (iter = self->priv->first_child;
1388        iter != NULL;
1389        iter = iter->priv->next_sibling)
1390     {
1391       clutter_actor_map (iter);
1392     }
1393 }
1394
1395 /**
1396  * clutter_actor_map:
1397  * @self: A #ClutterActor
1398  *
1399  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1400  * and realizes its children if they are visible. Does nothing if the
1401  * actor is not visible.
1402  *
1403  * Calling this function is strongly disencouraged: the default
1404  * implementation of #ClutterActorClass.map() will map all the children
1405  * of an actor when mapping its parent.
1406  *
1407  * When overriding map, it is mandatory to chain up to the parent
1408  * implementation.
1409  *
1410  * Since: 1.0
1411  */
1412 void
1413 clutter_actor_map (ClutterActor *self)
1414 {
1415   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1416
1417   if (CLUTTER_ACTOR_IS_MAPPED (self))
1418     return;
1419
1420   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1421     return;
1422
1423   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1424 }
1425
1426 static void
1427 clutter_actor_real_unmap (ClutterActor *self)
1428 {
1429   ClutterActorPrivate *priv = self->priv;
1430   ClutterActor *iter;
1431
1432   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1433
1434   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1435                 _clutter_actor_get_debug_name (self));
1436
1437   for (iter = self->priv->first_child;
1438        iter != NULL;
1439        iter = iter->priv->next_sibling)
1440     {
1441       clutter_actor_unmap (iter);
1442     }
1443
1444   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1445
1446   /* clear the contents of the last paint volume, so that hiding + moving +
1447    * showing will not result in the wrong area being repainted
1448    */
1449   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1450   priv->last_paint_volume_valid = TRUE;
1451
1452   /* notify on parent mapped after potentially unmapping
1453    * children, so apps see a bottom-up notification.
1454    */
1455   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1456
1457   /* relinquish keyboard focus if we were unmapped while owning it */
1458   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1459     {
1460       ClutterStage *stage;
1461
1462       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1463
1464       if (stage != NULL)
1465         _clutter_stage_release_pick_id (stage, priv->pick_id);
1466
1467       priv->pick_id = -1;
1468
1469       if (stage != NULL &&
1470           clutter_stage_get_key_focus (stage) == self)
1471         {
1472           clutter_stage_set_key_focus (stage, NULL);
1473         }
1474     }
1475 }
1476
1477 /**
1478  * clutter_actor_unmap:
1479  * @self: A #ClutterActor
1480  *
1481  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1482  * unmaps its children if they were mapped.
1483  *
1484  * Calling this function is not encouraged: the default #ClutterActor
1485  * implementation of #ClutterActorClass.unmap() will also unmap any
1486  * eventual children by default when their parent is unmapped.
1487  *
1488  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1489  * chain up to the parent implementation.
1490  *
1491  * <note>It is important to note that the implementation of the
1492  * #ClutterActorClass.unmap() virtual function may be called after
1493  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1494  * implementation, but it is guaranteed to be called before the
1495  * #GObjectClass.finalize() implementation.</note>
1496  *
1497  * Since: 1.0
1498  */
1499 void
1500 clutter_actor_unmap (ClutterActor *self)
1501 {
1502   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1503
1504   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1505     return;
1506
1507   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1508 }
1509
1510 static void
1511 clutter_actor_real_show (ClutterActor *self)
1512 {
1513   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1514     {
1515       ClutterActorPrivate *priv = self->priv;
1516
1517       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1518
1519       /* we notify on the "visible" flag in the clutter_actor_show()
1520        * wrapper so the entire show signal emission completes first
1521        * (?)
1522        */
1523       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1524
1525       /* we queue a relayout unless the actor is inside a
1526        * container that explicitly told us not to
1527        */
1528       if (priv->parent != NULL &&
1529           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1530         {
1531           /* While an actor is hidden the parent may not have
1532            * allocated/requested so we need to start from scratch
1533            * and avoid the short-circuiting in
1534            * clutter_actor_queue_relayout().
1535            */
1536           priv->needs_width_request  = FALSE;
1537           priv->needs_height_request = FALSE;
1538           priv->needs_allocation     = FALSE;
1539           clutter_actor_queue_relayout (self);
1540         }
1541     }
1542 }
1543
1544 static inline void
1545 set_show_on_set_parent (ClutterActor *self,
1546                         gboolean      set_show)
1547 {
1548   ClutterActorPrivate *priv = self->priv;
1549
1550   set_show = !!set_show;
1551
1552   if (priv->show_on_set_parent == set_show)
1553     return;
1554
1555   if (priv->parent == NULL)
1556     {
1557       priv->show_on_set_parent = set_show;
1558       g_object_notify_by_pspec (G_OBJECT (self),
1559                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1560     }
1561 }
1562
1563 /**
1564  * clutter_actor_show:
1565  * @self: A #ClutterActor
1566  *
1567  * Flags an actor to be displayed. An actor that isn't shown will not
1568  * be rendered on the stage.
1569  *
1570  * Actors are visible by default.
1571  *
1572  * If this function is called on an actor without a parent, the
1573  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1574  * effect.
1575  */
1576 void
1577 clutter_actor_show (ClutterActor *self)
1578 {
1579   ClutterActorPrivate *priv;
1580
1581   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1582
1583   /* simple optimization */
1584   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1585     {
1586       /* we still need to set the :show-on-set-parent property, in
1587        * case show() is called on an unparented actor
1588        */
1589       set_show_on_set_parent (self, TRUE);
1590       return;
1591     }
1592
1593 #ifdef CLUTTER_ENABLE_DEBUG
1594   clutter_actor_verify_map_state (self);
1595 #endif
1596
1597   priv = self->priv;
1598
1599   g_object_freeze_notify (G_OBJECT (self));
1600
1601   set_show_on_set_parent (self, TRUE);
1602
1603   g_signal_emit (self, actor_signals[SHOW], 0);
1604   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1605
1606   if (priv->parent != NULL)
1607     clutter_actor_queue_redraw (priv->parent);
1608
1609   g_object_thaw_notify (G_OBJECT (self));
1610 }
1611
1612 /**
1613  * clutter_actor_show_all:
1614  * @self: a #ClutterActor
1615  *
1616  * Calls clutter_actor_show() on all children of an actor (if any).
1617  *
1618  * Since: 0.2
1619  *
1620  * Deprecated: 1.10: Actors are visible by default
1621  */
1622 void
1623 clutter_actor_show_all (ClutterActor *self)
1624 {
1625   ClutterActorClass *klass;
1626
1627   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1628
1629   klass = CLUTTER_ACTOR_GET_CLASS (self);
1630   if (klass->show_all)
1631     klass->show_all (self);
1632 }
1633
1634 static void
1635 clutter_actor_real_hide (ClutterActor *self)
1636 {
1637   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1638     {
1639       ClutterActorPrivate *priv = self->priv;
1640
1641       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1642
1643       /* we notify on the "visible" flag in the clutter_actor_hide()
1644        * wrapper so the entire hide signal emission completes first
1645        * (?)
1646        */
1647       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1648
1649       /* we queue a relayout unless the actor is inside a
1650        * container that explicitly told us not to
1651        */
1652       if (priv->parent != NULL &&
1653           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1654         clutter_actor_queue_relayout (priv->parent);
1655     }
1656 }
1657
1658 /**
1659  * clutter_actor_hide:
1660  * @self: A #ClutterActor
1661  *
1662  * Flags an actor to be hidden. A hidden actor will not be
1663  * rendered on the stage.
1664  *
1665  * Actors are visible by default.
1666  *
1667  * If this function is called on an actor without a parent, the
1668  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1669  * as a side-effect.
1670  */
1671 void
1672 clutter_actor_hide (ClutterActor *self)
1673 {
1674   ClutterActorPrivate *priv;
1675
1676   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1677
1678   /* simple optimization */
1679   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1680     {
1681       /* we still need to set the :show-on-set-parent property, in
1682        * case hide() is called on an unparented actor
1683        */
1684       set_show_on_set_parent (self, FALSE);
1685       return;
1686     }
1687
1688 #ifdef CLUTTER_ENABLE_DEBUG
1689   clutter_actor_verify_map_state (self);
1690 #endif
1691
1692   priv = self->priv;
1693
1694   g_object_freeze_notify (G_OBJECT (self));
1695
1696   set_show_on_set_parent (self, FALSE);
1697
1698   g_signal_emit (self, actor_signals[HIDE], 0);
1699   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1700
1701   if (priv->parent != NULL)
1702     clutter_actor_queue_redraw (priv->parent);
1703
1704   g_object_thaw_notify (G_OBJECT (self));
1705 }
1706
1707 /**
1708  * clutter_actor_hide_all:
1709  * @self: a #ClutterActor
1710  *
1711  * Calls clutter_actor_hide() on all child actors (if any).
1712  *
1713  * Since: 0.2
1714  *
1715  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1716  *   prevent its children from being painted as well.
1717  */
1718 void
1719 clutter_actor_hide_all (ClutterActor *self)
1720 {
1721   ClutterActorClass *klass;
1722
1723   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1724
1725   klass = CLUTTER_ACTOR_GET_CLASS (self);
1726   if (klass->hide_all)
1727     klass->hide_all (self);
1728 }
1729
1730 /**
1731  * clutter_actor_realize:
1732  * @self: A #ClutterActor
1733  *
1734  * Realization informs the actor that it is attached to a stage. It
1735  * can use this to allocate resources if it wanted to delay allocation
1736  * until it would be rendered. However it is perfectly acceptable for
1737  * an actor to create resources before being realized because Clutter
1738  * only ever has a single rendering context so that actor is free to
1739  * be moved from one stage to another.
1740  *
1741  * This function does nothing if the actor is already realized.
1742  *
1743  * Because a realized actor must have realized parent actors, calling
1744  * clutter_actor_realize() will also realize all parents of the actor.
1745  *
1746  * This function does not realize child actors, except in the special
1747  * case that realizing the stage, when the stage is visible, will
1748  * suddenly map (and thus realize) the children of the stage.
1749  **/
1750 void
1751 clutter_actor_realize (ClutterActor *self)
1752 {
1753   ClutterActorPrivate *priv;
1754
1755   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1756
1757   priv = self->priv;
1758
1759 #ifdef CLUTTER_ENABLE_DEBUG
1760   clutter_actor_verify_map_state (self);
1761 #endif
1762
1763   if (CLUTTER_ACTOR_IS_REALIZED (self))
1764     return;
1765
1766   /* To be realized, our parent actors must be realized first.
1767    * This will only succeed if we're inside a toplevel.
1768    */
1769   if (priv->parent != NULL)
1770     clutter_actor_realize (priv->parent);
1771
1772   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1773     {
1774       /* toplevels can be realized at any time */
1775     }
1776   else
1777     {
1778       /* "Fail" the realization if parent is missing or unrealized;
1779        * this should really be a g_warning() not some kind of runtime
1780        * failure; how can an app possibly recover? Instead it's a bug
1781        * in the app and the app should get an explanatory warning so
1782        * someone can fix it. But for now it's too hard to fix this
1783        * because e.g. ClutterTexture needs reworking.
1784        */
1785       if (priv->parent == NULL ||
1786           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1787         return;
1788     }
1789
1790   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1791
1792   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1793   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1794
1795   g_signal_emit (self, actor_signals[REALIZE], 0);
1796
1797   /* Stage actor is allowed to unset the realized flag again in its
1798    * default signal handler, though that is a pathological situation.
1799    */
1800
1801   /* If realization "failed" we'll have to update child state. */
1802   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1803 }
1804
1805 static void
1806 clutter_actor_real_unrealize (ClutterActor *self)
1807 {
1808   /* we must be unmapped (implying our children are also unmapped) */
1809   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1810 }
1811
1812 /**
1813  * clutter_actor_unrealize:
1814  * @self: A #ClutterActor
1815  *
1816  * Unrealization informs the actor that it may be being destroyed or
1817  * moved to another stage. The actor may want to destroy any
1818  * underlying graphics resources at this point. However it is
1819  * perfectly acceptable for it to retain the resources until the actor
1820  * is destroyed because Clutter only ever uses a single rendering
1821  * context and all of the graphics resources are valid on any stage.
1822  *
1823  * Because mapped actors must be realized, actors may not be
1824  * unrealized if they are mapped. This function hides the actor to be
1825  * sure it isn't mapped, an application-visible side effect that you
1826  * may not be expecting.
1827  *
1828  * This function should not be called by application code.
1829  */
1830 void
1831 clutter_actor_unrealize (ClutterActor *self)
1832 {
1833   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1834   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1835
1836 /* This function should not really be in the public API, because
1837  * there isn't a good reason to call it. ClutterActor will already
1838  * unrealize things for you when it's important to do so.
1839  *
1840  * If you were using clutter_actor_unrealize() in a dispose
1841  * implementation, then don't, just chain up to ClutterActor's
1842  * dispose.
1843  *
1844  * If you were using clutter_actor_unrealize() to implement
1845  * unrealizing children of your container, then don't, ClutterActor
1846  * will already take care of that.
1847  *
1848  * If you were using clutter_actor_unrealize() to re-realize to
1849  * create your resources in a different way, then use
1850  * _clutter_actor_rerealize() (inside Clutter) or just call your
1851  * code that recreates your resources directly (outside Clutter).
1852  */
1853
1854 #ifdef CLUTTER_ENABLE_DEBUG
1855   clutter_actor_verify_map_state (self);
1856 #endif
1857
1858   clutter_actor_hide (self);
1859
1860   clutter_actor_unrealize_not_hiding (self);
1861 }
1862
1863 static ClutterActorTraverseVisitFlags
1864 unrealize_actor_before_children_cb (ClutterActor *self,
1865                                     int depth,
1866                                     void *user_data)
1867 {
1868   /* If an actor is already unrealized we know its children have also
1869    * already been unrealized... */
1870   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1871     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1872
1873   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1874
1875   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1876 }
1877
1878 static ClutterActorTraverseVisitFlags
1879 unrealize_actor_after_children_cb (ClutterActor *self,
1880                                    int depth,
1881                                    void *user_data)
1882 {
1883   /* We want to unset the realized flag only _after_
1884    * child actors are unrealized, to maintain invariants.
1885    */
1886   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1887   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1888   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1889 }
1890
1891 /*
1892  * clutter_actor_unrealize_not_hiding:
1893  * @self: A #ClutterActor
1894  *
1895  * Unrealization informs the actor that it may be being destroyed or
1896  * moved to another stage. The actor may want to destroy any
1897  * underlying graphics resources at this point. However it is
1898  * perfectly acceptable for it to retain the resources until the actor
1899  * is destroyed because Clutter only ever uses a single rendering
1900  * context and all of the graphics resources are valid on any stage.
1901  *
1902  * Because mapped actors must be realized, actors may not be
1903  * unrealized if they are mapped. You must hide the actor or one of
1904  * its parents before attempting to unrealize.
1905  *
1906  * This function is separate from clutter_actor_unrealize() because it
1907  * does not automatically hide the actor.
1908  * Actors need not be hidden to be unrealized, they just need to
1909  * be unmapped. In fact we don't want to mess up the application's
1910  * setting of the "visible" flag, so hiding is very undesirable.
1911  *
1912  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1913  * backward compatibility.
1914  */
1915 static void
1916 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1917 {
1918   _clutter_actor_traverse (self,
1919                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1920                            unrealize_actor_before_children_cb,
1921                            unrealize_actor_after_children_cb,
1922                            NULL);
1923 }
1924
1925 /*
1926  * _clutter_actor_rerealize:
1927  * @self: A #ClutterActor
1928  * @callback: Function to call while unrealized
1929  * @data: data for callback
1930  *
1931  * If an actor is already unrealized, this just calls the callback.
1932  *
1933  * If it is realized, it unrealizes temporarily, calls the callback,
1934  * and then re-realizes the actor.
1935  *
1936  * As a side effect, leaves all children of the actor unrealized if
1937  * the actor was realized but not showing.  This is because when we
1938  * unrealize the actor temporarily we must unrealize its children
1939  * (e.g. children of a stage can't be realized if stage window is
1940  * gone). And we aren't clever enough to save the realization state of
1941  * all children. In most cases this should not matter, because
1942  * the children will automatically realize when they next become mapped.
1943  */
1944 void
1945 _clutter_actor_rerealize (ClutterActor    *self,
1946                           ClutterCallback  callback,
1947                           void            *data)
1948 {
1949   gboolean was_mapped;
1950   gboolean was_showing;
1951   gboolean was_realized;
1952
1953   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1954
1955 #ifdef CLUTTER_ENABLE_DEBUG
1956   clutter_actor_verify_map_state (self);
1957 #endif
1958
1959   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1960   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1961   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1962
1963   /* Must be unmapped to unrealize. Note we only have to hide this
1964    * actor if it was mapped (if all parents were showing).  If actor
1965    * is merely visible (but not mapped), then that's fine, we can
1966    * leave it visible.
1967    */
1968   if (was_mapped)
1969     clutter_actor_hide (self);
1970
1971   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1972
1973   /* unrealize self and all children */
1974   clutter_actor_unrealize_not_hiding (self);
1975
1976   if (callback != NULL)
1977     {
1978       (* callback) (self, data);
1979     }
1980
1981   if (was_showing)
1982     clutter_actor_show (self); /* will realize only if mapping implies it */
1983   else if (was_realized)
1984     clutter_actor_realize (self); /* realize self and all parents */
1985 }
1986
1987 static void
1988 clutter_actor_real_pick (ClutterActor       *self,
1989                          const ClutterColor *color)
1990 {
1991   /* the default implementation is just to paint a rectangle
1992    * with the same size of the actor using the passed color
1993    */
1994   if (clutter_actor_should_pick_paint (self))
1995     {
1996       ClutterActorBox box = { 0, };
1997       float width, height;
1998
1999       clutter_actor_get_allocation_box (self, &box);
2000
2001       width = box.x2 - box.x1;
2002       height = box.y2 - box.y1;
2003
2004       cogl_set_source_color4ub (color->red,
2005                                 color->green,
2006                                 color->blue,
2007                                 color->alpha);
2008
2009       cogl_rectangle (0, 0, width, height);
2010     }
2011
2012   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2013    * with existing container classes that override the pick() virtual
2014    * and chain up to the default implementation - otherwise we'll end up
2015    * painting our children twice.
2016    *
2017    * this has to go away for 2.0; hopefully along the pick() itself.
2018    */
2019   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2020     {
2021       ClutterActor *iter;
2022
2023       for (iter = self->priv->first_child;
2024            iter != NULL;
2025            iter = iter->priv->next_sibling)
2026         clutter_actor_paint (iter);
2027     }
2028 }
2029
2030 /**
2031  * clutter_actor_should_pick_paint:
2032  * @self: A #ClutterActor
2033  *
2034  * Should be called inside the implementation of the
2035  * #ClutterActor::pick virtual function in order to check whether
2036  * the actor should paint itself in pick mode or not.
2037  *
2038  * This function should never be called directly by applications.
2039  *
2040  * Return value: %TRUE if the actor should paint its silhouette,
2041  *   %FALSE otherwise
2042  */
2043 gboolean
2044 clutter_actor_should_pick_paint (ClutterActor *self)
2045 {
2046   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2047
2048   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2049       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2050        CLUTTER_ACTOR_IS_REACTIVE (self)))
2051     return TRUE;
2052
2053   return FALSE;
2054 }
2055
2056 static void
2057 clutter_actor_real_get_preferred_width (ClutterActor *self,
2058                                         gfloat        for_height,
2059                                         gfloat       *min_width_p,
2060                                         gfloat       *natural_width_p)
2061 {
2062   ClutterActorPrivate *priv = self->priv;
2063
2064   if (priv->n_children != 0 &&
2065       priv->layout_manager != NULL)
2066     {
2067       ClutterContainer *container = CLUTTER_CONTAINER (self);
2068
2069       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2070                     "for the preferred width",
2071                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2072                     priv->layout_manager);
2073
2074       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2075                                                   container,
2076                                                   for_height,
2077                                                   min_width_p,
2078                                                   natural_width_p);
2079
2080       return;
2081     }
2082
2083   /* Default implementation is always 0x0, usually an actor
2084    * using this default is relying on someone to set the
2085    * request manually
2086    */
2087   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2088
2089   if (min_width_p)
2090     *min_width_p = 0;
2091
2092   if (natural_width_p)
2093     *natural_width_p = 0;
2094 }
2095
2096 static void
2097 clutter_actor_real_get_preferred_height (ClutterActor *self,
2098                                          gfloat        for_width,
2099                                          gfloat       *min_height_p,
2100                                          gfloat       *natural_height_p)
2101 {
2102   ClutterActorPrivate *priv = self->priv;
2103
2104   if (priv->n_children != 0 &&
2105       priv->layout_manager != NULL)
2106     {
2107       ClutterContainer *container = CLUTTER_CONTAINER (self);
2108
2109       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2110                     "for the preferred height",
2111                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2112                     priv->layout_manager);
2113
2114       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2115                                                    container,
2116                                                    for_width,
2117                                                    min_height_p,
2118                                                    natural_height_p);
2119
2120       return;
2121     }
2122   /* Default implementation is always 0x0, usually an actor
2123    * using this default is relying on someone to set the
2124    * request manually
2125    */
2126   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2127
2128   if (min_height_p)
2129     *min_height_p = 0;
2130
2131   if (natural_height_p)
2132     *natural_height_p = 0;
2133 }
2134
2135 static void
2136 clutter_actor_store_old_geometry (ClutterActor    *self,
2137                                   ClutterActorBox *box)
2138 {
2139   *box = self->priv->allocation;
2140 }
2141
2142 static inline void
2143 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2144                                           const ClutterActorBox *old)
2145 {
2146   ClutterActorPrivate *priv = self->priv;
2147   GObject *obj = G_OBJECT (self);
2148
2149   g_object_freeze_notify (obj);
2150
2151   /* to avoid excessive requisition or allocation cycles we
2152    * use the cached values.
2153    *
2154    * - if we don't have an allocation we assume that we need
2155    *   to notify anyway
2156    * - if we don't have a width or a height request we notify
2157    *   width and height
2158    * - if we have a valid allocation then we check the old
2159    *   bounding box with the current allocation and we notify
2160    *   the changes
2161    */
2162   if (priv->needs_allocation)
2163     {
2164       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2165       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2166       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2167       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2168     }
2169   else if (priv->needs_width_request || priv->needs_height_request)
2170     {
2171       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2172       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2173     }
2174   else
2175     {
2176       gfloat x, y;
2177       gfloat width, height;
2178
2179       x = priv->allocation.x1;
2180       y = priv->allocation.y1;
2181       width = priv->allocation.x2 - priv->allocation.x1;
2182       height = priv->allocation.y2 - priv->allocation.y1;
2183
2184       if (x != old->x1)
2185         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2186
2187       if (y != old->y1)
2188         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2189
2190       if (width != (old->x2 - old->x1))
2191         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2192
2193       if (height != (old->y2 - old->y1))
2194         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2195     }
2196
2197   g_object_thaw_notify (obj);
2198 }
2199
2200 /*< private >
2201  * clutter_actor_set_allocation_internal:
2202  * @self: a #ClutterActor
2203  * @box: a #ClutterActorBox
2204  * @flags: allocation flags
2205  *
2206  * Stores the allocation of @self.
2207  *
2208  * This function only performs basic storage and property notification.
2209  *
2210  * This function should be called by clutter_actor_set_allocation()
2211  * and by the default implementation of #ClutterActorClass.allocate().
2212  *
2213  * Return value: %TRUE if the allocation of the #ClutterActor has been
2214  *   changed, and %FALSE otherwise
2215  */
2216 static inline gboolean
2217 clutter_actor_set_allocation_internal (ClutterActor           *self,
2218                                        const ClutterActorBox  *box,
2219                                        ClutterAllocationFlags  flags)
2220 {
2221   ClutterActorPrivate *priv = self->priv;
2222   GObject *obj;
2223   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2224   gboolean flags_changed;
2225   gboolean retval;
2226   ClutterActorBox old_alloc = { 0, };
2227
2228   obj = G_OBJECT (self);
2229
2230   g_object_freeze_notify (obj);
2231
2232   clutter_actor_store_old_geometry (self, &old_alloc);
2233
2234   x1_changed = priv->allocation.x1 != box->x1;
2235   y1_changed = priv->allocation.y1 != box->y1;
2236   x2_changed = priv->allocation.x2 != box->x2;
2237   y2_changed = priv->allocation.y2 != box->y2;
2238
2239   flags_changed = priv->allocation_flags != flags;
2240
2241   priv->allocation = *box;
2242   priv->allocation_flags = flags;
2243
2244   /* allocation is authoritative */
2245   priv->needs_width_request = FALSE;
2246   priv->needs_height_request = FALSE;
2247   priv->needs_allocation = FALSE;
2248
2249   if (x1_changed || y1_changed ||
2250       x2_changed || y2_changed ||
2251       flags_changed)
2252     {
2253       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2254                     _clutter_actor_get_debug_name (self));
2255
2256       priv->transform_valid = FALSE;
2257
2258       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2259
2260       /* if the allocation changes, so does the content box */
2261       if (priv->content != NULL)
2262         g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2263
2264       retval = TRUE;
2265     }
2266   else
2267     retval = FALSE;
2268
2269   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2270
2271   g_object_thaw_notify (obj);
2272
2273   return retval;
2274 }
2275
2276 static void clutter_actor_real_allocate (ClutterActor           *self,
2277                                          const ClutterActorBox  *box,
2278                                          ClutterAllocationFlags  flags);
2279
2280 static inline void
2281 clutter_actor_maybe_layout_children (ClutterActor           *self,
2282                                      const ClutterActorBox  *allocation,
2283                                      ClutterAllocationFlags  flags)
2284 {
2285   ClutterActorPrivate *priv = self->priv;
2286
2287   /* this is going to be a bit hard to follow, so let's put an explanation
2288    * here.
2289    *
2290    * we want ClutterActor to have a default layout manager if the actor was
2291    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2292    *
2293    * we also want any subclass of ClutterActor that does not override the
2294    * ::allocate() virtual function to delegate to a layout manager.
2295    *
2296    * finally, we want to allow people subclassing ClutterActor and overriding
2297    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2298    *
2299    * on the other hand, we want existing actor subclasses overriding the
2300    * ::allocate() virtual function and chaining up to the parent's
2301    * implementation to continue working without allocating their children
2302    * twice, or without entering an allocation loop.
2303    *
2304    * for the first two points, we check if the class of the actor is
2305    * overridding the ::allocate() virtual function; if it isn't, then we
2306    * follow through with checking whether we have children and a layout
2307    * manager, and eventually calling clutter_layout_manager_allocate().
2308    *
2309    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2310    * allocation flags that we got passed, and if it is present, we continue
2311    * with the check above.
2312    *
2313    * if neither of these two checks yields a positive result, we just
2314    * assume that the ::allocate() virtual function that resulted in this
2315    * function being called will also allocate the children of the actor.
2316    */
2317
2318   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2319     goto check_layout;
2320
2321   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2322     goto check_layout;
2323
2324   return;
2325
2326 check_layout:
2327   if (priv->n_children != 0 &&
2328       priv->layout_manager != NULL)
2329     {
2330       ClutterContainer *container = CLUTTER_CONTAINER (self);
2331       ClutterAllocationFlags children_flags;
2332       ClutterActorBox children_box;
2333
2334       /* normalize the box passed to the layout manager */
2335       children_box.x1 = children_box.y1 = 0.f;
2336       children_box.x2 = (allocation->x2 - allocation->x1);
2337       children_box.y2 = (allocation->y2 - allocation->y1);
2338
2339       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2340        * the actor's children, since it refers only to the current
2341        * actor's allocation.
2342        */
2343       children_flags = flags;
2344       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2345
2346       CLUTTER_NOTE (LAYOUT,
2347                     "Allocating %d children of %s "
2348                     "at { %.2f, %.2f - %.2f x %.2f } "
2349                     "using %s",
2350                     priv->n_children,
2351                     _clutter_actor_get_debug_name (self),
2352                     allocation->x1,
2353                     allocation->y1,
2354                     (allocation->x2 - allocation->x1),
2355                     (allocation->y2 - allocation->y1),
2356                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2357
2358       clutter_layout_manager_allocate (priv->layout_manager,
2359                                        container,
2360                                        &children_box,
2361                                        children_flags);
2362     }
2363 }
2364
2365 static void
2366 clutter_actor_real_allocate (ClutterActor           *self,
2367                              const ClutterActorBox  *box,
2368                              ClutterAllocationFlags  flags)
2369 {
2370   ClutterActorPrivate *priv = self->priv;
2371   gboolean changed;
2372
2373   g_object_freeze_notify (G_OBJECT (self));
2374
2375   changed = clutter_actor_set_allocation_internal (self, box, flags);
2376
2377   /* we allocate our children before we notify changes in our geometry,
2378    * so that people connecting to properties will be able to get valid
2379    * data out of the sub-tree of the scene graph that has this actor at
2380    * the root.
2381    */
2382   clutter_actor_maybe_layout_children (self, box, flags);
2383
2384   if (changed)
2385     {
2386       ClutterActorBox signal_box = priv->allocation;
2387       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2388
2389       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2390                      &signal_box,
2391                      signal_flags);
2392     }
2393
2394   g_object_thaw_notify (G_OBJECT (self));
2395 }
2396
2397 static void
2398 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2399                                     ClutterActor *origin)
2400 {
2401   /* no point in queuing a redraw on a destroyed actor */
2402   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2403     return;
2404
2405   /* NB: We can't bail out early here if the actor is hidden in case
2406    * the actor bas been cloned. In this case the clone will need to
2407    * receive the signal so it can queue its own redraw.
2408    */
2409
2410   /* calls klass->queue_redraw in default handler */
2411   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2412 }
2413
2414 static void
2415 clutter_actor_real_queue_redraw (ClutterActor *self,
2416                                  ClutterActor *origin)
2417 {
2418   ClutterActor *parent;
2419
2420   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2421                 _clutter_actor_get_debug_name (self),
2422                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2423                                : "same actor");
2424
2425   /* no point in queuing a redraw on a destroyed actor */
2426   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2427     return;
2428
2429   /* If the queue redraw is coming from a child then the actor has
2430      become dirty and any queued effect is no longer valid */
2431   if (self != origin)
2432     {
2433       self->priv->is_dirty = TRUE;
2434       self->priv->effect_to_redraw = NULL;
2435     }
2436
2437   /* If the actor isn't visible, we still had to emit the signal
2438    * to allow for a ClutterClone, but the appearance of the parent
2439    * won't change so we don't have to propagate up the hierarchy.
2440    */
2441   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2442     return;
2443
2444   /* Although we could determine here that a full stage redraw
2445    * has already been queued and immediately bail out, we actually
2446    * guarantee that we will propagate a queue-redraw signal to our
2447    * parent at least once so that it's possible to implement a
2448    * container that tracks which of its children have queued a
2449    * redraw.
2450    */
2451   if (self->priv->propagated_one_redraw)
2452     {
2453       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2454       if (stage != NULL &&
2455           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2456         return;
2457     }
2458
2459   self->priv->propagated_one_redraw = TRUE;
2460
2461   /* notify parents, if they are all visible eventually we'll
2462    * queue redraw on the stage, which queues the redraw idle.
2463    */
2464   parent = clutter_actor_get_parent (self);
2465   if (parent != NULL)
2466     {
2467       /* this will go up recursively */
2468       _clutter_actor_signal_queue_redraw (parent, origin);
2469     }
2470 }
2471
2472 static void
2473 clutter_actor_real_queue_relayout (ClutterActor *self)
2474 {
2475   ClutterActorPrivate *priv = self->priv;
2476
2477   /* no point in queueing a redraw on a destroyed actor */
2478   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2479     return;
2480
2481   priv->needs_width_request  = TRUE;
2482   priv->needs_height_request = TRUE;
2483   priv->needs_allocation     = TRUE;
2484
2485   /* reset the cached size requests */
2486   memset (priv->width_requests, 0,
2487           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2488   memset (priv->height_requests, 0,
2489           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2490
2491   /* We need to go all the way up the hierarchy */
2492   if (priv->parent != NULL)
2493     _clutter_actor_queue_only_relayout (priv->parent);
2494 }
2495
2496 /**
2497  * clutter_actor_apply_relative_transform_to_point:
2498  * @self: A #ClutterActor
2499  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2500  *   default #ClutterStage
2501  * @point: A point as #ClutterVertex
2502  * @vertex: (out caller-allocates): The translated #ClutterVertex
2503  *
2504  * Transforms @point in coordinates relative to the actor into
2505  * ancestor-relative coordinates using the relevant transform
2506  * stack (i.e. scale, rotation, etc).
2507  *
2508  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2509  * this case, the coordinates returned will be the coordinates on
2510  * the stage before the projection is applied. This is different from
2511  * the behaviour of clutter_actor_apply_transform_to_point().
2512  *
2513  * Since: 0.6
2514  */
2515 void
2516 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2517                                                  ClutterActor        *ancestor,
2518                                                  const ClutterVertex *point,
2519                                                  ClutterVertex       *vertex)
2520 {
2521   gfloat w;
2522   CoglMatrix matrix;
2523
2524   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2525   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2526   g_return_if_fail (point != NULL);
2527   g_return_if_fail (vertex != NULL);
2528
2529   *vertex = *point;
2530   w = 1.0;
2531
2532   if (ancestor == NULL)
2533     ancestor = _clutter_actor_get_stage_internal (self);
2534
2535   if (ancestor == NULL)
2536     {
2537       *vertex = *point;
2538       return;
2539     }
2540
2541   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2542   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2543 }
2544
2545 static gboolean
2546 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2547                                          const ClutterVertex *vertices_in,
2548                                          ClutterVertex *vertices_out,
2549                                          int n_vertices)
2550 {
2551   ClutterActor *stage;
2552   CoglMatrix modelview;
2553   CoglMatrix projection;
2554   float viewport[4];
2555
2556   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2557
2558   stage = _clutter_actor_get_stage_internal (self);
2559
2560   /* We really can't do anything meaningful in this case so don't try
2561    * to do any transform */
2562   if (stage == NULL)
2563     return FALSE;
2564
2565   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2566    * that gets us to stage coordinates, we want to go all the way to eye
2567    * coordinates */
2568   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2569
2570   /* Fetch the projection and viewport */
2571   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2572   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2573                                &viewport[0],
2574                                &viewport[1],
2575                                &viewport[2],
2576                                &viewport[3]);
2577
2578   _clutter_util_fully_transform_vertices (&modelview,
2579                                           &projection,
2580                                           viewport,
2581                                           vertices_in,
2582                                           vertices_out,
2583                                           n_vertices);
2584
2585   return TRUE;
2586 }
2587
2588 /**
2589  * clutter_actor_apply_transform_to_point:
2590  * @self: A #ClutterActor
2591  * @point: A point as #ClutterVertex
2592  * @vertex: (out caller-allocates): The translated #ClutterVertex
2593  *
2594  * Transforms @point in coordinates relative to the actor
2595  * into screen-relative coordinates with the current actor
2596  * transformation (i.e. scale, rotation, etc)
2597  *
2598  * Since: 0.4
2599  **/
2600 void
2601 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2602                                         const ClutterVertex *point,
2603                                         ClutterVertex       *vertex)
2604 {
2605   g_return_if_fail (point != NULL);
2606   g_return_if_fail (vertex != NULL);
2607   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2608 }
2609
2610 /*
2611  * _clutter_actor_get_relative_transformation_matrix:
2612  * @self: The actor whose coordinate space you want to transform from.
2613  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2614  *            or %NULL if you want to transform all the way to eye coordinates.
2615  * @matrix: A #CoglMatrix to store the transformation
2616  *
2617  * This gets a transformation @matrix that will transform coordinates from the
2618  * coordinate space of @self into the coordinate space of @ancestor.
2619  *
2620  * For example if you need a matrix that can transform the local actor
2621  * coordinates of @self into stage coordinates you would pass the actor's stage
2622  * pointer as the @ancestor.
2623  *
2624  * If you pass %NULL then the transformation will take you all the way through
2625  * to eye coordinates. This can be useful if you want to extract the entire
2626  * modelview transform that Clutter applies before applying the projection
2627  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2628  * using cogl_set_modelview_matrix() for example then you would want a matrix
2629  * that transforms into eye coordinates.
2630  *
2631  * <note><para>This function explicitly initializes the given @matrix. If you just
2632  * want clutter to multiply a relative transformation with an existing matrix
2633  * you can use clutter_actor_apply_relative_transformation_matrix()
2634  * instead.</para></note>
2635  *
2636  */
2637 /* XXX: We should consider caching the stage relative modelview along with
2638  * the actor itself */
2639 static void
2640 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2641                                                    ClutterActor *ancestor,
2642                                                    CoglMatrix *matrix)
2643 {
2644   cogl_matrix_init_identity (matrix);
2645
2646   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2647 }
2648
2649 /* Project the given @box into stage window coordinates, writing the
2650  * transformed vertices to @verts[]. */
2651 static gboolean
2652 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2653                                           const ClutterActorBox *box,
2654                                           ClutterVertex          verts[])
2655 {
2656   ClutterVertex box_vertices[4];
2657
2658   box_vertices[0].x = box->x1;
2659   box_vertices[0].y = box->y1;
2660   box_vertices[0].z = 0;
2661   box_vertices[1].x = box->x2;
2662   box_vertices[1].y = box->y1;
2663   box_vertices[1].z = 0;
2664   box_vertices[2].x = box->x1;
2665   box_vertices[2].y = box->y2;
2666   box_vertices[2].z = 0;
2667   box_vertices[3].x = box->x2;
2668   box_vertices[3].y = box->y2;
2669   box_vertices[3].z = 0;
2670
2671   return
2672     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2673 }
2674
2675 /**
2676  * clutter_actor_get_allocation_vertices:
2677  * @self: A #ClutterActor
2678  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2679  *   against, or %NULL to use the #ClutterStage
2680  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2681  *   location for an array of 4 #ClutterVertex in which to store the result
2682  *
2683  * Calculates the transformed coordinates of the four corners of the
2684  * actor in the plane of @ancestor. The returned vertices relate to
2685  * the #ClutterActorBox coordinates as follows:
2686  * <itemizedlist>
2687  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2688  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2689  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2690  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2691  * </itemizedlist>
2692  *
2693  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2694  * this case, the coordinates returned will be the coordinates on
2695  * the stage before the projection is applied. This is different from
2696  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2697  *
2698  * Since: 0.6
2699  */
2700 void
2701 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2702                                        ClutterActor  *ancestor,
2703                                        ClutterVertex  verts[])
2704 {
2705   ClutterActorPrivate *priv;
2706   ClutterActorBox box;
2707   ClutterVertex vertices[4];
2708   CoglMatrix modelview;
2709
2710   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2711   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2712
2713   if (ancestor == NULL)
2714     ancestor = _clutter_actor_get_stage_internal (self);
2715
2716   /* Fallback to a NOP transform if the actor isn't parented under a
2717    * stage. */
2718   if (ancestor == NULL)
2719     ancestor = self;
2720
2721   priv = self->priv;
2722
2723   /* if the actor needs to be allocated we force a relayout, so that
2724    * we will have valid values to use in the transformations */
2725   if (priv->needs_allocation)
2726     {
2727       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2728       if (stage)
2729         _clutter_stage_maybe_relayout (stage);
2730       else
2731         {
2732           box.x1 = box.y1 = 0;
2733           /* The result isn't really meaningful in this case but at
2734            * least try to do something *vaguely* reasonable... */
2735           clutter_actor_get_size (self, &box.x2, &box.y2);
2736         }
2737     }
2738
2739   clutter_actor_get_allocation_box (self, &box);
2740
2741   vertices[0].x = box.x1;
2742   vertices[0].y = box.y1;
2743   vertices[0].z = 0;
2744   vertices[1].x = box.x2;
2745   vertices[1].y = box.y1;
2746   vertices[1].z = 0;
2747   vertices[2].x = box.x1;
2748   vertices[2].y = box.y2;
2749   vertices[2].z = 0;
2750   vertices[3].x = box.x2;
2751   vertices[3].y = box.y2;
2752   vertices[3].z = 0;
2753
2754   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2755                                                      &modelview);
2756
2757   cogl_matrix_transform_points (&modelview,
2758                                 3,
2759                                 sizeof (ClutterVertex),
2760                                 vertices,
2761                                 sizeof (ClutterVertex),
2762                                 vertices,
2763                                 4);
2764 }
2765
2766 /**
2767  * clutter_actor_get_abs_allocation_vertices:
2768  * @self: A #ClutterActor
2769  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2770  *   of 4 #ClutterVertex where to store the result.
2771  *
2772  * Calculates the transformed screen coordinates of the four corners of
2773  * the actor; the returned vertices relate to the #ClutterActorBox
2774  * coordinates  as follows:
2775  * <itemizedlist>
2776  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2777  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2778  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2779  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2780  * </itemizedlist>
2781  *
2782  * Since: 0.4
2783  */
2784 void
2785 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2786                                            ClutterVertex  verts[])
2787 {
2788   ClutterActorPrivate *priv;
2789   ClutterActorBox actor_space_allocation;
2790
2791   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2792
2793   priv = self->priv;
2794
2795   /* if the actor needs to be allocated we force a relayout, so that
2796    * the actor allocation box will be valid for
2797    * _clutter_actor_transform_and_project_box()
2798    */
2799   if (priv->needs_allocation)
2800     {
2801       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2802       /* There's nothing meaningful we can do now */
2803       if (!stage)
2804         return;
2805
2806       _clutter_stage_maybe_relayout (stage);
2807     }
2808
2809   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2810    * own coordinate space... */
2811   actor_space_allocation.x1 = 0;
2812   actor_space_allocation.y1 = 0;
2813   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2814   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2815   _clutter_actor_transform_and_project_box (self,
2816                                             &actor_space_allocation,
2817                                             verts);
2818 }
2819
2820 static void
2821 clutter_actor_real_apply_transform (ClutterActor *self,
2822                                     CoglMatrix   *matrix)
2823 {
2824   ClutterActorPrivate *priv = self->priv;
2825
2826   if (!priv->transform_valid)
2827     {
2828       CoglMatrix *transform = &priv->transform;
2829       const ClutterTransformInfo *info;
2830
2831       info = _clutter_actor_get_transform_info_or_defaults (self);
2832
2833       cogl_matrix_init_identity (transform);
2834
2835       cogl_matrix_translate (transform,
2836                              priv->allocation.x1,
2837                              priv->allocation.y1,
2838                              0.0);
2839
2840       if (info->depth)
2841         cogl_matrix_translate (transform, 0, 0, info->depth);
2842
2843       /*
2844        * because the rotation involves translations, we must scale
2845        * before applying the rotations (if we apply the scale after
2846        * the rotations, the translations included in the rotation are
2847        * not scaled and so the entire object will move on the screen
2848        * as a result of rotating it).
2849        */
2850       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2851         {
2852           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2853                                         &info->scale_center,
2854                                         cogl_matrix_scale (transform,
2855                                                            info->scale_x,
2856                                                            info->scale_y,
2857                                                            1.0));
2858         }
2859
2860       if (info->rz_angle)
2861         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2862                                       &info->rz_center,
2863                                       cogl_matrix_rotate (transform,
2864                                                           info->rz_angle,
2865                                                           0, 0, 1.0));
2866
2867       if (info->ry_angle)
2868         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2869                                       &info->ry_center,
2870                                       cogl_matrix_rotate (transform,
2871                                                           info->ry_angle,
2872                                                           0, 1.0, 0));
2873
2874       if (info->rx_angle)
2875         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2876                                       &info->rx_center,
2877                                       cogl_matrix_rotate (transform,
2878                                                           info->rx_angle,
2879                                                           1.0, 0, 0));
2880
2881       if (!clutter_anchor_coord_is_zero (&info->anchor))
2882         {
2883           gfloat x, y, z;
2884
2885           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2886           cogl_matrix_translate (transform, -x, -y, -z);
2887         }
2888
2889       priv->transform_valid = TRUE;
2890     }
2891
2892   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2893 }
2894
2895 /* Applies the transforms associated with this actor to the given
2896  * matrix. */
2897 void
2898 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2899                                           CoglMatrix *matrix)
2900 {
2901   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2902 }
2903
2904 /*
2905  * clutter_actor_apply_relative_transformation_matrix:
2906  * @self: The actor whose coordinate space you want to transform from.
2907  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2908  *            or %NULL if you want to transform all the way to eye coordinates.
2909  * @matrix: A #CoglMatrix to apply the transformation too.
2910  *
2911  * This multiplies a transform with @matrix that will transform coordinates
2912  * from the coordinate space of @self into the coordinate space of @ancestor.
2913  *
2914  * For example if you need a matrix that can transform the local actor
2915  * coordinates of @self into stage coordinates you would pass the actor's stage
2916  * pointer as the @ancestor.
2917  *
2918  * If you pass %NULL then the transformation will take you all the way through
2919  * to eye coordinates. This can be useful if you want to extract the entire
2920  * modelview transform that Clutter applies before applying the projection
2921  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2922  * using cogl_set_modelview_matrix() for example then you would want a matrix
2923  * that transforms into eye coordinates.
2924  *
2925  * <note>This function doesn't initialize the given @matrix, it simply
2926  * multiplies the requested transformation matrix with the existing contents of
2927  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2928  * before calling this function, or you can use
2929  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2930  */
2931 void
2932 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2933                                                      ClutterActor *ancestor,
2934                                                      CoglMatrix *matrix)
2935 {
2936   ClutterActor *parent;
2937
2938   /* Note we terminate before ever calling stage->apply_transform()
2939    * since that would conceptually be relative to the underlying
2940    * window OpenGL coordinates so we'd need a special @ancestor
2941    * value to represent the fake parent of the stage. */
2942   if (self == ancestor)
2943     return;
2944
2945   parent = clutter_actor_get_parent (self);
2946
2947   if (parent != NULL)
2948     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2949                                                          matrix);
2950
2951   _clutter_actor_apply_modelview_transform (self, matrix);
2952 }
2953
2954 static void
2955 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2956                                        ClutterPaintVolume *pv,
2957                                        const char *label,
2958                                        const CoglColor *color)
2959 {
2960   static CoglPipeline *outline = NULL;
2961   CoglPrimitive *prim;
2962   ClutterVertex line_ends[12 * 2];
2963   int n_vertices;
2964   CoglContext *ctx =
2965     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2966   /* XXX: at some point we'll query this from the stage but we can't
2967    * do that until the osx backend uses Cogl natively. */
2968   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2969
2970   if (outline == NULL)
2971     outline = cogl_pipeline_new (ctx);
2972
2973   _clutter_paint_volume_complete (pv);
2974
2975   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2976
2977   /* Front face */
2978   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2979   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2980   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2981   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2982
2983   if (!pv->is_2d)
2984     {
2985       /* Back face */
2986       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2987       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2988       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2989       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2990
2991       /* Lines connecting front face to back face */
2992       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2993       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2994       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2995       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2996     }
2997
2998   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2999                                 n_vertices,
3000                                 (CoglVertexP3 *)line_ends);
3001
3002   cogl_pipeline_set_color (outline, color);
3003   cogl_framebuffer_draw_primitive (fb, outline, prim);
3004   cogl_object_unref (prim);
3005
3006   if (label)
3007     {
3008       PangoLayout *layout;
3009       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3010       pango_layout_set_text (layout, label, -1);
3011       cogl_pango_render_layout (layout,
3012                                 pv->vertices[0].x,
3013                                 pv->vertices[0].y,
3014                                 color,
3015                                 0);
3016       g_object_unref (layout);
3017     }
3018 }
3019
3020 static void
3021 _clutter_actor_draw_paint_volume (ClutterActor *self)
3022 {
3023   ClutterPaintVolume *pv;
3024   CoglColor color;
3025
3026   pv = _clutter_actor_get_paint_volume_mutable (self);
3027   if (!pv)
3028     {
3029       gfloat width, height;
3030       ClutterPaintVolume fake_pv;
3031
3032       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3033       _clutter_paint_volume_init_static (&fake_pv, stage);
3034
3035       clutter_actor_get_size (self, &width, &height);
3036       clutter_paint_volume_set_width (&fake_pv, width);
3037       clutter_paint_volume_set_height (&fake_pv, height);
3038
3039       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3040       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3041                                              _clutter_actor_get_debug_name (self),
3042                                              &color);
3043
3044       clutter_paint_volume_free (&fake_pv);
3045     }
3046   else
3047     {
3048       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3049       _clutter_actor_draw_paint_volume_full (self, pv,
3050                                              _clutter_actor_get_debug_name (self),
3051                                              &color);
3052     }
3053 }
3054
3055 static void
3056 _clutter_actor_paint_cull_result (ClutterActor *self,
3057                                   gboolean success,
3058                                   ClutterCullResult result)
3059 {
3060   ClutterPaintVolume *pv;
3061   CoglColor color;
3062
3063   if (success)
3064     {
3065       if (result == CLUTTER_CULL_RESULT_IN)
3066         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3067       else if (result == CLUTTER_CULL_RESULT_OUT)
3068         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3069       else
3070         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3071     }
3072   else
3073     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3074
3075   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3076     _clutter_actor_draw_paint_volume_full (self, pv,
3077                                            _clutter_actor_get_debug_name (self),
3078                                            &color);
3079   else
3080     {
3081       PangoLayout *layout;
3082       char *label =
3083         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3084       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3085       cogl_set_source_color (&color);
3086
3087       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3088       pango_layout_set_text (layout, label, -1);
3089       cogl_pango_render_layout (layout,
3090                                 0,
3091                                 0,
3092                                 &color,
3093                                 0);
3094       g_free (label);
3095       g_object_unref (layout);
3096     }
3097 }
3098
3099 static int clone_paint_level = 0;
3100
3101 void
3102 _clutter_actor_push_clone_paint (void)
3103 {
3104   clone_paint_level++;
3105 }
3106
3107 void
3108 _clutter_actor_pop_clone_paint (void)
3109 {
3110   clone_paint_level--;
3111 }
3112
3113 static gboolean
3114 in_clone_paint (void)
3115 {
3116   return clone_paint_level > 0;
3117 }
3118
3119 /* Returns TRUE if the actor can be ignored */
3120 /* FIXME: we should return a ClutterCullResult, and
3121  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3122  * means there's no point in trying to cull descendants of the current
3123  * node. */
3124 static gboolean
3125 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3126 {
3127   ClutterActorPrivate *priv = self->priv;
3128   ClutterActor *stage;
3129   const ClutterPlane *stage_clip;
3130
3131   if (!priv->last_paint_volume_valid)
3132     {
3133       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3134                     "->last_paint_volume_valid == FALSE",
3135                     _clutter_actor_get_debug_name (self));
3136       return FALSE;
3137     }
3138
3139   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3140     return FALSE;
3141
3142   stage = _clutter_actor_get_stage_internal (self);
3143   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3144   if (G_UNLIKELY (!stage_clip))
3145     {
3146       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3147                     "No stage clip set",
3148                     _clutter_actor_get_debug_name (self));
3149       return FALSE;
3150     }
3151
3152   if (cogl_get_draw_framebuffer () !=
3153       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3154     {
3155       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3156                     "Current framebuffer doesn't correspond to stage",
3157                     _clutter_actor_get_debug_name (self));
3158       return FALSE;
3159     }
3160
3161   *result_out =
3162     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3163   return TRUE;
3164 }
3165
3166 static void
3167 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3168 {
3169   ClutterActorPrivate *priv = self->priv;
3170   const ClutterPaintVolume *pv;
3171
3172   if (priv->last_paint_volume_valid)
3173     {
3174       clutter_paint_volume_free (&priv->last_paint_volume);
3175       priv->last_paint_volume_valid = FALSE;
3176     }
3177
3178   pv = clutter_actor_get_paint_volume (self);
3179   if (!pv)
3180     {
3181       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3182                     "Actor failed to report a paint volume",
3183                     _clutter_actor_get_debug_name (self));
3184       return;
3185     }
3186
3187   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3188
3189   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3190                                             NULL); /* eye coordinates */
3191
3192   priv->last_paint_volume_valid = TRUE;
3193 }
3194
3195 static inline gboolean
3196 actor_has_shader_data (ClutterActor *self)
3197 {
3198   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3199 }
3200
3201 guint32
3202 _clutter_actor_get_pick_id (ClutterActor *self)
3203 {
3204   if (self->priv->pick_id < 0)
3205     return 0;
3206
3207   return self->priv->pick_id;
3208 }
3209
3210 /* This is the same as clutter_actor_add_effect except that it doesn't
3211    queue a redraw and it doesn't notify on the effect property */
3212 static void
3213 _clutter_actor_add_effect_internal (ClutterActor  *self,
3214                                     ClutterEffect *effect)
3215 {
3216   ClutterActorPrivate *priv = self->priv;
3217
3218   if (priv->effects == NULL)
3219     {
3220       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3221       priv->effects->actor = self;
3222     }
3223
3224   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3225 }
3226
3227 /* This is the same as clutter_actor_remove_effect except that it doesn't
3228    queue a redraw and it doesn't notify on the effect property */
3229 static void
3230 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3231                                        ClutterEffect *effect)
3232 {
3233   ClutterActorPrivate *priv = self->priv;
3234
3235   if (priv->effects == NULL)
3236     return;
3237
3238   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3239 }
3240
3241 static gboolean
3242 needs_flatten_effect (ClutterActor *self)
3243 {
3244   ClutterActorPrivate *priv = self->priv;
3245
3246   if (G_UNLIKELY (clutter_paint_debug_flags &
3247                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3248     return FALSE;
3249
3250   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3251     return TRUE;
3252   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3253     {
3254       if (clutter_actor_get_paint_opacity (self) < 255 &&
3255           clutter_actor_has_overlaps (self))
3256         return TRUE;
3257     }
3258
3259   return FALSE;
3260 }
3261
3262 static void
3263 add_or_remove_flatten_effect (ClutterActor *self)
3264 {
3265   ClutterActorPrivate *priv = self->priv;
3266
3267   /* Add or remove the flatten effect depending on the
3268      offscreen-redirect property. */
3269   if (needs_flatten_effect (self))
3270     {
3271       if (priv->flatten_effect == NULL)
3272         {
3273           ClutterActorMeta *actor_meta;
3274           gint priority;
3275
3276           priv->flatten_effect = _clutter_flatten_effect_new ();
3277           /* Keep a reference to the effect so that we can queue
3278              redraws from it */
3279           g_object_ref_sink (priv->flatten_effect);
3280
3281           /* Set the priority of the effect to high so that it will
3282              always be applied to the actor first. It uses an internal
3283              priority so that it won't be visible to applications */
3284           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3285           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3286           _clutter_actor_meta_set_priority (actor_meta, priority);
3287
3288           /* This will add the effect without queueing a redraw */
3289           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3290         }
3291     }
3292   else
3293     {
3294       if (priv->flatten_effect != NULL)
3295         {
3296           /* Destroy the effect so that it will lose its fbo cache of
3297              the actor */
3298           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3299           g_clear_object (&priv->flatten_effect);
3300         }
3301     }
3302 }
3303
3304 static void
3305 clutter_actor_real_paint (ClutterActor *actor)
3306 {
3307   ClutterActorPrivate *priv = actor->priv;
3308   ClutterActor *iter;
3309
3310   for (iter = priv->first_child;
3311        iter != NULL;
3312        iter = iter->priv->next_sibling)
3313     {
3314       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3315                     _clutter_actor_get_debug_name (iter),
3316                     _clutter_actor_get_debug_name (actor),
3317                     iter->priv->allocation.x1,
3318                     iter->priv->allocation.y1,
3319                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3320                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3321
3322       clutter_actor_paint (iter);
3323     }
3324 }
3325
3326 static gboolean
3327 clutter_actor_paint_node (ClutterActor     *actor,
3328                           ClutterPaintNode *root)
3329 {
3330   ClutterActorPrivate *priv = actor->priv;
3331
3332   if (root == NULL)
3333     return FALSE;
3334
3335   if (priv->bg_color_set &&
3336       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3337     {
3338       ClutterPaintNode *node;
3339       ClutterColor bg_color;
3340       ClutterActorBox box;
3341
3342       box.x1 = 0.f;
3343       box.y1 = 0.f;
3344       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3345       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3346
3347       bg_color = priv->bg_color;
3348       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3349                      * priv->bg_color.alpha
3350                      / 255;
3351
3352       node = clutter_color_node_new (&bg_color);
3353       clutter_paint_node_set_name (node, "backgroundColor");
3354       clutter_paint_node_add_rectangle (node, &box);
3355       clutter_paint_node_add_child (root, node);
3356       clutter_paint_node_unref (node);
3357     }
3358
3359   if (priv->content != NULL)
3360     _clutter_content_paint_content (priv->content, actor, root);
3361
3362   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3363     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3364
3365   if (clutter_paint_node_get_n_children (root) == 0)
3366     return FALSE;
3367
3368 #ifdef CLUTTER_ENABLE_DEBUG
3369   if (CLUTTER_HAS_DEBUG (PAINT))
3370     {
3371       /* dump the tree only if we have one */
3372       _clutter_paint_node_dump_tree (root);
3373     }
3374 #endif /* CLUTTER_ENABLE_DEBUG */
3375
3376   _clutter_paint_node_paint (root);
3377
3378 #if 0
3379   /* XXX: Uncomment this when we disable emitting the paint signal */
3380   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3381 #endif
3382
3383   return TRUE;
3384 }
3385
3386 /**
3387  * clutter_actor_paint:
3388  * @self: A #ClutterActor
3389  *
3390  * Renders the actor to display.
3391  *
3392  * This function should not be called directly by applications.
3393  * Call clutter_actor_queue_redraw() to queue paints, instead.
3394  *
3395  * This function is context-aware, and will either cause a
3396  * regular paint or a pick paint.
3397  *
3398  * This function will emit the #ClutterActor::paint signal or
3399  * the #ClutterActor::pick signal, depending on the context.
3400  *
3401  * This function does not paint the actor if the actor is set to 0,
3402  * unless it is performing a pick paint.
3403  */
3404 void
3405 clutter_actor_paint (ClutterActor *self)
3406 {
3407   ClutterActorPrivate *priv;
3408   ClutterPickMode pick_mode;
3409   gboolean clip_set = FALSE;
3410   gboolean shader_applied = FALSE;
3411
3412   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3413                           "Actor real-paint counter",
3414                           "Increments each time any actor is painted",
3415                           0 /* no application private data */);
3416   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3417                           "Actor pick-paint counter",
3418                           "Increments each time any actor is painted "
3419                           "for picking",
3420                           0 /* no application private data */);
3421
3422   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3423
3424   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3425     return;
3426
3427   priv = self->priv;
3428
3429   pick_mode = _clutter_context_get_pick_mode ();
3430
3431   if (pick_mode == CLUTTER_PICK_NONE)
3432     priv->propagated_one_redraw = FALSE;
3433
3434   /* It's an important optimization that we consider painting of
3435    * actors with 0 opacity to be a NOP... */
3436   if (pick_mode == CLUTTER_PICK_NONE &&
3437       /* ignore top-levels, since they might be transparent */
3438       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3439       /* Use the override opacity if its been set */
3440       ((priv->opacity_override >= 0) ?
3441        priv->opacity_override : priv->opacity) == 0)
3442     return;
3443
3444   /* if we aren't paintable (not in a toplevel with all
3445    * parents paintable) then do nothing.
3446    */
3447   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3448     return;
3449
3450   /* mark that we are in the paint process */
3451   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3452
3453   cogl_push_matrix();
3454
3455   if (priv->enable_model_view_transform)
3456     {
3457       CoglMatrix matrix;
3458
3459       /* XXX: It could be better to cache the modelview with the actor
3460        * instead of progressively building up the transformations on
3461        * the matrix stack every time we paint. */
3462       cogl_get_modelview_matrix (&matrix);
3463       _clutter_actor_apply_modelview_transform (self, &matrix);
3464
3465 #ifdef CLUTTER_ENABLE_DEBUG
3466       /* Catch when out-of-band transforms have been made by actors not as part
3467        * of an apply_transform vfunc... */
3468       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3469         {
3470           CoglMatrix expected_matrix;
3471
3472           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3473                                                              &expected_matrix);
3474
3475           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3476             {
3477               GString *buf = g_string_sized_new (1024);
3478               ClutterActor *parent;
3479
3480               parent = self;
3481               while (parent != NULL)
3482                 {
3483                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3484
3485                   if (parent->priv->parent != NULL)
3486                     g_string_append (buf, "->");
3487
3488                   parent = parent->priv->parent;
3489                 }
3490
3491               g_warning ("Unexpected transform found when painting actor "
3492                          "\"%s\". This will be caused by one of the actor's "
3493                          "ancestors (%s) using the Cogl API directly to transform "
3494                          "children instead of using ::apply_transform().",
3495                          _clutter_actor_get_debug_name (self),
3496                          buf->str);
3497
3498               g_string_free (buf, TRUE);
3499             }
3500         }
3501 #endif /* CLUTTER_ENABLE_DEBUG */
3502
3503       cogl_set_modelview_matrix (&matrix);
3504     }
3505
3506   if (priv->has_clip)
3507     {
3508       cogl_clip_push_rectangle (priv->clip.x,
3509                                 priv->clip.y,
3510                                 priv->clip.x + priv->clip.width,
3511                                 priv->clip.y + priv->clip.height);
3512       clip_set = TRUE;
3513     }
3514   else if (priv->clip_to_allocation)
3515     {
3516       gfloat width, height;
3517
3518       width  = priv->allocation.x2 - priv->allocation.x1;
3519       height = priv->allocation.y2 - priv->allocation.y1;
3520
3521       cogl_clip_push_rectangle (0, 0, width, height);
3522       clip_set = TRUE;
3523     }
3524
3525   if (pick_mode == CLUTTER_PICK_NONE)
3526     {
3527       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3528
3529       /* We check whether we need to add the flatten effect before
3530          each paint so that we can avoid having a mechanism for
3531          applications to notify when the value of the
3532          has_overlaps virtual changes. */
3533       add_or_remove_flatten_effect (self);
3534     }
3535   else
3536     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3537
3538   /* We save the current paint volume so that the next time the
3539    * actor queues a redraw we can constrain the redraw to just
3540    * cover the union of the new bounding box and the old.
3541    *
3542    * We also fetch the current paint volume to perform culling so
3543    * we can avoid painting actors outside the current clip region.
3544    *
3545    * If we are painting inside a clone, we should neither update
3546    * the paint volume or use it to cull painting, since the paint
3547    * box represents the location of the source actor on the
3548    * screen.
3549    *
3550    * XXX: We are starting to do a lot of vertex transforms on
3551    * the CPU in a typical paint, so at some point we should
3552    * audit these and consider caching some things.
3553    *
3554    * NB: We don't perform culling while picking at this point because
3555    * clutter-stage.c doesn't setup the clipping planes appropriately.
3556    *
3557    * NB: We don't want to update the last-paint-volume during picking
3558    * because the last-paint-volume is used to determine the old screen
3559    * space location of an actor that has moved so we can know the
3560    * minimal region to redraw to clear an old view of the actor. If we
3561    * update this during picking then by the time we come around to
3562    * paint then the last-paint-volume would likely represent the new
3563    * actor position not the old.
3564    */
3565   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3566     {
3567       gboolean success;
3568       /* annoyingly gcc warns if uninitialized even though
3569        * the initialization is redundant :-( */
3570       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3571
3572       if (G_LIKELY ((clutter_paint_debug_flags &
3573                      (CLUTTER_DEBUG_DISABLE_CULLING |
3574                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3575                     (CLUTTER_DEBUG_DISABLE_CULLING |
3576                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3577         _clutter_actor_update_last_paint_volume (self);
3578
3579       success = cull_actor (self, &result);
3580
3581       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3582         _clutter_actor_paint_cull_result (self, success, result);
3583       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3584         goto done;
3585     }
3586
3587   if (priv->effects == NULL)
3588     {
3589       if (pick_mode == CLUTTER_PICK_NONE &&
3590           actor_has_shader_data (self))
3591         {
3592           _clutter_actor_shader_pre_paint (self, FALSE);
3593           shader_applied = TRUE;
3594         }
3595
3596       priv->next_effect_to_paint = NULL;
3597     }
3598   else
3599     priv->next_effect_to_paint =
3600       _clutter_meta_group_peek_metas (priv->effects);
3601
3602   clutter_actor_continue_paint (self);
3603
3604   if (shader_applied)
3605     _clutter_actor_shader_post_paint (self);
3606
3607   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3608                   pick_mode == CLUTTER_PICK_NONE))
3609     _clutter_actor_draw_paint_volume (self);
3610
3611 done:
3612   /* If we make it here then the actor has run through a complete
3613      paint run including all the effects so it's no longer dirty */
3614   if (pick_mode == CLUTTER_PICK_NONE)
3615     priv->is_dirty = FALSE;
3616
3617   if (clip_set)
3618     cogl_clip_pop();
3619
3620   cogl_pop_matrix();
3621
3622   /* paint sequence complete */
3623   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3624 }
3625
3626 /**
3627  * clutter_actor_continue_paint:
3628  * @self: A #ClutterActor
3629  *
3630  * Run the next stage of the paint sequence. This function should only
3631  * be called within the implementation of the ‘run’ virtual of a
3632  * #ClutterEffect. It will cause the run method of the next effect to
3633  * be applied, or it will paint the actual actor if the current effect
3634  * is the last effect in the chain.
3635  *
3636  * Since: 1.8
3637  */
3638 void
3639 clutter_actor_continue_paint (ClutterActor *self)
3640 {
3641   ClutterActorPrivate *priv;
3642
3643   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3644   /* This should only be called from with in the ‘run’ implementation
3645      of a ClutterEffect */
3646   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3647
3648   priv = self->priv;
3649
3650   /* Skip any effects that are disabled */
3651   while (priv->next_effect_to_paint &&
3652          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3653     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3654
3655   /* If this has come from the last effect then we'll just paint the
3656      actual actor */
3657   if (priv->next_effect_to_paint == NULL)
3658     {
3659       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3660         {
3661           ClutterPaintNode *dummy;
3662
3663           /* XXX - this will go away in 2.0, when we can get rid of this
3664            * stuff and switch to a pure retained render tree of PaintNodes
3665            * for the entire frame, starting from the Stage; the paint()
3666            * virtual function can then be called directly.
3667            */
3668           dummy = _clutter_dummy_node_new (self);
3669           clutter_paint_node_set_name (dummy, "Root");
3670
3671           /* XXX - for 1.12, we use the return value of paint_node() to
3672            * decide whether we should emit the ::paint signal.
3673            */
3674           clutter_actor_paint_node (self, dummy);
3675           clutter_paint_node_unref (dummy);
3676
3677           g_signal_emit (self, actor_signals[PAINT], 0);
3678         }
3679       else
3680         {
3681           ClutterColor col = { 0, };
3682
3683           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3684
3685           /* Actor will then paint silhouette of itself in supplied
3686            * color.  See clutter_stage_get_actor_at_pos() for where
3687            * picking is enabled.
3688            */
3689           g_signal_emit (self, actor_signals[PICK], 0, &col);
3690         }
3691     }
3692   else
3693     {
3694       ClutterEffect *old_current_effect;
3695       ClutterEffectPaintFlags run_flags = 0;
3696
3697       /* Cache the current effect so that we can put it back before
3698          returning */
3699       old_current_effect = priv->current_effect;
3700
3701       priv->current_effect = priv->next_effect_to_paint->data;
3702       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3703
3704       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3705         {
3706           if (priv->is_dirty)
3707             {
3708               /* If there's an effect queued with this redraw then all
3709                  effects up to that one will be considered dirty. It
3710                  is expected the queued effect will paint the cached
3711                  image and not call clutter_actor_continue_paint again
3712                  (although it should work ok if it does) */
3713               if (priv->effect_to_redraw == NULL ||
3714                   priv->current_effect != priv->effect_to_redraw)
3715                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3716             }
3717
3718           _clutter_effect_paint (priv->current_effect, run_flags);
3719         }
3720       else
3721         {
3722           /* We can't determine when an actor has been modified since
3723              its last pick so lets just assume it has always been
3724              modified */
3725           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3726
3727           _clutter_effect_pick (priv->current_effect, run_flags);
3728         }
3729
3730       priv->current_effect = old_current_effect;
3731     }
3732 }
3733
3734 static ClutterActorTraverseVisitFlags
3735 invalidate_queue_redraw_entry (ClutterActor *self,
3736                                int           depth,
3737                                gpointer      user_data)
3738 {
3739   ClutterActorPrivate *priv = self->priv;
3740
3741   if (priv->queue_redraw_entry != NULL)
3742     {
3743       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3744       priv->queue_redraw_entry = NULL;
3745     }
3746
3747   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3748 }
3749
3750 static inline void
3751 remove_child (ClutterActor *self,
3752               ClutterActor *child)
3753 {
3754   ClutterActor *prev_sibling, *next_sibling;
3755
3756   prev_sibling = child->priv->prev_sibling;
3757   next_sibling = child->priv->next_sibling;
3758
3759   if (prev_sibling != NULL)
3760     prev_sibling->priv->next_sibling = next_sibling;
3761
3762   if (next_sibling != NULL)
3763     next_sibling->priv->prev_sibling = prev_sibling;
3764
3765   if (self->priv->first_child == child)
3766     self->priv->first_child = next_sibling;
3767
3768   if (self->priv->last_child == child)
3769     self->priv->last_child = prev_sibling;
3770
3771   child->priv->parent = NULL;
3772   child->priv->prev_sibling = NULL;
3773   child->priv->next_sibling = NULL;
3774 }
3775
3776 typedef enum {
3777   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3778   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3779   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3780   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3781   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3782   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3783
3784   /* default flags for public API */
3785   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3786                                     REMOVE_CHILD_EMIT_PARENT_SET |
3787                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3788                                     REMOVE_CHILD_CHECK_STATE |
3789                                     REMOVE_CHILD_FLUSH_QUEUE |
3790                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3791
3792   /* flags for legacy/deprecated API */
3793   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3794                                     REMOVE_CHILD_FLUSH_QUEUE |
3795                                     REMOVE_CHILD_EMIT_PARENT_SET |
3796                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3797 } ClutterActorRemoveChildFlags;
3798
3799 /*< private >
3800  * clutter_actor_remove_child_internal:
3801  * @self: a #ClutterActor
3802  * @child: the child of @self that has to be removed
3803  * @flags: control the removal operations
3804  *
3805  * Removes @child from the list of children of @self.
3806  */
3807 static void
3808 clutter_actor_remove_child_internal (ClutterActor                 *self,
3809                                      ClutterActor                 *child,
3810                                      ClutterActorRemoveChildFlags  flags)
3811 {
3812   ClutterActor *old_first, *old_last;
3813   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3814   gboolean flush_queue;
3815   gboolean notify_first_last;
3816   gboolean was_mapped;
3817
3818   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3819   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3820   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3821   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3822   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3823   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3824
3825   g_object_freeze_notify (G_OBJECT (self));
3826
3827   if (destroy_meta)
3828     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3829
3830   if (check_state)
3831     {
3832       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3833
3834       /* we need to unrealize *before* we set parent_actor to NULL,
3835        * because in an unrealize method actors are dissociating from the
3836        * stage, which means they need to be able to
3837        * clutter_actor_get_stage().
3838        *
3839        * yhis should unmap and unrealize, unless we're reparenting.
3840        */
3841       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3842     }
3843   else
3844     was_mapped = FALSE;
3845
3846   if (flush_queue)
3847     {
3848       /* We take this opportunity to invalidate any queue redraw entry
3849        * associated with the actor and descendants since we won't be able to
3850        * determine the appropriate stage after this.
3851        *
3852        * we do this after we updated the mapped state because actors might
3853        * end up queueing redraws inside their mapped/unmapped virtual
3854        * functions, and if we invalidate the redraw entry we could end up
3855        * with an inconsistent state and weird memory corruption. see
3856        * bugs:
3857        *
3858        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3859        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3860        */
3861       _clutter_actor_traverse (child,
3862                                0,
3863                                invalidate_queue_redraw_entry,
3864                                NULL,
3865                                NULL);
3866     }
3867
3868   old_first = self->priv->first_child;
3869   old_last = self->priv->last_child;
3870
3871   remove_child (self, child);
3872
3873   self->priv->n_children -= 1;
3874
3875   self->priv->age += 1;
3876
3877   /* clutter_actor_reparent() will emit ::parent-set for us */
3878   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3879     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3880
3881   /* if the child was mapped then we need to relayout ourselves to account
3882    * for the removed child
3883    */
3884   if (was_mapped)
3885     clutter_actor_queue_relayout (self);
3886
3887   /* we need to emit the signal before dropping the reference */
3888   if (emit_actor_removed)
3889     g_signal_emit_by_name (self, "actor-removed", child);
3890
3891   if (notify_first_last)
3892     {
3893       if (old_first != self->priv->first_child)
3894         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3895
3896       if (old_last != self->priv->last_child)
3897         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3898     }
3899
3900   g_object_thaw_notify (G_OBJECT (self));
3901
3902   /* remove the reference we acquired in clutter_actor_add_child() */
3903   g_object_unref (child);
3904 }
3905
3906 static const ClutterTransformInfo default_transform_info = {
3907   0.0, { 0, },          /* rotation-x */
3908   0.0, { 0, },          /* rotation-y */
3909   0.0, { 0, },          /* rotation-z */
3910
3911   1.0, 1.0, { 0, },     /* scale */
3912
3913   { 0, },               /* anchor */
3914
3915   0.0,                  /* depth */
3916 };
3917
3918 /*< private >
3919  * _clutter_actor_get_transform_info_or_defaults:
3920  * @self: a #ClutterActor
3921  *
3922  * Retrieves the ClutterTransformInfo structure associated to an actor.
3923  *
3924  * If the actor does not have a ClutterTransformInfo structure associated
3925  * to it, then the default structure will be returned.
3926  *
3927  * This function should only be used for getters.
3928  *
3929  * Return value: a const pointer to the ClutterTransformInfo structure
3930  */
3931 const ClutterTransformInfo *
3932 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3933 {
3934   ClutterTransformInfo *info;
3935
3936   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3937   if (info != NULL)
3938     return info;
3939
3940   return &default_transform_info;
3941 }
3942
3943 static void
3944 clutter_transform_info_free (gpointer data)
3945 {
3946   if (data != NULL)
3947     g_slice_free (ClutterTransformInfo, data);
3948 }
3949
3950 /*< private >
3951  * _clutter_actor_get_transform_info:
3952  * @self: a #ClutterActor
3953  *
3954  * Retrieves a pointer to the ClutterTransformInfo structure.
3955  *
3956  * If the actor does not have a ClutterTransformInfo associated to it, one
3957  * will be created and initialized to the default values.
3958  *
3959  * This function should be used for setters.
3960  *
3961  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3962  * instead.
3963  *
3964  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3965  *   structure
3966  */
3967 ClutterTransformInfo *
3968 _clutter_actor_get_transform_info (ClutterActor *self)
3969 {
3970   ClutterTransformInfo *info;
3971
3972   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3973   if (info == NULL)
3974     {
3975       info = g_slice_new (ClutterTransformInfo);
3976
3977       *info = default_transform_info;
3978
3979       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3980                                info,
3981                                clutter_transform_info_free);
3982     }
3983
3984   return info;
3985 }
3986
3987 /*< private >
3988  * clutter_actor_set_rotation_angle_internal:
3989  * @self: a #ClutterActor
3990  * @axis: the axis of the angle to change
3991  * @angle: the angle of rotation
3992  *
3993  * Sets the rotation angle on the given axis without affecting the
3994  * rotation center point.
3995  */
3996 static inline void
3997 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3998                                            ClutterRotateAxis  axis,
3999                                            gdouble            angle)
4000 {
4001   GObject *obj = G_OBJECT (self);
4002   ClutterTransformInfo *info;
4003
4004   info = _clutter_actor_get_transform_info (self);
4005
4006   g_object_freeze_notify (obj);
4007
4008   switch (axis)
4009     {
4010     case CLUTTER_X_AXIS:
4011       info->rx_angle = angle;
4012       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4013       break;
4014
4015     case CLUTTER_Y_AXIS:
4016       info->ry_angle = angle;
4017       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4018       break;
4019
4020     case CLUTTER_Z_AXIS:
4021       info->rz_angle = angle;
4022       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4023       break;
4024     }
4025
4026   self->priv->transform_valid = FALSE;
4027
4028   g_object_thaw_notify (obj);
4029
4030   clutter_actor_queue_redraw (self);
4031 }
4032
4033 static inline void
4034 clutter_actor_set_rotation_angle (ClutterActor      *self,
4035                                   ClutterRotateAxis  axis,
4036                                   gdouble            angle)
4037 {
4038   const ClutterTransformInfo *info;
4039   const double *cur_angle_p = NULL;
4040   GParamSpec *pspec = NULL;
4041
4042   info = _clutter_actor_get_transform_info_or_defaults (self);
4043
4044   switch (axis)
4045     {
4046     case CLUTTER_X_AXIS:
4047       cur_angle_p = &info->rx_angle;
4048       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4049       break;
4050
4051     case CLUTTER_Y_AXIS:
4052       cur_angle_p = &info->ry_angle;
4053       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4054       break;
4055
4056     case CLUTTER_Z_AXIS:
4057       cur_angle_p = &info->rz_angle;
4058       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4059       break;
4060     }
4061
4062   g_assert (pspec != NULL);
4063   g_assert (cur_angle_p != NULL);
4064
4065   if (_clutter_actor_get_transition (self, pspec) == NULL)
4066     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4067   else
4068     _clutter_actor_update_transition (self, pspec, angle);
4069
4070   clutter_actor_queue_redraw (self);
4071 }
4072
4073 /*< private >
4074  * clutter_actor_set_rotation_center_internal:
4075  * @self: a #ClutterActor
4076  * @axis: the axis of the center to change
4077  * @center: the coordinates of the rotation center
4078  *
4079  * Sets the rotation center on the given axis without affecting the
4080  * rotation angle.
4081  */
4082 static inline void
4083 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4084                                             ClutterRotateAxis    axis,
4085                                             const ClutterVertex *center)
4086 {
4087   GObject *obj = G_OBJECT (self);
4088   ClutterTransformInfo *info;
4089   ClutterVertex v = { 0, 0, 0 };
4090
4091   info = _clutter_actor_get_transform_info (self);
4092
4093   if (center != NULL)
4094     v = *center;
4095
4096   g_object_freeze_notify (obj);
4097
4098   switch (axis)
4099     {
4100     case CLUTTER_X_AXIS:
4101       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4102       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4103       break;
4104
4105     case CLUTTER_Y_AXIS:
4106       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4107       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4108       break;
4109
4110     case CLUTTER_Z_AXIS:
4111       /* if the previously set rotation center was fractional, then
4112        * setting explicit coordinates will have to notify the
4113        * :rotation-center-z-gravity property as well
4114        */
4115       if (info->rz_center.is_fractional)
4116         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4117
4118       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4119       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4120       break;
4121     }
4122
4123   self->priv->transform_valid = FALSE;
4124
4125   g_object_thaw_notify (obj);
4126
4127   clutter_actor_queue_redraw (self);
4128 }
4129
4130 static void
4131 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4132                                          double factor,
4133                                          GParamSpec *pspec)
4134 {
4135   GObject *obj = G_OBJECT (self);
4136   ClutterTransformInfo *info;
4137
4138   info = _clutter_actor_get_transform_info (self);
4139
4140   if (pspec == obj_props[PROP_SCALE_X])
4141     info->scale_x = factor;
4142   else
4143     info->scale_y = factor;
4144
4145   self->priv->transform_valid = FALSE;
4146   clutter_actor_queue_redraw (self);
4147   g_object_notify_by_pspec (obj, pspec);
4148 }
4149
4150 static inline void
4151 clutter_actor_set_scale_factor (ClutterActor      *self,
4152                                 ClutterRotateAxis  axis,
4153                                 gdouble            factor)
4154 {
4155   const ClutterTransformInfo *info;
4156   const double *scale_p = NULL;
4157   GParamSpec *pspec = NULL;
4158
4159   info = _clutter_actor_get_transform_info_or_defaults (self);
4160
4161   switch (axis)
4162     {
4163     case CLUTTER_X_AXIS:
4164       pspec = obj_props[PROP_SCALE_X];
4165       scale_p = &info->scale_x;
4166       break;
4167
4168     case CLUTTER_Y_AXIS:
4169       pspec = obj_props[PROP_SCALE_Y];
4170       scale_p = &info->scale_y;
4171       break;
4172
4173     case CLUTTER_Z_AXIS:
4174       break;
4175     }
4176
4177   g_assert (pspec != NULL);
4178   g_assert (scale_p != NULL);
4179
4180   if (_clutter_actor_get_transition (self, pspec) == NULL)
4181     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4182   else
4183     _clutter_actor_update_transition (self, pspec, factor);
4184
4185   clutter_actor_queue_redraw (self);
4186 }
4187
4188 static inline void
4189 clutter_actor_set_scale_center (ClutterActor      *self,
4190                                 ClutterRotateAxis  axis,
4191                                 gfloat             coord)
4192 {
4193   GObject *obj = G_OBJECT (self);
4194   ClutterTransformInfo *info;
4195   gfloat center_x, center_y;
4196
4197   info = _clutter_actor_get_transform_info (self);
4198
4199   g_object_freeze_notify (obj);
4200
4201   /* get the current scale center coordinates */
4202   clutter_anchor_coord_get_units (self, &info->scale_center,
4203                                   &center_x,
4204                                   &center_y,
4205                                   NULL);
4206
4207   /* we need to notify this too, because setting explicit coordinates will
4208    * change the gravity as a side effect
4209    */
4210   if (info->scale_center.is_fractional)
4211     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4212
4213   switch (axis)
4214     {
4215     case CLUTTER_X_AXIS:
4216       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4217       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4218       break;
4219
4220     case CLUTTER_Y_AXIS:
4221       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4222       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4223       break;
4224
4225     default:
4226       g_assert_not_reached ();
4227     }
4228
4229   self->priv->transform_valid = FALSE;
4230
4231   clutter_actor_queue_redraw (self);
4232
4233   g_object_thaw_notify (obj);
4234 }
4235
4236 static inline void
4237 clutter_actor_set_scale_gravity (ClutterActor   *self,
4238                                  ClutterGravity  gravity)
4239 {
4240   ClutterTransformInfo *info;
4241   GObject *obj;
4242
4243   info = _clutter_actor_get_transform_info (self);
4244   obj = G_OBJECT (self);
4245
4246   if (gravity == CLUTTER_GRAVITY_NONE)
4247     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4248   else
4249     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4250
4251   self->priv->transform_valid = FALSE;
4252
4253   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4254   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4255   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4256
4257   clutter_actor_queue_redraw (self);
4258 }
4259
4260 static inline void
4261 clutter_actor_set_anchor_coord (ClutterActor      *self,
4262                                 ClutterRotateAxis  axis,
4263                                 gfloat             coord)
4264 {
4265   GObject *obj = G_OBJECT (self);
4266   ClutterTransformInfo *info;
4267   gfloat anchor_x, anchor_y;
4268
4269   info = _clutter_actor_get_transform_info (self);
4270
4271   g_object_freeze_notify (obj);
4272
4273   clutter_anchor_coord_get_units (self, &info->anchor,
4274                                   &anchor_x,
4275                                   &anchor_y,
4276                                   NULL);
4277
4278   if (info->anchor.is_fractional)
4279     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4280
4281   switch (axis)
4282     {
4283     case CLUTTER_X_AXIS:
4284       clutter_anchor_coord_set_units (&info->anchor,
4285                                       coord,
4286                                       anchor_y,
4287                                       0.0);
4288       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4289       break;
4290
4291     case CLUTTER_Y_AXIS:
4292       clutter_anchor_coord_set_units (&info->anchor,
4293                                       anchor_x,
4294                                       coord,
4295                                       0.0);
4296       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4297       break;
4298
4299     default:
4300       g_assert_not_reached ();
4301     }
4302
4303   self->priv->transform_valid = FALSE;
4304
4305   clutter_actor_queue_redraw (self);
4306
4307   g_object_thaw_notify (obj);
4308 }
4309
4310 static void
4311 clutter_actor_set_property (GObject      *object,
4312                             guint         prop_id,
4313                             const GValue *value,
4314                             GParamSpec   *pspec)
4315 {
4316   ClutterActor *actor = CLUTTER_ACTOR (object);
4317   ClutterActorPrivate *priv = actor->priv;
4318
4319   switch (prop_id)
4320     {
4321     case PROP_X:
4322       clutter_actor_set_x (actor, g_value_get_float (value));
4323       break;
4324
4325     case PROP_Y:
4326       clutter_actor_set_y (actor, g_value_get_float (value));
4327       break;
4328
4329     case PROP_WIDTH:
4330       clutter_actor_set_width (actor, g_value_get_float (value));
4331       break;
4332
4333     case PROP_HEIGHT:
4334       clutter_actor_set_height (actor, g_value_get_float (value));
4335       break;
4336
4337     case PROP_FIXED_X:
4338       clutter_actor_set_x (actor, g_value_get_float (value));
4339       break;
4340
4341     case PROP_FIXED_Y:
4342       clutter_actor_set_y (actor, g_value_get_float (value));
4343       break;
4344
4345     case PROP_FIXED_POSITION_SET:
4346       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4347       break;
4348
4349     case PROP_MIN_WIDTH:
4350       clutter_actor_set_min_width (actor, g_value_get_float (value));
4351       break;
4352
4353     case PROP_MIN_HEIGHT:
4354       clutter_actor_set_min_height (actor, g_value_get_float (value));
4355       break;
4356
4357     case PROP_NATURAL_WIDTH:
4358       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4359       break;
4360
4361     case PROP_NATURAL_HEIGHT:
4362       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4363       break;
4364
4365     case PROP_MIN_WIDTH_SET:
4366       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4367       break;
4368
4369     case PROP_MIN_HEIGHT_SET:
4370       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4371       break;
4372
4373     case PROP_NATURAL_WIDTH_SET:
4374       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4375       break;
4376
4377     case PROP_NATURAL_HEIGHT_SET:
4378       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4379       break;
4380
4381     case PROP_REQUEST_MODE:
4382       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4383       break;
4384
4385     case PROP_DEPTH:
4386       clutter_actor_set_depth (actor, g_value_get_float (value));
4387       break;
4388
4389     case PROP_OPACITY:
4390       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4391       break;
4392
4393     case PROP_OFFSCREEN_REDIRECT:
4394       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4395       break;
4396
4397     case PROP_NAME:
4398       clutter_actor_set_name (actor, g_value_get_string (value));
4399       break;
4400
4401     case PROP_VISIBLE:
4402       if (g_value_get_boolean (value) == TRUE)
4403         clutter_actor_show (actor);
4404       else
4405         clutter_actor_hide (actor);
4406       break;
4407
4408     case PROP_SCALE_X:
4409       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4410                                       g_value_get_double (value));
4411       break;
4412
4413     case PROP_SCALE_Y:
4414       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4415                                       g_value_get_double (value));
4416       break;
4417
4418     case PROP_SCALE_CENTER_X:
4419       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4420                                       g_value_get_float (value));
4421       break;
4422
4423     case PROP_SCALE_CENTER_Y:
4424       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4425                                       g_value_get_float (value));
4426       break;
4427
4428     case PROP_SCALE_GRAVITY:
4429       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4430       break;
4431
4432     case PROP_CLIP:
4433       {
4434         const ClutterGeometry *geom = g_value_get_boxed (value);
4435
4436         clutter_actor_set_clip (actor,
4437                                 geom->x, geom->y,
4438                                 geom->width, geom->height);
4439       }
4440       break;
4441
4442     case PROP_CLIP_TO_ALLOCATION:
4443       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4444       break;
4445
4446     case PROP_REACTIVE:
4447       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4448       break;
4449
4450     case PROP_ROTATION_ANGLE_X:
4451       clutter_actor_set_rotation_angle (actor,
4452                                         CLUTTER_X_AXIS,
4453                                         g_value_get_double (value));
4454       break;
4455
4456     case PROP_ROTATION_ANGLE_Y:
4457       clutter_actor_set_rotation_angle (actor,
4458                                         CLUTTER_Y_AXIS,
4459                                         g_value_get_double (value));
4460       break;
4461
4462     case PROP_ROTATION_ANGLE_Z:
4463       clutter_actor_set_rotation_angle (actor,
4464                                         CLUTTER_Z_AXIS,
4465                                         g_value_get_double (value));
4466       break;
4467
4468     case PROP_ROTATION_CENTER_X:
4469       clutter_actor_set_rotation_center_internal (actor,
4470                                                   CLUTTER_X_AXIS,
4471                                                   g_value_get_boxed (value));
4472       break;
4473
4474     case PROP_ROTATION_CENTER_Y:
4475       clutter_actor_set_rotation_center_internal (actor,
4476                                                   CLUTTER_Y_AXIS,
4477                                                   g_value_get_boxed (value));
4478       break;
4479
4480     case PROP_ROTATION_CENTER_Z:
4481       clutter_actor_set_rotation_center_internal (actor,
4482                                                   CLUTTER_Z_AXIS,
4483                                                   g_value_get_boxed (value));
4484       break;
4485
4486     case PROP_ROTATION_CENTER_Z_GRAVITY:
4487       {
4488         const ClutterTransformInfo *info;
4489
4490         info = _clutter_actor_get_transform_info_or_defaults (actor);
4491         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4492                                                    g_value_get_enum (value));
4493       }
4494       break;
4495
4496     case PROP_ANCHOR_X:
4497       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4498                                       g_value_get_float (value));
4499       break;
4500
4501     case PROP_ANCHOR_Y:
4502       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4503                                       g_value_get_float (value));
4504       break;
4505
4506     case PROP_ANCHOR_GRAVITY:
4507       clutter_actor_set_anchor_point_from_gravity (actor,
4508                                                    g_value_get_enum (value));
4509       break;
4510
4511     case PROP_SHOW_ON_SET_PARENT:
4512       priv->show_on_set_parent = g_value_get_boolean (value);
4513       break;
4514
4515     case PROP_TEXT_DIRECTION:
4516       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4517       break;
4518
4519     case PROP_ACTIONS:
4520       clutter_actor_add_action (actor, g_value_get_object (value));
4521       break;
4522
4523     case PROP_CONSTRAINTS:
4524       clutter_actor_add_constraint (actor, g_value_get_object (value));
4525       break;
4526
4527     case PROP_EFFECT:
4528       clutter_actor_add_effect (actor, g_value_get_object (value));
4529       break;
4530
4531     case PROP_LAYOUT_MANAGER:
4532       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4533       break;
4534
4535     case PROP_X_ALIGN:
4536       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4537       break;
4538
4539     case PROP_Y_ALIGN:
4540       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4541       break;
4542
4543     case PROP_MARGIN_TOP:
4544       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4545       break;
4546
4547     case PROP_MARGIN_BOTTOM:
4548       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4549       break;
4550
4551     case PROP_MARGIN_LEFT:
4552       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4553       break;
4554
4555     case PROP_MARGIN_RIGHT:
4556       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4557       break;
4558
4559     case PROP_BACKGROUND_COLOR:
4560       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4561       break;
4562
4563     case PROP_CONTENT:
4564       clutter_actor_set_content (actor, g_value_get_object (value));
4565       break;
4566
4567     case PROP_CONTENT_GRAVITY:
4568       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4569       break;
4570
4571     case PROP_MINIFICATION_FILTER:
4572       clutter_actor_set_content_scaling_filters (actor,
4573                                                  g_value_get_enum (value),
4574                                                  actor->priv->mag_filter);
4575       break;
4576
4577     case PROP_MAGNIFICATION_FILTER:
4578       clutter_actor_set_content_scaling_filters (actor,
4579                                                  actor->priv->min_filter,
4580                                                  g_value_get_enum (value));
4581       break;
4582
4583     default:
4584       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4585       break;
4586     }
4587 }
4588
4589 static void
4590 clutter_actor_get_property (GObject    *object,
4591                             guint       prop_id,
4592                             GValue     *value,
4593                             GParamSpec *pspec)
4594 {
4595   ClutterActor *actor = CLUTTER_ACTOR (object);
4596   ClutterActorPrivate *priv = actor->priv;
4597
4598   switch (prop_id)
4599     {
4600     case PROP_X:
4601       g_value_set_float (value, clutter_actor_get_x (actor));
4602       break;
4603
4604     case PROP_Y:
4605       g_value_set_float (value, clutter_actor_get_y (actor));
4606       break;
4607
4608     case PROP_WIDTH:
4609       g_value_set_float (value, clutter_actor_get_width (actor));
4610       break;
4611
4612     case PROP_HEIGHT:
4613       g_value_set_float (value, clutter_actor_get_height (actor));
4614       break;
4615
4616     case PROP_FIXED_X:
4617       {
4618         const ClutterLayoutInfo *info;
4619
4620         info = _clutter_actor_get_layout_info_or_defaults (actor);
4621         g_value_set_float (value, info->fixed_x);
4622       }
4623       break;
4624
4625     case PROP_FIXED_Y:
4626       {
4627         const ClutterLayoutInfo *info;
4628
4629         info = _clutter_actor_get_layout_info_or_defaults (actor);
4630         g_value_set_float (value, info->fixed_y);
4631       }
4632       break;
4633
4634     case PROP_FIXED_POSITION_SET:
4635       g_value_set_boolean (value, priv->position_set);
4636       break;
4637
4638     case PROP_MIN_WIDTH:
4639       {
4640         const ClutterLayoutInfo *info;
4641
4642         info = _clutter_actor_get_layout_info_or_defaults (actor);
4643         g_value_set_float (value, info->min_width);
4644       }
4645       break;
4646
4647     case PROP_MIN_HEIGHT:
4648       {
4649         const ClutterLayoutInfo *info;
4650
4651         info = _clutter_actor_get_layout_info_or_defaults (actor);
4652         g_value_set_float (value, info->min_height);
4653       }
4654       break;
4655
4656     case PROP_NATURAL_WIDTH:
4657       {
4658         const ClutterLayoutInfo *info;
4659
4660         info = _clutter_actor_get_layout_info_or_defaults (actor);
4661         g_value_set_float (value, info->natural_width);
4662       }
4663       break;
4664
4665     case PROP_NATURAL_HEIGHT:
4666       {
4667         const ClutterLayoutInfo *info;
4668
4669         info = _clutter_actor_get_layout_info_or_defaults (actor);
4670         g_value_set_float (value, info->natural_height);
4671       }
4672       break;
4673
4674     case PROP_MIN_WIDTH_SET:
4675       g_value_set_boolean (value, priv->min_width_set);
4676       break;
4677
4678     case PROP_MIN_HEIGHT_SET:
4679       g_value_set_boolean (value, priv->min_height_set);
4680       break;
4681
4682     case PROP_NATURAL_WIDTH_SET:
4683       g_value_set_boolean (value, priv->natural_width_set);
4684       break;
4685
4686     case PROP_NATURAL_HEIGHT_SET:
4687       g_value_set_boolean (value, priv->natural_height_set);
4688       break;
4689
4690     case PROP_REQUEST_MODE:
4691       g_value_set_enum (value, priv->request_mode);
4692       break;
4693
4694     case PROP_ALLOCATION:
4695       g_value_set_boxed (value, &priv->allocation);
4696       break;
4697
4698     case PROP_DEPTH:
4699       g_value_set_float (value, clutter_actor_get_depth (actor));
4700       break;
4701
4702     case PROP_OPACITY:
4703       g_value_set_uint (value, priv->opacity);
4704       break;
4705
4706     case PROP_OFFSCREEN_REDIRECT:
4707       g_value_set_enum (value, priv->offscreen_redirect);
4708       break;
4709
4710     case PROP_NAME:
4711       g_value_set_string (value, priv->name);
4712       break;
4713
4714     case PROP_VISIBLE:
4715       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4716       break;
4717
4718     case PROP_MAPPED:
4719       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4720       break;
4721
4722     case PROP_REALIZED:
4723       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4724       break;
4725
4726     case PROP_HAS_CLIP:
4727       g_value_set_boolean (value, priv->has_clip);
4728       break;
4729
4730     case PROP_CLIP:
4731       {
4732         ClutterGeometry clip;
4733
4734         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4735         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4736         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4737         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4738
4739         g_value_set_boxed (value, &clip);
4740       }
4741       break;
4742
4743     case PROP_CLIP_TO_ALLOCATION:
4744       g_value_set_boolean (value, priv->clip_to_allocation);
4745       break;
4746
4747     case PROP_SCALE_X:
4748       {
4749         const ClutterTransformInfo *info;
4750
4751         info = _clutter_actor_get_transform_info_or_defaults (actor);
4752         g_value_set_double (value, info->scale_x);
4753       }
4754       break;
4755
4756     case PROP_SCALE_Y:
4757       {
4758         const ClutterTransformInfo *info;
4759
4760         info = _clutter_actor_get_transform_info_or_defaults (actor);
4761         g_value_set_double (value, info->scale_y);
4762       }
4763       break;
4764
4765     case PROP_SCALE_CENTER_X:
4766       {
4767         gfloat center;
4768
4769         clutter_actor_get_scale_center (actor, &center, NULL);
4770
4771         g_value_set_float (value, center);
4772       }
4773       break;
4774
4775     case PROP_SCALE_CENTER_Y:
4776       {
4777         gfloat center;
4778
4779         clutter_actor_get_scale_center (actor, NULL, &center);
4780
4781         g_value_set_float (value, center);
4782       }
4783       break;
4784
4785     case PROP_SCALE_GRAVITY:
4786       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4787       break;
4788
4789     case PROP_REACTIVE:
4790       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4791       break;
4792
4793     case PROP_ROTATION_ANGLE_X:
4794       {
4795         const ClutterTransformInfo *info;
4796
4797         info = _clutter_actor_get_transform_info_or_defaults (actor);
4798         g_value_set_double (value, info->rx_angle);
4799       }
4800       break;
4801
4802     case PROP_ROTATION_ANGLE_Y:
4803       {
4804         const ClutterTransformInfo *info;
4805
4806         info = _clutter_actor_get_transform_info_or_defaults (actor);
4807         g_value_set_double (value, info->ry_angle);
4808       }
4809       break;
4810
4811     case PROP_ROTATION_ANGLE_Z:
4812       {
4813         const ClutterTransformInfo *info;
4814
4815         info = _clutter_actor_get_transform_info_or_defaults (actor);
4816         g_value_set_double (value, info->rz_angle);
4817       }
4818       break;
4819
4820     case PROP_ROTATION_CENTER_X:
4821       {
4822         ClutterVertex center;
4823
4824         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4825                                     &center.x,
4826                                     &center.y,
4827                                     &center.z);
4828
4829         g_value_set_boxed (value, &center);
4830       }
4831       break;
4832
4833     case PROP_ROTATION_CENTER_Y:
4834       {
4835         ClutterVertex center;
4836
4837         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4838                                     &center.x,
4839                                     &center.y,
4840                                     &center.z);
4841
4842         g_value_set_boxed (value, &center);
4843       }
4844       break;
4845
4846     case PROP_ROTATION_CENTER_Z:
4847       {
4848         ClutterVertex center;
4849
4850         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4851                                     &center.x,
4852                                     &center.y,
4853                                     &center.z);
4854
4855         g_value_set_boxed (value, &center);
4856       }
4857       break;
4858
4859     case PROP_ROTATION_CENTER_Z_GRAVITY:
4860       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4861       break;
4862
4863     case PROP_ANCHOR_X:
4864       {
4865         const ClutterTransformInfo *info;
4866         gfloat anchor_x;
4867
4868         info = _clutter_actor_get_transform_info_or_defaults (actor);
4869         clutter_anchor_coord_get_units (actor, &info->anchor,
4870                                         &anchor_x,
4871                                         NULL,
4872                                         NULL);
4873         g_value_set_float (value, anchor_x);
4874       }
4875       break;
4876
4877     case PROP_ANCHOR_Y:
4878       {
4879         const ClutterTransformInfo *info;
4880         gfloat anchor_y;
4881
4882         info = _clutter_actor_get_transform_info_or_defaults (actor);
4883         clutter_anchor_coord_get_units (actor, &info->anchor,
4884                                         NULL,
4885                                         &anchor_y,
4886                                         NULL);
4887         g_value_set_float (value, anchor_y);
4888       }
4889       break;
4890
4891     case PROP_ANCHOR_GRAVITY:
4892       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4893       break;
4894
4895     case PROP_SHOW_ON_SET_PARENT:
4896       g_value_set_boolean (value, priv->show_on_set_parent);
4897       break;
4898
4899     case PROP_TEXT_DIRECTION:
4900       g_value_set_enum (value, priv->text_direction);
4901       break;
4902
4903     case PROP_HAS_POINTER:
4904       g_value_set_boolean (value, priv->has_pointer);
4905       break;
4906
4907     case PROP_LAYOUT_MANAGER:
4908       g_value_set_object (value, priv->layout_manager);
4909       break;
4910
4911     case PROP_X_ALIGN:
4912       {
4913         const ClutterLayoutInfo *info;
4914
4915         info = _clutter_actor_get_layout_info_or_defaults (actor);
4916         g_value_set_enum (value, info->x_align);
4917       }
4918       break;
4919
4920     case PROP_Y_ALIGN:
4921       {
4922         const ClutterLayoutInfo *info;
4923
4924         info = _clutter_actor_get_layout_info_or_defaults (actor);
4925         g_value_set_enum (value, info->y_align);
4926       }
4927       break;
4928
4929     case PROP_MARGIN_TOP:
4930       {
4931         const ClutterLayoutInfo *info;
4932
4933         info = _clutter_actor_get_layout_info_or_defaults (actor);
4934         g_value_set_float (value, info->margin.top);
4935       }
4936       break;
4937
4938     case PROP_MARGIN_BOTTOM:
4939       {
4940         const ClutterLayoutInfo *info;
4941
4942         info = _clutter_actor_get_layout_info_or_defaults (actor);
4943         g_value_set_float (value, info->margin.bottom);
4944       }
4945       break;
4946
4947     case PROP_MARGIN_LEFT:
4948       {
4949         const ClutterLayoutInfo *info;
4950
4951         info = _clutter_actor_get_layout_info_or_defaults (actor);
4952         g_value_set_float (value, info->margin.left);
4953       }
4954       break;
4955
4956     case PROP_MARGIN_RIGHT:
4957       {
4958         const ClutterLayoutInfo *info;
4959
4960         info = _clutter_actor_get_layout_info_or_defaults (actor);
4961         g_value_set_float (value, info->margin.right);
4962       }
4963       break;
4964
4965     case PROP_BACKGROUND_COLOR_SET:
4966       g_value_set_boolean (value, priv->bg_color_set);
4967       break;
4968
4969     case PROP_BACKGROUND_COLOR:
4970       g_value_set_boxed (value, &priv->bg_color);
4971       break;
4972
4973     case PROP_FIRST_CHILD:
4974       g_value_set_object (value, priv->first_child);
4975       break;
4976
4977     case PROP_LAST_CHILD:
4978       g_value_set_object (value, priv->last_child);
4979       break;
4980
4981     case PROP_CONTENT:
4982       g_value_set_object (value, priv->content);
4983       break;
4984
4985     case PROP_CONTENT_GRAVITY:
4986       g_value_set_enum (value, priv->content_gravity);
4987       break;
4988
4989     case PROP_CONTENT_BOX:
4990       {
4991         ClutterActorBox box = { 0, };
4992
4993         clutter_actor_get_content_box (actor, &box);
4994         g_value_set_boxed (value, &box);
4995       }
4996       break;
4997
4998     case PROP_MINIFICATION_FILTER:
4999       g_value_set_enum (value, priv->min_filter);
5000       break;
5001
5002     case PROP_MAGNIFICATION_FILTER:
5003       g_value_set_enum (value, priv->mag_filter);
5004       break;
5005
5006     default:
5007       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5008       break;
5009     }
5010 }
5011
5012 static void
5013 clutter_actor_dispose (GObject *object)
5014 {
5015   ClutterActor *self = CLUTTER_ACTOR (object);
5016   ClutterActorPrivate *priv = self->priv;
5017
5018   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5019                 priv->id,
5020                 g_type_name (G_OBJECT_TYPE (self)),
5021                 object->ref_count);
5022
5023   g_signal_emit (self, actor_signals[DESTROY], 0);
5024
5025   /* avoid recursing when called from clutter_actor_destroy() */
5026   if (priv->parent != NULL)
5027     {
5028       ClutterActor *parent = priv->parent;
5029
5030       /* go through the Container implementation unless this
5031        * is an internal child and has been marked as such.
5032        *
5033        * removing the actor from its parent will reset the
5034        * realized and mapped states.
5035        */
5036       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5037         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5038       else
5039         clutter_actor_remove_child_internal (parent, self,
5040                                              REMOVE_CHILD_LEGACY_FLAGS);
5041     }
5042
5043   /* parent must be gone at this point */
5044   g_assert (priv->parent == NULL);
5045
5046   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5047     {
5048       /* can't be mapped or realized with no parent */
5049       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5050       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5051     }
5052
5053   g_clear_object (&priv->pango_context);
5054   g_clear_object (&priv->actions);
5055   g_clear_object (&priv->constraints);
5056   g_clear_object (&priv->effects);
5057   g_clear_object (&priv->flatten_effect);
5058
5059   if (priv->layout_manager != NULL)
5060     {
5061       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5062       g_clear_object (&priv->layout_manager);
5063     }
5064
5065   if (priv->content != NULL)
5066     {
5067       _clutter_content_detached (priv->content, self);
5068       g_clear_object (&priv->content);
5069     }
5070
5071   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5072 }
5073
5074 static void
5075 clutter_actor_finalize (GObject *object)
5076 {
5077   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5078
5079   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5080                 priv->name != NULL ? priv->name : "<none>",
5081                 priv->id,
5082                 g_type_name (G_OBJECT_TYPE (object)));
5083
5084   _clutter_context_release_id (priv->id);
5085
5086   g_free (priv->name);
5087
5088   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5089 }
5090
5091
5092 /**
5093  * clutter_actor_get_accessible:
5094  * @self: a #ClutterActor
5095  *
5096  * Returns the accessible object that describes the actor to an
5097  * assistive technology.
5098  *
5099  * If no class-specific #AtkObject implementation is available for the
5100  * actor instance in question, it will inherit an #AtkObject
5101  * implementation from the first ancestor class for which such an
5102  * implementation is defined.
5103  *
5104  * The documentation of the <ulink
5105  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5106  * library contains more information about accessible objects and
5107  * their uses.
5108  *
5109  * Returns: (transfer none): the #AtkObject associated with @actor
5110  */
5111 AtkObject *
5112 clutter_actor_get_accessible (ClutterActor *self)
5113 {
5114   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5115
5116   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5117 }
5118
5119 static AtkObject *
5120 clutter_actor_real_get_accessible (ClutterActor *actor)
5121 {
5122   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5123 }
5124
5125 static AtkObject *
5126 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5127 {
5128   AtkObject *accessible;
5129
5130   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5131   if (accessible != NULL)
5132     g_object_ref (accessible);
5133
5134   return accessible;
5135 }
5136
5137 static void
5138 atk_implementor_iface_init (AtkImplementorIface *iface)
5139 {
5140   iface->ref_accessible = _clutter_actor_ref_accessible;
5141 }
5142
5143 static gboolean
5144 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5145                                            ClutterPaintVolume *volume)
5146 {
5147   ClutterActorPrivate *priv = self->priv;
5148   gboolean res = FALSE;
5149
5150   /* we start from the allocation */
5151   clutter_paint_volume_set_width (volume,
5152                                   priv->allocation.x2 - priv->allocation.x1);
5153   clutter_paint_volume_set_height (volume,
5154                                    priv->allocation.y2 - priv->allocation.y1);
5155
5156   /* if the actor has a clip set then we have a pretty definite
5157    * size for the paint volume: the actor cannot possibly paint
5158    * outside the clip region.
5159    */
5160   if (priv->clip_to_allocation)
5161     {
5162       /* the allocation has already been set, so we just flip the
5163        * return value
5164        */
5165       res = TRUE;
5166     }
5167   else
5168     {
5169       ClutterActor *child;
5170
5171       if (priv->has_clip &&
5172           priv->clip.width >= 0 &&
5173           priv->clip.height >= 0)
5174         {
5175           ClutterVertex origin;
5176
5177           origin.x = priv->clip.x;
5178           origin.y = priv->clip.y;
5179           origin.z = 0;
5180
5181           clutter_paint_volume_set_origin (volume, &origin);
5182           clutter_paint_volume_set_width (volume, priv->clip.width);
5183           clutter_paint_volume_set_height (volume, priv->clip.height);
5184
5185           res = TRUE;
5186         }
5187
5188       /* if we don't have children we just bail out here... */
5189       if (priv->n_children == 0)
5190         return res;
5191
5192       /* ...but if we have children then we ask for their paint volume in
5193        * our coordinates. if any of our children replies that it doesn't
5194        * have a paint volume, we bail out
5195        */
5196       for (child = priv->first_child;
5197            child != NULL;
5198            child = child->priv->next_sibling)
5199         {
5200           const ClutterPaintVolume *child_volume;
5201
5202           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5203           if (child_volume == NULL)
5204             {
5205               res = FALSE;
5206               break;
5207             }
5208
5209           clutter_paint_volume_union (volume, child_volume);
5210           res = TRUE;
5211         }
5212     }
5213
5214   return res;
5215
5216 }
5217
5218 static gboolean
5219 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5220                                      ClutterPaintVolume *volume)
5221 {
5222   ClutterActorClass *klass;
5223   gboolean res;
5224
5225   klass = CLUTTER_ACTOR_GET_CLASS (self);
5226
5227   /* XXX - this thoroughly sucks, but we don't want to penalize users
5228    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5229    * redraw. This should go away in 2.0.
5230    */
5231   if (klass->paint == clutter_actor_real_paint &&
5232       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5233     {
5234       res = TRUE;
5235     }
5236   else
5237     {
5238       /* this is the default return value: we cannot know if a class
5239        * is going to paint outside its allocation, so we take the
5240        * conservative approach.
5241        */
5242       res = FALSE;
5243     }
5244
5245   if (clutter_actor_update_default_paint_volume (self, volume))
5246     return res;
5247
5248   return FALSE;
5249 }
5250
5251 /**
5252  * clutter_actor_get_default_paint_volume:
5253  * @self: a #ClutterActor
5254  *
5255  * Retrieves the default paint volume for @self.
5256  *
5257  * This function provides the same #ClutterPaintVolume that would be
5258  * computed by the default implementation inside #ClutterActor of the
5259  * #ClutterActorClass.get_paint_volume() virtual function.
5260  *
5261  * This function should only be used by #ClutterActor subclasses that
5262  * cannot chain up to the parent implementation when computing their
5263  * paint volume.
5264  *
5265  * Return value: (transfer none): a pointer to the default
5266  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5267  *   the actor could not compute a valid paint volume. The returned value
5268  *   is not guaranteed to be stable across multiple frames, so if you
5269  *   want to retain it, you will need to copy it using
5270  *   clutter_paint_volume_copy().
5271  *
5272  * Since: 1.10
5273  */
5274 const ClutterPaintVolume *
5275 clutter_actor_get_default_paint_volume (ClutterActor *self)
5276 {
5277   ClutterPaintVolume volume;
5278   ClutterPaintVolume *res;
5279
5280   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5281
5282   res = NULL;
5283   _clutter_paint_volume_init_static (&volume, self);
5284   if (clutter_actor_update_default_paint_volume (self, &volume))
5285     {
5286       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5287
5288       if (stage != NULL)
5289         {
5290           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5291           _clutter_paint_volume_copy_static (&volume, res);
5292         }
5293     }
5294
5295   clutter_paint_volume_free (&volume);
5296
5297   return res;
5298 }
5299
5300 static gboolean
5301 clutter_actor_real_has_overlaps (ClutterActor *self)
5302 {
5303   /* By default we'll assume that all actors need an offscreen redirect to get
5304    * the correct opacity. Actors such as ClutterTexture that would never need
5305    * an offscreen redirect can override this to return FALSE. */
5306   return TRUE;
5307 }
5308
5309 static void
5310 clutter_actor_real_destroy (ClutterActor *actor)
5311 {
5312   ClutterActorIter iter;
5313
5314   g_object_freeze_notify (G_OBJECT (actor));
5315
5316   clutter_actor_iter_init (&iter, actor);
5317   while (clutter_actor_iter_next (&iter, NULL))
5318     clutter_actor_iter_destroy (&iter);
5319
5320   g_object_thaw_notify (G_OBJECT (actor));
5321 }
5322
5323 static GObject *
5324 clutter_actor_constructor (GType gtype,
5325                            guint n_props,
5326                            GObjectConstructParam *props)
5327 {
5328   GObjectClass *gobject_class;
5329   ClutterActor *self;
5330   GObject *retval;
5331
5332   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5333   retval = gobject_class->constructor (gtype, n_props, props);
5334   self = CLUTTER_ACTOR (retval);
5335
5336   if (self->priv->layout_manager == NULL)
5337     {
5338       ClutterLayoutManager *default_layout;
5339
5340       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5341
5342       default_layout = clutter_fixed_layout_new ();
5343       clutter_actor_set_layout_manager (self, default_layout);
5344     }
5345
5346   return retval;
5347 }
5348
5349 static void
5350 clutter_actor_class_init (ClutterActorClass *klass)
5351 {
5352   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5353
5354   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5355   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5356   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5357   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5358
5359   object_class->constructor = clutter_actor_constructor;
5360   object_class->set_property = clutter_actor_set_property;
5361   object_class->get_property = clutter_actor_get_property;
5362   object_class->dispose = clutter_actor_dispose;
5363   object_class->finalize = clutter_actor_finalize;
5364
5365   klass->show = clutter_actor_real_show;
5366   klass->show_all = clutter_actor_show;
5367   klass->hide = clutter_actor_real_hide;
5368   klass->hide_all = clutter_actor_hide;
5369   klass->map = clutter_actor_real_map;
5370   klass->unmap = clutter_actor_real_unmap;
5371   klass->unrealize = clutter_actor_real_unrealize;
5372   klass->pick = clutter_actor_real_pick;
5373   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5374   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5375   klass->allocate = clutter_actor_real_allocate;
5376   klass->queue_redraw = clutter_actor_real_queue_redraw;
5377   klass->queue_relayout = clutter_actor_real_queue_relayout;
5378   klass->apply_transform = clutter_actor_real_apply_transform;
5379   klass->get_accessible = clutter_actor_real_get_accessible;
5380   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5381   klass->has_overlaps = clutter_actor_real_has_overlaps;
5382   klass->paint = clutter_actor_real_paint;
5383   klass->destroy = clutter_actor_real_destroy;
5384
5385   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5386
5387   /**
5388    * ClutterActor:x:
5389    *
5390    * X coordinate of the actor in pixels. If written, forces a fixed
5391    * position for the actor. If read, returns the fixed position if any,
5392    * otherwise the allocation if available, otherwise 0.
5393    *
5394    * The #ClutterActor:x property is animatable.
5395    */
5396   obj_props[PROP_X] =
5397     g_param_spec_float ("x",
5398                         P_("X coordinate"),
5399                         P_("X coordinate of the actor"),
5400                         -G_MAXFLOAT, G_MAXFLOAT,
5401                         0.0,
5402                         G_PARAM_READWRITE |
5403                         G_PARAM_STATIC_STRINGS |
5404                         CLUTTER_PARAM_ANIMATABLE);
5405
5406   /**
5407    * ClutterActor:y:
5408    *
5409    * Y coordinate of the actor in pixels. If written, forces a fixed
5410    * position for the actor.  If read, returns the fixed position if
5411    * any, otherwise the allocation if available, otherwise 0.
5412    *
5413    * The #ClutterActor:y property is animatable.
5414    */
5415   obj_props[PROP_Y] =
5416     g_param_spec_float ("y",
5417                         P_("Y coordinate"),
5418                         P_("Y coordinate of the actor"),
5419                         -G_MAXFLOAT, G_MAXFLOAT,
5420                         0.0,
5421                         G_PARAM_READWRITE |
5422                         G_PARAM_STATIC_STRINGS |
5423                         CLUTTER_PARAM_ANIMATABLE);
5424
5425   /**
5426    * ClutterActor:width:
5427    *
5428    * Width of the actor (in pixels). If written, forces the minimum and
5429    * natural size request of the actor to the given width. If read, returns
5430    * the allocated width if available, otherwise the width request.
5431    *
5432    * The #ClutterActor:width property is animatable.
5433    */
5434   obj_props[PROP_WIDTH] =
5435     g_param_spec_float ("width",
5436                         P_("Width"),
5437                         P_("Width of the actor"),
5438                         0.0, G_MAXFLOAT,
5439                         0.0,
5440                         G_PARAM_READWRITE |
5441                         G_PARAM_STATIC_STRINGS |
5442                         CLUTTER_PARAM_ANIMATABLE);
5443
5444   /**
5445    * ClutterActor:height:
5446    *
5447    * Height of the actor (in pixels).  If written, forces the minimum and
5448    * natural size request of the actor to the given height. If read, returns
5449    * the allocated height if available, otherwise the height request.
5450    *
5451    * The #ClutterActor:height property is animatable.
5452    */
5453   obj_props[PROP_HEIGHT] =
5454     g_param_spec_float ("height",
5455                         P_("Height"),
5456                         P_("Height of the actor"),
5457                         0.0, G_MAXFLOAT,
5458                         0.0,
5459                         G_PARAM_READWRITE |
5460                         G_PARAM_STATIC_STRINGS |
5461                         CLUTTER_PARAM_ANIMATABLE);
5462
5463   /**
5464    * ClutterActor:fixed-x:
5465    *
5466    * The fixed X position of the actor in pixels.
5467    *
5468    * Writing this property sets #ClutterActor:fixed-position-set
5469    * property as well, as a side effect
5470    *
5471    * Since: 0.8
5472    */
5473   obj_props[PROP_FIXED_X] =
5474     g_param_spec_float ("fixed-x",
5475                         P_("Fixed X"),
5476                         P_("Forced X position of the actor"),
5477                         -G_MAXFLOAT, G_MAXFLOAT,
5478                         0.0,
5479                         CLUTTER_PARAM_READWRITE);
5480
5481   /**
5482    * ClutterActor:fixed-y:
5483    *
5484    * The fixed Y position of the actor in pixels.
5485    *
5486    * Writing this property sets the #ClutterActor:fixed-position-set
5487    * property as well, as a side effect
5488    *
5489    * Since: 0.8
5490    */
5491   obj_props[PROP_FIXED_Y] =
5492     g_param_spec_float ("fixed-y",
5493                         P_("Fixed Y"),
5494                         P_("Forced Y position of the actor"),
5495                         -G_MAXFLOAT, G_MAXFLOAT,
5496                         0,
5497                         CLUTTER_PARAM_READWRITE);
5498
5499   /**
5500    * ClutterActor:fixed-position-set:
5501    *
5502    * This flag controls whether the #ClutterActor:fixed-x and
5503    * #ClutterActor:fixed-y properties are used
5504    *
5505    * Since: 0.8
5506    */
5507   obj_props[PROP_FIXED_POSITION_SET] =
5508     g_param_spec_boolean ("fixed-position-set",
5509                           P_("Fixed position set"),
5510                           P_("Whether to use fixed positioning for the actor"),
5511                           FALSE,
5512                           CLUTTER_PARAM_READWRITE);
5513
5514   /**
5515    * ClutterActor:min-width:
5516    *
5517    * A forced minimum width request for the actor, in pixels
5518    *
5519    * Writing this property sets the #ClutterActor:min-width-set property
5520    * as well, as a side effect.
5521    *
5522    *This property overrides the usual width request of the actor.
5523    *
5524    * Since: 0.8
5525    */
5526   obj_props[PROP_MIN_WIDTH] =
5527     g_param_spec_float ("min-width",
5528                         P_("Min Width"),
5529                         P_("Forced minimum width request for the actor"),
5530                         0.0, G_MAXFLOAT,
5531                         0.0,
5532                         CLUTTER_PARAM_READWRITE);
5533
5534   /**
5535    * ClutterActor:min-height:
5536    *
5537    * A forced minimum height request for the actor, in pixels
5538    *
5539    * Writing this property sets the #ClutterActor:min-height-set property
5540    * as well, as a side effect. This property overrides the usual height
5541    * request of the actor.
5542    *
5543    * Since: 0.8
5544    */
5545   obj_props[PROP_MIN_HEIGHT] =
5546     g_param_spec_float ("min-height",
5547                         P_("Min Height"),
5548                         P_("Forced minimum height request for the actor"),
5549                         0.0, G_MAXFLOAT,
5550                         0.0,
5551                         CLUTTER_PARAM_READWRITE);
5552
5553   /**
5554    * ClutterActor:natural-width:
5555    *
5556    * A forced natural width request for the actor, in pixels
5557    *
5558    * Writing this property sets the #ClutterActor:natural-width-set
5559    * property as well, as a side effect. This property overrides the
5560    * usual width request of the actor
5561    *
5562    * Since: 0.8
5563    */
5564   obj_props[PROP_NATURAL_WIDTH] =
5565     g_param_spec_float ("natural-width",
5566                         P_("Natural Width"),
5567                         P_("Forced natural width request for the actor"),
5568                         0.0, G_MAXFLOAT,
5569                         0.0,
5570                         CLUTTER_PARAM_READWRITE);
5571
5572   /**
5573    * ClutterActor:natural-height:
5574    *
5575    * A forced natural height request for the actor, in pixels
5576    *
5577    * Writing this property sets the #ClutterActor:natural-height-set
5578    * property as well, as a side effect. This property overrides the
5579    * usual height request of the actor
5580    *
5581    * Since: 0.8
5582    */
5583   obj_props[PROP_NATURAL_HEIGHT] =
5584     g_param_spec_float ("natural-height",
5585                         P_("Natural Height"),
5586                         P_("Forced natural height request for the actor"),
5587                         0.0, G_MAXFLOAT,
5588                         0.0,
5589                         CLUTTER_PARAM_READWRITE);
5590
5591   /**
5592    * ClutterActor:min-width-set:
5593    *
5594    * This flag controls whether the #ClutterActor:min-width property
5595    * is used
5596    *
5597    * Since: 0.8
5598    */
5599   obj_props[PROP_MIN_WIDTH_SET] =
5600     g_param_spec_boolean ("min-width-set",
5601                           P_("Minimum width set"),
5602                           P_("Whether to use the min-width property"),
5603                           FALSE,
5604                           CLUTTER_PARAM_READWRITE);
5605
5606   /**
5607    * ClutterActor:min-height-set:
5608    *
5609    * This flag controls whether the #ClutterActor:min-height property
5610    * is used
5611    *
5612    * Since: 0.8
5613    */
5614   obj_props[PROP_MIN_HEIGHT_SET] =
5615     g_param_spec_boolean ("min-height-set",
5616                           P_("Minimum height set"),
5617                           P_("Whether to use the min-height property"),
5618                           FALSE,
5619                           CLUTTER_PARAM_READWRITE);
5620
5621   /**
5622    * ClutterActor:natural-width-set:
5623    *
5624    * This flag controls whether the #ClutterActor:natural-width property
5625    * is used
5626    *
5627    * Since: 0.8
5628    */
5629   obj_props[PROP_NATURAL_WIDTH_SET] =
5630     g_param_spec_boolean ("natural-width-set",
5631                           P_("Natural width set"),
5632                           P_("Whether to use the natural-width property"),
5633                           FALSE,
5634                           CLUTTER_PARAM_READWRITE);
5635
5636   /**
5637    * ClutterActor:natural-height-set:
5638    *
5639    * This flag controls whether the #ClutterActor:natural-height property
5640    * is used
5641    *
5642    * Since: 0.8
5643    */
5644   obj_props[PROP_NATURAL_HEIGHT_SET] =
5645     g_param_spec_boolean ("natural-height-set",
5646                           P_("Natural height set"),
5647                           P_("Whether to use the natural-height property"),
5648                           FALSE,
5649                           CLUTTER_PARAM_READWRITE);
5650
5651   /**
5652    * ClutterActor:allocation:
5653    *
5654    * The allocation for the actor, in pixels
5655    *
5656    * This is property is read-only, but you might monitor it to know when an
5657    * actor moves or resizes
5658    *
5659    * Since: 0.8
5660    */
5661   obj_props[PROP_ALLOCATION] =
5662     g_param_spec_boxed ("allocation",
5663                         P_("Allocation"),
5664                         P_("The actor's allocation"),
5665                         CLUTTER_TYPE_ACTOR_BOX,
5666                         CLUTTER_PARAM_READABLE);
5667
5668   /**
5669    * ClutterActor:request-mode:
5670    *
5671    * Request mode for the #ClutterActor. The request mode determines the
5672    * type of geometry management used by the actor, either height for width
5673    * (the default) or width for height.
5674    *
5675    * For actors implementing height for width, the parent container should get
5676    * the preferred width first, and then the preferred height for that width.
5677    *
5678    * For actors implementing width for height, the parent container should get
5679    * the preferred height first, and then the preferred width for that height.
5680    *
5681    * For instance:
5682    *
5683    * |[
5684    *   ClutterRequestMode mode;
5685    *   gfloat natural_width, min_width;
5686    *   gfloat natural_height, min_height;
5687    *
5688    *   mode = clutter_actor_get_request_mode (child);
5689    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5690    *     {
5691    *       clutter_actor_get_preferred_width (child, -1,
5692    *                                          &amp;min_width,
5693    *                                          &amp;natural_width);
5694    *       clutter_actor_get_preferred_height (child, natural_width,
5695    *                                           &amp;min_height,
5696    *                                           &amp;natural_height);
5697    *     }
5698    *   else
5699    *     {
5700    *       clutter_actor_get_preferred_height (child, -1,
5701    *                                           &amp;min_height,
5702    *                                           &amp;natural_height);
5703    *       clutter_actor_get_preferred_width (child, natural_height,
5704    *                                          &amp;min_width,
5705    *                                          &amp;natural_width);
5706    *     }
5707    * ]|
5708    *
5709    * will retrieve the minimum and natural width and height depending on the
5710    * preferred request mode of the #ClutterActor "child".
5711    *
5712    * The clutter_actor_get_preferred_size() function will implement this
5713    * check for you.
5714    *
5715    * Since: 0.8
5716    */
5717   obj_props[PROP_REQUEST_MODE] =
5718     g_param_spec_enum ("request-mode",
5719                        P_("Request Mode"),
5720                        P_("The actor's request mode"),
5721                        CLUTTER_TYPE_REQUEST_MODE,
5722                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5723                        CLUTTER_PARAM_READWRITE);
5724
5725   /**
5726    * ClutterActor:depth:
5727    *
5728    * The position of the actor on the Z axis.
5729    *
5730    * The #ClutterActor:depth property is relative to the parent's
5731    * modelview matrix.
5732    *
5733    * The #ClutterActor:depth property is animatable.
5734    *
5735    * Since: 0.6
5736    */
5737   obj_props[PROP_DEPTH] =
5738     g_param_spec_float ("depth",
5739                         P_("Depth"),
5740                         P_("Position on the Z axis"),
5741                         -G_MAXFLOAT, G_MAXFLOAT,
5742                         0.0,
5743                         G_PARAM_READWRITE |
5744                         G_PARAM_STATIC_STRINGS |
5745                         CLUTTER_PARAM_ANIMATABLE);
5746
5747   /**
5748    * ClutterActor:opacity:
5749    *
5750    * Opacity of an actor, between 0 (fully transparent) and
5751    * 255 (fully opaque)
5752    *
5753    * The #ClutterActor:opacity property is animatable.
5754    */
5755   obj_props[PROP_OPACITY] =
5756     g_param_spec_uint ("opacity",
5757                        P_("Opacity"),
5758                        P_("Opacity of an actor"),
5759                        0, 255,
5760                        255,
5761                        G_PARAM_READWRITE |
5762                        G_PARAM_STATIC_STRINGS |
5763                        CLUTTER_PARAM_ANIMATABLE);
5764
5765   /**
5766    * ClutterActor:offscreen-redirect:
5767    *
5768    * Determines the conditions in which the actor will be redirected
5769    * to an offscreen framebuffer while being painted. For example this
5770    * can be used to cache an actor in a framebuffer or for improved
5771    * handling of transparent actors. See
5772    * clutter_actor_set_offscreen_redirect() for details.
5773    *
5774    * Since: 1.8
5775    */
5776   obj_props[PROP_OFFSCREEN_REDIRECT] =
5777     g_param_spec_flags ("offscreen-redirect",
5778                         P_("Offscreen redirect"),
5779                         P_("Flags controlling when to flatten the actor into a single image"),
5780                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5781                         0,
5782                         CLUTTER_PARAM_READWRITE);
5783
5784   /**
5785    * ClutterActor:visible:
5786    *
5787    * Whether the actor is set to be visible or not
5788    *
5789    * See also #ClutterActor:mapped
5790    */
5791   obj_props[PROP_VISIBLE] =
5792     g_param_spec_boolean ("visible",
5793                           P_("Visible"),
5794                           P_("Whether the actor is visible or not"),
5795                           FALSE,
5796                           CLUTTER_PARAM_READWRITE);
5797
5798   /**
5799    * ClutterActor:mapped:
5800    *
5801    * Whether the actor is mapped (will be painted when the stage
5802    * to which it belongs is mapped)
5803    *
5804    * Since: 1.0
5805    */
5806   obj_props[PROP_MAPPED] =
5807     g_param_spec_boolean ("mapped",
5808                           P_("Mapped"),
5809                           P_("Whether the actor will be painted"),
5810                           FALSE,
5811                           CLUTTER_PARAM_READABLE);
5812
5813   /**
5814    * ClutterActor:realized:
5815    *
5816    * Whether the actor has been realized
5817    *
5818    * Since: 1.0
5819    */
5820   obj_props[PROP_REALIZED] =
5821     g_param_spec_boolean ("realized",
5822                           P_("Realized"),
5823                           P_("Whether the actor has been realized"),
5824                           FALSE,
5825                           CLUTTER_PARAM_READABLE);
5826
5827   /**
5828    * ClutterActor:reactive:
5829    *
5830    * Whether the actor is reactive to events or not
5831    *
5832    * Only reactive actors will emit event-related signals
5833    *
5834    * Since: 0.6
5835    */
5836   obj_props[PROP_REACTIVE] =
5837     g_param_spec_boolean ("reactive",
5838                           P_("Reactive"),
5839                           P_("Whether the actor is reactive to events"),
5840                           FALSE,
5841                           CLUTTER_PARAM_READWRITE);
5842
5843   /**
5844    * ClutterActor:has-clip:
5845    *
5846    * Whether the actor has the #ClutterActor:clip property set or not
5847    */
5848   obj_props[PROP_HAS_CLIP] =
5849     g_param_spec_boolean ("has-clip",
5850                           P_("Has Clip"),
5851                           P_("Whether the actor has a clip set"),
5852                           FALSE,
5853                           CLUTTER_PARAM_READABLE);
5854
5855   /**
5856    * ClutterActor:clip:
5857    *
5858    * The clip region for the actor, in actor-relative coordinates
5859    *
5860    * Every part of the actor outside the clip region will not be
5861    * painted
5862    */
5863   obj_props[PROP_CLIP] =
5864     g_param_spec_boxed ("clip",
5865                         P_("Clip"),
5866                         P_("The clip region for the actor"),
5867                         CLUTTER_TYPE_GEOMETRY,
5868                         CLUTTER_PARAM_READWRITE);
5869
5870   /**
5871    * ClutterActor:name:
5872    *
5873    * The name of the actor
5874    *
5875    * Since: 0.2
5876    */
5877   obj_props[PROP_NAME] =
5878     g_param_spec_string ("name",
5879                          P_("Name"),
5880                          P_("Name of the actor"),
5881                          NULL,
5882                          CLUTTER_PARAM_READWRITE);
5883
5884   /**
5885    * ClutterActor:scale-x:
5886    *
5887    * The horizontal scale of the actor.
5888    *
5889    * The #ClutterActor:scale-x property is animatable.
5890    *
5891    * Since: 0.6
5892    */
5893   obj_props[PROP_SCALE_X] =
5894     g_param_spec_double ("scale-x",
5895                          P_("Scale X"),
5896                          P_("Scale factor on the X axis"),
5897                          0.0, G_MAXDOUBLE,
5898                          1.0,
5899                          G_PARAM_READWRITE |
5900                          G_PARAM_STATIC_STRINGS |
5901                          CLUTTER_PARAM_ANIMATABLE);
5902
5903   /**
5904    * ClutterActor:scale-y:
5905    *
5906    * The vertical scale of the actor.
5907    *
5908    * The #ClutterActor:scale-y property is animatable.
5909    *
5910    * Since: 0.6
5911    */
5912   obj_props[PROP_SCALE_Y] =
5913     g_param_spec_double ("scale-y",
5914                          P_("Scale Y"),
5915                          P_("Scale factor on the Y axis"),
5916                          0.0, G_MAXDOUBLE,
5917                          1.0,
5918                          G_PARAM_READWRITE |
5919                          G_PARAM_STATIC_STRINGS |
5920                          CLUTTER_PARAM_ANIMATABLE);
5921
5922   /**
5923    * ClutterActor:scale-center-x:
5924    *
5925    * The horizontal center point for scaling
5926    *
5927    * Since: 1.0
5928    */
5929   obj_props[PROP_SCALE_CENTER_X] =
5930     g_param_spec_float ("scale-center-x",
5931                         P_("Scale Center X"),
5932                         P_("Horizontal scale center"),
5933                         -G_MAXFLOAT, G_MAXFLOAT,
5934                         0.0,
5935                         CLUTTER_PARAM_READWRITE);
5936
5937   /**
5938    * ClutterActor:scale-center-y:
5939    *
5940    * The vertical center point for scaling
5941    *
5942    * Since: 1.0
5943    */
5944   obj_props[PROP_SCALE_CENTER_Y] =
5945     g_param_spec_float ("scale-center-y",
5946                         P_("Scale Center Y"),
5947                         P_("Vertical scale center"),
5948                         -G_MAXFLOAT, G_MAXFLOAT,
5949                         0.0,
5950                         CLUTTER_PARAM_READWRITE);
5951
5952   /**
5953    * ClutterActor:scale-gravity:
5954    *
5955    * The center point for scaling expressed as a #ClutterGravity
5956    *
5957    * Since: 1.0
5958    */
5959   obj_props[PROP_SCALE_GRAVITY] =
5960     g_param_spec_enum ("scale-gravity",
5961                        P_("Scale Gravity"),
5962                        P_("The center of scaling"),
5963                        CLUTTER_TYPE_GRAVITY,
5964                        CLUTTER_GRAVITY_NONE,
5965                        CLUTTER_PARAM_READWRITE);
5966
5967   /**
5968    * ClutterActor:rotation-angle-x:
5969    *
5970    * The rotation angle on the X axis.
5971    *
5972    * The #ClutterActor:rotation-angle-x property is animatable.
5973    *
5974    * Since: 0.6
5975    */
5976   obj_props[PROP_ROTATION_ANGLE_X] =
5977     g_param_spec_double ("rotation-angle-x",
5978                          P_("Rotation Angle X"),
5979                          P_("The rotation angle on the X axis"),
5980                          -G_MAXDOUBLE, G_MAXDOUBLE,
5981                          0.0,
5982                          G_PARAM_READWRITE |
5983                          G_PARAM_STATIC_STRINGS |
5984                          CLUTTER_PARAM_ANIMATABLE);
5985
5986   /**
5987    * ClutterActor:rotation-angle-y:
5988    *
5989    * The rotation angle on the Y axis
5990    *
5991    * The #ClutterActor:rotation-angle-y property is animatable.
5992    *
5993    * Since: 0.6
5994    */
5995   obj_props[PROP_ROTATION_ANGLE_Y] =
5996     g_param_spec_double ("rotation-angle-y",
5997                          P_("Rotation Angle Y"),
5998                          P_("The rotation angle on the Y axis"),
5999                          -G_MAXDOUBLE, G_MAXDOUBLE,
6000                          0.0,
6001                          G_PARAM_READWRITE |
6002                          G_PARAM_STATIC_STRINGS |
6003                          CLUTTER_PARAM_ANIMATABLE);
6004
6005   /**
6006    * ClutterActor:rotation-angle-z:
6007    *
6008    * The rotation angle on the Z axis
6009    *
6010    * The #ClutterActor:rotation-angle-z property is animatable.
6011    *
6012    * Since: 0.6
6013    */
6014   obj_props[PROP_ROTATION_ANGLE_Z] =
6015     g_param_spec_double ("rotation-angle-z",
6016                          P_("Rotation Angle Z"),
6017                          P_("The rotation angle on the Z axis"),
6018                          -G_MAXDOUBLE, G_MAXDOUBLE,
6019                          0.0,
6020                          G_PARAM_READWRITE |
6021                          G_PARAM_STATIC_STRINGS |
6022                          CLUTTER_PARAM_ANIMATABLE);
6023
6024   /**
6025    * ClutterActor:rotation-center-x:
6026    *
6027    * The rotation center on the X axis.
6028    *
6029    * Since: 0.6
6030    */
6031   obj_props[PROP_ROTATION_CENTER_X] =
6032     g_param_spec_boxed ("rotation-center-x",
6033                         P_("Rotation Center X"),
6034                         P_("The rotation center on the X axis"),
6035                         CLUTTER_TYPE_VERTEX,
6036                         CLUTTER_PARAM_READWRITE);
6037
6038   /**
6039    * ClutterActor:rotation-center-y:
6040    *
6041    * The rotation center on the Y axis.
6042    *
6043    * Since: 0.6
6044    */
6045   obj_props[PROP_ROTATION_CENTER_Y] =
6046     g_param_spec_boxed ("rotation-center-y",
6047                         P_("Rotation Center Y"),
6048                         P_("The rotation center on the Y axis"),
6049                         CLUTTER_TYPE_VERTEX,
6050                         CLUTTER_PARAM_READWRITE);
6051
6052   /**
6053    * ClutterActor:rotation-center-z:
6054    *
6055    * The rotation center on the Z axis.
6056    *
6057    * Since: 0.6
6058    */
6059   obj_props[PROP_ROTATION_CENTER_Z] =
6060     g_param_spec_boxed ("rotation-center-z",
6061                         P_("Rotation Center Z"),
6062                         P_("The rotation center on the Z axis"),
6063                         CLUTTER_TYPE_VERTEX,
6064                         CLUTTER_PARAM_READWRITE);
6065
6066   /**
6067    * ClutterActor:rotation-center-z-gravity:
6068    *
6069    * The rotation center on the Z axis expressed as a #ClutterGravity.
6070    *
6071    * Since: 1.0
6072    */
6073   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6074     g_param_spec_enum ("rotation-center-z-gravity",
6075                        P_("Rotation Center Z Gravity"),
6076                        P_("Center point for rotation around the Z axis"),
6077                        CLUTTER_TYPE_GRAVITY,
6078                        CLUTTER_GRAVITY_NONE,
6079                        CLUTTER_PARAM_READWRITE);
6080
6081   /**
6082    * ClutterActor:anchor-x:
6083    *
6084    * The X coordinate of an actor's anchor point, relative to
6085    * the actor coordinate space, in pixels
6086    *
6087    * Since: 0.8
6088    */
6089   obj_props[PROP_ANCHOR_X] =
6090     g_param_spec_float ("anchor-x",
6091                         P_("Anchor X"),
6092                         P_("X coordinate of the anchor point"),
6093                         -G_MAXFLOAT, G_MAXFLOAT,
6094                         0,
6095                         CLUTTER_PARAM_READWRITE);
6096
6097   /**
6098    * ClutterActor:anchor-y:
6099    *
6100    * The Y coordinate of an actor's anchor point, relative to
6101    * the actor coordinate space, in pixels
6102    *
6103    * Since: 0.8
6104    */
6105   obj_props[PROP_ANCHOR_Y] =
6106     g_param_spec_float ("anchor-y",
6107                         P_("Anchor Y"),
6108                         P_("Y coordinate of the anchor point"),
6109                         -G_MAXFLOAT, G_MAXFLOAT,
6110                         0,
6111                         CLUTTER_PARAM_READWRITE);
6112
6113   /**
6114    * ClutterActor:anchor-gravity:
6115    *
6116    * The anchor point expressed as a #ClutterGravity
6117    *
6118    * Since: 1.0
6119    */
6120   obj_props[PROP_ANCHOR_GRAVITY] =
6121     g_param_spec_enum ("anchor-gravity",
6122                        P_("Anchor Gravity"),
6123                        P_("The anchor point as a ClutterGravity"),
6124                        CLUTTER_TYPE_GRAVITY,
6125                        CLUTTER_GRAVITY_NONE,
6126                        CLUTTER_PARAM_READWRITE);
6127
6128   /**
6129    * ClutterActor:show-on-set-parent:
6130    *
6131    * If %TRUE, the actor is automatically shown when parented.
6132    *
6133    * Calling clutter_actor_hide() on an actor which has not been
6134    * parented will set this property to %FALSE as a side effect.
6135    *
6136    * Since: 0.8
6137    */
6138   obj_props[PROP_SHOW_ON_SET_PARENT] =
6139     g_param_spec_boolean ("show-on-set-parent",
6140                           P_("Show on set parent"),
6141                           P_("Whether the actor is shown when parented"),
6142                           TRUE,
6143                           CLUTTER_PARAM_READWRITE);
6144
6145   /**
6146    * ClutterActor:clip-to-allocation:
6147    *
6148    * Whether the clip region should track the allocated area
6149    * of the actor.
6150    *
6151    * This property is ignored if a clip area has been explicitly
6152    * set using clutter_actor_set_clip().
6153    *
6154    * Since: 1.0
6155    */
6156   obj_props[PROP_CLIP_TO_ALLOCATION] =
6157     g_param_spec_boolean ("clip-to-allocation",
6158                           P_("Clip to Allocation"),
6159                           P_("Sets the clip region to track the actor's allocation"),
6160                           FALSE,
6161                           CLUTTER_PARAM_READWRITE);
6162
6163   /**
6164    * ClutterActor:text-direction:
6165    *
6166    * The direction of the text inside a #ClutterActor.
6167    *
6168    * Since: 1.0
6169    */
6170   obj_props[PROP_TEXT_DIRECTION] =
6171     g_param_spec_enum ("text-direction",
6172                        P_("Text Direction"),
6173                        P_("Direction of the text"),
6174                        CLUTTER_TYPE_TEXT_DIRECTION,
6175                        CLUTTER_TEXT_DIRECTION_LTR,
6176                        CLUTTER_PARAM_READWRITE);
6177
6178   /**
6179    * ClutterActor:has-pointer:
6180    *
6181    * Whether the actor contains the pointer of a #ClutterInputDevice
6182    * or not.
6183    *
6184    * Since: 1.2
6185    */
6186   obj_props[PROP_HAS_POINTER] =
6187     g_param_spec_boolean ("has-pointer",
6188                           P_("Has Pointer"),
6189                           P_("Whether the actor contains the pointer of an input device"),
6190                           FALSE,
6191                           CLUTTER_PARAM_READABLE);
6192
6193   /**
6194    * ClutterActor:actions:
6195    *
6196    * Adds a #ClutterAction to the actor
6197    *
6198    * Since: 1.4
6199    */
6200   obj_props[PROP_ACTIONS] =
6201     g_param_spec_object ("actions",
6202                          P_("Actions"),
6203                          P_("Adds an action to the actor"),
6204                          CLUTTER_TYPE_ACTION,
6205                          CLUTTER_PARAM_WRITABLE);
6206
6207   /**
6208    * ClutterActor:constraints:
6209    *
6210    * Adds a #ClutterConstraint to the actor
6211    *
6212    * Since: 1.4
6213    */
6214   obj_props[PROP_CONSTRAINTS] =
6215     g_param_spec_object ("constraints",
6216                          P_("Constraints"),
6217                          P_("Adds a constraint to the actor"),
6218                          CLUTTER_TYPE_CONSTRAINT,
6219                          CLUTTER_PARAM_WRITABLE);
6220
6221   /**
6222    * ClutterActor:effect:
6223    *
6224    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6225    *
6226    * Since: 1.4
6227    */
6228   obj_props[PROP_EFFECT] =
6229     g_param_spec_object ("effect",
6230                          P_("Effect"),
6231                          P_("Add an effect to be applied on the actor"),
6232                          CLUTTER_TYPE_EFFECT,
6233                          CLUTTER_PARAM_WRITABLE);
6234
6235   /**
6236    * ClutterActor:layout-manager:
6237    *
6238    * A delegate object for controlling the layout of the children of
6239    * an actor.
6240    *
6241    * Since: 1.10
6242    */
6243   obj_props[PROP_LAYOUT_MANAGER] =
6244     g_param_spec_object ("layout-manager",
6245                          P_("Layout Manager"),
6246                          P_("The object controlling the layout of an actor's children"),
6247                          CLUTTER_TYPE_LAYOUT_MANAGER,
6248                          CLUTTER_PARAM_READWRITE);
6249
6250
6251   /**
6252    * ClutterActor:x-align:
6253    *
6254    * The alignment of an actor on the X axis, if the actor has been given
6255    * extra space for its allocation.
6256    *
6257    * Since: 1.10
6258    */
6259   obj_props[PROP_X_ALIGN] =
6260     g_param_spec_enum ("x-align",
6261                        P_("X Alignment"),
6262                        P_("The alignment of the actor on the X axis within its allocation"),
6263                        CLUTTER_TYPE_ACTOR_ALIGN,
6264                        CLUTTER_ACTOR_ALIGN_FILL,
6265                        CLUTTER_PARAM_READWRITE);
6266
6267   /**
6268    * ClutterActor:y-align:
6269    *
6270    * The alignment of an actor on the Y axis, if the actor has been given
6271    * extra space for its allocation.
6272    *
6273    * Since: 1.10
6274    */
6275   obj_props[PROP_Y_ALIGN] =
6276     g_param_spec_enum ("y-align",
6277                        P_("Y Alignment"),
6278                        P_("The alignment of the actor on the Y axis within its allocation"),
6279                        CLUTTER_TYPE_ACTOR_ALIGN,
6280                        CLUTTER_ACTOR_ALIGN_FILL,
6281                        CLUTTER_PARAM_READWRITE);
6282
6283   /**
6284    * ClutterActor:margin-top:
6285    *
6286    * The margin (in pixels) from the top of the actor.
6287    *
6288    * This property adds a margin to the actor's preferred size; the margin
6289    * will be automatically taken into account when allocating the actor.
6290    *
6291    * Since: 1.10
6292    */
6293   obj_props[PROP_MARGIN_TOP] =
6294     g_param_spec_float ("margin-top",
6295                         P_("Margin Top"),
6296                         P_("Extra space at the top"),
6297                         0.0, G_MAXFLOAT,
6298                         0.0,
6299                         CLUTTER_PARAM_READWRITE);
6300
6301   /**
6302    * ClutterActor:margin-bottom:
6303    *
6304    * The margin (in pixels) from the bottom of the actor.
6305    *
6306    * This property adds a margin to the actor's preferred size; the margin
6307    * will be automatically taken into account when allocating the actor.
6308    *
6309    * Since: 1.10
6310    */
6311   obj_props[PROP_MARGIN_BOTTOM] =
6312     g_param_spec_float ("margin-bottom",
6313                         P_("Margin Bottom"),
6314                         P_("Extra space at the bottom"),
6315                         0.0, G_MAXFLOAT,
6316                         0.0,
6317                         CLUTTER_PARAM_READWRITE);
6318
6319   /**
6320    * ClutterActor:margin-left:
6321    *
6322    * The margin (in pixels) from the left of the actor.
6323    *
6324    * This property adds a margin to the actor's preferred size; the margin
6325    * will be automatically taken into account when allocating the actor.
6326    *
6327    * Since: 1.10
6328    */
6329   obj_props[PROP_MARGIN_LEFT] =
6330     g_param_spec_float ("margin-left",
6331                         P_("Margin Left"),
6332                         P_("Extra space at the left"),
6333                         0.0, G_MAXFLOAT,
6334                         0.0,
6335                         CLUTTER_PARAM_READWRITE);
6336
6337   /**
6338    * ClutterActor:margin-right:
6339    *
6340    * The margin (in pixels) from the right of the actor.
6341    *
6342    * This property adds a margin to the actor's preferred size; the margin
6343    * will be automatically taken into account when allocating the actor.
6344    *
6345    * Since: 1.10
6346    */
6347   obj_props[PROP_MARGIN_RIGHT] =
6348     g_param_spec_float ("margin-right",
6349                         P_("Margin Right"),
6350                         P_("Extra space at the right"),
6351                         0.0, G_MAXFLOAT,
6352                         0.0,
6353                         CLUTTER_PARAM_READWRITE);
6354
6355   /**
6356    * ClutterActor:background-color-set:
6357    *
6358    * Whether the #ClutterActor:background-color property has been set.
6359    *
6360    * Since: 1.10
6361    */
6362   obj_props[PROP_BACKGROUND_COLOR_SET] =
6363     g_param_spec_boolean ("background-color-set",
6364                           P_("Background Color Set"),
6365                           P_("Whether the background color is set"),
6366                           FALSE,
6367                           CLUTTER_PARAM_READABLE);
6368
6369   /**
6370    * ClutterActor:background-color:
6371    *
6372    * Paints a solid fill of the actor's allocation using the specified
6373    * color.
6374    *
6375    * The #ClutterActor:background-color property is animatable.
6376    *
6377    * Since: 1.10
6378    */
6379   obj_props[PROP_BACKGROUND_COLOR] =
6380     clutter_param_spec_color ("background-color",
6381                               P_("Background color"),
6382                               P_("The actor's background color"),
6383                               CLUTTER_COLOR_Transparent,
6384                               G_PARAM_READWRITE |
6385                               G_PARAM_STATIC_STRINGS |
6386                               CLUTTER_PARAM_ANIMATABLE);
6387
6388   /**
6389    * ClutterActor:first-child:
6390    *
6391    * The actor's first child.
6392    *
6393    * Since: 1.10
6394    */
6395   obj_props[PROP_FIRST_CHILD] =
6396     g_param_spec_object ("first-child",
6397                          P_("First Child"),
6398                          P_("The actor's first child"),
6399                          CLUTTER_TYPE_ACTOR,
6400                          CLUTTER_PARAM_READABLE);
6401
6402   /**
6403    * ClutterActor:last-child:
6404    *
6405    * The actor's last child.
6406    *
6407    * Since: 1.10
6408    */
6409   obj_props[PROP_LAST_CHILD] =
6410     g_param_spec_object ("last-child",
6411                          P_("Last Child"),
6412                          P_("The actor's last child"),
6413                          CLUTTER_TYPE_ACTOR,
6414                          CLUTTER_PARAM_READABLE);
6415
6416   /**
6417    * ClutterActor:content:
6418    *
6419    * The #ClutterContent implementation that controls the content
6420    * of the actor.
6421    *
6422    * Since: 1.10
6423    */
6424   obj_props[PROP_CONTENT] =
6425     g_param_spec_object ("content",
6426                          P_("Content"),
6427                          P_("Delegate object for painting the actor's content"),
6428                          CLUTTER_TYPE_CONTENT,
6429                          CLUTTER_PARAM_READWRITE);
6430
6431   /**
6432    * ClutterActor:content-gravity:
6433    *
6434    * The alignment that should be honoured by the #ClutterContent
6435    * set with the #ClutterActor:content property.
6436    *
6437    * Changing the value of this property will change the bounding box of
6438    * the content; you can use the #ClutterActor:content-box property to
6439    * get the position and size of the content within the actor's
6440    * allocation.
6441    *
6442    * This property is meaningful only for #ClutterContent implementations
6443    * that have a preferred size, and if the preferred size is smaller than
6444    * the actor's allocation.
6445    *
6446    * Since: 1.10
6447    */
6448   obj_props[PROP_CONTENT_GRAVITY] =
6449     g_param_spec_enum ("content-gravity",
6450                        P_("Content Gravity"),
6451                        P_("Alignment of the actor's content"),
6452                        CLUTTER_TYPE_CONTENT_GRAVITY,
6453                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6454                        CLUTTER_PARAM_READWRITE);
6455
6456   /**
6457    * ClutterActor:content-box:
6458    *
6459    * The bounding box for the #ClutterContent used by the actor.
6460    *
6461    * The value of this property is controlled by the #ClutterActor:allocation
6462    * and #ClutterActor:content-gravity properties of #ClutterActor.
6463    *
6464    * The bounding box for the content is guaranteed to never exceed the
6465    * allocation's of the actor.
6466    *
6467    * Since: 1.10
6468    */
6469   obj_props[PROP_CONTENT_BOX] =
6470     g_param_spec_boxed ("content-box",
6471                         P_("Content Box"),
6472                         P_("The bounding box of the actor's content"),
6473                         CLUTTER_TYPE_ACTOR_BOX,
6474                         CLUTTER_PARAM_READABLE);
6475
6476   obj_props[PROP_MINIFICATION_FILTER] =
6477     g_param_spec_enum ("minification-filter",
6478                        P_("Minification Filter"),
6479                        P_("The filter used when reducing the size of the content"),
6480                        CLUTTER_TYPE_SCALING_FILTER,
6481                        CLUTTER_SCALING_FILTER_LINEAR,
6482                        CLUTTER_PARAM_READWRITE);
6483
6484   obj_props[PROP_MAGNIFICATION_FILTER] =
6485     g_param_spec_enum ("magnification-filter",
6486                        P_("Magnification Filter"),
6487                        P_("The filter used when increasing the size of the content"),
6488                        CLUTTER_TYPE_SCALING_FILTER,
6489                        CLUTTER_SCALING_FILTER_LINEAR,
6490                        CLUTTER_PARAM_READWRITE);
6491
6492   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6493
6494   /**
6495    * ClutterActor::destroy:
6496    * @actor: the #ClutterActor which emitted the signal
6497    *
6498    * The ::destroy signal notifies that all references held on the
6499    * actor which emitted it should be released.
6500    *
6501    * The ::destroy signal should be used by all holders of a reference
6502    * on @actor.
6503    *
6504    * This signal might result in the finalization of the #ClutterActor
6505    * if all references are released.
6506    *
6507    * Composite actors and actors implementing the #ClutterContainer
6508    * interface should override the default implementation of the
6509    * class handler of this signal and call clutter_actor_destroy() on
6510    * their children. When overriding the default class handler, it is
6511    * required to chain up to the parent's implementation.
6512    *
6513    * Since: 0.2
6514    */
6515   actor_signals[DESTROY] =
6516     g_signal_new (I_("destroy"),
6517                   G_TYPE_FROM_CLASS (object_class),
6518                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6519                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6520                   NULL, NULL,
6521                   _clutter_marshal_VOID__VOID,
6522                   G_TYPE_NONE, 0);
6523   /**
6524    * ClutterActor::show:
6525    * @actor: the object which received the signal
6526    *
6527    * The ::show signal is emitted when an actor is visible and
6528    * rendered on the stage.
6529    *
6530    * Since: 0.2
6531    */
6532   actor_signals[SHOW] =
6533     g_signal_new (I_("show"),
6534                   G_TYPE_FROM_CLASS (object_class),
6535                   G_SIGNAL_RUN_FIRST,
6536                   G_STRUCT_OFFSET (ClutterActorClass, show),
6537                   NULL, NULL,
6538                   _clutter_marshal_VOID__VOID,
6539                   G_TYPE_NONE, 0);
6540   /**
6541    * ClutterActor::hide:
6542    * @actor: the object which received the signal
6543    *
6544    * The ::hide signal is emitted when an actor is no longer rendered
6545    * on the stage.
6546    *
6547    * Since: 0.2
6548    */
6549   actor_signals[HIDE] =
6550     g_signal_new (I_("hide"),
6551                   G_TYPE_FROM_CLASS (object_class),
6552                   G_SIGNAL_RUN_FIRST,
6553                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6554                   NULL, NULL,
6555                   _clutter_marshal_VOID__VOID,
6556                   G_TYPE_NONE, 0);
6557   /**
6558    * ClutterActor::parent-set:
6559    * @actor: the object which received the signal
6560    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6561    *
6562    * This signal is emitted when the parent of the actor changes.
6563    *
6564    * Since: 0.2
6565    */
6566   actor_signals[PARENT_SET] =
6567     g_signal_new (I_("parent-set"),
6568                   G_TYPE_FROM_CLASS (object_class),
6569                   G_SIGNAL_RUN_LAST,
6570                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6571                   NULL, NULL,
6572                   _clutter_marshal_VOID__OBJECT,
6573                   G_TYPE_NONE, 1,
6574                   CLUTTER_TYPE_ACTOR);
6575
6576   /**
6577    * ClutterActor::queue-redraw:
6578    * @actor: the actor we're bubbling the redraw request through
6579    * @origin: the actor which initiated the redraw request
6580    *
6581    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6582    * is called on @origin.
6583    *
6584    * The default implementation for #ClutterActor chains up to the
6585    * parent actor and queues a redraw on the parent, thus "bubbling"
6586    * the redraw queue up through the actor graph. The default
6587    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6588    * in a main loop idle handler.
6589    *
6590    * Note that the @origin actor may be the stage, or a container; it
6591    * does not have to be a leaf node in the actor graph.
6592    *
6593    * Toolkits embedding a #ClutterStage which require a redraw and
6594    * relayout cycle can stop the emission of this signal using the
6595    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6596    * themselves, like:
6597    *
6598    * |[
6599    *   static void
6600    *   on_redraw_complete (gpointer data)
6601    *   {
6602    *     ClutterStage *stage = data;
6603    *
6604    *     /&ast; execute the Clutter drawing pipeline &ast;/
6605    *     clutter_stage_ensure_redraw (stage);
6606    *   }
6607    *
6608    *   static void
6609    *   on_stage_queue_redraw (ClutterStage *stage)
6610    *   {
6611    *     /&ast; this prevents the default handler to run &ast;/
6612    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6613    *
6614    *     /&ast; queue a redraw with the host toolkit and call
6615    *      &ast; a function when the redraw has been completed
6616    *      &ast;/
6617    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6618    *   }
6619    * ]|
6620    *
6621    * <note><para>This signal is emitted before the Clutter paint
6622    * pipeline is executed. If you want to know when the pipeline has
6623    * been completed you should connect to the ::paint signal on the
6624    * Stage with g_signal_connect_after().</para></note>
6625    *
6626    * Since: 1.0
6627    */
6628   actor_signals[QUEUE_REDRAW] =
6629     g_signal_new (I_("queue-redraw"),
6630                   G_TYPE_FROM_CLASS (object_class),
6631                   G_SIGNAL_RUN_LAST |
6632                   G_SIGNAL_NO_HOOKS,
6633                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6634                   NULL, NULL,
6635                   _clutter_marshal_VOID__OBJECT,
6636                   G_TYPE_NONE, 1,
6637                   CLUTTER_TYPE_ACTOR);
6638
6639   /**
6640    * ClutterActor::queue-relayout
6641    * @actor: the actor being queued for relayout
6642    *
6643    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6644    * is called on an actor.
6645    *
6646    * The default implementation for #ClutterActor chains up to the
6647    * parent actor and queues a relayout on the parent, thus "bubbling"
6648    * the relayout queue up through the actor graph.
6649    *
6650    * The main purpose of this signal is to allow relayout to be propagated
6651    * properly in the procense of #ClutterClone actors. Applications will
6652    * not normally need to connect to this signal.
6653    *
6654    * Since: 1.2
6655    */
6656   actor_signals[QUEUE_RELAYOUT] =
6657     g_signal_new (I_("queue-relayout"),
6658                   G_TYPE_FROM_CLASS (object_class),
6659                   G_SIGNAL_RUN_LAST |
6660                   G_SIGNAL_NO_HOOKS,
6661                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6662                   NULL, NULL,
6663                   _clutter_marshal_VOID__VOID,
6664                   G_TYPE_NONE, 0);
6665
6666   /**
6667    * ClutterActor::event:
6668    * @actor: the actor which received the event
6669    * @event: a #ClutterEvent
6670    *
6671    * The ::event signal is emitted each time an event is received
6672    * by the @actor. This signal will be emitted on every actor,
6673    * following the hierarchy chain, until it reaches the top-level
6674    * container (the #ClutterStage).
6675    *
6676    * Return value: %TRUE if the event has been handled by the actor,
6677    *   or %FALSE to continue the emission.
6678    *
6679    * Since: 0.6
6680    */
6681   actor_signals[EVENT] =
6682     g_signal_new (I_("event"),
6683                   G_TYPE_FROM_CLASS (object_class),
6684                   G_SIGNAL_RUN_LAST,
6685                   G_STRUCT_OFFSET (ClutterActorClass, event),
6686                   _clutter_boolean_handled_accumulator, NULL,
6687                   _clutter_marshal_BOOLEAN__BOXED,
6688                   G_TYPE_BOOLEAN, 1,
6689                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6690   /**
6691    * ClutterActor::button-press-event:
6692    * @actor: the actor which received the event
6693    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6694    *
6695    * The ::button-press-event signal is emitted each time a mouse button
6696    * is pressed on @actor.
6697    *
6698    * Return value: %TRUE if the event has been handled by the actor,
6699    *   or %FALSE to continue the emission.
6700    *
6701    * Since: 0.6
6702    */
6703   actor_signals[BUTTON_PRESS_EVENT] =
6704     g_signal_new (I_("button-press-event"),
6705                   G_TYPE_FROM_CLASS (object_class),
6706                   G_SIGNAL_RUN_LAST,
6707                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6708                   _clutter_boolean_handled_accumulator, NULL,
6709                   _clutter_marshal_BOOLEAN__BOXED,
6710                   G_TYPE_BOOLEAN, 1,
6711                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6712   /**
6713    * ClutterActor::button-release-event:
6714    * @actor: the actor which received the event
6715    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6716    *
6717    * The ::button-release-event signal is emitted each time a mouse button
6718    * is released on @actor.
6719    *
6720    * Return value: %TRUE if the event has been handled by the actor,
6721    *   or %FALSE to continue the emission.
6722    *
6723    * Since: 0.6
6724    */
6725   actor_signals[BUTTON_RELEASE_EVENT] =
6726     g_signal_new (I_("button-release-event"),
6727                   G_TYPE_FROM_CLASS (object_class),
6728                   G_SIGNAL_RUN_LAST,
6729                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6730                   _clutter_boolean_handled_accumulator, NULL,
6731                   _clutter_marshal_BOOLEAN__BOXED,
6732                   G_TYPE_BOOLEAN, 1,
6733                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6734   /**
6735    * ClutterActor::scroll-event:
6736    * @actor: the actor which received the event
6737    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6738    *
6739    * The ::scroll-event signal is emitted each time the mouse is
6740    * scrolled on @actor
6741    *
6742    * Return value: %TRUE if the event has been handled by the actor,
6743    *   or %FALSE to continue the emission.
6744    *
6745    * Since: 0.6
6746    */
6747   actor_signals[SCROLL_EVENT] =
6748     g_signal_new (I_("scroll-event"),
6749                   G_TYPE_FROM_CLASS (object_class),
6750                   G_SIGNAL_RUN_LAST,
6751                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6752                   _clutter_boolean_handled_accumulator, NULL,
6753                   _clutter_marshal_BOOLEAN__BOXED,
6754                   G_TYPE_BOOLEAN, 1,
6755                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6756   /**
6757    * ClutterActor::key-press-event:
6758    * @actor: the actor which received the event
6759    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6760    *
6761    * The ::key-press-event signal is emitted each time a keyboard button
6762    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6763    *
6764    * Return value: %TRUE if the event has been handled by the actor,
6765    *   or %FALSE to continue the emission.
6766    *
6767    * Since: 0.6
6768    */
6769   actor_signals[KEY_PRESS_EVENT] =
6770     g_signal_new (I_("key-press-event"),
6771                   G_TYPE_FROM_CLASS (object_class),
6772                   G_SIGNAL_RUN_LAST,
6773                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6774                   _clutter_boolean_handled_accumulator, NULL,
6775                   _clutter_marshal_BOOLEAN__BOXED,
6776                   G_TYPE_BOOLEAN, 1,
6777                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6778   /**
6779    * ClutterActor::key-release-event:
6780    * @actor: the actor which received the event
6781    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6782    *
6783    * The ::key-release-event signal is emitted each time a keyboard button
6784    * is released while @actor has key focus (see
6785    * clutter_stage_set_key_focus()).
6786    *
6787    * Return value: %TRUE if the event has been handled by the actor,
6788    *   or %FALSE to continue the emission.
6789    *
6790    * Since: 0.6
6791    */
6792   actor_signals[KEY_RELEASE_EVENT] =
6793     g_signal_new (I_("key-release-event"),
6794                   G_TYPE_FROM_CLASS (object_class),
6795                   G_SIGNAL_RUN_LAST,
6796                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6797                   _clutter_boolean_handled_accumulator, NULL,
6798                   _clutter_marshal_BOOLEAN__BOXED,
6799                   G_TYPE_BOOLEAN, 1,
6800                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6801   /**
6802    * ClutterActor::motion-event:
6803    * @actor: the actor which received the event
6804    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6805    *
6806    * The ::motion-event signal is emitted each time the mouse pointer is
6807    * moved over @actor.
6808    *
6809    * Return value: %TRUE if the event has been handled by the actor,
6810    *   or %FALSE to continue the emission.
6811    *
6812    * Since: 0.6
6813    */
6814   actor_signals[MOTION_EVENT] =
6815     g_signal_new (I_("motion-event"),
6816                   G_TYPE_FROM_CLASS (object_class),
6817                   G_SIGNAL_RUN_LAST,
6818                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6819                   _clutter_boolean_handled_accumulator, NULL,
6820                   _clutter_marshal_BOOLEAN__BOXED,
6821                   G_TYPE_BOOLEAN, 1,
6822                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6823
6824   /**
6825    * ClutterActor::key-focus-in:
6826    * @actor: the actor which now has key focus
6827    *
6828    * The ::key-focus-in signal is emitted when @actor receives key focus.
6829    *
6830    * Since: 0.6
6831    */
6832   actor_signals[KEY_FOCUS_IN] =
6833     g_signal_new (I_("key-focus-in"),
6834                   G_TYPE_FROM_CLASS (object_class),
6835                   G_SIGNAL_RUN_LAST,
6836                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6837                   NULL, NULL,
6838                   _clutter_marshal_VOID__VOID,
6839                   G_TYPE_NONE, 0);
6840
6841   /**
6842    * ClutterActor::key-focus-out:
6843    * @actor: the actor which now has key focus
6844    *
6845    * The ::key-focus-out signal is emitted when @actor loses key focus.
6846    *
6847    * Since: 0.6
6848    */
6849   actor_signals[KEY_FOCUS_OUT] =
6850     g_signal_new (I_("key-focus-out"),
6851                   G_TYPE_FROM_CLASS (object_class),
6852                   G_SIGNAL_RUN_LAST,
6853                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6854                   NULL, NULL,
6855                   _clutter_marshal_VOID__VOID,
6856                   G_TYPE_NONE, 0);
6857
6858   /**
6859    * ClutterActor::enter-event:
6860    * @actor: the actor which the pointer has entered.
6861    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6862    *
6863    * The ::enter-event signal is emitted when the pointer enters the @actor
6864    *
6865    * Return value: %TRUE if the event has been handled by the actor,
6866    *   or %FALSE to continue the emission.
6867    *
6868    * Since: 0.6
6869    */
6870   actor_signals[ENTER_EVENT] =
6871     g_signal_new (I_("enter-event"),
6872                   G_TYPE_FROM_CLASS (object_class),
6873                   G_SIGNAL_RUN_LAST,
6874                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6875                   _clutter_boolean_handled_accumulator, NULL,
6876                   _clutter_marshal_BOOLEAN__BOXED,
6877                   G_TYPE_BOOLEAN, 1,
6878                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6879
6880   /**
6881    * ClutterActor::leave-event:
6882    * @actor: the actor which the pointer has left
6883    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6884    *
6885    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6886    *
6887    * Return value: %TRUE if the event has been handled by the actor,
6888    *   or %FALSE to continue the emission.
6889    *
6890    * Since: 0.6
6891    */
6892   actor_signals[LEAVE_EVENT] =
6893     g_signal_new (I_("leave-event"),
6894                   G_TYPE_FROM_CLASS (object_class),
6895                   G_SIGNAL_RUN_LAST,
6896                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6897                   _clutter_boolean_handled_accumulator, NULL,
6898                   _clutter_marshal_BOOLEAN__BOXED,
6899                   G_TYPE_BOOLEAN, 1,
6900                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6901
6902   /**
6903    * ClutterActor::captured-event:
6904    * @actor: the actor which received the signal
6905    * @event: a #ClutterEvent
6906    *
6907    * The ::captured-event signal is emitted when an event is captured
6908    * by Clutter. This signal will be emitted starting from the top-level
6909    * container (the #ClutterStage) to the actor which received the event
6910    * going down the hierarchy. This signal can be used to intercept every
6911    * event before the specialized events (like
6912    * ClutterActor::button-press-event or ::key-released-event) are
6913    * emitted.
6914    *
6915    * Return value: %TRUE if the event has been handled by the actor,
6916    *   or %FALSE to continue the emission.
6917    *
6918    * Since: 0.6
6919    */
6920   actor_signals[CAPTURED_EVENT] =
6921     g_signal_new (I_("captured-event"),
6922                   G_TYPE_FROM_CLASS (object_class),
6923                   G_SIGNAL_RUN_LAST,
6924                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6925                   _clutter_boolean_handled_accumulator, NULL,
6926                   _clutter_marshal_BOOLEAN__BOXED,
6927                   G_TYPE_BOOLEAN, 1,
6928                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6929
6930   /**
6931    * ClutterActor::paint:
6932    * @actor: the #ClutterActor that received the signal
6933    *
6934    * The ::paint signal is emitted each time an actor is being painted.
6935    *
6936    * Subclasses of #ClutterActor should override the class signal handler
6937    * and paint themselves in that function.
6938    *
6939    * It is possible to connect a handler to the ::paint signal in order
6940    * to set up some custom aspect of a paint.
6941    *
6942    * Since: 0.8
6943    */
6944   actor_signals[PAINT] =
6945     g_signal_new (I_("paint"),
6946                   G_TYPE_FROM_CLASS (object_class),
6947                   G_SIGNAL_RUN_LAST |
6948                   G_SIGNAL_NO_HOOKS,
6949                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6950                   NULL, NULL,
6951                   _clutter_marshal_VOID__VOID,
6952                   G_TYPE_NONE, 0);
6953   /**
6954    * ClutterActor::realize:
6955    * @actor: the #ClutterActor that received the signal
6956    *
6957    * The ::realize signal is emitted each time an actor is being
6958    * realized.
6959    *
6960    * Since: 0.8
6961    */
6962   actor_signals[REALIZE] =
6963     g_signal_new (I_("realize"),
6964                   G_TYPE_FROM_CLASS (object_class),
6965                   G_SIGNAL_RUN_LAST,
6966                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6967                   NULL, NULL,
6968                   _clutter_marshal_VOID__VOID,
6969                   G_TYPE_NONE, 0);
6970   /**
6971    * ClutterActor::unrealize:
6972    * @actor: the #ClutterActor that received the signal
6973    *
6974    * The ::unrealize signal is emitted each time an actor is being
6975    * unrealized.
6976    *
6977    * Since: 0.8
6978    */
6979   actor_signals[UNREALIZE] =
6980     g_signal_new (I_("unrealize"),
6981                   G_TYPE_FROM_CLASS (object_class),
6982                   G_SIGNAL_RUN_LAST,
6983                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6984                   NULL, NULL,
6985                   _clutter_marshal_VOID__VOID,
6986                   G_TYPE_NONE, 0);
6987
6988   /**
6989    * ClutterActor::pick:
6990    * @actor: the #ClutterActor that received the signal
6991    * @color: the #ClutterColor to be used when picking
6992    *
6993    * The ::pick signal is emitted each time an actor is being painted
6994    * in "pick mode". The pick mode is used to identify the actor during
6995    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6996    * The actor should paint its shape using the passed @pick_color.
6997    *
6998    * Subclasses of #ClutterActor should override the class signal handler
6999    * and paint themselves in that function.
7000    *
7001    * It is possible to connect a handler to the ::pick signal in order
7002    * to set up some custom aspect of a paint in pick mode.
7003    *
7004    * Since: 1.0
7005    */
7006   actor_signals[PICK] =
7007     g_signal_new (I_("pick"),
7008                   G_TYPE_FROM_CLASS (object_class),
7009                   G_SIGNAL_RUN_LAST,
7010                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7011                   NULL, NULL,
7012                   _clutter_marshal_VOID__BOXED,
7013                   G_TYPE_NONE, 1,
7014                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7015
7016   /**
7017    * ClutterActor::allocation-changed:
7018    * @actor: the #ClutterActor that emitted the signal
7019    * @box: a #ClutterActorBox with the new allocation
7020    * @flags: #ClutterAllocationFlags for the allocation
7021    *
7022    * The ::allocation-changed signal is emitted when the
7023    * #ClutterActor:allocation property changes. Usually, application
7024    * code should just use the notifications for the :allocation property
7025    * but if you want to track the allocation flags as well, for instance
7026    * to know whether the absolute origin of @actor changed, then you might
7027    * want use this signal instead.
7028    *
7029    * Since: 1.0
7030    */
7031   actor_signals[ALLOCATION_CHANGED] =
7032     g_signal_new (I_("allocation-changed"),
7033                   G_TYPE_FROM_CLASS (object_class),
7034                   G_SIGNAL_RUN_LAST,
7035                   0,
7036                   NULL, NULL,
7037                   _clutter_marshal_VOID__BOXED_FLAGS,
7038                   G_TYPE_NONE, 2,
7039                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7040                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7041
7042   /**
7043    * ClutterActor::transitions-completed:
7044    * @actor: a #ClutterActor
7045    *
7046    * The ::transitions-completed signal is emitted once all transitions
7047    * involving @actor are complete.
7048    *
7049    * Since: 1.10
7050    */
7051   actor_signals[TRANSITIONS_COMPLETED] =
7052     g_signal_new (I_("transitions-completed"),
7053                   G_TYPE_FROM_CLASS (object_class),
7054                   G_SIGNAL_RUN_LAST,
7055                   0,
7056                   NULL, NULL,
7057                   _clutter_marshal_VOID__VOID,
7058                   G_TYPE_NONE, 0);
7059 }
7060
7061 static void
7062 clutter_actor_init (ClutterActor *self)
7063 {
7064   ClutterActorPrivate *priv;
7065
7066   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7067
7068   priv->id = _clutter_context_acquire_id (self);
7069   priv->pick_id = -1;
7070
7071   priv->opacity = 0xff;
7072   priv->show_on_set_parent = TRUE;
7073
7074   priv->needs_width_request = TRUE;
7075   priv->needs_height_request = TRUE;
7076   priv->needs_allocation = TRUE;
7077
7078   priv->cached_width_age = 1;
7079   priv->cached_height_age = 1;
7080
7081   priv->opacity_override = -1;
7082   priv->enable_model_view_transform = TRUE;
7083
7084   /* Initialize an empty paint volume to start with */
7085   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7086   priv->last_paint_volume_valid = TRUE;
7087
7088   priv->transform_valid = FALSE;
7089
7090   /* the default is to stretch the content, to match the
7091    * current behaviour of basically all actors. also, it's
7092    * the easiest thing to compute.
7093    */
7094   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7095   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7096   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7097 }
7098
7099 /**
7100  * clutter_actor_new:
7101  *
7102  * Creates a new #ClutterActor.
7103  *
7104  * A newly created actor has a floating reference, which will be sunk
7105  * when it is added to another actor.
7106  *
7107  * Return value: (transfer full): the newly created #ClutterActor
7108  *
7109  * Since: 1.10
7110  */
7111 ClutterActor *
7112 clutter_actor_new (void)
7113 {
7114   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7115 }
7116
7117 /**
7118  * clutter_actor_destroy:
7119  * @self: a #ClutterActor
7120  *
7121  * Destroys an actor.  When an actor is destroyed, it will break any
7122  * references it holds to other objects.  If the actor is inside a
7123  * container, the actor will be removed.
7124  *
7125  * When you destroy a container, its children will be destroyed as well.
7126  *
7127  * Note: you cannot destroy the #ClutterStage returned by
7128  * clutter_stage_get_default().
7129  */
7130 void
7131 clutter_actor_destroy (ClutterActor *self)
7132 {
7133   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7134
7135   g_object_ref (self);
7136
7137   /* avoid recursion while destroying */
7138   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7139     {
7140       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7141
7142       g_object_run_dispose (G_OBJECT (self));
7143
7144       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7145     }
7146
7147   g_object_unref (self);
7148 }
7149
7150 void
7151 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7152                                     ClutterPaintVolume *clip)
7153 {
7154   ClutterActorPrivate *priv = self->priv;
7155   ClutterPaintVolume *pv;
7156   gboolean clipped;
7157
7158   /* Remove queue entry early in the process, otherwise a new
7159      queue_redraw() during signal handling could put back this
7160      object in the stage redraw list (but the entry is freed as
7161      soon as we return from this function, causing a segfault
7162      later)
7163   */
7164   priv->queue_redraw_entry = NULL;
7165
7166   /* If we've been explicitly passed a clip volume then there's
7167    * nothing more to calculate, but otherwise the only thing we know
7168    * is that the change is constrained to the given actor.
7169    *
7170    * The idea is that if we know the paint volume for where the actor
7171    * was last drawn (in eye coordinates) and we also have the paint
7172    * volume for where it will be drawn next (in actor coordinates)
7173    * then if we queue a redraw for both these volumes that will cover
7174    * everything that needs to be redrawn to clear the old view and
7175    * show the latest view of the actor.
7176    *
7177    * Don't clip this redraw if we don't know what position we had for
7178    * the previous redraw since we don't know where to set the clip so
7179    * it will clear the actor as it is currently.
7180    */
7181   if (clip)
7182     {
7183       _clutter_actor_set_queue_redraw_clip (self, clip);
7184       clipped = TRUE;
7185     }
7186   else if (G_LIKELY (priv->last_paint_volume_valid))
7187     {
7188       pv = _clutter_actor_get_paint_volume_mutable (self);
7189       if (pv)
7190         {
7191           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7192
7193           /* make sure we redraw the actors old position... */
7194           _clutter_actor_set_queue_redraw_clip (stage,
7195                                                 &priv->last_paint_volume);
7196           _clutter_actor_signal_queue_redraw (stage, stage);
7197           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7198
7199           /* XXX: Ideally the redraw signal would take a clip volume
7200            * argument, but that would be an ABI break. Until we can
7201            * break the ABI we pass the argument out-of-band
7202            */
7203
7204           /* setup the clip for the actors new position... */
7205           _clutter_actor_set_queue_redraw_clip (self, pv);
7206           clipped = TRUE;
7207         }
7208       else
7209         clipped = FALSE;
7210     }
7211   else
7212     clipped = FALSE;
7213
7214   _clutter_actor_signal_queue_redraw (self, self);
7215
7216   /* Just in case anyone is manually firing redraw signals without
7217    * using the public queue_redraw() API we are careful to ensure that
7218    * our out-of-band clip member is cleared before returning...
7219    *
7220    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7221    */
7222   if (G_LIKELY (clipped))
7223     _clutter_actor_set_queue_redraw_clip (self, NULL);
7224 }
7225
7226 static void
7227 _clutter_actor_get_allocation_clip (ClutterActor *self,
7228                                     ClutterActorBox *clip)
7229 {
7230   ClutterActorBox allocation;
7231
7232   /* XXX: we don't care if we get an out of date allocation here
7233    * because clutter_actor_queue_redraw_with_clip knows to ignore
7234    * the clip if the actor's allocation is invalid.
7235    *
7236    * This is noted because clutter_actor_get_allocation_box does some
7237    * unnecessary work to support buggy code with a comment suggesting
7238    * that it could be changed later which would be good for this use
7239    * case!
7240    */
7241   clutter_actor_get_allocation_box (self, &allocation);
7242
7243   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7244    * actor's own coordinate space but the allocation is in parent
7245    * coordinates */
7246   clip->x1 = 0;
7247   clip->y1 = 0;
7248   clip->x2 = allocation.x2 - allocation.x1;
7249   clip->y2 = allocation.y2 - allocation.y1;
7250 }
7251
7252 void
7253 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7254                                   ClutterRedrawFlags  flags,
7255                                   ClutterPaintVolume *volume,
7256                                   ClutterEffect      *effect)
7257 {
7258   ClutterActorPrivate *priv = self->priv;
7259   ClutterPaintVolume allocation_pv;
7260   ClutterPaintVolume *pv;
7261   gboolean should_free_pv;
7262   ClutterActor *stage;
7263
7264   /* Here's an outline of the actor queue redraw mechanism:
7265    *
7266    * The process starts in one of the following two functions which
7267    * are wrappers for this function:
7268    * clutter_actor_queue_redraw
7269    * _clutter_actor_queue_redraw_with_clip
7270    *
7271    * additionally, an effect can queue a redraw by wrapping this
7272    * function in clutter_effect_queue_rerun
7273    *
7274    * This functions queues an entry in a list associated with the
7275    * stage which is a list of actors that queued a redraw while
7276    * updating the timelines, performing layouting and processing other
7277    * mainloop sources before the next paint starts.
7278    *
7279    * We aim to minimize the processing done at this point because
7280    * there is a good chance other events will happen while updating
7281    * the scenegraph that would invalidate any expensive work we might
7282    * otherwise try to do here. For example we don't try and resolve
7283    * the screen space bounding box of an actor at this stage so as to
7284    * minimize how much of the screen redraw because it's possible
7285    * something else will happen which will force a full redraw anyway.
7286    *
7287    * When all updates are complete and we come to paint the stage then
7288    * we iterate this list and actually emit the "queue-redraw" signals
7289    * for each of the listed actors which will bubble up to the stage
7290    * for each actor and at that point we will transform the actors
7291    * paint volume into screen coordinates to determine the clip region
7292    * for what needs to be redrawn in the next paint.
7293    *
7294    * Besides minimizing redundant work another reason for this
7295    * deferred design is that it's more likely we will be able to
7296    * determine the paint volume of an actor once we've finished
7297    * updating the scenegraph because its allocation should be up to
7298    * date. NB: If we can't determine an actors paint volume then we
7299    * can't automatically queue a clipped redraw which can make a big
7300    * difference to performance.
7301    *
7302    * So the control flow goes like this:
7303    * One of clutter_actor_queue_redraw,
7304    *        _clutter_actor_queue_redraw_with_clip
7305    *     or clutter_effect_queue_rerun
7306    *
7307    * then control moves to:
7308    *   _clutter_stage_queue_actor_redraw
7309    *
7310    * later during _clutter_stage_do_update, once relayouting is done
7311    * and the scenegraph has been updated we will call:
7312    * _clutter_stage_finish_queue_redraws
7313    *
7314    * _clutter_stage_finish_queue_redraws will call
7315    * _clutter_actor_finish_queue_redraw for each listed actor.
7316    * Note: actors *are* allowed to queue further redraws during this
7317    * process (considering clone actors or texture_new_from_actor which
7318    * respond to their source queueing a redraw by queuing a redraw
7319    * themselves). We repeat the process until the list is empty.
7320    *
7321    * This will result in the "queue-redraw" signal being fired for
7322    * each actor which will pass control to the default signal handler:
7323    * clutter_actor_real_queue_redraw
7324    *
7325    * This will bubble up to the stages handler:
7326    * clutter_stage_real_queue_redraw
7327    *
7328    * clutter_stage_real_queue_redraw will transform the actors paint
7329    * volume into screen space and add it as a clip region for the next
7330    * paint.
7331    */
7332
7333   /* ignore queueing a redraw for actors being destroyed */
7334   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7335     return;
7336
7337   stage = _clutter_actor_get_stage_internal (self);
7338
7339   /* Ignore queueing a redraw for actors not descended from a stage */
7340   if (stage == NULL)
7341     return;
7342
7343   /* ignore queueing a redraw on stages that are being destroyed */
7344   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7345     return;
7346
7347   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7348     {
7349       ClutterActorBox allocation_clip;
7350       ClutterVertex origin;
7351
7352       /* If the actor doesn't have a valid allocation then we will
7353        * queue a full stage redraw. */
7354       if (priv->needs_allocation)
7355         {
7356           /* NB: NULL denotes an undefined clip which will result in a
7357            * full redraw... */
7358           _clutter_actor_set_queue_redraw_clip (self, NULL);
7359           _clutter_actor_signal_queue_redraw (self, self);
7360           return;
7361         }
7362
7363       _clutter_paint_volume_init_static (&allocation_pv, self);
7364       pv = &allocation_pv;
7365
7366       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7367
7368       origin.x = allocation_clip.x1;
7369       origin.y = allocation_clip.y1;
7370       origin.z = 0;
7371       clutter_paint_volume_set_origin (pv, &origin);
7372       clutter_paint_volume_set_width (pv,
7373                                       allocation_clip.x2 - allocation_clip.x1);
7374       clutter_paint_volume_set_height (pv,
7375                                        allocation_clip.y2 -
7376                                        allocation_clip.y1);
7377       should_free_pv = TRUE;
7378     }
7379   else
7380     {
7381       pv = volume;
7382       should_free_pv = FALSE;
7383     }
7384
7385   self->priv->queue_redraw_entry =
7386     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7387                                        priv->queue_redraw_entry,
7388                                        self,
7389                                        pv);
7390
7391   if (should_free_pv)
7392     clutter_paint_volume_free (pv);
7393
7394   /* If this is the first redraw queued then we can directly use the
7395      effect parameter */
7396   if (!priv->is_dirty)
7397     priv->effect_to_redraw = effect;
7398   /* Otherwise we need to merge it with the existing effect parameter */
7399   else if (effect != NULL)
7400     {
7401       /* If there's already an effect then we need to use whichever is
7402          later in the chain of actors. Otherwise a full redraw has
7403          already been queued on the actor so we need to ignore the
7404          effect parameter */
7405       if (priv->effect_to_redraw != NULL)
7406         {
7407           if (priv->effects == NULL)
7408             g_warning ("Redraw queued with an effect that is "
7409                        "not applied to the actor");
7410           else
7411             {
7412               const GList *l;
7413
7414               for (l = _clutter_meta_group_peek_metas (priv->effects);
7415                    l != NULL;
7416                    l = l->next)
7417                 {
7418                   if (l->data == priv->effect_to_redraw ||
7419                       l->data == effect)
7420                     priv->effect_to_redraw = l->data;
7421                 }
7422             }
7423         }
7424     }
7425   else
7426     {
7427       /* If no effect is specified then we need to redraw the whole
7428          actor */
7429       priv->effect_to_redraw = NULL;
7430     }
7431
7432   priv->is_dirty = TRUE;
7433 }
7434
7435 /**
7436  * clutter_actor_queue_redraw:
7437  * @self: A #ClutterActor
7438  *
7439  * Queues up a redraw of an actor and any children. The redraw occurs
7440  * once the main loop becomes idle (after the current batch of events
7441  * has been processed, roughly).
7442  *
7443  * Applications rarely need to call this, as redraws are handled
7444  * automatically by modification functions.
7445  *
7446  * This function will not do anything if @self is not visible, or
7447  * if the actor is inside an invisible part of the scenegraph.
7448  *
7449  * Also be aware that painting is a NOP for actors with an opacity of
7450  * 0
7451  *
7452  * When you are implementing a custom actor you must queue a redraw
7453  * whenever some private state changes that will affect painting or
7454  * picking of your actor.
7455  */
7456 void
7457 clutter_actor_queue_redraw (ClutterActor *self)
7458 {
7459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7460
7461   _clutter_actor_queue_redraw_full (self,
7462                                     0, /* flags */
7463                                     NULL, /* clip volume */
7464                                     NULL /* effect */);
7465 }
7466
7467 /*< private >
7468  * _clutter_actor_queue_redraw_with_clip:
7469  * @self: A #ClutterActor
7470  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7471  *   this queue redraw.
7472  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7473  *   redrawn or %NULL if you are just using a @flag to state your
7474  *   desired clipping.
7475  *
7476  * Queues up a clipped redraw of an actor and any children. The redraw
7477  * occurs once the main loop becomes idle (after the current batch of
7478  * events has been processed, roughly).
7479  *
7480  * If no flags are given the clip volume is defined by @volume
7481  * specified in actor coordinates and tells Clutter that only content
7482  * within this volume has been changed so Clutter can optionally
7483  * optimize the redraw.
7484  *
7485  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7486  * should be %NULL and this tells Clutter to use the actor's current
7487  * allocation as a clip box. This flag can only be used for 2D actors,
7488  * because any actor with depth may be projected outside its
7489  * allocation.
7490  *
7491  * Applications rarely need to call this, as redraws are handled
7492  * automatically by modification functions.
7493  *
7494  * This function will not do anything if @self is not visible, or if
7495  * the actor is inside an invisible part of the scenegraph.
7496  *
7497  * Also be aware that painting is a NOP for actors with an opacity of
7498  * 0
7499  *
7500  * When you are implementing a custom actor you must queue a redraw
7501  * whenever some private state changes that will affect painting or
7502  * picking of your actor.
7503  */
7504 void
7505 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7506                                        ClutterRedrawFlags  flags,
7507                                        ClutterPaintVolume *volume)
7508 {
7509   _clutter_actor_queue_redraw_full (self,
7510                                     flags, /* flags */
7511                                     volume, /* clip volume */
7512                                     NULL /* effect */);
7513 }
7514
7515 static void
7516 _clutter_actor_queue_only_relayout (ClutterActor *self)
7517 {
7518   ClutterActorPrivate *priv = self->priv;
7519
7520   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7521     return;
7522
7523   if (priv->needs_width_request &&
7524       priv->needs_height_request &&
7525       priv->needs_allocation)
7526     return; /* save some cpu cycles */
7527
7528 #if CLUTTER_ENABLE_DEBUG
7529   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7530     {
7531       g_warning ("The actor '%s' is currently inside an allocation "
7532                  "cycle; calling clutter_actor_queue_relayout() is "
7533                  "not recommended",
7534                  _clutter_actor_get_debug_name (self));
7535     }
7536 #endif /* CLUTTER_ENABLE_DEBUG */
7537
7538   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7539 }
7540
7541 /**
7542  * clutter_actor_queue_redraw_with_clip:
7543  * @self: a #ClutterActor
7544  * @clip: (allow-none): a rectangular clip region, or %NULL
7545  *
7546  * Queues a redraw on @self limited to a specific, actor-relative
7547  * rectangular area.
7548  *
7549  * If @clip is %NULL this function is equivalent to
7550  * clutter_actor_queue_redraw().
7551  *
7552  * Since: 1.10
7553  */
7554 void
7555 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7556                                       const cairo_rectangle_int_t *clip)
7557 {
7558   ClutterPaintVolume volume;
7559   ClutterVertex origin;
7560
7561   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7562
7563   if (clip == NULL)
7564     {
7565       clutter_actor_queue_redraw (self);
7566       return;
7567     }
7568
7569   _clutter_paint_volume_init_static (&volume, self);
7570
7571   origin.x = clip->x;
7572   origin.y = clip->y;
7573   origin.z = 0.0f;
7574
7575   clutter_paint_volume_set_origin (&volume, &origin);
7576   clutter_paint_volume_set_width (&volume, clip->width);
7577   clutter_paint_volume_set_height (&volume, clip->height);
7578
7579   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7580
7581   clutter_paint_volume_free (&volume);
7582 }
7583
7584 /**
7585  * clutter_actor_queue_relayout:
7586  * @self: A #ClutterActor
7587  *
7588  * Indicates that the actor's size request or other layout-affecting
7589  * properties may have changed. This function is used inside #ClutterActor
7590  * subclass implementations, not by applications directly.
7591  *
7592  * Queueing a new layout automatically queues a redraw as well.
7593  *
7594  * Since: 0.8
7595  */
7596 void
7597 clutter_actor_queue_relayout (ClutterActor *self)
7598 {
7599   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7600
7601   _clutter_actor_queue_only_relayout (self);
7602   clutter_actor_queue_redraw (self);
7603 }
7604
7605 /**
7606  * clutter_actor_get_preferred_size:
7607  * @self: a #ClutterActor
7608  * @min_width_p: (out) (allow-none): return location for the minimum
7609  *   width, or %NULL
7610  * @min_height_p: (out) (allow-none): return location for the minimum
7611  *   height, or %NULL
7612  * @natural_width_p: (out) (allow-none): return location for the natural
7613  *   width, or %NULL
7614  * @natural_height_p: (out) (allow-none): return location for the natural
7615  *   height, or %NULL
7616  *
7617  * Computes the preferred minimum and natural size of an actor, taking into
7618  * account the actor's geometry management (either height-for-width
7619  * or width-for-height).
7620  *
7621  * The width and height used to compute the preferred height and preferred
7622  * width are the actor's natural ones.
7623  *
7624  * If you need to control the height for the preferred width, or the width for
7625  * the preferred height, you should use clutter_actor_get_preferred_width()
7626  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7627  * geometry management using the #ClutterActor:request-mode property.
7628  *
7629  * Since: 0.8
7630  */
7631 void
7632 clutter_actor_get_preferred_size (ClutterActor *self,
7633                                   gfloat       *min_width_p,
7634                                   gfloat       *min_height_p,
7635                                   gfloat       *natural_width_p,
7636                                   gfloat       *natural_height_p)
7637 {
7638   ClutterActorPrivate *priv;
7639   gfloat min_width, min_height;
7640   gfloat natural_width, natural_height;
7641
7642   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7643
7644   priv = self->priv;
7645
7646   min_width = min_height = 0;
7647   natural_width = natural_height = 0;
7648
7649   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7650     {
7651       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7652       clutter_actor_get_preferred_width (self, -1,
7653                                          &min_width,
7654                                          &natural_width);
7655       clutter_actor_get_preferred_height (self, natural_width,
7656                                           &min_height,
7657                                           &natural_height);
7658     }
7659   else
7660     {
7661       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7662       clutter_actor_get_preferred_height (self, -1,
7663                                           &min_height,
7664                                           &natural_height);
7665       clutter_actor_get_preferred_width (self, natural_height,
7666                                          &min_width,
7667                                          &natural_width);
7668     }
7669
7670   if (min_width_p)
7671     *min_width_p = min_width;
7672
7673   if (min_height_p)
7674     *min_height_p = min_height;
7675
7676   if (natural_width_p)
7677     *natural_width_p = natural_width;
7678
7679   if (natural_height_p)
7680     *natural_height_p = natural_height;
7681 }
7682
7683 /*< private >
7684  * effective_align:
7685  * @align: a #ClutterActorAlign
7686  * @direction: a #ClutterTextDirection
7687  *
7688  * Retrieves the correct alignment depending on the text direction
7689  *
7690  * Return value: the effective alignment
7691  */
7692 static ClutterActorAlign
7693 effective_align (ClutterActorAlign    align,
7694                  ClutterTextDirection direction)
7695 {
7696   ClutterActorAlign res;
7697
7698   switch (align)
7699     {
7700     case CLUTTER_ACTOR_ALIGN_START:
7701       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7702           ? CLUTTER_ACTOR_ALIGN_END
7703           : CLUTTER_ACTOR_ALIGN_START;
7704       break;
7705
7706     case CLUTTER_ACTOR_ALIGN_END:
7707       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7708           ? CLUTTER_ACTOR_ALIGN_START
7709           : CLUTTER_ACTOR_ALIGN_END;
7710       break;
7711
7712     default:
7713       res = align;
7714       break;
7715     }
7716
7717   return res;
7718 }
7719
7720 static inline void
7721 adjust_for_margin (float  margin_start,
7722                    float  margin_end,
7723                    float *minimum_size,
7724                    float *natural_size,
7725                    float *allocated_start,
7726                    float *allocated_end)
7727 {
7728   *minimum_size -= (margin_start + margin_end);
7729   *natural_size -= (margin_start + margin_end);
7730   *allocated_start += margin_start;
7731   *allocated_end -= margin_end;
7732 }
7733
7734 static inline void
7735 adjust_for_alignment (ClutterActorAlign  alignment,
7736                       float              natural_size,
7737                       float             *allocated_start,
7738                       float             *allocated_end)
7739 {
7740   float allocated_size = *allocated_end - *allocated_start;
7741
7742   switch (alignment)
7743     {
7744     case CLUTTER_ACTOR_ALIGN_FILL:
7745       /* do nothing */
7746       break;
7747
7748     case CLUTTER_ACTOR_ALIGN_START:
7749       /* keep start */
7750       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7751       break;
7752
7753     case CLUTTER_ACTOR_ALIGN_END:
7754       if (allocated_size > natural_size)
7755         {
7756           *allocated_start += (allocated_size - natural_size);
7757           *allocated_end = *allocated_start + natural_size;
7758         }
7759       break;
7760
7761     case CLUTTER_ACTOR_ALIGN_CENTER:
7762       if (allocated_size > natural_size)
7763         {
7764           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7765           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7766         }
7767       break;
7768     }
7769 }
7770
7771 /*< private >
7772  * clutter_actor_adjust_width:
7773  * @self: a #ClutterActor
7774  * @minimum_width: (inout): the actor's preferred minimum width, which
7775  *   will be adjusted depending on the margin
7776  * @natural_width: (inout): the actor's preferred natural width, which
7777  *   will be adjusted depending on the margin
7778  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7779  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7780  *
7781  * Adjusts the preferred and allocated position and size of an actor,
7782  * depending on the margin and alignment properties.
7783  */
7784 static void
7785 clutter_actor_adjust_width (ClutterActor *self,
7786                             gfloat       *minimum_width,
7787                             gfloat       *natural_width,
7788                             gfloat       *adjusted_x1,
7789                             gfloat       *adjusted_x2)
7790 {
7791   ClutterTextDirection text_dir;
7792   const ClutterLayoutInfo *info;
7793
7794   info = _clutter_actor_get_layout_info_or_defaults (self);
7795   text_dir = clutter_actor_get_text_direction (self);
7796
7797   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7798
7799   /* this will tweak natural_width to remove the margin, so that
7800    * adjust_for_alignment() will use the correct size
7801    */
7802   adjust_for_margin (info->margin.left, info->margin.right,
7803                      minimum_width, natural_width,
7804                      adjusted_x1, adjusted_x2);
7805
7806   adjust_for_alignment (effective_align (info->x_align, text_dir),
7807                         *natural_width,
7808                         adjusted_x1, adjusted_x2);
7809 }
7810
7811 /*< private >
7812  * clutter_actor_adjust_height:
7813  * @self: a #ClutterActor
7814  * @minimum_height: (inout): the actor's preferred minimum height, which
7815  *   will be adjusted depending on the margin
7816  * @natural_height: (inout): the actor's preferred natural height, which
7817  *   will be adjusted depending on the margin
7818  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7819  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7820  *
7821  * Adjusts the preferred and allocated position and size of an actor,
7822  * depending on the margin and alignment properties.
7823  */
7824 static void
7825 clutter_actor_adjust_height (ClutterActor *self,
7826                              gfloat       *minimum_height,
7827                              gfloat       *natural_height,
7828                              gfloat       *adjusted_y1,
7829                              gfloat       *adjusted_y2)
7830 {
7831   const ClutterLayoutInfo *info;
7832
7833   info = _clutter_actor_get_layout_info_or_defaults (self);
7834
7835   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7836
7837   /* this will tweak natural_height to remove the margin, so that
7838    * adjust_for_alignment() will use the correct size
7839    */
7840   adjust_for_margin (info->margin.top, info->margin.bottom,
7841                      minimum_height, natural_height,
7842                      adjusted_y1,
7843                      adjusted_y2);
7844
7845   /* we don't use effective_align() here, because text direction
7846    * only affects the horizontal axis
7847    */
7848   adjust_for_alignment (info->y_align,
7849                         *natural_height,
7850                         adjusted_y1,
7851                         adjusted_y2);
7852
7853 }
7854
7855 /* looks for a cached size request for this for_size. If not
7856  * found, returns the oldest entry so it can be overwritten */
7857 static gboolean
7858 _clutter_actor_get_cached_size_request (gfloat         for_size,
7859                                         SizeRequest   *cached_size_requests,
7860                                         SizeRequest  **result)
7861 {
7862   guint i;
7863
7864   *result = &cached_size_requests[0];
7865
7866   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7867     {
7868       SizeRequest *sr;
7869
7870       sr = &cached_size_requests[i];
7871
7872       if (sr->age > 0 &&
7873           sr->for_size == for_size)
7874         {
7875           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7876           *result = sr;
7877           return TRUE;
7878         }
7879       else if (sr->age < (*result)->age)
7880         {
7881           *result = sr;
7882         }
7883     }
7884
7885   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7886
7887   return FALSE;
7888 }
7889
7890 /**
7891  * clutter_actor_get_preferred_width:
7892  * @self: A #ClutterActor
7893  * @for_height: available height when computing the preferred width,
7894  *   or a negative value to indicate that no height is defined
7895  * @min_width_p: (out) (allow-none): return location for minimum width,
7896  *   or %NULL
7897  * @natural_width_p: (out) (allow-none): return location for the natural
7898  *   width, or %NULL
7899  *
7900  * Computes the requested minimum and natural widths for an actor,
7901  * optionally depending on the specified height, or if they are
7902  * already computed, returns the cached values.
7903  *
7904  * An actor may not get its request - depending on the layout
7905  * manager that's in effect.
7906  *
7907  * A request should not incorporate the actor's scale or anchor point;
7908  * those transformations do not affect layout, only rendering.
7909  *
7910  * Since: 0.8
7911  */
7912 void
7913 clutter_actor_get_preferred_width (ClutterActor *self,
7914                                    gfloat        for_height,
7915                                    gfloat       *min_width_p,
7916                                    gfloat       *natural_width_p)
7917 {
7918   float request_min_width, request_natural_width;
7919   SizeRequest *cached_size_request;
7920   const ClutterLayoutInfo *info;
7921   ClutterActorPrivate *priv;
7922   gboolean found_in_cache;
7923
7924   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7925
7926   priv = self->priv;
7927
7928   info = _clutter_actor_get_layout_info_or_defaults (self);
7929
7930   /* we shortcircuit the case of a fixed size set using set_width() */
7931   if (priv->min_width_set && priv->natural_width_set)
7932     {
7933       if (min_width_p != NULL)
7934         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7935
7936       if (natural_width_p != NULL)
7937         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7938
7939       return;
7940     }
7941
7942   /* the remaining cases are:
7943    *
7944    *   - either min_width or natural_width have been set
7945    *   - neither min_width or natural_width have been set
7946    *
7947    * in both cases, we go through the cache (and through the actor in case
7948    * of cache misses) and determine the authoritative value depending on
7949    * the *_set flags.
7950    */
7951
7952   if (!priv->needs_width_request)
7953     {
7954       found_in_cache =
7955         _clutter_actor_get_cached_size_request (for_height,
7956                                                 priv->width_requests,
7957                                                 &cached_size_request);
7958     }
7959   else
7960     {
7961       /* if the actor needs a width request we use the first slot */
7962       found_in_cache = FALSE;
7963       cached_size_request = &priv->width_requests[0];
7964     }
7965
7966   if (!found_in_cache)
7967     {
7968       gfloat minimum_width, natural_width;
7969       ClutterActorClass *klass;
7970
7971       minimum_width = natural_width = 0;
7972
7973       /* adjust for the margin */
7974       if (for_height >= 0)
7975         {
7976           for_height -= (info->margin.top + info->margin.bottom);
7977           if (for_height < 0)
7978             for_height = 0;
7979         }
7980
7981       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7982
7983       klass = CLUTTER_ACTOR_GET_CLASS (self);
7984       klass->get_preferred_width (self, for_height,
7985                                   &minimum_width,
7986                                   &natural_width);
7987
7988       /* adjust for the margin */
7989       minimum_width += (info->margin.left + info->margin.right);
7990       natural_width += (info->margin.left + info->margin.right);
7991
7992       /* Due to accumulated float errors, it's better not to warn
7993        * on this, but just fix it.
7994        */
7995       if (natural_width < minimum_width)
7996         natural_width = minimum_width;
7997
7998       cached_size_request->min_size = minimum_width;
7999       cached_size_request->natural_size = natural_width;
8000       cached_size_request->for_size = for_height;
8001       cached_size_request->age = priv->cached_width_age;
8002
8003       priv->cached_width_age += 1;
8004       priv->needs_width_request = FALSE;
8005     }
8006
8007   if (!priv->min_width_set)
8008     request_min_width = cached_size_request->min_size;
8009   else
8010     request_min_width = info->min_width;
8011
8012   if (!priv->natural_width_set)
8013     request_natural_width = cached_size_request->natural_size;
8014   else
8015     request_natural_width = info->natural_width;
8016
8017   if (min_width_p)
8018     *min_width_p = request_min_width;
8019
8020   if (natural_width_p)
8021     *natural_width_p = request_natural_width;
8022 }
8023
8024 /**
8025  * clutter_actor_get_preferred_height:
8026  * @self: A #ClutterActor
8027  * @for_width: available width to assume in computing desired height,
8028  *   or a negative value to indicate that no width is defined
8029  * @min_height_p: (out) (allow-none): return location for minimum height,
8030  *   or %NULL
8031  * @natural_height_p: (out) (allow-none): return location for natural
8032  *   height, or %NULL
8033  *
8034  * Computes the requested minimum and natural heights for an actor,
8035  * or if they are already computed, returns the cached values.
8036  *
8037  * An actor may not get its request - depending on the layout
8038  * manager that's in effect.
8039  *
8040  * A request should not incorporate the actor's scale or anchor point;
8041  * those transformations do not affect layout, only rendering.
8042  *
8043  * Since: 0.8
8044  */
8045 void
8046 clutter_actor_get_preferred_height (ClutterActor *self,
8047                                     gfloat        for_width,
8048                                     gfloat       *min_height_p,
8049                                     gfloat       *natural_height_p)
8050 {
8051   float request_min_height, request_natural_height;
8052   SizeRequest *cached_size_request;
8053   const ClutterLayoutInfo *info;
8054   ClutterActorPrivate *priv;
8055   gboolean found_in_cache;
8056
8057   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8058
8059   priv = self->priv;
8060
8061   info = _clutter_actor_get_layout_info_or_defaults (self);
8062
8063   /* we shortcircuit the case of a fixed size set using set_height() */
8064   if (priv->min_height_set && priv->natural_height_set)
8065     {
8066       if (min_height_p != NULL)
8067         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8068
8069       if (natural_height_p != NULL)
8070         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8071
8072       return;
8073     }
8074
8075   /* the remaining cases are:
8076    *
8077    *   - either min_height or natural_height have been set
8078    *   - neither min_height or natural_height have been set
8079    *
8080    * in both cases, we go through the cache (and through the actor in case
8081    * of cache misses) and determine the authoritative value depending on
8082    * the *_set flags.
8083    */
8084
8085   if (!priv->needs_height_request)
8086     {
8087       found_in_cache =
8088         _clutter_actor_get_cached_size_request (for_width,
8089                                                 priv->height_requests,
8090                                                 &cached_size_request);
8091     }
8092   else
8093     {
8094       found_in_cache = FALSE;
8095       cached_size_request = &priv->height_requests[0];
8096     }
8097
8098   if (!found_in_cache)
8099     {
8100       gfloat minimum_height, natural_height;
8101       ClutterActorClass *klass;
8102
8103       minimum_height = natural_height = 0;
8104
8105       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8106
8107       /* adjust for margin */
8108       if (for_width >= 0)
8109         {
8110           for_width -= (info->margin.left + info->margin.right);
8111           if (for_width < 0)
8112             for_width = 0;
8113         }
8114
8115       klass = CLUTTER_ACTOR_GET_CLASS (self);
8116       klass->get_preferred_height (self, for_width,
8117                                    &minimum_height,
8118                                    &natural_height);
8119
8120       /* adjust for margin */
8121       minimum_height += (info->margin.top + info->margin.bottom);
8122       natural_height += (info->margin.top + info->margin.bottom);
8123
8124       /* Due to accumulated float errors, it's better not to warn
8125        * on this, but just fix it.
8126        */
8127       if (natural_height < minimum_height)
8128         natural_height = minimum_height;
8129
8130       cached_size_request->min_size = minimum_height;
8131       cached_size_request->natural_size = natural_height;
8132       cached_size_request->for_size = for_width;
8133       cached_size_request->age = priv->cached_height_age;
8134
8135       priv->cached_height_age += 1;
8136       priv->needs_height_request = FALSE;
8137     }
8138
8139   if (!priv->min_height_set)
8140     request_min_height = cached_size_request->min_size;
8141   else
8142     request_min_height = info->min_height;
8143
8144   if (!priv->natural_height_set)
8145     request_natural_height = cached_size_request->natural_size;
8146   else
8147     request_natural_height = info->natural_height;
8148
8149   if (min_height_p)
8150     *min_height_p = request_min_height;
8151
8152   if (natural_height_p)
8153     *natural_height_p = request_natural_height;
8154 }
8155
8156 /**
8157  * clutter_actor_get_allocation_box:
8158  * @self: A #ClutterActor
8159  * @box: (out): the function fills this in with the actor's allocation
8160  *
8161  * Gets the layout box an actor has been assigned. The allocation can
8162  * only be assumed valid inside a paint() method; anywhere else, it
8163  * may be out-of-date.
8164  *
8165  * An allocation does not incorporate the actor's scale or anchor point;
8166  * those transformations do not affect layout, only rendering.
8167  *
8168  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8169  * of functions inside the implementation of the get_preferred_width()
8170  * or get_preferred_height() virtual functions.</note>
8171  *
8172  * Since: 0.8
8173  */
8174 void
8175 clutter_actor_get_allocation_box (ClutterActor    *self,
8176                                   ClutterActorBox *box)
8177 {
8178   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8179
8180   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8181    * which limits calling get_allocation to inside paint() basically; or
8182    * we can 2) force a layout, which could be expensive if someone calls
8183    * get_allocation somewhere silly; or we can 3) just return the latest
8184    * value, allowing it to be out-of-date, and assume people know what
8185    * they are doing.
8186    *
8187    * The least-surprises approach that keeps existing code working is
8188    * likely to be 2). People can end up doing some inefficient things,
8189    * though, and in general code that requires 2) is probably broken.
8190    */
8191
8192   /* this implements 2) */
8193   if (G_UNLIKELY (self->priv->needs_allocation))
8194     {
8195       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8196
8197       /* do not queue a relayout on an unparented actor */
8198       if (stage)
8199         _clutter_stage_maybe_relayout (stage);
8200     }
8201
8202   /* commenting out the code above and just keeping this assigment
8203    * implements 3)
8204    */
8205   *box = self->priv->allocation;
8206 }
8207
8208 /**
8209  * clutter_actor_get_allocation_geometry:
8210  * @self: A #ClutterActor
8211  * @geom: (out): allocation geometry in pixels
8212  *
8213  * Gets the layout box an actor has been assigned.  The allocation can
8214  * only be assumed valid inside a paint() method; anywhere else, it
8215  * may be out-of-date.
8216  *
8217  * An allocation does not incorporate the actor's scale or anchor point;
8218  * those transformations do not affect layout, only rendering.
8219  *
8220  * The returned rectangle is in pixels.
8221  *
8222  * Since: 0.8
8223  */
8224 void
8225 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8226                                        ClutterGeometry *geom)
8227 {
8228   ClutterActorBox box;
8229
8230   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8231   g_return_if_fail (geom != NULL);
8232
8233   clutter_actor_get_allocation_box (self, &box);
8234
8235   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8236   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8237   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8238   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8239 }
8240
8241 static void
8242 clutter_actor_update_constraints (ClutterActor    *self,
8243                                   ClutterActorBox *allocation)
8244 {
8245   ClutterActorPrivate *priv = self->priv;
8246   const GList *constraints, *l;
8247
8248   if (priv->constraints == NULL)
8249     return;
8250
8251   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8252   for (l = constraints; l != NULL; l = l->next)
8253     {
8254       ClutterConstraint *constraint = l->data;
8255       ClutterActorMeta *meta = l->data;
8256
8257       if (clutter_actor_meta_get_enabled (meta))
8258         {
8259           _clutter_constraint_update_allocation (constraint,
8260                                                  self,
8261                                                  allocation);
8262
8263           CLUTTER_NOTE (LAYOUT,
8264                         "Allocation of '%s' after constraint '%s': "
8265                         "{ %.2f, %.2f, %.2f, %.2f }",
8266                         _clutter_actor_get_debug_name (self),
8267                         _clutter_actor_meta_get_debug_name (meta),
8268                         allocation->x1,
8269                         allocation->y1,
8270                         allocation->x2,
8271                         allocation->y2);
8272         }
8273     }
8274 }
8275
8276 /*< private >
8277  * clutter_actor_adjust_allocation:
8278  * @self: a #ClutterActor
8279  * @allocation: (inout): the allocation to adjust
8280  *
8281  * Adjusts the passed allocation box taking into account the actor's
8282  * layout information, like alignment, expansion, and margin.
8283  */
8284 static void
8285 clutter_actor_adjust_allocation (ClutterActor    *self,
8286                                  ClutterActorBox *allocation)
8287 {
8288   ClutterActorBox adj_allocation;
8289   float alloc_width, alloc_height;
8290   float min_width, min_height;
8291   float nat_width, nat_height;
8292   ClutterRequestMode req_mode;
8293
8294   adj_allocation = *allocation;
8295
8296   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8297
8298   /* we want to hit the cache, so we use the public API */
8299   req_mode = clutter_actor_get_request_mode (self);
8300
8301   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8302     {
8303       clutter_actor_get_preferred_width (self, -1,
8304                                          &min_width,
8305                                          &nat_width);
8306       clutter_actor_get_preferred_height (self, alloc_width,
8307                                           &min_height,
8308                                           &nat_height);
8309     }
8310   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8311     {
8312       clutter_actor_get_preferred_height (self, -1,
8313                                           &min_height,
8314                                           &nat_height);
8315       clutter_actor_get_preferred_height (self, alloc_height,
8316                                           &min_width,
8317                                           &nat_width);
8318     }
8319
8320 #ifdef CLUTTER_ENABLE_DEBUG
8321   /* warn about underallocations */
8322   if (_clutter_diagnostic_enabled () &&
8323       (floorf (min_width - alloc_width) > 0 ||
8324        floorf (min_height - alloc_height) > 0))
8325     {
8326       ClutterActor *parent = clutter_actor_get_parent (self);
8327
8328       /* the only actors that are allowed to be underallocated are the Stage,
8329        * as it doesn't have an implicit size, and Actors that specifically
8330        * told us that they want to opt-out from layout control mechanisms
8331        * through the NO_LAYOUT escape hatch.
8332        */
8333       if (parent != NULL &&
8334           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8335         {
8336           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8337                      "of %.2f x %.2f from its parent actor '%s', but its "
8338                      "requested minimum size is of %.2f x %.2f",
8339                      _clutter_actor_get_debug_name (self),
8340                      alloc_width, alloc_height,
8341                      _clutter_actor_get_debug_name (parent),
8342                      min_width, min_height);
8343         }
8344     }
8345 #endif
8346
8347   clutter_actor_adjust_width (self,
8348                               &min_width,
8349                               &nat_width,
8350                               &adj_allocation.x1,
8351                               &adj_allocation.x2);
8352
8353   clutter_actor_adjust_height (self,
8354                                &min_height,
8355                                &nat_height,
8356                                &adj_allocation.y1,
8357                                &adj_allocation.y2);
8358
8359   /* we maintain the invariant that an allocation cannot be adjusted
8360    * to be outside the parent-given box
8361    */
8362   if (adj_allocation.x1 < allocation->x1 ||
8363       adj_allocation.y1 < allocation->y1 ||
8364       adj_allocation.x2 > allocation->x2 ||
8365       adj_allocation.y2 > allocation->y2)
8366     {
8367       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8368                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8369                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8370                  _clutter_actor_get_debug_name (self),
8371                  adj_allocation.x1, adj_allocation.y1,
8372                  adj_allocation.x2 - adj_allocation.x1,
8373                  adj_allocation.y2 - adj_allocation.y1,
8374                  allocation->x1, allocation->y1,
8375                  allocation->x2 - allocation->x1,
8376                  allocation->y2 - allocation->y1);
8377       return;
8378     }
8379
8380   *allocation = adj_allocation;
8381 }
8382
8383 /**
8384  * clutter_actor_allocate:
8385  * @self: A #ClutterActor
8386  * @box: new allocation of the actor, in parent-relative coordinates
8387  * @flags: flags that control the allocation
8388  *
8389  * Called by the parent of an actor to assign the actor its size.
8390  * Should never be called by applications (except when implementing
8391  * a container or layout manager).
8392  *
8393  * Actors can know from their allocation box whether they have moved
8394  * with respect to their parent actor. The @flags parameter describes
8395  * additional information about the allocation, for instance whether
8396  * the parent has moved with respect to the stage, for example because
8397  * a grandparent's origin has moved.
8398  *
8399  * Since: 0.8
8400  */
8401 void
8402 clutter_actor_allocate (ClutterActor           *self,
8403                         const ClutterActorBox  *box,
8404                         ClutterAllocationFlags  flags)
8405 {
8406   ClutterActorPrivate *priv;
8407   ClutterActorClass *klass;
8408   ClutterActorBox old_allocation, real_allocation;
8409   gboolean origin_changed, child_moved, size_changed;
8410   gboolean stage_allocation_changed;
8411
8412   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8413   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8414     {
8415       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8416                  "which isn't a descendent of the stage!\n",
8417                  self, _clutter_actor_get_debug_name (self));
8418       return;
8419     }
8420
8421   priv = self->priv;
8422
8423   old_allocation = priv->allocation;
8424   real_allocation = *box;
8425
8426   /* constraints are allowed to modify the allocation only here; we do
8427    * this prior to all the other checks so that we can bail out if the
8428    * allocation did not change
8429    */
8430   clutter_actor_update_constraints (self, &real_allocation);
8431
8432   /* adjust the allocation depending on the align/margin properties */
8433   clutter_actor_adjust_allocation (self, &real_allocation);
8434
8435   if (real_allocation.x2 < real_allocation.x1 ||
8436       real_allocation.y2 < real_allocation.y1)
8437     {
8438       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8439                  _clutter_actor_get_debug_name (self),
8440                  real_allocation.x2 - real_allocation.x1,
8441                  real_allocation.y2 - real_allocation.y1);
8442     }
8443
8444   /* we allow 0-sized actors, but not negative-sized ones */
8445   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8446   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8447
8448   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8449
8450   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8451                  real_allocation.y1 != old_allocation.y1);
8452
8453   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8454                   real_allocation.y2 != old_allocation.y2);
8455
8456   if (origin_changed || child_moved || size_changed)
8457     stage_allocation_changed = TRUE;
8458   else
8459     stage_allocation_changed = FALSE;
8460
8461   /* If we get an allocation "out of the blue"
8462    * (we did not queue relayout), then we want to
8463    * ignore it. But if we have needs_allocation set,
8464    * we want to guarantee that allocate() virtual
8465    * method is always called, i.e. that queue_relayout()
8466    * always results in an allocate() invocation on
8467    * an actor.
8468    *
8469    * The optimization here is to avoid re-allocating
8470    * actors that did not queue relayout and were
8471    * not moved.
8472    */
8473   if (!priv->needs_allocation && !stage_allocation_changed)
8474     {
8475       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8476       return;
8477     }
8478
8479   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8480    * clutter_actor_allocate(), it indicates whether the parent has its
8481    * absolute origin moved; when passed in to ClutterActor::allocate()
8482    * virtual method though, it indicates whether the child has its
8483    * absolute origin moved.  So we set it when child_moved is TRUE
8484    */
8485   if (child_moved)
8486     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8487
8488   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8489
8490   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8491                 _clutter_actor_get_debug_name (self));
8492
8493   klass = CLUTTER_ACTOR_GET_CLASS (self);
8494   klass->allocate (self, &real_allocation, flags);
8495
8496   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8497
8498   if (stage_allocation_changed)
8499     clutter_actor_queue_redraw (self);
8500 }
8501
8502 /**
8503  * clutter_actor_set_allocation:
8504  * @self: a #ClutterActor
8505  * @box: a #ClutterActorBox
8506  * @flags: allocation flags
8507  *
8508  * Stores the allocation of @self as defined by @box.
8509  *
8510  * This function can only be called from within the implementation of
8511  * the #ClutterActorClass.allocate() virtual function.
8512  *
8513  * The allocation should have been adjusted to take into account constraints,
8514  * alignment, and margin properties. If you are implementing a #ClutterActor
8515  * subclass that provides its own layout management policy for its children
8516  * instead of using a #ClutterLayoutManager delegate, you should not call
8517  * this function on the children of @self; instead, you should call
8518  * clutter_actor_allocate(), which will adjust the allocation box for
8519  * you.
8520  *
8521  * This function should only be used by subclasses of #ClutterActor
8522  * that wish to store their allocation but cannot chain up to the
8523  * parent's implementation; the default implementation of the
8524  * #ClutterActorClass.allocate() virtual function will call this
8525  * function.
8526  *
8527  * It is important to note that, while chaining up was the recommended
8528  * behaviour for #ClutterActor subclasses prior to the introduction of
8529  * this function, it is recommended to call clutter_actor_set_allocation()
8530  * instead.
8531  *
8532  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8533  * to handle the allocation of its children, this function will call
8534  * the clutter_layout_manager_allocate() function only if the
8535  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8536  * expected that the subclass will call clutter_layout_manager_allocate()
8537  * by itself. For instance, the following code:
8538  *
8539  * |[
8540  * static void
8541  * my_actor_allocate (ClutterActor *actor,
8542  *                    const ClutterActorBox *allocation,
8543  *                    ClutterAllocationFlags flags)
8544  * {
8545  *   ClutterActorBox new_alloc;
8546  *   ClutterAllocationFlags new_flags;
8547  *
8548  *   adjust_allocation (allocation, &amp;new_alloc);
8549  *
8550  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8551  *
8552  *   /&ast; this will use the layout manager set on the actor &ast;/
8553  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8554  * }
8555  * ]|
8556  *
8557  * is equivalent to this:
8558  *
8559  * |[
8560  * static void
8561  * my_actor_allocate (ClutterActor *actor,
8562  *                    const ClutterActorBox *allocation,
8563  *                    ClutterAllocationFlags flags)
8564  * {
8565  *   ClutterLayoutManager *layout;
8566  *   ClutterActorBox new_alloc;
8567  *
8568  *   adjust_allocation (allocation, &amp;new_alloc);
8569  *
8570  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8571  *
8572  *   layout = clutter_actor_get_layout_manager (actor);
8573  *   clutter_layout_manager_allocate (layout,
8574  *                                    CLUTTER_CONTAINER (actor),
8575  *                                    &amp;new_alloc,
8576  *                                    flags);
8577  * }
8578  * ]|
8579  *
8580  * Since: 1.10
8581  */
8582 void
8583 clutter_actor_set_allocation (ClutterActor           *self,
8584                               const ClutterActorBox  *box,
8585                               ClutterAllocationFlags  flags)
8586 {
8587   ClutterActorPrivate *priv;
8588   gboolean changed;
8589
8590   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8591   g_return_if_fail (box != NULL);
8592
8593   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8594     {
8595       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8596                   "can only be called from within the implementation of "
8597                   "the ClutterActor::allocate() virtual function.");
8598       return;
8599     }
8600
8601   priv = self->priv;
8602
8603   g_object_freeze_notify (G_OBJECT (self));
8604
8605   changed = clutter_actor_set_allocation_internal (self, box, flags);
8606
8607   /* we allocate our children before we notify changes in our geometry,
8608    * so that people connecting to properties will be able to get valid
8609    * data out of the sub-tree of the scene graph that has this actor at
8610    * the root.
8611    */
8612   clutter_actor_maybe_layout_children (self, box, flags);
8613
8614   if (changed)
8615     {
8616       ClutterActorBox signal_box = priv->allocation;
8617       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8618
8619       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8620                      &signal_box,
8621                      signal_flags);
8622     }
8623
8624   g_object_thaw_notify (G_OBJECT (self));
8625 }
8626
8627 /**
8628  * clutter_actor_set_geometry:
8629  * @self: A #ClutterActor
8630  * @geometry: A #ClutterGeometry
8631  *
8632  * Sets the actor's fixed position and forces its minimum and natural
8633  * size, in pixels. This means the untransformed actor will have the
8634  * given geometry. This is the same as calling clutter_actor_set_position()
8635  * and clutter_actor_set_size().
8636  *
8637  * Deprecated: 1.10: Use clutter_actor_set_position() and
8638  *   clutter_actor_set_size() instead.
8639  */
8640 void
8641 clutter_actor_set_geometry (ClutterActor          *self,
8642                             const ClutterGeometry *geometry)
8643 {
8644   g_object_freeze_notify (G_OBJECT (self));
8645
8646   clutter_actor_set_position (self, geometry->x, geometry->y);
8647   clutter_actor_set_size (self, geometry->width, geometry->height);
8648
8649   g_object_thaw_notify (G_OBJECT (self));
8650 }
8651
8652 /**
8653  * clutter_actor_get_geometry:
8654  * @self: A #ClutterActor
8655  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8656  *
8657  * Gets the size and position of an actor relative to its parent
8658  * actor. This is the same as calling clutter_actor_get_position() and
8659  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8660  * requested size and position if the actor's allocation is invalid.
8661  *
8662  * Deprecated: 1.10: Use clutter_actor_get_position() and
8663  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8664  *   instead.
8665  */
8666 void
8667 clutter_actor_get_geometry (ClutterActor    *self,
8668                             ClutterGeometry *geometry)
8669 {
8670   gfloat x, y, width, height;
8671
8672   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8673   g_return_if_fail (geometry != NULL);
8674
8675   clutter_actor_get_position (self, &x, &y);
8676   clutter_actor_get_size (self, &width, &height);
8677
8678   geometry->x = (int) x;
8679   geometry->y = (int) y;
8680   geometry->width = (int) width;
8681   geometry->height = (int) height;
8682 }
8683
8684 /**
8685  * clutter_actor_set_position:
8686  * @self: A #ClutterActor
8687  * @x: New left position of actor in pixels.
8688  * @y: New top position of actor in pixels.
8689  *
8690  * Sets the actor's fixed position in pixels relative to any parent
8691  * actor.
8692  *
8693  * If a layout manager is in use, this position will override the
8694  * layout manager and force a fixed position.
8695  */
8696 void
8697 clutter_actor_set_position (ClutterActor *self,
8698                             gfloat        x,
8699                             gfloat        y)
8700 {
8701   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8702
8703   g_object_freeze_notify (G_OBJECT (self));
8704
8705   clutter_actor_set_x (self, x);
8706   clutter_actor_set_y (self, y);
8707
8708   g_object_thaw_notify (G_OBJECT (self));
8709 }
8710
8711 /**
8712  * clutter_actor_get_fixed_position_set:
8713  * @self: A #ClutterActor
8714  *
8715  * Checks whether an actor has a fixed position set (and will thus be
8716  * unaffected by any layout manager).
8717  *
8718  * Return value: %TRUE if the fixed position is set on the actor
8719  *
8720  * Since: 0.8
8721  */
8722 gboolean
8723 clutter_actor_get_fixed_position_set (ClutterActor *self)
8724 {
8725   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8726
8727   return self->priv->position_set;
8728 }
8729
8730 /**
8731  * clutter_actor_set_fixed_position_set:
8732  * @self: A #ClutterActor
8733  * @is_set: whether to use fixed position
8734  *
8735  * Sets whether an actor has a fixed position set (and will thus be
8736  * unaffected by any layout manager).
8737  *
8738  * Since: 0.8
8739  */
8740 void
8741 clutter_actor_set_fixed_position_set (ClutterActor *self,
8742                                       gboolean      is_set)
8743 {
8744   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8745
8746   if (self->priv->position_set == (is_set != FALSE))
8747     return;
8748
8749   self->priv->position_set = is_set != FALSE;
8750   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8751
8752   clutter_actor_queue_relayout (self);
8753 }
8754
8755 /**
8756  * clutter_actor_move_by:
8757  * @self: A #ClutterActor
8758  * @dx: Distance to move Actor on X axis.
8759  * @dy: Distance to move Actor on Y axis.
8760  *
8761  * Moves an actor by the specified distance relative to its current
8762  * position in pixels.
8763  *
8764  * This function modifies the fixed position of an actor and thus removes
8765  * it from any layout management. Another way to move an actor is with an
8766  * anchor point, see clutter_actor_set_anchor_point().
8767  *
8768  * Since: 0.2
8769  */
8770 void
8771 clutter_actor_move_by (ClutterActor *self,
8772                        gfloat        dx,
8773                        gfloat        dy)
8774 {
8775   const ClutterLayoutInfo *info;
8776   gfloat x, y;
8777
8778   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8779
8780   info = _clutter_actor_get_layout_info_or_defaults (self);
8781   x = info->fixed_x;
8782   y = info->fixed_y;
8783
8784   clutter_actor_set_position (self, x + dx, y + dy);
8785 }
8786
8787 static void
8788 clutter_actor_set_min_width (ClutterActor *self,
8789                              gfloat        min_width)
8790 {
8791   ClutterActorPrivate *priv = self->priv;
8792   ClutterActorBox old = { 0, };
8793   ClutterLayoutInfo *info;
8794
8795   /* if we are setting the size on a top-level actor and the
8796    * backend only supports static top-levels (e.g. framebuffers)
8797    * then we ignore the passed value and we override it with
8798    * the stage implementation's preferred size.
8799    */
8800   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8801       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8802     return;
8803
8804   info = _clutter_actor_get_layout_info (self);
8805
8806   if (priv->min_width_set && min_width == info->min_width)
8807     return;
8808
8809   g_object_freeze_notify (G_OBJECT (self));
8810
8811   clutter_actor_store_old_geometry (self, &old);
8812
8813   info->min_width = min_width;
8814   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8815   clutter_actor_set_min_width_set (self, TRUE);
8816
8817   clutter_actor_notify_if_geometry_changed (self, &old);
8818
8819   g_object_thaw_notify (G_OBJECT (self));
8820
8821   clutter_actor_queue_relayout (self);
8822 }
8823
8824 static void
8825 clutter_actor_set_min_height (ClutterActor *self,
8826                               gfloat        min_height)
8827
8828 {
8829   ClutterActorPrivate *priv = self->priv;
8830   ClutterActorBox old = { 0, };
8831   ClutterLayoutInfo *info;
8832
8833   /* if we are setting the size on a top-level actor and the
8834    * backend only supports static top-levels (e.g. framebuffers)
8835    * then we ignore the passed value and we override it with
8836    * the stage implementation's preferred size.
8837    */
8838   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8839       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8840     return;
8841
8842   info = _clutter_actor_get_layout_info (self);
8843
8844   if (priv->min_height_set && min_height == info->min_height)
8845     return;
8846
8847   g_object_freeze_notify (G_OBJECT (self));
8848
8849   clutter_actor_store_old_geometry (self, &old);
8850
8851   info->min_height = min_height;
8852   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8853   clutter_actor_set_min_height_set (self, TRUE);
8854
8855   clutter_actor_notify_if_geometry_changed (self, &old);
8856
8857   g_object_thaw_notify (G_OBJECT (self));
8858
8859   clutter_actor_queue_relayout (self);
8860 }
8861
8862 static void
8863 clutter_actor_set_natural_width (ClutterActor *self,
8864                                  gfloat        natural_width)
8865 {
8866   ClutterActorPrivate *priv = self->priv;
8867   ClutterActorBox old = { 0, };
8868   ClutterLayoutInfo *info;
8869
8870   /* if we are setting the size on a top-level actor and the
8871    * backend only supports static top-levels (e.g. framebuffers)
8872    * then we ignore the passed value and we override it with
8873    * the stage implementation's preferred size.
8874    */
8875   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8876       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8877     return;
8878
8879   info = _clutter_actor_get_layout_info (self);
8880
8881   if (priv->natural_width_set && natural_width == info->natural_width)
8882     return;
8883
8884   g_object_freeze_notify (G_OBJECT (self));
8885
8886   clutter_actor_store_old_geometry (self, &old);
8887
8888   info->natural_width = natural_width;
8889   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8890   clutter_actor_set_natural_width_set (self, TRUE);
8891
8892   clutter_actor_notify_if_geometry_changed (self, &old);
8893
8894   g_object_thaw_notify (G_OBJECT (self));
8895
8896   clutter_actor_queue_relayout (self);
8897 }
8898
8899 static void
8900 clutter_actor_set_natural_height (ClutterActor *self,
8901                                   gfloat        natural_height)
8902 {
8903   ClutterActorPrivate *priv = self->priv;
8904   ClutterActorBox old = { 0, };
8905   ClutterLayoutInfo *info;
8906
8907   /* if we are setting the size on a top-level actor and the
8908    * backend only supports static top-levels (e.g. framebuffers)
8909    * then we ignore the passed value and we override it with
8910    * the stage implementation's preferred size.
8911    */
8912   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8913       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8914     return;
8915
8916   info = _clutter_actor_get_layout_info (self);
8917
8918   if (priv->natural_height_set && natural_height == info->natural_height)
8919     return;
8920
8921   g_object_freeze_notify (G_OBJECT (self));
8922
8923   clutter_actor_store_old_geometry (self, &old);
8924
8925   info->natural_height = natural_height;
8926   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8927   clutter_actor_set_natural_height_set (self, TRUE);
8928
8929   clutter_actor_notify_if_geometry_changed (self, &old);
8930
8931   g_object_thaw_notify (G_OBJECT (self));
8932
8933   clutter_actor_queue_relayout (self);
8934 }
8935
8936 static void
8937 clutter_actor_set_min_width_set (ClutterActor *self,
8938                                  gboolean      use_min_width)
8939 {
8940   ClutterActorPrivate *priv = self->priv;
8941   ClutterActorBox old = { 0, };
8942
8943   if (priv->min_width_set == (use_min_width != FALSE))
8944     return;
8945
8946   clutter_actor_store_old_geometry (self, &old);
8947
8948   priv->min_width_set = use_min_width != FALSE;
8949   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8950
8951   clutter_actor_notify_if_geometry_changed (self, &old);
8952
8953   clutter_actor_queue_relayout (self);
8954 }
8955
8956 static void
8957 clutter_actor_set_min_height_set (ClutterActor *self,
8958                                   gboolean      use_min_height)
8959 {
8960   ClutterActorPrivate *priv = self->priv;
8961   ClutterActorBox old = { 0, };
8962
8963   if (priv->min_height_set == (use_min_height != FALSE))
8964     return;
8965
8966   clutter_actor_store_old_geometry (self, &old);
8967
8968   priv->min_height_set = use_min_height != FALSE;
8969   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8970
8971   clutter_actor_notify_if_geometry_changed (self, &old);
8972
8973   clutter_actor_queue_relayout (self);
8974 }
8975
8976 static void
8977 clutter_actor_set_natural_width_set (ClutterActor *self,
8978                                      gboolean      use_natural_width)
8979 {
8980   ClutterActorPrivate *priv = self->priv;
8981   ClutterActorBox old = { 0, };
8982
8983   if (priv->natural_width_set == (use_natural_width != FALSE))
8984     return;
8985
8986   clutter_actor_store_old_geometry (self, &old);
8987
8988   priv->natural_width_set = use_natural_width != FALSE;
8989   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8990
8991   clutter_actor_notify_if_geometry_changed (self, &old);
8992
8993   clutter_actor_queue_relayout (self);
8994 }
8995
8996 static void
8997 clutter_actor_set_natural_height_set (ClutterActor *self,
8998                                       gboolean      use_natural_height)
8999 {
9000   ClutterActorPrivate *priv = self->priv;
9001   ClutterActorBox old = { 0, };
9002
9003   if (priv->natural_height_set == (use_natural_height != FALSE))
9004     return;
9005
9006   clutter_actor_store_old_geometry (self, &old);
9007
9008   priv->natural_height_set = use_natural_height != FALSE;
9009   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9010
9011   clutter_actor_notify_if_geometry_changed (self, &old);
9012
9013   clutter_actor_queue_relayout (self);
9014 }
9015
9016 /**
9017  * clutter_actor_set_request_mode:
9018  * @self: a #ClutterActor
9019  * @mode: the request mode
9020  *
9021  * Sets the geometry request mode of @self.
9022  *
9023  * The @mode determines the order for invoking
9024  * clutter_actor_get_preferred_width() and
9025  * clutter_actor_get_preferred_height()
9026  *
9027  * Since: 1.2
9028  */
9029 void
9030 clutter_actor_set_request_mode (ClutterActor       *self,
9031                                 ClutterRequestMode  mode)
9032 {
9033   ClutterActorPrivate *priv;
9034
9035   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9036
9037   priv = self->priv;
9038
9039   if (priv->request_mode == mode)
9040     return;
9041
9042   priv->request_mode = mode;
9043
9044   priv->needs_width_request = TRUE;
9045   priv->needs_height_request = TRUE;
9046
9047   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9048
9049   clutter_actor_queue_relayout (self);
9050 }
9051
9052 /**
9053  * clutter_actor_get_request_mode:
9054  * @self: a #ClutterActor
9055  *
9056  * Retrieves the geometry request mode of @self
9057  *
9058  * Return value: the request mode for the actor
9059  *
9060  * Since: 1.2
9061  */
9062 ClutterRequestMode
9063 clutter_actor_get_request_mode (ClutterActor *self)
9064 {
9065   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9066                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9067
9068   return self->priv->request_mode;
9069 }
9070
9071 /* variant of set_width() without checks and without notification
9072  * freeze+thaw, for internal usage only
9073  */
9074 static inline void
9075 clutter_actor_set_width_internal (ClutterActor *self,
9076                                   gfloat        width)
9077 {
9078   if (width >= 0)
9079     {
9080       /* the Stage will use the :min-width to control the minimum
9081        * width to be resized to, so we should not be setting it
9082        * along with the :natural-width
9083        */
9084       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9085         clutter_actor_set_min_width (self, width);
9086
9087       clutter_actor_set_natural_width (self, width);
9088     }
9089   else
9090     {
9091       /* we only unset the :natural-width for the Stage */
9092       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9093         clutter_actor_set_min_width_set (self, FALSE);
9094
9095       clutter_actor_set_natural_width_set (self, FALSE);
9096     }
9097 }
9098
9099 /* variant of set_height() without checks and without notification
9100  * freeze+thaw, for internal usage only
9101  */
9102 static inline void
9103 clutter_actor_set_height_internal (ClutterActor *self,
9104                                    gfloat        height)
9105 {
9106   if (height >= 0)
9107     {
9108       /* see the comment above in set_width_internal() */
9109       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9110         clutter_actor_set_min_height (self, height);
9111
9112       clutter_actor_set_natural_height (self, height);
9113     }
9114   else
9115     {
9116       /* see the comment above in set_width_internal() */
9117       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9118         clutter_actor_set_min_height_set (self, FALSE);
9119
9120       clutter_actor_set_natural_height_set (self, FALSE);
9121     }
9122 }
9123
9124 /**
9125  * clutter_actor_set_size:
9126  * @self: A #ClutterActor
9127  * @width: New width of actor in pixels, or -1
9128  * @height: New height of actor in pixels, or -1
9129  *
9130  * Sets the actor's size request in pixels. This overrides any
9131  * "normal" size request the actor would have. For example
9132  * a text actor might normally request the size of the text;
9133  * this function would force a specific size instead.
9134  *
9135  * If @width and/or @height are -1 the actor will use its
9136  * "normal" size request instead of overriding it, i.e.
9137  * you can "unset" the size with -1.
9138  *
9139  * This function sets or unsets both the minimum and natural size.
9140  */
9141 void
9142 clutter_actor_set_size (ClutterActor *self,
9143                         gfloat        width,
9144                         gfloat        height)
9145 {
9146   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9147
9148   g_object_freeze_notify (G_OBJECT (self));
9149
9150   clutter_actor_set_width (self, width);
9151   clutter_actor_set_height (self, height);
9152
9153   g_object_thaw_notify (G_OBJECT (self));
9154 }
9155
9156 /**
9157  * clutter_actor_get_size:
9158  * @self: A #ClutterActor
9159  * @width: (out) (allow-none): return location for the width, or %NULL.
9160  * @height: (out) (allow-none): return location for the height, or %NULL.
9161  *
9162  * This function tries to "do what you mean" and return
9163  * the size an actor will have. If the actor has a valid
9164  * allocation, the allocation will be returned; otherwise,
9165  * the actors natural size request will be returned.
9166  *
9167  * If you care whether you get the request vs. the allocation, you
9168  * should probably call a different function like
9169  * clutter_actor_get_allocation_box() or
9170  * clutter_actor_get_preferred_width().
9171  *
9172  * Since: 0.2
9173  */
9174 void
9175 clutter_actor_get_size (ClutterActor *self,
9176                         gfloat       *width,
9177                         gfloat       *height)
9178 {
9179   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9180
9181   if (width)
9182     *width = clutter_actor_get_width (self);
9183
9184   if (height)
9185     *height = clutter_actor_get_height (self);
9186 }
9187
9188 /**
9189  * clutter_actor_get_position:
9190  * @self: a #ClutterActor
9191  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9192  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9193  *
9194  * This function tries to "do what you mean" and tell you where the
9195  * actor is, prior to any transformations. Retrieves the fixed
9196  * position of an actor in pixels, if one has been set; otherwise, if
9197  * the allocation is valid, returns the actor's allocated position;
9198  * otherwise, returns 0,0.
9199  *
9200  * The returned position is in pixels.
9201  *
9202  * Since: 0.6
9203  */
9204 void
9205 clutter_actor_get_position (ClutterActor *self,
9206                             gfloat       *x,
9207                             gfloat       *y)
9208 {
9209   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9210
9211   if (x)
9212     *x = clutter_actor_get_x (self);
9213
9214   if (y)
9215     *y = clutter_actor_get_y (self);
9216 }
9217
9218 /**
9219  * clutter_actor_get_transformed_position:
9220  * @self: A #ClutterActor
9221  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9222  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9223  *
9224  * Gets the absolute position of an actor, in pixels relative to the stage.
9225  *
9226  * Since: 0.8
9227  */
9228 void
9229 clutter_actor_get_transformed_position (ClutterActor *self,
9230                                         gfloat       *x,
9231                                         gfloat       *y)
9232 {
9233   ClutterVertex v1;
9234   ClutterVertex v2;
9235
9236   v1.x = v1.y = v1.z = 0;
9237   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9238
9239   if (x)
9240     *x = v2.x;
9241
9242   if (y)
9243     *y = v2.y;
9244 }
9245
9246 /**
9247  * clutter_actor_get_transformed_size:
9248  * @self: A #ClutterActor
9249  * @width: (out) (allow-none): return location for the width, or %NULL
9250  * @height: (out) (allow-none): return location for the height, or %NULL
9251  *
9252  * Gets the absolute size of an actor in pixels, taking into account the
9253  * scaling factors.
9254  *
9255  * If the actor has a valid allocation, the allocated size will be used.
9256  * If the actor has not a valid allocation then the preferred size will
9257  * be transformed and returned.
9258  *
9259  * If you want the transformed allocation, see
9260  * clutter_actor_get_abs_allocation_vertices() instead.
9261  *
9262  * <note>When the actor (or one of its ancestors) is rotated around the
9263  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9264  * as a generic quadrangle; in that case this function returns the size
9265  * of the smallest rectangle that encapsulates the entire quad. Please
9266  * note that in this case no assumptions can be made about the relative
9267  * position of this envelope to the absolute position of the actor, as
9268  * returned by clutter_actor_get_transformed_position(); if you need this
9269  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9270  * to get the coords of the actual quadrangle.</note>
9271  *
9272  * Since: 0.8
9273  */
9274 void
9275 clutter_actor_get_transformed_size (ClutterActor *self,
9276                                     gfloat       *width,
9277                                     gfloat       *height)
9278 {
9279   ClutterActorPrivate *priv;
9280   ClutterVertex v[4];
9281   gfloat x_min, x_max, y_min, y_max;
9282   gint i;
9283
9284   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9285
9286   priv = self->priv;
9287
9288   /* if the actor hasn't been allocated yet, get the preferred
9289    * size and transform that
9290    */
9291   if (priv->needs_allocation)
9292     {
9293       gfloat natural_width, natural_height;
9294       ClutterActorBox box;
9295
9296       /* Make a fake allocation to transform.
9297        *
9298        * NB: _clutter_actor_transform_and_project_box expects a box in
9299        * the actor's coordinate space... */
9300
9301       box.x1 = 0;
9302       box.y1 = 0;
9303
9304       natural_width = natural_height = 0;
9305       clutter_actor_get_preferred_size (self, NULL, NULL,
9306                                         &natural_width,
9307                                         &natural_height);
9308
9309       box.x2 = natural_width;
9310       box.y2 = natural_height;
9311
9312       _clutter_actor_transform_and_project_box (self, &box, v);
9313     }
9314   else
9315     clutter_actor_get_abs_allocation_vertices (self, v);
9316
9317   x_min = x_max = v[0].x;
9318   y_min = y_max = v[0].y;
9319
9320   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9321     {
9322       if (v[i].x < x_min)
9323         x_min = v[i].x;
9324
9325       if (v[i].x > x_max)
9326         x_max = v[i].x;
9327
9328       if (v[i].y < y_min)
9329         y_min = v[i].y;
9330
9331       if (v[i].y > y_max)
9332         y_max = v[i].y;
9333     }
9334
9335   if (width)
9336     *width  = x_max - x_min;
9337
9338   if (height)
9339     *height = y_max - y_min;
9340 }
9341
9342 /**
9343  * clutter_actor_get_width:
9344  * @self: A #ClutterActor
9345  *
9346  * Retrieves the width of a #ClutterActor.
9347  *
9348  * If the actor has a valid allocation, this function will return the
9349  * width of the allocated area given to the actor.
9350  *
9351  * If the actor does not have a valid allocation, this function will
9352  * return the actor's natural width, that is the preferred width of
9353  * the actor.
9354  *
9355  * If you care whether you get the preferred width or the width that
9356  * has been assigned to the actor, you should probably call a different
9357  * function like clutter_actor_get_allocation_box() to retrieve the
9358  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9359  * preferred width.
9360  *
9361  * If an actor has a fixed width, for instance a width that has been
9362  * assigned using clutter_actor_set_width(), the width returned will
9363  * be the same value.
9364  *
9365  * Return value: the width of the actor, in pixels
9366  */
9367 gfloat
9368 clutter_actor_get_width (ClutterActor *self)
9369 {
9370   ClutterActorPrivate *priv;
9371
9372   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9373
9374   priv = self->priv;
9375
9376   if (priv->needs_allocation)
9377     {
9378       gfloat natural_width = 0;
9379
9380       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9381         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9382       else
9383         {
9384           gfloat natural_height = 0;
9385
9386           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9387           clutter_actor_get_preferred_width (self, natural_height,
9388                                              NULL,
9389                                              &natural_width);
9390         }
9391
9392       return natural_width;
9393     }
9394   else
9395     return priv->allocation.x2 - priv->allocation.x1;
9396 }
9397
9398 /**
9399  * clutter_actor_get_height:
9400  * @self: A #ClutterActor
9401  *
9402  * Retrieves the height of a #ClutterActor.
9403  *
9404  * If the actor has a valid allocation, this function will return the
9405  * height of the allocated area given to the actor.
9406  *
9407  * If the actor does not have a valid allocation, this function will
9408  * return the actor's natural height, that is the preferred height of
9409  * the actor.
9410  *
9411  * If you care whether you get the preferred height or the height that
9412  * has been assigned to the actor, you should probably call a different
9413  * function like clutter_actor_get_allocation_box() to retrieve the
9414  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9415  * preferred height.
9416  *
9417  * If an actor has a fixed height, for instance a height that has been
9418  * assigned using clutter_actor_set_height(), the height returned will
9419  * be the same value.
9420  *
9421  * Return value: the height of the actor, in pixels
9422  */
9423 gfloat
9424 clutter_actor_get_height (ClutterActor *self)
9425 {
9426   ClutterActorPrivate *priv;
9427
9428   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9429
9430   priv = self->priv;
9431
9432   if (priv->needs_allocation)
9433     {
9434       gfloat natural_height = 0;
9435
9436       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9437         {
9438           gfloat natural_width = 0;
9439
9440           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9441           clutter_actor_get_preferred_height (self, natural_width,
9442                                               NULL, &natural_height);
9443         }
9444       else
9445         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9446
9447       return natural_height;
9448     }
9449   else
9450     return priv->allocation.y2 - priv->allocation.y1;
9451 }
9452
9453 /**
9454  * clutter_actor_set_width:
9455  * @self: A #ClutterActor
9456  * @width: Requested new width for the actor, in pixels, or -1
9457  *
9458  * Forces a width on an actor, causing the actor's preferred width
9459  * and height (if any) to be ignored.
9460  *
9461  * If @width is -1 the actor will use its preferred width request
9462  * instead of overriding it, i.e. you can "unset" the width with -1.
9463  *
9464  * This function sets both the minimum and natural size of the actor.
9465  *
9466  * since: 0.2
9467  */
9468 void
9469 clutter_actor_set_width (ClutterActor *self,
9470                          gfloat        width)
9471 {
9472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9473
9474   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9475     {
9476       float cur_size;
9477
9478       /* minor optimization: if we don't have a duration
9479        * then we can skip the get_width() below, to avoid
9480        * the chance of going through get_preferred_width()
9481        * just to jump to a new desired width.
9482        */
9483       if (clutter_actor_get_easing_duration (self) == 0)
9484         {
9485           g_object_freeze_notify (G_OBJECT (self));
9486
9487           clutter_actor_set_width_internal (self, width);
9488
9489           g_object_thaw_notify (G_OBJECT (self));
9490
9491           return;
9492         }
9493       else
9494         cur_size = clutter_actor_get_width (self);
9495
9496       _clutter_actor_create_transition (self,
9497                                         obj_props[PROP_WIDTH],
9498                                         cur_size,
9499                                         width);
9500     }
9501   else
9502     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9503
9504   clutter_actor_queue_relayout (self);
9505 }
9506
9507 /**
9508  * clutter_actor_set_height:
9509  * @self: A #ClutterActor
9510  * @height: Requested new height for the actor, in pixels, or -1
9511  *
9512  * Forces a height on an actor, causing the actor's preferred width
9513  * and height (if any) to be ignored.
9514  *
9515  * If @height is -1 the actor will use its preferred height instead of
9516  * overriding it, i.e. you can "unset" the height with -1.
9517  *
9518  * This function sets both the minimum and natural size of the actor.
9519  *
9520  * since: 0.2
9521  */
9522 void
9523 clutter_actor_set_height (ClutterActor *self,
9524                           gfloat        height)
9525 {
9526   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9527
9528   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9529     {
9530       float cur_size;
9531
9532       /* see the comment in clutter_actor_set_width() above */
9533       if (clutter_actor_get_easing_duration (self) == 0)
9534         {
9535           g_object_freeze_notify (G_OBJECT (self));
9536
9537           clutter_actor_set_height_internal (self, height);
9538
9539           g_object_thaw_notify (G_OBJECT (self));
9540
9541           return;
9542         }
9543       else
9544         cur_size = clutter_actor_get_height (self);
9545
9546       _clutter_actor_create_transition (self,
9547                                         obj_props[PROP_HEIGHT],
9548                                         cur_size,
9549                                         height);
9550     }
9551   else
9552     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9553
9554   clutter_actor_queue_relayout (self);
9555 }
9556
9557 static inline void
9558 clutter_actor_set_x_internal (ClutterActor *self,
9559                               float         x)
9560 {
9561   ClutterActorPrivate *priv = self->priv;
9562   ClutterLayoutInfo *linfo;
9563   ClutterActorBox old = { 0, };
9564
9565   linfo = _clutter_actor_get_layout_info (self);
9566
9567   if (priv->position_set && linfo->fixed_x == x)
9568     return;
9569
9570   clutter_actor_store_old_geometry (self, &old);
9571
9572   linfo->fixed_x = x;
9573   clutter_actor_set_fixed_position_set (self, TRUE);
9574
9575   clutter_actor_notify_if_geometry_changed (self, &old);
9576
9577   clutter_actor_queue_relayout (self);
9578 }
9579
9580 static inline void
9581 clutter_actor_set_y_internal (ClutterActor *self,
9582                               float         y)
9583 {
9584   ClutterActorPrivate *priv = self->priv;
9585   ClutterLayoutInfo *linfo;
9586   ClutterActorBox old = { 0, };
9587
9588   linfo = _clutter_actor_get_layout_info (self);
9589
9590   if (priv->position_set && linfo->fixed_y == y)
9591     return;
9592
9593   clutter_actor_store_old_geometry (self, &old);
9594
9595   linfo->fixed_y = y;
9596   clutter_actor_set_fixed_position_set (self, TRUE);
9597
9598   clutter_actor_notify_if_geometry_changed (self, &old);
9599
9600   clutter_actor_queue_relayout (self);
9601 }
9602
9603 /**
9604  * clutter_actor_set_x:
9605  * @self: a #ClutterActor
9606  * @x: the actor's position on the X axis
9607  *
9608  * Sets the actor's X coordinate, relative to its parent, in pixels.
9609  *
9610  * Overrides any layout manager and forces a fixed position for
9611  * the actor.
9612  *
9613  * The #ClutterActor:x property is animatable.
9614  *
9615  * Since: 0.6
9616  */
9617 void
9618 clutter_actor_set_x (ClutterActor *self,
9619                      gfloat        x)
9620 {
9621   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9622
9623   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9624     {
9625       float cur_position = clutter_actor_get_x (self);
9626
9627       _clutter_actor_create_transition (self, obj_props[PROP_X],
9628                                         cur_position,
9629                                         x);
9630     }
9631   else
9632     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9633
9634   clutter_actor_queue_relayout (self);
9635 }
9636
9637 /**
9638  * clutter_actor_set_y:
9639  * @self: a #ClutterActor
9640  * @y: the actor's position on the Y axis
9641  *
9642  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9643  *
9644  * Overrides any layout manager and forces a fixed position for
9645  * the actor.
9646  *
9647  * The #ClutterActor:y property is animatable.
9648  *
9649  * Since: 0.6
9650  */
9651 void
9652 clutter_actor_set_y (ClutterActor *self,
9653                      gfloat        y)
9654 {
9655   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9656
9657   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9658     {
9659       float cur_position = clutter_actor_get_y (self);
9660
9661       _clutter_actor_create_transition (self, obj_props[PROP_Y],
9662                                         cur_position,
9663                                         y);
9664     }
9665   else
9666     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9667
9668   clutter_actor_queue_relayout (self);
9669 }
9670
9671 /**
9672  * clutter_actor_get_x:
9673  * @self: A #ClutterActor
9674  *
9675  * Retrieves the X coordinate of a #ClutterActor.
9676  *
9677  * This function tries to "do what you mean", by returning the
9678  * correct value depending on the actor's state.
9679  *
9680  * If the actor has a valid allocation, this function will return
9681  * the X coordinate of the origin of the allocation box.
9682  *
9683  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9684  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9685  * function will return that coordinate.
9686  *
9687  * If both the allocation and a fixed position are missing, this function
9688  * will return 0.
9689  *
9690  * Return value: the X coordinate, in pixels, ignoring any
9691  *   transformation (i.e. scaling, rotation)
9692  */
9693 gfloat
9694 clutter_actor_get_x (ClutterActor *self)
9695 {
9696   ClutterActorPrivate *priv;
9697
9698   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9699
9700   priv = self->priv;
9701
9702   if (priv->needs_allocation)
9703     {
9704       if (priv->position_set)
9705         {
9706           const ClutterLayoutInfo *info;
9707
9708           info = _clutter_actor_get_layout_info_or_defaults (self);
9709
9710           return info->fixed_x;
9711         }
9712       else
9713         return 0;
9714     }
9715   else
9716     return priv->allocation.x1;
9717 }
9718
9719 /**
9720  * clutter_actor_get_y:
9721  * @self: A #ClutterActor
9722  *
9723  * Retrieves the Y coordinate of a #ClutterActor.
9724  *
9725  * This function tries to "do what you mean", by returning the
9726  * correct value depending on the actor's state.
9727  *
9728  * If the actor has a valid allocation, this function will return
9729  * the Y coordinate of the origin of the allocation box.
9730  *
9731  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9732  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9733  * function will return that coordinate.
9734  *
9735  * If both the allocation and a fixed position are missing, this function
9736  * will return 0.
9737  *
9738  * Return value: the Y coordinate, in pixels, ignoring any
9739  *   transformation (i.e. scaling, rotation)
9740  */
9741 gfloat
9742 clutter_actor_get_y (ClutterActor *self)
9743 {
9744   ClutterActorPrivate *priv;
9745
9746   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9747
9748   priv = self->priv;
9749
9750   if (priv->needs_allocation)
9751     {
9752       if (priv->position_set)
9753         {
9754           const ClutterLayoutInfo *info;
9755
9756           info = _clutter_actor_get_layout_info_or_defaults (self);
9757
9758           return info->fixed_y;
9759         }
9760       else
9761         return 0;
9762     }
9763   else
9764     return priv->allocation.y1;
9765 }
9766
9767 /**
9768  * clutter_actor_set_scale:
9769  * @self: A #ClutterActor
9770  * @scale_x: double factor to scale actor by horizontally.
9771  * @scale_y: double factor to scale actor by vertically.
9772  *
9773  * Scales an actor with the given factors. The scaling is relative to
9774  * the scale center and the anchor point. The scale center is
9775  * unchanged by this function and defaults to 0,0.
9776  *
9777  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9778  * animatable.
9779  *
9780  * Since: 0.2
9781  */
9782 void
9783 clutter_actor_set_scale (ClutterActor *self,
9784                          gdouble       scale_x,
9785                          gdouble       scale_y)
9786 {
9787   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9788
9789   g_object_freeze_notify (G_OBJECT (self));
9790
9791   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9792   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9793
9794   g_object_thaw_notify (G_OBJECT (self));
9795 }
9796
9797 /**
9798  * clutter_actor_set_scale_full:
9799  * @self: A #ClutterActor
9800  * @scale_x: double factor to scale actor by horizontally.
9801  * @scale_y: double factor to scale actor by vertically.
9802  * @center_x: X coordinate of the center of the scale.
9803  * @center_y: Y coordinate of the center of the scale
9804  *
9805  * Scales an actor with the given factors around the given center
9806  * point. The center point is specified in pixels relative to the
9807  * anchor point (usually the top left corner of the actor).
9808  *
9809  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9810  * are animatable.
9811  *
9812  * Since: 1.0
9813  */
9814 void
9815 clutter_actor_set_scale_full (ClutterActor *self,
9816                               gdouble       scale_x,
9817                               gdouble       scale_y,
9818                               gfloat        center_x,
9819                               gfloat        center_y)
9820 {
9821   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9822
9823   g_object_freeze_notify (G_OBJECT (self));
9824
9825   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9826   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9827   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9828   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9829
9830   g_object_thaw_notify (G_OBJECT (self));
9831 }
9832
9833 /**
9834  * clutter_actor_set_scale_with_gravity:
9835  * @self: A #ClutterActor
9836  * @scale_x: double factor to scale actor by horizontally.
9837  * @scale_y: double factor to scale actor by vertically.
9838  * @gravity: the location of the scale center expressed as a compass
9839  * direction.
9840  *
9841  * Scales an actor with the given factors around the given
9842  * center point. The center point is specified as one of the compass
9843  * directions in #ClutterGravity. For example, setting it to north
9844  * will cause the top of the actor to remain unchanged and the rest of
9845  * the actor to expand left, right and downwards.
9846  *
9847  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9848  * animatable.
9849  *
9850  * Since: 1.0
9851  */
9852 void
9853 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9854                                       gdouble         scale_x,
9855                                       gdouble         scale_y,
9856                                       ClutterGravity  gravity)
9857 {
9858   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9859
9860   g_object_freeze_notify (G_OBJECT (self));
9861
9862   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9863   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9864   clutter_actor_set_scale_gravity (self, gravity);
9865
9866   g_object_thaw_notify (G_OBJECT (self));
9867 }
9868
9869 /**
9870  * clutter_actor_get_scale:
9871  * @self: A #ClutterActor
9872  * @scale_x: (out) (allow-none): Location to store horizonal
9873  *   scale factor, or %NULL.
9874  * @scale_y: (out) (allow-none): Location to store vertical
9875  *   scale factor, or %NULL.
9876  *
9877  * Retrieves an actors scale factors.
9878  *
9879  * Since: 0.2
9880  */
9881 void
9882 clutter_actor_get_scale (ClutterActor *self,
9883                          gdouble      *scale_x,
9884                          gdouble      *scale_y)
9885 {
9886   const ClutterTransformInfo *info;
9887
9888   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9889
9890   info = _clutter_actor_get_transform_info_or_defaults (self);
9891
9892   if (scale_x)
9893     *scale_x = info->scale_x;
9894
9895   if (scale_y)
9896     *scale_y = info->scale_y;
9897 }
9898
9899 /**
9900  * clutter_actor_get_scale_center:
9901  * @self: A #ClutterActor
9902  * @center_x: (out) (allow-none): Location to store the X position
9903  *   of the scale center, or %NULL.
9904  * @center_y: (out) (allow-none): Location to store the Y position
9905  *   of the scale center, or %NULL.
9906  *
9907  * Retrieves the scale center coordinate in pixels relative to the top
9908  * left corner of the actor. If the scale center was specified using a
9909  * #ClutterGravity this will calculate the pixel offset using the
9910  * current size of the actor.
9911  *
9912  * Since: 1.0
9913  */
9914 void
9915 clutter_actor_get_scale_center (ClutterActor *self,
9916                                 gfloat       *center_x,
9917                                 gfloat       *center_y)
9918 {
9919   const ClutterTransformInfo *info;
9920
9921   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9922
9923   info = _clutter_actor_get_transform_info_or_defaults (self);
9924
9925   clutter_anchor_coord_get_units (self, &info->scale_center,
9926                                   center_x,
9927                                   center_y,
9928                                   NULL);
9929 }
9930
9931 /**
9932  * clutter_actor_get_scale_gravity:
9933  * @self: A #ClutterActor
9934  *
9935  * Retrieves the scale center as a compass direction. If the scale
9936  * center was specified in pixels or units this will return
9937  * %CLUTTER_GRAVITY_NONE.
9938  *
9939  * Return value: the scale gravity
9940  *
9941  * Since: 1.0
9942  */
9943 ClutterGravity
9944 clutter_actor_get_scale_gravity (ClutterActor *self)
9945 {
9946   const ClutterTransformInfo *info;
9947
9948   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9949
9950   info = _clutter_actor_get_transform_info_or_defaults (self);
9951
9952   return clutter_anchor_coord_get_gravity (&info->scale_center);
9953 }
9954
9955 static inline void
9956 clutter_actor_set_opacity_internal (ClutterActor *self,
9957                                     guint8        opacity)
9958 {
9959   ClutterActorPrivate *priv = self->priv;
9960
9961   if (priv->opacity != opacity)
9962     {
9963       priv->opacity = opacity;
9964
9965       /* Queue a redraw from the flatten effect so that it can use
9966          its cached image if available instead of having to redraw the
9967          actual actor. If it doesn't end up using the FBO then the
9968          effect is still able to continue the paint anyway. If there
9969          is no flatten effect yet then this is equivalent to queueing
9970          a full redraw */
9971       _clutter_actor_queue_redraw_full (self,
9972                                         0, /* flags */
9973                                         NULL, /* clip */
9974                                         priv->flatten_effect);
9975
9976       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9977     }
9978 }
9979
9980 /**
9981  * clutter_actor_set_opacity:
9982  * @self: A #ClutterActor
9983  * @opacity: New opacity value for the actor.
9984  *
9985  * Sets the actor's opacity, with zero being completely transparent and
9986  * 255 (0xff) being fully opaque.
9987  *
9988  * The #ClutterActor:opacity property is animatable.
9989  */
9990 void
9991 clutter_actor_set_opacity (ClutterActor *self,
9992                            guint8        opacity)
9993 {
9994   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9995
9996   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
9997     {
9998       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
9999                                         self->priv->opacity,
10000                                         opacity);
10001     }
10002   else
10003     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10004
10005   clutter_actor_queue_redraw (self);
10006 }
10007
10008 /*
10009  * clutter_actor_get_paint_opacity_internal:
10010  * @self: a #ClutterActor
10011  *
10012  * Retrieves the absolute opacity of the actor, as it appears on the stage
10013  *
10014  * This function does not do type checks
10015  *
10016  * Return value: the absolute opacity of the actor
10017  */
10018 static guint8
10019 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10020 {
10021   ClutterActorPrivate *priv = self->priv;
10022   ClutterActor *parent;
10023
10024   /* override the top-level opacity to always be 255; even in
10025    * case of ClutterStage:use-alpha being TRUE we want the rest
10026    * of the scene to be painted
10027    */
10028   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10029     return 255;
10030
10031   if (priv->opacity_override >= 0)
10032     return priv->opacity_override;
10033
10034   parent = priv->parent;
10035
10036   /* Factor in the actual actors opacity with parents */
10037   if (parent != NULL)
10038     {
10039       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10040
10041       if (opacity != 0xff)
10042         return (opacity * priv->opacity) / 0xff;
10043     }
10044
10045   return priv->opacity;
10046
10047 }
10048
10049 /**
10050  * clutter_actor_get_paint_opacity:
10051  * @self: A #ClutterActor
10052  *
10053  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10054  *
10055  * This function traverses the hierarchy chain and composites the opacity of
10056  * the actor with that of its parents.
10057  *
10058  * This function is intended for subclasses to use in the paint virtual
10059  * function, to paint themselves with the correct opacity.
10060  *
10061  * Return value: The actor opacity value.
10062  *
10063  * Since: 0.8
10064  */
10065 guint8
10066 clutter_actor_get_paint_opacity (ClutterActor *self)
10067 {
10068   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10069
10070   return clutter_actor_get_paint_opacity_internal (self);
10071 }
10072
10073 /**
10074  * clutter_actor_get_opacity:
10075  * @self: a #ClutterActor
10076  *
10077  * Retrieves the opacity value of an actor, as set by
10078  * clutter_actor_set_opacity().
10079  *
10080  * For retrieving the absolute opacity of the actor inside a paint
10081  * virtual function, see clutter_actor_get_paint_opacity().
10082  *
10083  * Return value: the opacity of the actor
10084  */
10085 guint8
10086 clutter_actor_get_opacity (ClutterActor *self)
10087 {
10088   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10089
10090   return self->priv->opacity;
10091 }
10092
10093 /**
10094  * clutter_actor_set_offscreen_redirect:
10095  * @self: A #ClutterActor
10096  * @redirect: New offscreen redirect flags for the actor.
10097  *
10098  * Defines the circumstances where the actor should be redirected into
10099  * an offscreen image. The offscreen image is used to flatten the
10100  * actor into a single image while painting for two main reasons.
10101  * Firstly, when the actor is painted a second time without any of its
10102  * contents changing it can simply repaint the cached image without
10103  * descending further down the actor hierarchy. Secondly, it will make
10104  * the opacity look correct even if there are overlapping primitives
10105  * in the actor.
10106  *
10107  * Caching the actor could in some cases be a performance win and in
10108  * some cases be a performance lose so it is important to determine
10109  * which value is right for an actor before modifying this value. For
10110  * example, there is never any reason to flatten an actor that is just
10111  * a single texture (such as a #ClutterTexture) because it is
10112  * effectively already cached in an image so the offscreen would be
10113  * redundant. Also if the actor contains primitives that are far apart
10114  * with a large transparent area in the middle (such as a large
10115  * CluterGroup with a small actor in the top left and a small actor in
10116  * the bottom right) then the cached image will contain the entire
10117  * image of the large area and the paint will waste time blending all
10118  * of the transparent pixels in the middle.
10119  *
10120  * The default method of implementing opacity on a container simply
10121  * forwards on the opacity to all of the children. If the children are
10122  * overlapping then it will appear as if they are two separate glassy
10123  * objects and there will be a break in the color where they
10124  * overlap. By redirecting to an offscreen buffer it will be as if the
10125  * two opaque objects are combined into one and then made transparent
10126  * which is usually what is expected.
10127  *
10128  * The image below demonstrates the difference between redirecting and
10129  * not. The image shows two Clutter groups, each containing a red and
10130  * a green rectangle which overlap. The opacity on the group is set to
10131  * 128 (which is 50%). When the offscreen redirect is not used, the
10132  * red rectangle can be seen through the blue rectangle as if the two
10133  * rectangles were separately transparent. When the redirect is used
10134  * the group as a whole is transparent instead so the red rectangle is
10135  * not visible where they overlap.
10136  *
10137  * <figure id="offscreen-redirect">
10138  *   <title>Sample of using an offscreen redirect for transparency</title>
10139  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10140  * </figure>
10141  *
10142  * The default value for this property is 0, so we effectively will
10143  * never redirect an actor offscreen by default. This means that there
10144  * are times that transparent actors may look glassy as described
10145  * above. The reason this is the default is because there is a
10146  * performance trade off between quality and performance here. In many
10147  * cases the default form of glassy opacity looks good enough, but if
10148  * it's not you will need to set the
10149  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10150  * redirection for opacity.
10151  *
10152  * Custom actors that don't contain any overlapping primitives are
10153  * recommended to override the has_overlaps() virtual to return %FALSE
10154  * for maximum efficiency.
10155  *
10156  * Since: 1.8
10157  */
10158 void
10159 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10160                                       ClutterOffscreenRedirect redirect)
10161 {
10162   ClutterActorPrivate *priv;
10163
10164   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10165
10166   priv = self->priv;
10167
10168   if (priv->offscreen_redirect != redirect)
10169     {
10170       priv->offscreen_redirect = redirect;
10171
10172       /* Queue a redraw from the effect so that it can use its cached
10173          image if available instead of having to redraw the actual
10174          actor. If it doesn't end up using the FBO then the effect is
10175          still able to continue the paint anyway. If there is no
10176          effect then this is equivalent to queuing a full redraw */
10177       _clutter_actor_queue_redraw_full (self,
10178                                         0, /* flags */
10179                                         NULL, /* clip */
10180                                         priv->flatten_effect);
10181
10182       g_object_notify_by_pspec (G_OBJECT (self),
10183                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10184     }
10185 }
10186
10187 /**
10188  * clutter_actor_get_offscreen_redirect:
10189  * @self: a #ClutterActor
10190  *
10191  * Retrieves whether to redirect the actor to an offscreen buffer, as
10192  * set by clutter_actor_set_offscreen_redirect().
10193  *
10194  * Return value: the value of the offscreen-redirect property of the actor
10195  *
10196  * Since: 1.8
10197  */
10198 ClutterOffscreenRedirect
10199 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10200 {
10201   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10202
10203   return self->priv->offscreen_redirect;
10204 }
10205
10206 /**
10207  * clutter_actor_set_name:
10208  * @self: A #ClutterActor
10209  * @name: Textual tag to apply to actor
10210  *
10211  * Sets the given name to @self. The name can be used to identify
10212  * a #ClutterActor.
10213  */
10214 void
10215 clutter_actor_set_name (ClutterActor *self,
10216                         const gchar  *name)
10217 {
10218   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10219
10220   g_free (self->priv->name);
10221   self->priv->name = g_strdup (name);
10222
10223   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10224 }
10225
10226 /**
10227  * clutter_actor_get_name:
10228  * @self: A #ClutterActor
10229  *
10230  * Retrieves the name of @self.
10231  *
10232  * Return value: the name of the actor, or %NULL. The returned string is
10233  *   owned by the actor and should not be modified or freed.
10234  */
10235 const gchar *
10236 clutter_actor_get_name (ClutterActor *self)
10237 {
10238   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10239
10240   return self->priv->name;
10241 }
10242
10243 /**
10244  * clutter_actor_get_gid:
10245  * @self: A #ClutterActor
10246  *
10247  * Retrieves the unique id for @self.
10248  *
10249  * Return value: Globally unique value for this object instance.
10250  *
10251  * Since: 0.6
10252  *
10253  * Deprecated: 1.8: The id is not used any longer.
10254  */
10255 guint32
10256 clutter_actor_get_gid (ClutterActor *self)
10257 {
10258   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10259
10260   return self->priv->id;
10261 }
10262
10263 static inline void
10264 clutter_actor_set_depth_internal (ClutterActor *self,
10265                                   float         depth)
10266 {
10267   ClutterTransformInfo *info;
10268
10269   info = _clutter_actor_get_transform_info (self);
10270
10271   if (info->depth != depth)
10272     {
10273       /* Sets Z value - XXX 2.0: should we invert? */
10274       info->depth = depth;
10275
10276       self->priv->transform_valid = FALSE;
10277
10278       /* FIXME - remove this crap; sadly, there are still containers
10279        * in Clutter that depend on this utter brain damage
10280        */
10281       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10282
10283       clutter_actor_queue_redraw (self);
10284
10285       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10286     }
10287 }
10288
10289 /**
10290  * clutter_actor_set_depth:
10291  * @self: a #ClutterActor
10292  * @depth: Z co-ord
10293  *
10294  * Sets the Z coordinate of @self to @depth.
10295  *
10296  * The unit used by @depth is dependant on the perspective setup. See
10297  * also clutter_stage_set_perspective().
10298  */
10299 void
10300 clutter_actor_set_depth (ClutterActor *self,
10301                          gfloat        depth)
10302 {
10303   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10304
10305   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10306     {
10307       const ClutterTransformInfo *info;
10308
10309       info = _clutter_actor_get_transform_info_or_defaults (self);
10310
10311       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10312                                         info->depth,
10313                                         depth);
10314     }
10315   else
10316     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10317
10318   clutter_actor_queue_redraw (self);
10319 }
10320
10321 /**
10322  * clutter_actor_get_depth:
10323  * @self: a #ClutterActor
10324  *
10325  * Retrieves the depth of @self.
10326  *
10327  * Return value: the depth of the actor
10328  */
10329 gfloat
10330 clutter_actor_get_depth (ClutterActor *self)
10331 {
10332   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10333
10334   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10335 }
10336
10337 /**
10338  * clutter_actor_set_rotation:
10339  * @self: a #ClutterActor
10340  * @axis: the axis of rotation
10341  * @angle: the angle of rotation
10342  * @x: X coordinate of the rotation center
10343  * @y: Y coordinate of the rotation center
10344  * @z: Z coordinate of the rotation center
10345  *
10346  * Sets the rotation angle of @self around the given axis.
10347  *
10348  * The rotation center coordinates used depend on the value of @axis:
10349  * <itemizedlist>
10350  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10351  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10352  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10353  * </itemizedlist>
10354  *
10355  * The rotation coordinates are relative to the anchor point of the
10356  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10357  * point is set, the upper left corner is assumed as the origin.
10358  *
10359  * Since: 0.8
10360  */
10361 void
10362 clutter_actor_set_rotation (ClutterActor      *self,
10363                             ClutterRotateAxis  axis,
10364                             gdouble            angle,
10365                             gfloat             x,
10366                             gfloat             y,
10367                             gfloat             z)
10368 {
10369   ClutterVertex v;
10370
10371   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10372
10373   v.x = x;
10374   v.y = y;
10375   v.z = z;
10376
10377   g_object_freeze_notify (G_OBJECT (self));
10378
10379   clutter_actor_set_rotation_angle (self, axis, angle);
10380   clutter_actor_set_rotation_center_internal (self, axis, &v);
10381
10382   g_object_thaw_notify (G_OBJECT (self));
10383 }
10384
10385 /**
10386  * clutter_actor_set_z_rotation_from_gravity:
10387  * @self: a #ClutterActor
10388  * @angle: the angle of rotation
10389  * @gravity: the center point of the rotation
10390  *
10391  * Sets the rotation angle of @self around the Z axis using the center
10392  * point specified as a compass point. For example to rotate such that
10393  * the center of the actor remains static you can use
10394  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10395  * will move accordingly.
10396  *
10397  * Since: 1.0
10398  */
10399 void
10400 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10401                                            gdouble         angle,
10402                                            ClutterGravity  gravity)
10403 {
10404   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10405
10406   if (gravity == CLUTTER_GRAVITY_NONE)
10407     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10408   else
10409     {
10410       GObject *obj = G_OBJECT (self);
10411       ClutterTransformInfo *info;
10412
10413       info = _clutter_actor_get_transform_info (self);
10414
10415       g_object_freeze_notify (obj);
10416
10417       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10418
10419       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10420       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10421       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10422
10423       g_object_thaw_notify (obj);
10424     }
10425 }
10426
10427 /**
10428  * clutter_actor_get_rotation:
10429  * @self: a #ClutterActor
10430  * @axis: the axis of rotation
10431  * @x: (out): return value for the X coordinate of the center of rotation
10432  * @y: (out): return value for the Y coordinate of the center of rotation
10433  * @z: (out): return value for the Z coordinate of the center of rotation
10434  *
10435  * Retrieves the angle and center of rotation on the given axis,
10436  * set using clutter_actor_set_rotation().
10437  *
10438  * Return value: the angle of rotation
10439  *
10440  * Since: 0.8
10441  */
10442 gdouble
10443 clutter_actor_get_rotation (ClutterActor      *self,
10444                             ClutterRotateAxis  axis,
10445                             gfloat            *x,
10446                             gfloat            *y,
10447                             gfloat            *z)
10448 {
10449   const ClutterTransformInfo *info;
10450   const AnchorCoord *anchor_coord;
10451   gdouble retval = 0;
10452
10453   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10454
10455   info = _clutter_actor_get_transform_info_or_defaults (self);
10456
10457   switch (axis)
10458     {
10459     case CLUTTER_X_AXIS:
10460       anchor_coord = &info->rx_center;
10461       retval = info->rx_angle;
10462       break;
10463
10464     case CLUTTER_Y_AXIS:
10465       anchor_coord = &info->ry_center;
10466       retval = info->ry_angle;
10467       break;
10468
10469     case CLUTTER_Z_AXIS:
10470       anchor_coord = &info->rz_center;
10471       retval = info->rz_angle;
10472       break;
10473
10474     default:
10475       anchor_coord = NULL;
10476       retval = 0.0;
10477       break;
10478     }
10479
10480   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10481
10482   return retval;
10483 }
10484
10485 /**
10486  * clutter_actor_get_z_rotation_gravity:
10487  * @self: A #ClutterActor
10488  *
10489  * Retrieves the center for the rotation around the Z axis as a
10490  * compass direction. If the center was specified in pixels or units
10491  * this will return %CLUTTER_GRAVITY_NONE.
10492  *
10493  * Return value: the Z rotation center
10494  *
10495  * Since: 1.0
10496  */
10497 ClutterGravity
10498 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10499 {
10500   const ClutterTransformInfo *info;
10501
10502   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10503
10504   info = _clutter_actor_get_transform_info_or_defaults (self);
10505
10506   return clutter_anchor_coord_get_gravity (&info->rz_center);
10507 }
10508
10509 /**
10510  * clutter_actor_set_clip:
10511  * @self: A #ClutterActor
10512  * @xoff: X offset of the clip rectangle
10513  * @yoff: Y offset of the clip rectangle
10514  * @width: Width of the clip rectangle
10515  * @height: Height of the clip rectangle
10516  *
10517  * Sets clip area for @self. The clip area is always computed from the
10518  * upper left corner of the actor, even if the anchor point is set
10519  * otherwise.
10520  *
10521  * Since: 0.6
10522  */
10523 void
10524 clutter_actor_set_clip (ClutterActor *self,
10525                         gfloat        xoff,
10526                         gfloat        yoff,
10527                         gfloat        width,
10528                         gfloat        height)
10529 {
10530   ClutterActorPrivate *priv;
10531
10532   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10533
10534   priv = self->priv;
10535
10536   if (priv->has_clip &&
10537       priv->clip.x == xoff &&
10538       priv->clip.y == yoff &&
10539       priv->clip.width == width &&
10540       priv->clip.height == height)
10541     return;
10542
10543   priv->clip.x = xoff;
10544   priv->clip.y = yoff;
10545   priv->clip.width = width;
10546   priv->clip.height = height;
10547
10548   priv->has_clip = TRUE;
10549
10550   clutter_actor_queue_redraw (self);
10551
10552   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10553   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10554 }
10555
10556 /**
10557  * clutter_actor_remove_clip:
10558  * @self: A #ClutterActor
10559  *
10560  * Removes clip area from @self.
10561  */
10562 void
10563 clutter_actor_remove_clip (ClutterActor *self)
10564 {
10565   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10566
10567   if (!self->priv->has_clip)
10568     return;
10569
10570   self->priv->has_clip = FALSE;
10571
10572   clutter_actor_queue_redraw (self);
10573
10574   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10575 }
10576
10577 /**
10578  * clutter_actor_has_clip:
10579  * @self: a #ClutterActor
10580  *
10581  * Determines whether the actor has a clip area set or not.
10582  *
10583  * Return value: %TRUE if the actor has a clip area set.
10584  *
10585  * Since: 0.1.1
10586  */
10587 gboolean
10588 clutter_actor_has_clip (ClutterActor *self)
10589 {
10590   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10591
10592   return self->priv->has_clip;
10593 }
10594
10595 /**
10596  * clutter_actor_get_clip:
10597  * @self: a #ClutterActor
10598  * @xoff: (out) (allow-none): return location for the X offset of
10599  *   the clip rectangle, or %NULL
10600  * @yoff: (out) (allow-none): return location for the Y offset of
10601  *   the clip rectangle, or %NULL
10602  * @width: (out) (allow-none): return location for the width of
10603  *   the clip rectangle, or %NULL
10604  * @height: (out) (allow-none): return location for the height of
10605  *   the clip rectangle, or %NULL
10606  *
10607  * Gets the clip area for @self, if any is set
10608  *
10609  * Since: 0.6
10610  */
10611 void
10612 clutter_actor_get_clip (ClutterActor *self,
10613                         gfloat       *xoff,
10614                         gfloat       *yoff,
10615                         gfloat       *width,
10616                         gfloat       *height)
10617 {
10618   ClutterActorPrivate *priv;
10619
10620   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10621
10622   priv = self->priv;
10623
10624   if (!priv->has_clip)
10625     return;
10626
10627   if (xoff != NULL)
10628     *xoff = priv->clip.x;
10629
10630   if (yoff != NULL)
10631     *yoff = priv->clip.y;
10632
10633   if (width != NULL)
10634     *width = priv->clip.width;
10635
10636   if (height != NULL)
10637     *height = priv->clip.height;
10638 }
10639
10640 /**
10641  * clutter_actor_get_children:
10642  * @self: a #ClutterActor
10643  *
10644  * Retrieves the list of children of @self.
10645  *
10646  * Return value: (transfer container) (element-type ClutterActor): A newly
10647  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10648  *   done.
10649  *
10650  * Since: 1.10
10651  */
10652 GList *
10653 clutter_actor_get_children (ClutterActor *self)
10654 {
10655   ClutterActor *iter;
10656   GList *res;
10657
10658   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10659
10660   /* we walk the list backward so that we can use prepend(),
10661    * which is O(1)
10662    */
10663   for (iter = self->priv->last_child, res = NULL;
10664        iter != NULL;
10665        iter = iter->priv->prev_sibling)
10666     {
10667       res = g_list_prepend (res, iter);
10668     }
10669
10670   return res;
10671 }
10672
10673 /*< private >
10674  * insert_child_at_depth:
10675  * @self: a #ClutterActor
10676  * @child: a #ClutterActor
10677  *
10678  * Inserts @child inside the list of children held by @self, using
10679  * the depth as the insertion criteria.
10680  *
10681  * This sadly makes the insertion not O(1), but we can keep the
10682  * list sorted so that the painters algorithm we use for painting
10683  * the children will work correctly.
10684  */
10685 static void
10686 insert_child_at_depth (ClutterActor *self,
10687                        ClutterActor *child,
10688                        gpointer      dummy G_GNUC_UNUSED)
10689 {
10690   ClutterActor *iter;
10691   float child_depth;
10692
10693   child->priv->parent = self;
10694
10695   child_depth =
10696     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10697
10698   /* special-case the first child */
10699   if (self->priv->n_children == 0)
10700     {
10701       self->priv->first_child = child;
10702       self->priv->last_child = child;
10703
10704       child->priv->next_sibling = NULL;
10705       child->priv->prev_sibling = NULL;
10706
10707       return;
10708     }
10709
10710   /* Find the right place to insert the child so that it will still be
10711      sorted and the child will be after all of the actors at the same
10712      dept */
10713   for (iter = self->priv->first_child;
10714        iter != NULL;
10715        iter = iter->priv->next_sibling)
10716     {
10717       float iter_depth;
10718
10719       iter_depth =
10720         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10721
10722       if (iter_depth > child_depth)
10723         break;
10724     }
10725
10726   if (iter != NULL)
10727     {
10728       ClutterActor *tmp = iter->priv->prev_sibling;
10729
10730       if (tmp != NULL)
10731         tmp->priv->next_sibling = child;
10732
10733       /* Insert the node before the found one */
10734       child->priv->prev_sibling = iter->priv->prev_sibling;
10735       child->priv->next_sibling = iter;
10736       iter->priv->prev_sibling = child;
10737     }
10738   else
10739     {
10740       ClutterActor *tmp = self->priv->last_child;
10741
10742       if (tmp != NULL)
10743         tmp->priv->next_sibling = child;
10744
10745       /* insert the node at the end of the list */
10746       child->priv->prev_sibling = self->priv->last_child;
10747       child->priv->next_sibling = NULL;
10748     }
10749
10750   if (child->priv->prev_sibling == NULL)
10751     self->priv->first_child = child;
10752
10753   if (child->priv->next_sibling == NULL)
10754     self->priv->last_child = child;
10755 }
10756
10757 static void
10758 insert_child_at_index (ClutterActor *self,
10759                        ClutterActor *child,
10760                        gpointer      data_)
10761 {
10762   gint index_ = GPOINTER_TO_INT (data_);
10763
10764   child->priv->parent = self;
10765
10766   if (index_ == 0)
10767     {
10768       ClutterActor *tmp = self->priv->first_child;
10769
10770       if (tmp != NULL)
10771         tmp->priv->prev_sibling = child;
10772
10773       child->priv->prev_sibling = NULL;
10774       child->priv->next_sibling = tmp;
10775     }
10776   else if (index_ < 0 || index_ >= self->priv->n_children)
10777     {
10778       ClutterActor *tmp = self->priv->last_child;
10779
10780       if (tmp != NULL)
10781         tmp->priv->next_sibling = child;
10782
10783       child->priv->prev_sibling = tmp;
10784       child->priv->next_sibling = NULL;
10785     }
10786   else
10787     {
10788       ClutterActor *iter;
10789       int i;
10790
10791       for (iter = self->priv->first_child, i = 0;
10792            iter != NULL;
10793            iter = iter->priv->next_sibling, i += 1)
10794         {
10795           if (index_ == i)
10796             {
10797               ClutterActor *tmp = iter->priv->prev_sibling;
10798
10799               child->priv->prev_sibling = tmp;
10800               child->priv->next_sibling = iter;
10801
10802               iter->priv->prev_sibling = child;
10803
10804               if (tmp != NULL)
10805                 tmp->priv->next_sibling = child;
10806
10807               break;
10808             }
10809         }
10810     }
10811
10812   if (child->priv->prev_sibling == NULL)
10813     self->priv->first_child = child;
10814
10815   if (child->priv->next_sibling == NULL)
10816     self->priv->last_child = child;
10817 }
10818
10819 static void
10820 insert_child_above (ClutterActor *self,
10821                     ClutterActor *child,
10822                     gpointer      data)
10823 {
10824   ClutterActor *sibling = data;
10825
10826   child->priv->parent = self;
10827
10828   if (sibling == NULL)
10829     sibling = self->priv->last_child;
10830
10831   child->priv->prev_sibling = sibling;
10832
10833   if (sibling != NULL)
10834     {
10835       ClutterActor *tmp = sibling->priv->next_sibling;
10836
10837       child->priv->next_sibling = tmp;
10838
10839       if (tmp != NULL)
10840         tmp->priv->prev_sibling = child;
10841
10842       sibling->priv->next_sibling = child;
10843     }
10844   else
10845     child->priv->next_sibling = NULL;
10846
10847   if (child->priv->prev_sibling == NULL)
10848     self->priv->first_child = child;
10849
10850   if (child->priv->next_sibling == NULL)
10851     self->priv->last_child = child;
10852 }
10853
10854 static void
10855 insert_child_below (ClutterActor *self,
10856                     ClutterActor *child,
10857                     gpointer      data)
10858 {
10859   ClutterActor *sibling = data;
10860
10861   child->priv->parent = self;
10862
10863   if (sibling == NULL)
10864     sibling = self->priv->first_child;
10865
10866   child->priv->next_sibling = sibling;
10867
10868   if (sibling != NULL)
10869     {
10870       ClutterActor *tmp = sibling->priv->prev_sibling;
10871
10872       child->priv->prev_sibling = tmp;
10873
10874       if (tmp != NULL)
10875         tmp->priv->next_sibling = child;
10876
10877       sibling->priv->prev_sibling = child;
10878     }
10879   else
10880     child->priv->prev_sibling = NULL;
10881
10882   if (child->priv->prev_sibling == NULL)
10883     self->priv->first_child = child;
10884
10885   if (child->priv->next_sibling == NULL)
10886     self->priv->last_child = child;
10887 }
10888
10889 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10890                                            ClutterActor *child,
10891                                            gpointer      data);
10892
10893 typedef enum {
10894   ADD_CHILD_CREATE_META       = 1 << 0,
10895   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10896   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10897   ADD_CHILD_CHECK_STATE       = 1 << 3,
10898   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10899
10900   /* default flags for public API */
10901   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10902                                ADD_CHILD_EMIT_PARENT_SET |
10903                                ADD_CHILD_EMIT_ACTOR_ADDED |
10904                                ADD_CHILD_CHECK_STATE |
10905                                ADD_CHILD_NOTIFY_FIRST_LAST,
10906
10907   /* flags for legacy/deprecated API */
10908   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10909                                ADD_CHILD_CHECK_STATE |
10910                                ADD_CHILD_NOTIFY_FIRST_LAST
10911 } ClutterActorAddChildFlags;
10912
10913 /*< private >
10914  * clutter_actor_add_child_internal:
10915  * @self: a #ClutterActor
10916  * @child: a #ClutterActor
10917  * @flags: control flags for actions
10918  * @add_func: delegate function
10919  * @data: (closure): data to pass to @add_func
10920  *
10921  * Adds @child to the list of children of @self.
10922  *
10923  * The actual insertion inside the list is delegated to @add_func: this
10924  * function will just set up the state, perform basic checks, and emit
10925  * signals.
10926  *
10927  * The @flags argument is used to perform additional operations.
10928  */
10929 static inline void
10930 clutter_actor_add_child_internal (ClutterActor              *self,
10931                                   ClutterActor              *child,
10932                                   ClutterActorAddChildFlags  flags,
10933                                   ClutterActorAddChildFunc   add_func,
10934                                   gpointer                   data)
10935 {
10936   ClutterTextDirection text_dir;
10937   gboolean create_meta;
10938   gboolean emit_parent_set, emit_actor_added;
10939   gboolean check_state;
10940   gboolean notify_first_last;
10941   ClutterActor *old_first_child, *old_last_child;
10942
10943   if (child->priv->parent != NULL)
10944     {
10945       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10946                  "use clutter_actor_remove_child() first.",
10947                  _clutter_actor_get_debug_name (child),
10948                  _clutter_actor_get_debug_name (child->priv->parent));
10949       return;
10950     }
10951
10952   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10953     {
10954       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10955                  "a child of another actor.",
10956                  _clutter_actor_get_debug_name (child));
10957       return;
10958     }
10959
10960 #if 0
10961   /* XXX - this check disallows calling methods that change the stacking
10962    * order within the destruction sequence, by triggering a critical
10963    * warning first, and leaving the actor in an undefined state, which
10964    * then ends up being caught by an assertion.
10965    *
10966    * the reproducible sequence is:
10967    *
10968    *   - actor gets destroyed;
10969    *   - another actor, linked to the first, will try to change the
10970    *     stacking order of the first actor;
10971    *   - changing the stacking order is a composite operation composed
10972    *     by the following steps:
10973    *     1. ref() the child;
10974    *     2. remove_child_internal(), which removes the reference;
10975    *     3. add_child_internal(), which adds a reference;
10976    *   - the state of the actor is not changed between (2) and (3), as
10977    *     it could be an expensive recomputation;
10978    *   - if (3) bails out, then the actor is in an undefined state, but
10979    *     still alive;
10980    *   - the destruction sequence terminates, but the actor is unparented
10981    *     while its state indicates being parented instead.
10982    *   - assertion failure.
10983    *
10984    * the obvious fix would be to decompose each set_child_*_sibling()
10985    * method into proper remove_child()/add_child(), with state validation;
10986    * this may cause excessive work, though, and trigger a cascade of other
10987    * bugs in code that assumes that a change in the stacking order is an
10988    * atomic operation.
10989    *
10990    * another potential fix is to just remove this check here, and let
10991    * code doing stacking order changes inside the destruction sequence
10992    * of an actor continue doing the work.
10993    *
10994    * the third fix is to silently bail out early from every
10995    * set_child_*_sibling() and set_child_at_index() method, and avoid
10996    * doing work.
10997    *
10998    * I have a preference for the second solution, since it involves the
10999    * least amount of work, and the least amount of code duplication.
11000    *
11001    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11002    */
11003   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11004     {
11005       g_warning ("The actor '%s' is currently being destroyed, and "
11006                  "cannot be added as a child of another actor.",
11007                  _clutter_actor_get_debug_name (child));
11008       return;
11009     }
11010 #endif
11011
11012   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11013   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11014   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11015   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11016   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11017
11018   old_first_child = self->priv->first_child;
11019   old_last_child = self->priv->last_child;
11020
11021   g_object_freeze_notify (G_OBJECT (self));
11022
11023   if (create_meta)
11024     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11025
11026   g_object_ref_sink (child);
11027   child->priv->parent = NULL;
11028   child->priv->next_sibling = NULL;
11029   child->priv->prev_sibling = NULL;
11030
11031   /* delegate the actual insertion */
11032   add_func (self, child, data);
11033
11034   g_assert (child->priv->parent == self);
11035
11036   self->priv->n_children += 1;
11037
11038   self->priv->age += 1;
11039
11040   /* if push_internal() has been called then we automatically set
11041    * the flag on the actor
11042    */
11043   if (self->priv->internal_child)
11044     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11045
11046   /* clutter_actor_reparent() will emit ::parent-set for us */
11047   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11048     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11049
11050   if (check_state)
11051     {
11052       /* If parent is mapped or realized, we need to also be mapped or
11053        * realized once we're inside the parent.
11054        */
11055       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11056
11057       /* propagate the parent's text direction to the child */
11058       text_dir = clutter_actor_get_text_direction (self);
11059       clutter_actor_set_text_direction (child, text_dir);
11060     }
11061
11062   if (child->priv->show_on_set_parent)
11063     clutter_actor_show (child);
11064
11065   if (CLUTTER_ACTOR_IS_MAPPED (child))
11066     clutter_actor_queue_redraw (child);
11067
11068   /* maintain the invariant that if an actor needs layout,
11069    * its parents do as well
11070    */
11071   if (child->priv->needs_width_request ||
11072       child->priv->needs_height_request ||
11073       child->priv->needs_allocation)
11074     {
11075       /* we work around the short-circuiting we do
11076        * in clutter_actor_queue_relayout() since we
11077        * want to force a relayout
11078        */
11079       child->priv->needs_width_request = TRUE;
11080       child->priv->needs_height_request = TRUE;
11081       child->priv->needs_allocation = TRUE;
11082
11083       clutter_actor_queue_relayout (child->priv->parent);
11084     }
11085
11086   if (emit_actor_added)
11087     g_signal_emit_by_name (self, "actor-added", child);
11088
11089   if (notify_first_last)
11090     {
11091       if (old_first_child != self->priv->first_child)
11092         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11093
11094       if (old_last_child != self->priv->last_child)
11095         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11096     }
11097
11098   g_object_thaw_notify (G_OBJECT (self));
11099 }
11100
11101 /**
11102  * clutter_actor_add_child:
11103  * @self: a #ClutterActor
11104  * @child: a #ClutterActor
11105  *
11106  * Adds @child to the children of @self.
11107  *
11108  * This function will acquire a reference on @child that will only
11109  * be released when calling clutter_actor_remove_child().
11110  *
11111  * This function will take into consideration the #ClutterActor:depth
11112  * of @child, and will keep the list of children sorted.
11113  *
11114  * This function will emit the #ClutterContainer::actor-added signal
11115  * on @self.
11116  *
11117  * Since: 1.10
11118  */
11119 void
11120 clutter_actor_add_child (ClutterActor *self,
11121                          ClutterActor *child)
11122 {
11123   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11124   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11125   g_return_if_fail (self != child);
11126   g_return_if_fail (child->priv->parent == NULL);
11127
11128   clutter_actor_add_child_internal (self, child,
11129                                     ADD_CHILD_DEFAULT_FLAGS,
11130                                     insert_child_at_depth,
11131                                     NULL);
11132 }
11133
11134 /**
11135  * clutter_actor_insert_child_at_index:
11136  * @self: a #ClutterActor
11137  * @child: a #ClutterActor
11138  * @index_: the index
11139  *
11140  * Inserts @child into the list of children of @self, using the
11141  * given @index_. If @index_ is greater than the number of children
11142  * in @self, or is less than 0, then the new child is added at the end.
11143  *
11144  * This function will acquire a reference on @child that will only
11145  * be released when calling clutter_actor_remove_child().
11146  *
11147  * This function will not take into consideration the #ClutterActor:depth
11148  * of @child.
11149  *
11150  * This function will emit the #ClutterContainer::actor-added signal
11151  * on @self.
11152  *
11153  * Since: 1.10
11154  */
11155 void
11156 clutter_actor_insert_child_at_index (ClutterActor *self,
11157                                      ClutterActor *child,
11158                                      gint          index_)
11159 {
11160   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11161   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11162   g_return_if_fail (self != child);
11163   g_return_if_fail (child->priv->parent == NULL);
11164
11165   clutter_actor_add_child_internal (self, child,
11166                                     ADD_CHILD_DEFAULT_FLAGS,
11167                                     insert_child_at_index,
11168                                     GINT_TO_POINTER (index_));
11169 }
11170
11171 /**
11172  * clutter_actor_insert_child_above:
11173  * @self: a #ClutterActor
11174  * @child: a #ClutterActor
11175  * @sibling: (allow-none): a child of @self, or %NULL
11176  *
11177  * Inserts @child into the list of children of @self, above another
11178  * child of @self or, if @sibling is %NULL, above all the children
11179  * of @self.
11180  *
11181  * This function will acquire a reference on @child that will only
11182  * be released when calling clutter_actor_remove_child().
11183  *
11184  * This function will not take into consideration the #ClutterActor:depth
11185  * of @child.
11186  *
11187  * This function will emit the #ClutterContainer::actor-added signal
11188  * on @self.
11189  *
11190  * Since: 1.10
11191  */
11192 void
11193 clutter_actor_insert_child_above (ClutterActor *self,
11194                                   ClutterActor *child,
11195                                   ClutterActor *sibling)
11196 {
11197   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11198   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11199   g_return_if_fail (self != child);
11200   g_return_if_fail (child != sibling);
11201   g_return_if_fail (child->priv->parent == NULL);
11202   g_return_if_fail (sibling == NULL ||
11203                     (CLUTTER_IS_ACTOR (sibling) &&
11204                      sibling->priv->parent == self));
11205
11206   clutter_actor_add_child_internal (self, child,
11207                                     ADD_CHILD_DEFAULT_FLAGS,
11208                                     insert_child_above,
11209                                     sibling);
11210 }
11211
11212 /**
11213  * clutter_actor_insert_child_below:
11214  * @self: a #ClutterActor
11215  * @child: a #ClutterActor
11216  * @sibling: (allow-none): a child of @self, or %NULL
11217  *
11218  * Inserts @child into the list of children of @self, below another
11219  * child of @self or, if @sibling is %NULL, below all the children
11220  * of @self.
11221  *
11222  * This function will acquire a reference on @child that will only
11223  * be released when calling clutter_actor_remove_child().
11224  *
11225  * This function will not take into consideration the #ClutterActor:depth
11226  * of @child.
11227  *
11228  * This function will emit the #ClutterContainer::actor-added signal
11229  * on @self.
11230  *
11231  * Since: 1.10
11232  */
11233 void
11234 clutter_actor_insert_child_below (ClutterActor *self,
11235                                   ClutterActor *child,
11236                                   ClutterActor *sibling)
11237 {
11238   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11239   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11240   g_return_if_fail (self != child);
11241   g_return_if_fail (child != sibling);
11242   g_return_if_fail (child->priv->parent == NULL);
11243   g_return_if_fail (sibling == NULL ||
11244                     (CLUTTER_IS_ACTOR (sibling) &&
11245                      sibling->priv->parent == self));
11246
11247   clutter_actor_add_child_internal (self, child,
11248                                     ADD_CHILD_DEFAULT_FLAGS,
11249                                     insert_child_below,
11250                                     sibling);
11251 }
11252
11253 /**
11254  * clutter_actor_set_parent:
11255  * @self: A #ClutterActor
11256  * @parent: A new #ClutterActor parent
11257  *
11258  * Sets the parent of @self to @parent.
11259  *
11260  * This function will result in @parent acquiring a reference on @self,
11261  * eventually by sinking its floating reference first. The reference
11262  * will be released by clutter_actor_unparent().
11263  *
11264  * This function should only be called by legacy #ClutterActor<!-- -->s
11265  * implementing the #ClutterContainer interface.
11266  *
11267  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11268  */
11269 void
11270 clutter_actor_set_parent (ClutterActor *self,
11271                           ClutterActor *parent)
11272 {
11273   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11274   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11275   g_return_if_fail (self != parent);
11276   g_return_if_fail (self->priv->parent == NULL);
11277
11278   /* as this function will be called inside ClutterContainer::add
11279    * implementations or when building up a composite actor, we have
11280    * to preserve the old behaviour, and not create child meta or
11281    * emit the ::actor-added signal, to avoid recursion or double
11282    * emissions
11283    */
11284   clutter_actor_add_child_internal (parent, self,
11285                                     ADD_CHILD_LEGACY_FLAGS,
11286                                     insert_child_at_depth,
11287                                     NULL);
11288 }
11289
11290 /**
11291  * clutter_actor_get_parent:
11292  * @self: A #ClutterActor
11293  *
11294  * Retrieves the parent of @self.
11295  *
11296  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11297  *  if no parent is set
11298  */
11299 ClutterActor *
11300 clutter_actor_get_parent (ClutterActor *self)
11301 {
11302   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11303
11304   return self->priv->parent;
11305 }
11306
11307 /**
11308  * clutter_actor_get_paint_visibility:
11309  * @self: A #ClutterActor
11310  *
11311  * Retrieves the 'paint' visibility of an actor recursively checking for non
11312  * visible parents.
11313  *
11314  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11315  *
11316  * Return Value: %TRUE if the actor is visibile and will be painted.
11317  *
11318  * Since: 0.8.4
11319  */
11320 gboolean
11321 clutter_actor_get_paint_visibility (ClutterActor *actor)
11322 {
11323   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11324
11325   return CLUTTER_ACTOR_IS_MAPPED (actor);
11326 }
11327
11328 /**
11329  * clutter_actor_remove_child:
11330  * @self: a #ClutterActor
11331  * @child: a #ClutterActor
11332  *
11333  * Removes @child from the children of @self.
11334  *
11335  * This function will release the reference added by
11336  * clutter_actor_add_child(), so if you want to keep using @child
11337  * you will have to acquire a referenced on it before calling this
11338  * function.
11339  *
11340  * This function will emit the #ClutterContainer::actor-removed
11341  * signal on @self.
11342  *
11343  * Since: 1.10
11344  */
11345 void
11346 clutter_actor_remove_child (ClutterActor *self,
11347                             ClutterActor *child)
11348 {
11349   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11350   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11351   g_return_if_fail (self != child);
11352   g_return_if_fail (child->priv->parent != NULL);
11353   g_return_if_fail (child->priv->parent == self);
11354
11355   clutter_actor_remove_child_internal (self, child,
11356                                        REMOVE_CHILD_DEFAULT_FLAGS);
11357 }
11358
11359 /**
11360  * clutter_actor_remove_all_children:
11361  * @self: a #ClutterActor
11362  *
11363  * Removes all children of @self.
11364  *
11365  * This function releases the reference added by inserting a child actor
11366  * in the list of children of @self.
11367  *
11368  * If the reference count of a child drops to zero, the child will be
11369  * destroyed. If you want to ensure the destruction of all the children
11370  * of @self, use clutter_actor_destroy_all_children().
11371  *
11372  * Since: 1.10
11373  */
11374 void
11375 clutter_actor_remove_all_children (ClutterActor *self)
11376 {
11377   ClutterActorIter iter;
11378
11379   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11380
11381   if (self->priv->n_children == 0)
11382     return;
11383
11384   g_object_freeze_notify (G_OBJECT (self));
11385
11386   clutter_actor_iter_init (&iter, self);
11387   while (clutter_actor_iter_next (&iter, NULL))
11388     clutter_actor_iter_remove (&iter);
11389
11390   g_object_thaw_notify (G_OBJECT (self));
11391
11392   /* sanity check */
11393   g_assert (self->priv->first_child == NULL);
11394   g_assert (self->priv->last_child == NULL);
11395   g_assert (self->priv->n_children == 0);
11396 }
11397
11398 /**
11399  * clutter_actor_destroy_all_children:
11400  * @self: a #ClutterActor
11401  *
11402  * Destroys all children of @self.
11403  *
11404  * This function releases the reference added by inserting a child
11405  * actor in the list of children of @self, and ensures that the
11406  * #ClutterActor::destroy signal is emitted on each child of the
11407  * actor.
11408  *
11409  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11410  * when its reference count drops to 0; the default handler of the
11411  * #ClutterActor::destroy signal will destroy all the children of an
11412  * actor. This function ensures that all children are destroyed, instead
11413  * of just removed from @self, unlike clutter_actor_remove_all_children()
11414  * which will merely release the reference and remove each child.
11415  *
11416  * Unless you acquired an additional reference on each child of @self
11417  * prior to calling clutter_actor_remove_all_children() and want to reuse
11418  * the actors, you should use clutter_actor_destroy_all_children() in
11419  * order to make sure that children are destroyed and signal handlers
11420  * are disconnected even in cases where circular references prevent this
11421  * from automatically happening through reference counting alone.
11422  *
11423  * Since: 1.10
11424  */
11425 void
11426 clutter_actor_destroy_all_children (ClutterActor *self)
11427 {
11428   ClutterActorIter iter;
11429
11430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11431
11432   if (self->priv->n_children == 0)
11433     return;
11434
11435   g_object_freeze_notify (G_OBJECT (self));
11436
11437   clutter_actor_iter_init (&iter, self);
11438   while (clutter_actor_iter_next (&iter, NULL))
11439     clutter_actor_iter_destroy (&iter);
11440
11441   g_object_thaw_notify (G_OBJECT (self));
11442
11443   /* sanity check */
11444   g_assert (self->priv->first_child == NULL);
11445   g_assert (self->priv->last_child == NULL);
11446   g_assert (self->priv->n_children == 0);
11447 }
11448
11449 typedef struct _InsertBetweenData {
11450   ClutterActor *prev_sibling;
11451   ClutterActor *next_sibling;
11452 } InsertBetweenData;
11453
11454 static void
11455 insert_child_between (ClutterActor *self,
11456                       ClutterActor *child,
11457                       gpointer      data_)
11458 {
11459   InsertBetweenData *data = data_;
11460   ClutterActor *prev_sibling = data->prev_sibling;
11461   ClutterActor *next_sibling = data->next_sibling;
11462
11463   child->priv->parent = self;
11464   child->priv->prev_sibling = prev_sibling;
11465   child->priv->next_sibling = next_sibling;
11466
11467   if (prev_sibling != NULL)
11468     prev_sibling->priv->next_sibling = child;
11469
11470   if (next_sibling != NULL)
11471     next_sibling->priv->prev_sibling = child;
11472
11473   if (child->priv->prev_sibling == NULL)
11474     self->priv->first_child = child;
11475
11476   if (child->priv->next_sibling == NULL)
11477     self->priv->last_child = child;
11478 }
11479
11480 /**
11481  * clutter_actor_replace_child:
11482  * @self: a #ClutterActor
11483  * @old_child: the child of @self to replace
11484  * @new_child: the #ClutterActor to replace @old_child
11485  *
11486  * Replaces @old_child with @new_child in the list of children of @self.
11487  *
11488  * Since: 1.10
11489  */
11490 void
11491 clutter_actor_replace_child (ClutterActor *self,
11492                              ClutterActor *old_child,
11493                              ClutterActor *new_child)
11494 {
11495   ClutterActor *prev_sibling, *next_sibling;
11496   InsertBetweenData clos;
11497
11498   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11499   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11500   g_return_if_fail (old_child->priv->parent == self);
11501   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11502   g_return_if_fail (old_child != new_child);
11503   g_return_if_fail (new_child != self);
11504   g_return_if_fail (new_child->priv->parent == NULL);
11505
11506   prev_sibling = old_child->priv->prev_sibling;
11507   next_sibling = old_child->priv->next_sibling;
11508   clutter_actor_remove_child_internal (self, old_child,
11509                                        REMOVE_CHILD_DEFAULT_FLAGS);
11510
11511   clos.prev_sibling = prev_sibling;
11512   clos.next_sibling = next_sibling;
11513   clutter_actor_add_child_internal (self, new_child,
11514                                     ADD_CHILD_DEFAULT_FLAGS,
11515                                     insert_child_between,
11516                                     &clos);
11517 }
11518
11519 /**
11520  * clutter_actor_unparent:
11521  * @self: a #ClutterActor
11522  *
11523  * Removes the parent of @self.
11524  *
11525  * This will cause the parent of @self to release the reference
11526  * acquired when calling clutter_actor_set_parent(), so if you
11527  * want to keep @self you will have to acquire a reference of
11528  * your own, through g_object_ref().
11529  *
11530  * This function should only be called by legacy #ClutterActor<!-- -->s
11531  * implementing the #ClutterContainer interface.
11532  *
11533  * Since: 0.1.1
11534  *
11535  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11536  */
11537 void
11538 clutter_actor_unparent (ClutterActor *self)
11539 {
11540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11541
11542   if (self->priv->parent == NULL)
11543     return;
11544
11545   clutter_actor_remove_child_internal (self->priv->parent, self,
11546                                        REMOVE_CHILD_LEGACY_FLAGS);
11547 }
11548
11549 /**
11550  * clutter_actor_reparent:
11551  * @self: a #ClutterActor
11552  * @new_parent: the new #ClutterActor parent
11553  *
11554  * Resets the parent actor of @self.
11555  *
11556  * This function is logically equivalent to calling clutter_actor_unparent()
11557  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11558  * ensures the child is not finalized when unparented, and emits the
11559  * #ClutterActor::parent-set signal only once.
11560  *
11561  * In reality, calling this function is less useful than it sounds, as some
11562  * application code may rely on changes in the intermediate state between
11563  * removal and addition of the actor from its old parent to the @new_parent.
11564  * Thus, it is strongly encouraged to avoid using this function in application
11565  * code.
11566  *
11567  * Since: 0.2
11568  *
11569  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11570  *   clutter_actor_add_child() instead; remember to take a reference on
11571  *   the actor being removed before calling clutter_actor_remove_child()
11572  *   to avoid the reference count dropping to zero and the actor being
11573  *   destroyed.
11574  */
11575 void
11576 clutter_actor_reparent (ClutterActor *self,
11577                         ClutterActor *new_parent)
11578 {
11579   ClutterActorPrivate *priv;
11580
11581   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11582   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11583   g_return_if_fail (self != new_parent);
11584
11585   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11586     {
11587       g_warning ("Cannot set a parent on a toplevel actor");
11588       return;
11589     }
11590
11591   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11592     {
11593       g_warning ("Cannot set a parent currently being destroyed");
11594       return;
11595     }
11596
11597   priv = self->priv;
11598
11599   if (priv->parent != new_parent)
11600     {
11601       ClutterActor *old_parent;
11602
11603       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11604
11605       old_parent = priv->parent;
11606
11607       g_object_ref (self);
11608
11609       if (old_parent != NULL)
11610         {
11611          /* go through the Container implementation if this is a regular
11612           * child and not an internal one
11613           */
11614          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11615            {
11616              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11617
11618              /* this will have to call unparent() */
11619              clutter_container_remove_actor (parent, self);
11620            }
11621          else
11622            clutter_actor_remove_child_internal (old_parent, self,
11623                                                 REMOVE_CHILD_LEGACY_FLAGS);
11624         }
11625
11626       /* Note, will call set_parent() */
11627       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11628         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11629       else
11630         clutter_actor_add_child_internal (new_parent, self,
11631                                           ADD_CHILD_LEGACY_FLAGS,
11632                                           insert_child_at_depth,
11633                                           NULL);
11634
11635       /* we emit the ::parent-set signal once */
11636       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11637
11638       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11639
11640       /* the IN_REPARENT flag suspends state updates */
11641       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11642
11643       g_object_unref (self);
11644    }
11645 }
11646
11647 /**
11648  * clutter_actor_contains:
11649  * @self: A #ClutterActor
11650  * @descendant: A #ClutterActor, possibly contained in @self
11651  *
11652  * Determines if @descendant is contained inside @self (either as an
11653  * immediate child, or as a deeper descendant). If @self and
11654  * @descendant point to the same actor then it will also return %TRUE.
11655  *
11656  * Return value: whether @descendent is contained within @self
11657  *
11658  * Since: 1.4
11659  */
11660 gboolean
11661 clutter_actor_contains (ClutterActor *self,
11662                         ClutterActor *descendant)
11663 {
11664   ClutterActor *actor;
11665
11666   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11667   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11668
11669   for (actor = descendant; actor; actor = actor->priv->parent)
11670     if (actor == self)
11671       return TRUE;
11672
11673   return FALSE;
11674 }
11675
11676 /**
11677  * clutter_actor_set_child_above_sibling:
11678  * @self: a #ClutterActor
11679  * @child: a #ClutterActor child of @self
11680  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11681  *
11682  * Sets @child to be above @sibling in the list of children of @self.
11683  *
11684  * If @sibling is %NULL, @child will be the new last child of @self.
11685  *
11686  * This function is logically equivalent to removing @child and using
11687  * clutter_actor_insert_child_above(), but it will not emit signals
11688  * or change state on @child.
11689  *
11690  * Since: 1.10
11691  */
11692 void
11693 clutter_actor_set_child_above_sibling (ClutterActor *self,
11694                                        ClutterActor *child,
11695                                        ClutterActor *sibling)
11696 {
11697   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11698   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11699   g_return_if_fail (child->priv->parent == self);
11700   g_return_if_fail (child != sibling);
11701   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11702
11703   if (sibling != NULL)
11704     g_return_if_fail (sibling->priv->parent == self);
11705
11706   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11707       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11708       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11709     return;
11710
11711   /* we don't want to change the state of child, or emit signals, or
11712    * regenerate ChildMeta instances here, but we still want to follow
11713    * the correct sequence of steps encoded in remove_child() and
11714    * add_child(), so that correctness is ensured, and we only go
11715    * through one known code path.
11716    */
11717   g_object_ref (child);
11718   clutter_actor_remove_child_internal (self, child, 0);
11719   clutter_actor_add_child_internal (self, child,
11720                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11721                                     insert_child_above,
11722                                     sibling);
11723
11724   clutter_actor_queue_relayout (self);
11725 }
11726
11727 /**
11728  * clutter_actor_set_child_below_sibling:
11729  * @self: a #ClutterActor
11730  * @child: a #ClutterActor child of @self
11731  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11732  *
11733  * Sets @child to be below @sibling in the list of children of @self.
11734  *
11735  * If @sibling is %NULL, @child will be the new first child of @self.
11736  *
11737  * This function is logically equivalent to removing @self and using
11738  * clutter_actor_insert_child_below(), but it will not emit signals
11739  * or change state on @child.
11740  *
11741  * Since: 1.10
11742  */
11743 void
11744 clutter_actor_set_child_below_sibling (ClutterActor *self,
11745                                        ClutterActor *child,
11746                                        ClutterActor *sibling)
11747 {
11748   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11749   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11750   g_return_if_fail (child->priv->parent == self);
11751   g_return_if_fail (child != sibling);
11752   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11753
11754   if (sibling != NULL)
11755     g_return_if_fail (sibling->priv->parent == self);
11756
11757   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11758       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11759       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11760     return;
11761
11762   /* see the comment in set_child_above_sibling() */
11763   g_object_ref (child);
11764   clutter_actor_remove_child_internal (self, child, 0);
11765   clutter_actor_add_child_internal (self, child,
11766                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11767                                     insert_child_below,
11768                                     sibling);
11769
11770   clutter_actor_queue_relayout (self);
11771 }
11772
11773 /**
11774  * clutter_actor_set_child_at_index:
11775  * @self: a #ClutterActor
11776  * @child: a #ClutterActor child of @self
11777  * @index_: the new index for @child
11778  *
11779  * Changes the index of @child in the list of children of @self.
11780  *
11781  * This function is logically equivalent to removing @child and
11782  * calling clutter_actor_insert_child_at_index(), but it will not
11783  * emit signals or change state on @child.
11784  *
11785  * Since: 1.10
11786  */
11787 void
11788 clutter_actor_set_child_at_index (ClutterActor *self,
11789                                   ClutterActor *child,
11790                                   gint          index_)
11791 {
11792   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11793   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11794   g_return_if_fail (child->priv->parent == self);
11795   g_return_if_fail (index_ <= self->priv->n_children);
11796
11797   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11798       CLUTTER_ACTOR_IN_DESTRUCTION (child))
11799     return;
11800
11801   g_object_ref (child);
11802   clutter_actor_remove_child_internal (self, child, 0);
11803   clutter_actor_add_child_internal (self, child,
11804                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11805                                     insert_child_at_index,
11806                                     GINT_TO_POINTER (index_));
11807
11808   clutter_actor_queue_relayout (self);
11809 }
11810
11811 /**
11812  * clutter_actor_raise:
11813  * @self: A #ClutterActor
11814  * @below: (allow-none): A #ClutterActor to raise above.
11815  *
11816  * Puts @self above @below.
11817  *
11818  * Both actors must have the same parent, and the parent must implement
11819  * the #ClutterContainer interface
11820  *
11821  * This function calls clutter_container_raise_child() internally.
11822  *
11823  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11824  */
11825 void
11826 clutter_actor_raise (ClutterActor *self,
11827                      ClutterActor *below)
11828 {
11829   ClutterActor *parent;
11830
11831   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11832
11833   parent = clutter_actor_get_parent (self);
11834   if (parent == NULL)
11835     {
11836       g_warning ("%s: Actor '%s' is not inside a container",
11837                  G_STRFUNC,
11838                  _clutter_actor_get_debug_name (self));
11839       return;
11840     }
11841
11842   if (below != NULL)
11843     {
11844       if (parent != clutter_actor_get_parent (below))
11845         {
11846           g_warning ("%s Actor '%s' is not in the same container as "
11847                      "actor '%s'",
11848                      G_STRFUNC,
11849                      _clutter_actor_get_debug_name (self),
11850                      _clutter_actor_get_debug_name (below));
11851           return;
11852         }
11853     }
11854
11855   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11856 }
11857
11858 /**
11859  * clutter_actor_lower:
11860  * @self: A #ClutterActor
11861  * @above: (allow-none): A #ClutterActor to lower below
11862  *
11863  * Puts @self below @above.
11864  *
11865  * Both actors must have the same parent, and the parent must implement
11866  * the #ClutterContainer interface.
11867  *
11868  * This function calls clutter_container_lower_child() internally.
11869  *
11870  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11871  */
11872 void
11873 clutter_actor_lower (ClutterActor *self,
11874                      ClutterActor *above)
11875 {
11876   ClutterActor *parent;
11877
11878   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11879
11880   parent = clutter_actor_get_parent (self);
11881   if (parent == NULL)
11882     {
11883       g_warning ("%s: Actor of type %s is not inside a container",
11884                  G_STRFUNC,
11885                  _clutter_actor_get_debug_name (self));
11886       return;
11887     }
11888
11889   if (above)
11890     {
11891       if (parent != clutter_actor_get_parent (above))
11892         {
11893           g_warning ("%s: Actor '%s' is not in the same container as "
11894                      "actor '%s'",
11895                      G_STRFUNC,
11896                      _clutter_actor_get_debug_name (self),
11897                      _clutter_actor_get_debug_name (above));
11898           return;
11899         }
11900     }
11901
11902   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11903 }
11904
11905 /**
11906  * clutter_actor_raise_top:
11907  * @self: A #ClutterActor
11908  *
11909  * Raises @self to the top.
11910  *
11911  * This function calls clutter_actor_raise() internally.
11912  *
11913  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11914  *   a %NULL sibling, instead.
11915  */
11916 void
11917 clutter_actor_raise_top (ClutterActor *self)
11918 {
11919   clutter_actor_raise (self, NULL);
11920 }
11921
11922 /**
11923  * clutter_actor_lower_bottom:
11924  * @self: A #ClutterActor
11925  *
11926  * Lowers @self to the bottom.
11927  *
11928  * This function calls clutter_actor_lower() internally.
11929  *
11930  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11931  *   a %NULL sibling, instead.
11932  */
11933 void
11934 clutter_actor_lower_bottom (ClutterActor *self)
11935 {
11936   clutter_actor_lower (self, NULL);
11937 }
11938
11939 /*
11940  * Event handling
11941  */
11942
11943 /**
11944  * clutter_actor_event:
11945  * @actor: a #ClutterActor
11946  * @event: a #ClutterEvent
11947  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11948  *
11949  * This function is used to emit an event on the main stage.
11950  * You should rarely need to use this function, except for
11951  * synthetising events.
11952  *
11953  * Return value: the return value from the signal emission: %TRUE
11954  *   if the actor handled the event, or %FALSE if the event was
11955  *   not handled
11956  *
11957  * Since: 0.6
11958  */
11959 gboolean
11960 clutter_actor_event (ClutterActor *actor,
11961                      ClutterEvent *event,
11962                      gboolean      capture)
11963 {
11964   gboolean retval = FALSE;
11965   gint signal_num = -1;
11966
11967   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11968   g_return_val_if_fail (event != NULL, FALSE);
11969
11970   g_object_ref (actor);
11971
11972   if (capture)
11973     {
11974       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11975                      event,
11976                      &retval);
11977       goto out;
11978     }
11979
11980   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11981
11982   if (!retval)
11983     {
11984       switch (event->type)
11985         {
11986         case CLUTTER_NOTHING:
11987           break;
11988         case CLUTTER_BUTTON_PRESS:
11989           signal_num = BUTTON_PRESS_EVENT;
11990           break;
11991         case CLUTTER_BUTTON_RELEASE:
11992           signal_num = BUTTON_RELEASE_EVENT;
11993           break;
11994         case CLUTTER_SCROLL:
11995           signal_num = SCROLL_EVENT;
11996           break;
11997         case CLUTTER_KEY_PRESS:
11998           signal_num = KEY_PRESS_EVENT;
11999           break;
12000         case CLUTTER_KEY_RELEASE:
12001           signal_num = KEY_RELEASE_EVENT;
12002           break;
12003         case CLUTTER_MOTION:
12004           signal_num = MOTION_EVENT;
12005           break;
12006         case CLUTTER_ENTER:
12007           signal_num = ENTER_EVENT;
12008           break;
12009         case CLUTTER_LEAVE:
12010           signal_num = LEAVE_EVENT;
12011           break;
12012         case CLUTTER_DELETE:
12013         case CLUTTER_DESTROY_NOTIFY:
12014         case CLUTTER_CLIENT_MESSAGE:
12015         default:
12016           signal_num = -1;
12017           break;
12018         }
12019
12020       if (signal_num != -1)
12021         g_signal_emit (actor, actor_signals[signal_num], 0,
12022                        event, &retval);
12023     }
12024
12025 out:
12026   g_object_unref (actor);
12027
12028   return retval;
12029 }
12030
12031 /**
12032  * clutter_actor_set_reactive:
12033  * @actor: a #ClutterActor
12034  * @reactive: whether the actor should be reactive to events
12035  *
12036  * Sets @actor as reactive. Reactive actors will receive events.
12037  *
12038  * Since: 0.6
12039  */
12040 void
12041 clutter_actor_set_reactive (ClutterActor *actor,
12042                             gboolean      reactive)
12043 {
12044   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12045
12046   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12047     return;
12048
12049   if (reactive)
12050     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12051   else
12052     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12053
12054   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12055 }
12056
12057 /**
12058  * clutter_actor_get_reactive:
12059  * @actor: a #ClutterActor
12060  *
12061  * Checks whether @actor is marked as reactive.
12062  *
12063  * Return value: %TRUE if the actor is reactive
12064  *
12065  * Since: 0.6
12066  */
12067 gboolean
12068 clutter_actor_get_reactive (ClutterActor *actor)
12069 {
12070   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12071
12072   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12073 }
12074
12075 /**
12076  * clutter_actor_get_anchor_point:
12077  * @self: a #ClutterActor
12078  * @anchor_x: (out): return location for the X coordinate of the anchor point
12079  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12080  *
12081  * Gets the current anchor point of the @actor in pixels.
12082  *
12083  * Since: 0.6
12084  */
12085 void
12086 clutter_actor_get_anchor_point (ClutterActor *self,
12087                                 gfloat       *anchor_x,
12088                                 gfloat       *anchor_y)
12089 {
12090   const ClutterTransformInfo *info;
12091
12092   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12093
12094   info = _clutter_actor_get_transform_info_or_defaults (self);
12095   clutter_anchor_coord_get_units (self, &info->anchor,
12096                                   anchor_x,
12097                                   anchor_y,
12098                                   NULL);
12099 }
12100
12101 /**
12102  * clutter_actor_set_anchor_point:
12103  * @self: a #ClutterActor
12104  * @anchor_x: X coordinate of the anchor point
12105  * @anchor_y: Y coordinate of the anchor point
12106  *
12107  * Sets an anchor point for @self. The anchor point is a point in the
12108  * coordinate space of an actor to which the actor position within its
12109  * parent is relative; the default is (0, 0), i.e. the top-left corner
12110  * of the actor.
12111  *
12112  * Since: 0.6
12113  */
12114 void
12115 clutter_actor_set_anchor_point (ClutterActor *self,
12116                                 gfloat        anchor_x,
12117                                 gfloat        anchor_y)
12118 {
12119   ClutterTransformInfo *info;
12120   ClutterActorPrivate *priv;
12121   gboolean changed = FALSE;
12122   gfloat old_anchor_x, old_anchor_y;
12123   GObject *obj;
12124
12125   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12126
12127   obj = G_OBJECT (self);
12128   priv = self->priv;
12129   info = _clutter_actor_get_transform_info (self);
12130
12131   g_object_freeze_notify (obj);
12132
12133   clutter_anchor_coord_get_units (self, &info->anchor,
12134                                   &old_anchor_x,
12135                                   &old_anchor_y,
12136                                   NULL);
12137
12138   if (info->anchor.is_fractional)
12139     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12140
12141   if (old_anchor_x != anchor_x)
12142     {
12143       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12144       changed = TRUE;
12145     }
12146
12147   if (old_anchor_y != anchor_y)
12148     {
12149       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12150       changed = TRUE;
12151     }
12152
12153   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12154
12155   if (changed)
12156     {
12157       priv->transform_valid = FALSE;
12158       clutter_actor_queue_redraw (self);
12159     }
12160
12161   g_object_thaw_notify (obj);
12162 }
12163
12164 /**
12165  * clutter_actor_get_anchor_point_gravity:
12166  * @self: a #ClutterActor
12167  *
12168  * Retrieves the anchor position expressed as a #ClutterGravity. If
12169  * the anchor point was specified using pixels or units this will
12170  * return %CLUTTER_GRAVITY_NONE.
12171  *
12172  * Return value: the #ClutterGravity used by the anchor point
12173  *
12174  * Since: 1.0
12175  */
12176 ClutterGravity
12177 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12178 {
12179   const ClutterTransformInfo *info;
12180
12181   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12182
12183   info = _clutter_actor_get_transform_info_or_defaults (self);
12184
12185   return clutter_anchor_coord_get_gravity (&info->anchor);
12186 }
12187
12188 /**
12189  * clutter_actor_move_anchor_point:
12190  * @self: a #ClutterActor
12191  * @anchor_x: X coordinate of the anchor point
12192  * @anchor_y: Y coordinate of the anchor point
12193  *
12194  * Sets an anchor point for the actor, and adjusts the actor postion so that
12195  * the relative position of the actor toward its parent remains the same.
12196  *
12197  * Since: 0.6
12198  */
12199 void
12200 clutter_actor_move_anchor_point (ClutterActor *self,
12201                                  gfloat        anchor_x,
12202                                  gfloat        anchor_y)
12203 {
12204   gfloat old_anchor_x, old_anchor_y;
12205   const ClutterTransformInfo *info;
12206
12207   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12208
12209   info = _clutter_actor_get_transform_info (self);
12210   clutter_anchor_coord_get_units (self, &info->anchor,
12211                                   &old_anchor_x,
12212                                   &old_anchor_y,
12213                                   NULL);
12214
12215   g_object_freeze_notify (G_OBJECT (self));
12216
12217   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12218
12219   if (self->priv->position_set)
12220     clutter_actor_move_by (self,
12221                            anchor_x - old_anchor_x,
12222                            anchor_y - old_anchor_y);
12223
12224   g_object_thaw_notify (G_OBJECT (self));
12225 }
12226
12227 /**
12228  * clutter_actor_move_anchor_point_from_gravity:
12229  * @self: a #ClutterActor
12230  * @gravity: #ClutterGravity.
12231  *
12232  * Sets an anchor point on the actor based on the given gravity, adjusting the
12233  * actor postion so that its relative position within its parent remains
12234  * unchanged.
12235  *
12236  * Since version 1.0 the anchor point will be stored as a gravity so
12237  * that if the actor changes size then the anchor point will move. For
12238  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12239  * and later double the size of the actor, the anchor point will move
12240  * to the bottom right.
12241  *
12242  * Since: 0.6
12243  */
12244 void
12245 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12246                                               ClutterGravity  gravity)
12247 {
12248   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12249   const ClutterTransformInfo *info;
12250   ClutterActorPrivate *priv;
12251
12252   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12253
12254   priv = self->priv;
12255   info = _clutter_actor_get_transform_info (self);
12256
12257   g_object_freeze_notify (G_OBJECT (self));
12258
12259   clutter_anchor_coord_get_units (self, &info->anchor,
12260                                   &old_anchor_x,
12261                                   &old_anchor_y,
12262                                   NULL);
12263   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12264   clutter_anchor_coord_get_units (self, &info->anchor,
12265                                   &new_anchor_x,
12266                                   &new_anchor_y,
12267                                   NULL);
12268
12269   if (priv->position_set)
12270     clutter_actor_move_by (self,
12271                            new_anchor_x - old_anchor_x,
12272                            new_anchor_y - old_anchor_y);
12273
12274   g_object_thaw_notify (G_OBJECT (self));
12275 }
12276
12277 /**
12278  * clutter_actor_set_anchor_point_from_gravity:
12279  * @self: a #ClutterActor
12280  * @gravity: #ClutterGravity.
12281  *
12282  * Sets an anchor point on the actor, based on the given gravity (this is a
12283  * convenience function wrapping clutter_actor_set_anchor_point()).
12284  *
12285  * Since version 1.0 the anchor point will be stored as a gravity so
12286  * that if the actor changes size then the anchor point will move. For
12287  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12288  * and later double the size of the actor, the anchor point will move
12289  * to the bottom right.
12290  *
12291  * Since: 0.6
12292  */
12293 void
12294 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12295                                              ClutterGravity  gravity)
12296 {
12297   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12298
12299   if (gravity == CLUTTER_GRAVITY_NONE)
12300     clutter_actor_set_anchor_point (self, 0, 0);
12301   else
12302     {
12303       GObject *obj = G_OBJECT (self);
12304       ClutterTransformInfo *info;
12305
12306       g_object_freeze_notify (obj);
12307
12308       info = _clutter_actor_get_transform_info (self);
12309       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12310
12311       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12312       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12313       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12314
12315       self->priv->transform_valid = FALSE;
12316
12317       clutter_actor_queue_redraw (self);
12318
12319       g_object_thaw_notify (obj);
12320     }
12321 }
12322
12323 static void
12324 clutter_container_iface_init (ClutterContainerIface *iface)
12325 {
12326   /* we don't override anything, as ClutterContainer already has a default
12327    * implementation that we can use, and which calls into our own API.
12328    */
12329 }
12330
12331 typedef enum
12332 {
12333   PARSE_X,
12334   PARSE_Y,
12335   PARSE_WIDTH,
12336   PARSE_HEIGHT,
12337   PARSE_ANCHOR_X,
12338   PARSE_ANCHOR_Y
12339 } ParseDimension;
12340
12341 static gfloat
12342 parse_units (ClutterActor   *self,
12343              ParseDimension  dimension,
12344              JsonNode       *node)
12345 {
12346   GValue value = G_VALUE_INIT;
12347   gfloat retval = 0;
12348
12349   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12350     return 0;
12351
12352   json_node_get_value (node, &value);
12353
12354   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12355     {
12356       retval = (gfloat) g_value_get_int64 (&value);
12357     }
12358   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12359     {
12360       retval = g_value_get_double (&value);
12361     }
12362   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12363     {
12364       ClutterUnits units;
12365       gboolean res;
12366
12367       res = clutter_units_from_string (&units, g_value_get_string (&value));
12368       if (res)
12369         retval = clutter_units_to_pixels (&units);
12370       else
12371         {
12372           g_warning ("Invalid value '%s': integers, strings or floating point "
12373                      "values can be used for the x, y, width and height "
12374                      "properties. Valid modifiers for strings are 'px', 'mm', "
12375                      "'pt' and 'em'.",
12376                      g_value_get_string (&value));
12377           retval = 0;
12378         }
12379     }
12380   else
12381     {
12382       g_warning ("Invalid value of type '%s': integers, strings of floating "
12383                  "point values can be used for the x, y, width, height "
12384                  "anchor-x and anchor-y properties.",
12385                  g_type_name (G_VALUE_TYPE (&value)));
12386     }
12387
12388   g_value_unset (&value);
12389
12390   return retval;
12391 }
12392
12393 typedef struct {
12394   ClutterRotateAxis axis;
12395
12396   gdouble angle;
12397
12398   gfloat center_x;
12399   gfloat center_y;
12400   gfloat center_z;
12401 } RotationInfo;
12402
12403 static inline gboolean
12404 parse_rotation_array (ClutterActor *actor,
12405                       JsonArray    *array,
12406                       RotationInfo *info)
12407 {
12408   JsonNode *element;
12409
12410   if (json_array_get_length (array) != 2)
12411     return FALSE;
12412
12413   /* angle */
12414   element = json_array_get_element (array, 0);
12415   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12416     info->angle = json_node_get_double (element);
12417   else
12418     return FALSE;
12419
12420   /* center */
12421   element = json_array_get_element (array, 1);
12422   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12423     {
12424       JsonArray *center = json_node_get_array (element);
12425
12426       if (json_array_get_length (center) != 2)
12427         return FALSE;
12428
12429       switch (info->axis)
12430         {
12431         case CLUTTER_X_AXIS:
12432           info->center_y = parse_units (actor, PARSE_Y,
12433                                         json_array_get_element (center, 0));
12434           info->center_z = parse_units (actor, PARSE_Y,
12435                                         json_array_get_element (center, 1));
12436           return TRUE;
12437
12438         case CLUTTER_Y_AXIS:
12439           info->center_x = parse_units (actor, PARSE_X,
12440                                         json_array_get_element (center, 0));
12441           info->center_z = parse_units (actor, PARSE_X,
12442                                         json_array_get_element (center, 1));
12443           return TRUE;
12444
12445         case CLUTTER_Z_AXIS:
12446           info->center_x = parse_units (actor, PARSE_X,
12447                                         json_array_get_element (center, 0));
12448           info->center_y = parse_units (actor, PARSE_Y,
12449                                         json_array_get_element (center, 1));
12450           return TRUE;
12451         }
12452     }
12453
12454   return FALSE;
12455 }
12456
12457 static gboolean
12458 parse_rotation (ClutterActor *actor,
12459                 JsonNode     *node,
12460                 RotationInfo *info)
12461 {
12462   JsonArray *array;
12463   guint len, i;
12464   gboolean retval = FALSE;
12465
12466   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12467     {
12468       g_warning ("Invalid node of type '%s' found, expecting an array",
12469                  json_node_type_name (node));
12470       return FALSE;
12471     }
12472
12473   array = json_node_get_array (node);
12474   len = json_array_get_length (array);
12475
12476   for (i = 0; i < len; i++)
12477     {
12478       JsonNode *element = json_array_get_element (array, i);
12479       JsonObject *object;
12480       JsonNode *member;
12481
12482       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12483         {
12484           g_warning ("Invalid node of type '%s' found, expecting an object",
12485                      json_node_type_name (element));
12486           return FALSE;
12487         }
12488
12489       object = json_node_get_object (element);
12490
12491       if (json_object_has_member (object, "x-axis"))
12492         {
12493           member = json_object_get_member (object, "x-axis");
12494
12495           info->axis = CLUTTER_X_AXIS;
12496
12497           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12498             {
12499               info->angle = json_node_get_double (member);
12500               retval = TRUE;
12501             }
12502           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12503             retval = parse_rotation_array (actor,
12504                                            json_node_get_array (member),
12505                                            info);
12506           else
12507             retval = FALSE;
12508         }
12509       else if (json_object_has_member (object, "y-axis"))
12510         {
12511           member = json_object_get_member (object, "y-axis");
12512
12513           info->axis = CLUTTER_Y_AXIS;
12514
12515           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12516             {
12517               info->angle = json_node_get_double (member);
12518               retval = TRUE;
12519             }
12520           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12521             retval = parse_rotation_array (actor,
12522                                            json_node_get_array (member),
12523                                            info);
12524           else
12525             retval = FALSE;
12526         }
12527       else if (json_object_has_member (object, "z-axis"))
12528         {
12529           member = json_object_get_member (object, "z-axis");
12530
12531           info->axis = CLUTTER_Z_AXIS;
12532
12533           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12534             {
12535               info->angle = json_node_get_double (member);
12536               retval = TRUE;
12537             }
12538           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12539             retval = parse_rotation_array (actor,
12540                                            json_node_get_array (member),
12541                                            info);
12542           else
12543             retval = FALSE;
12544         }
12545     }
12546
12547   return retval;
12548 }
12549
12550 static GSList *
12551 parse_actor_metas (ClutterScript *script,
12552                    ClutterActor  *actor,
12553                    JsonNode      *node)
12554 {
12555   GList *elements, *l;
12556   GSList *retval = NULL;
12557
12558   if (!JSON_NODE_HOLDS_ARRAY (node))
12559     return NULL;
12560
12561   elements = json_array_get_elements (json_node_get_array (node));
12562
12563   for (l = elements; l != NULL; l = l->next)
12564     {
12565       JsonNode *element = l->data;
12566       const gchar *id_ = _clutter_script_get_id_from_node (element);
12567       GObject *meta;
12568
12569       if (id_ == NULL || *id_ == '\0')
12570         continue;
12571
12572       meta = clutter_script_get_object (script, id_);
12573       if (meta == NULL)
12574         continue;
12575
12576       retval = g_slist_prepend (retval, meta);
12577     }
12578
12579   g_list_free (elements);
12580
12581   return g_slist_reverse (retval);
12582 }
12583
12584 static GSList *
12585 parse_behaviours (ClutterScript *script,
12586                   ClutterActor  *actor,
12587                   JsonNode      *node)
12588 {
12589   GList *elements, *l;
12590   GSList *retval = NULL;
12591
12592   if (!JSON_NODE_HOLDS_ARRAY (node))
12593     return NULL;
12594
12595   elements = json_array_get_elements (json_node_get_array (node));
12596
12597   for (l = elements; l != NULL; l = l->next)
12598     {
12599       JsonNode *element = l->data;
12600       const gchar *id_ = _clutter_script_get_id_from_node (element);
12601       GObject *behaviour;
12602
12603       if (id_ == NULL || *id_ == '\0')
12604         continue;
12605
12606       behaviour = clutter_script_get_object (script, id_);
12607       if (behaviour == NULL)
12608         continue;
12609
12610       retval = g_slist_prepend (retval, behaviour);
12611     }
12612
12613   g_list_free (elements);
12614
12615   return g_slist_reverse (retval);
12616 }
12617
12618 static gboolean
12619 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12620                                  ClutterScript     *script,
12621                                  GValue            *value,
12622                                  const gchar       *name,
12623                                  JsonNode          *node)
12624 {
12625   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12626   gboolean retval = FALSE;
12627
12628   if ((name[0] == 'x' && name[1] == '\0') ||
12629       (name[0] == 'y' && name[1] == '\0') ||
12630       (strcmp (name, "width") == 0) ||
12631       (strcmp (name, "height") == 0) ||
12632       (strcmp (name, "anchor_x") == 0) ||
12633       (strcmp (name, "anchor_y") == 0))
12634     {
12635       ParseDimension dimension;
12636       gfloat units;
12637
12638       if (name[0] == 'x')
12639         dimension = PARSE_X;
12640       else if (name[0] == 'y')
12641         dimension = PARSE_Y;
12642       else if (name[0] == 'w')
12643         dimension = PARSE_WIDTH;
12644       else if (name[0] == 'h')
12645         dimension = PARSE_HEIGHT;
12646       else if (name[0] == 'a' && name[7] == 'x')
12647         dimension = PARSE_ANCHOR_X;
12648       else if (name[0] == 'a' && name[7] == 'y')
12649         dimension = PARSE_ANCHOR_Y;
12650       else
12651         return FALSE;
12652
12653       units = parse_units (actor, dimension, node);
12654
12655       /* convert back to pixels: all properties are pixel-based */
12656       g_value_init (value, G_TYPE_FLOAT);
12657       g_value_set_float (value, units);
12658
12659       retval = TRUE;
12660     }
12661   else if (strcmp (name, "rotation") == 0)
12662     {
12663       RotationInfo *info;
12664
12665       info = g_slice_new0 (RotationInfo);
12666       retval = parse_rotation (actor, node, info);
12667
12668       if (retval)
12669         {
12670           g_value_init (value, G_TYPE_POINTER);
12671           g_value_set_pointer (value, info);
12672         }
12673       else
12674         g_slice_free (RotationInfo, info);
12675     }
12676   else if (strcmp (name, "behaviours") == 0)
12677     {
12678       GSList *l;
12679
12680 #ifdef CLUTTER_ENABLE_DEBUG
12681       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12682         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12683                                      "and it should not be used in newly "
12684                                      "written ClutterScript definitions.");
12685 #endif
12686
12687       l = parse_behaviours (script, actor, node);
12688
12689       g_value_init (value, G_TYPE_POINTER);
12690       g_value_set_pointer (value, l);
12691
12692       retval = TRUE;
12693     }
12694   else if (strcmp (name, "actions") == 0 ||
12695            strcmp (name, "constraints") == 0 ||
12696            strcmp (name, "effects") == 0)
12697     {
12698       GSList *l;
12699
12700       l = parse_actor_metas (script, actor, node);
12701
12702       g_value_init (value, G_TYPE_POINTER);
12703       g_value_set_pointer (value, l);
12704
12705       retval = TRUE;
12706     }
12707
12708   return retval;
12709 }
12710
12711 static void
12712 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12713                                    ClutterScript     *script,
12714                                    const gchar       *name,
12715                                    const GValue      *value)
12716 {
12717   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12718
12719 #ifdef CLUTTER_ENABLE_DEBUG
12720   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12721     {
12722       gchar *tmp = g_strdup_value_contents (value);
12723
12724       CLUTTER_NOTE (SCRIPT,
12725                     "in ClutterActor::set_custom_property('%s') = %s",
12726                     name,
12727                     tmp);
12728
12729       g_free (tmp);
12730     }
12731 #endif /* CLUTTER_ENABLE_DEBUG */
12732
12733   if (strcmp (name, "rotation") == 0)
12734     {
12735       RotationInfo *info;
12736
12737       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12738         return;
12739
12740       info = g_value_get_pointer (value);
12741
12742       clutter_actor_set_rotation (actor,
12743                                   info->axis, info->angle,
12744                                   info->center_x,
12745                                   info->center_y,
12746                                   info->center_z);
12747
12748       g_slice_free (RotationInfo, info);
12749
12750       return;
12751     }
12752
12753   if (strcmp (name, "behaviours") == 0)
12754     {
12755       GSList *behaviours, *l;
12756
12757       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12758         return;
12759
12760       behaviours = g_value_get_pointer (value);
12761       for (l = behaviours; l != NULL; l = l->next)
12762         {
12763           ClutterBehaviour *behaviour = l->data;
12764
12765           clutter_behaviour_apply (behaviour, actor);
12766         }
12767
12768       g_slist_free (behaviours);
12769
12770       return;
12771     }
12772
12773   if (strcmp (name, "actions") == 0 ||
12774       strcmp (name, "constraints") == 0 ||
12775       strcmp (name, "effects") == 0)
12776     {
12777       GSList *metas, *l;
12778
12779       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12780         return;
12781
12782       metas = g_value_get_pointer (value);
12783       for (l = metas; l != NULL; l = l->next)
12784         {
12785           if (name[0] == 'a')
12786             clutter_actor_add_action (actor, l->data);
12787
12788           if (name[0] == 'c')
12789             clutter_actor_add_constraint (actor, l->data);
12790
12791           if (name[0] == 'e')
12792             clutter_actor_add_effect (actor, l->data);
12793         }
12794
12795       g_slist_free (metas);
12796
12797       return;
12798     }
12799
12800   g_object_set_property (G_OBJECT (scriptable), name, value);
12801 }
12802
12803 static void
12804 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12805 {
12806   iface->parse_custom_node = clutter_actor_parse_custom_node;
12807   iface->set_custom_property = clutter_actor_set_custom_property;
12808 }
12809
12810 static ClutterActorMeta *
12811 get_meta_from_animation_property (ClutterActor  *actor,
12812                                   const gchar   *name,
12813                                   gchar        **name_p)
12814 {
12815   ClutterActorPrivate *priv = actor->priv;
12816   ClutterActorMeta *meta = NULL;
12817   gchar **tokens;
12818
12819   /* if this is not a special property, fall through */
12820   if (name[0] != '@')
12821     return NULL;
12822
12823   /* detect the properties named using the following spec:
12824    *
12825    *   @<section>.<meta-name>.<property-name>
12826    *
12827    * where <section> can be one of the following:
12828    *
12829    *   - actions
12830    *   - constraints
12831    *   - effects
12832    *
12833    * and <meta-name> is the name set on a specific ActorMeta
12834    */
12835
12836   tokens = g_strsplit (name + 1, ".", -1);
12837   if (tokens == NULL || g_strv_length (tokens) != 3)
12838     {
12839       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12840                     name + 1);
12841       g_strfreev (tokens);
12842       return NULL;
12843     }
12844
12845   if (strcmp (tokens[0], "actions") == 0)
12846     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12847
12848   if (strcmp (tokens[0], "constraints") == 0)
12849     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12850
12851   if (strcmp (tokens[0], "effects") == 0)
12852     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12853
12854   if (name_p != NULL)
12855     *name_p = g_strdup (tokens[2]);
12856
12857   CLUTTER_NOTE (ANIMATION,
12858                 "Looking for property '%s' of object '%s' in section '%s'",
12859                 tokens[2],
12860                 tokens[1],
12861                 tokens[0]);
12862
12863   g_strfreev (tokens);
12864
12865   return meta;
12866 }
12867
12868 static GParamSpec *
12869 clutter_actor_find_property (ClutterAnimatable *animatable,
12870                              const gchar       *property_name)
12871 {
12872   ClutterActorMeta *meta = NULL;
12873   GObjectClass *klass = NULL;
12874   GParamSpec *pspec = NULL;
12875   gchar *p_name = NULL;
12876
12877   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12878                                            property_name,
12879                                            &p_name);
12880
12881   if (meta != NULL)
12882     {
12883       klass = G_OBJECT_GET_CLASS (meta);
12884
12885       pspec = g_object_class_find_property (klass, p_name);
12886     }
12887   else
12888     {
12889       klass = G_OBJECT_GET_CLASS (animatable);
12890
12891       pspec = g_object_class_find_property (klass, property_name);
12892     }
12893
12894   g_free (p_name);
12895
12896   return pspec;
12897 }
12898
12899 static void
12900 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12901                                  const gchar       *property_name,
12902                                  GValue            *initial)
12903 {
12904   ClutterActorMeta *meta = NULL;
12905   gchar *p_name = NULL;
12906
12907   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12908                                            property_name,
12909                                            &p_name);
12910
12911   if (meta != NULL)
12912     g_object_get_property (G_OBJECT (meta), p_name, initial);
12913   else
12914     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12915
12916   g_free (p_name);
12917 }
12918
12919 /*
12920  * clutter_actor_set_animatable_property:
12921  * @actor: a #ClutterActor
12922  * @prop_id: the paramspec id
12923  * @value: the value to set
12924  * @pspec: the paramspec
12925  *
12926  * Sets values of animatable properties.
12927  *
12928  * This is a variant of clutter_actor_set_property() that gets called
12929  * by the #ClutterAnimatable implementation of #ClutterActor for the
12930  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12931  * #GParamSpec.
12932  *
12933  * Unlike the implementation of #GObjectClass.set_property(), this
12934  * function will not update the interval if a transition involving an
12935  * animatable property is in progress - this avoids cycles with the
12936  * transition API calling the public API.
12937  */
12938 static void
12939 clutter_actor_set_animatable_property (ClutterActor *actor,
12940                                        guint         prop_id,
12941                                        const GValue *value,
12942                                        GParamSpec   *pspec)
12943 {
12944   GObject *obj = G_OBJECT (actor);
12945
12946   g_object_freeze_notify (obj);
12947
12948   switch (prop_id)
12949     {
12950     case PROP_X:
12951       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12952       break;
12953
12954     case PROP_Y:
12955       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12956       break;
12957
12958     case PROP_WIDTH:
12959       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12960       break;
12961
12962     case PROP_HEIGHT:
12963       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12964       break;
12965
12966     case PROP_DEPTH:
12967       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12968       break;
12969
12970     case PROP_OPACITY:
12971       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12972       break;
12973
12974     case PROP_BACKGROUND_COLOR:
12975       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12976       break;
12977
12978     case PROP_SCALE_X:
12979       clutter_actor_set_scale_factor_internal (actor,
12980                                                g_value_get_double (value),
12981                                                pspec);
12982       break;
12983
12984     case PROP_SCALE_Y:
12985       clutter_actor_set_scale_factor_internal (actor,
12986                                                g_value_get_double (value),
12987                                                pspec);
12988       break;
12989
12990     case PROP_ROTATION_ANGLE_X:
12991       clutter_actor_set_rotation_angle_internal (actor,
12992                                                  CLUTTER_X_AXIS,
12993                                                  g_value_get_double (value));
12994       break;
12995
12996     case PROP_ROTATION_ANGLE_Y:
12997       clutter_actor_set_rotation_angle_internal (actor,
12998                                                  CLUTTER_Y_AXIS,
12999                                                  g_value_get_double (value));
13000       break;
13001
13002     case PROP_ROTATION_ANGLE_Z:
13003       clutter_actor_set_rotation_angle_internal (actor,
13004                                                  CLUTTER_Z_AXIS,
13005                                                  g_value_get_double (value));
13006       break;
13007
13008     default:
13009       g_object_set_property (obj, pspec->name, value);
13010       break;
13011     }
13012
13013   g_object_thaw_notify (obj);
13014 }
13015
13016 static void
13017 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13018                                const gchar       *property_name,
13019                                const GValue      *final)
13020 {
13021   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13022   ClutterActorMeta *meta = NULL;
13023   gchar *p_name = NULL;
13024
13025   meta = get_meta_from_animation_property (actor,
13026                                            property_name,
13027                                            &p_name);
13028   if (meta != NULL)
13029     g_object_set_property (G_OBJECT (meta), p_name, final);
13030   else
13031     {
13032       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13033       GParamSpec *pspec;
13034
13035       pspec = g_object_class_find_property (obj_class, property_name);
13036
13037       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13038         {
13039           /* XXX - I'm going to the special hell for this */
13040           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13041         }
13042       else
13043         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13044     }
13045
13046   g_free (p_name);
13047 }
13048
13049 static void
13050 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13051 {
13052   iface->find_property = clutter_actor_find_property;
13053   iface->get_initial_state = clutter_actor_get_initial_state;
13054   iface->set_final_state = clutter_actor_set_final_state;
13055 }
13056
13057 /**
13058  * clutter_actor_transform_stage_point:
13059  * @self: A #ClutterActor
13060  * @x: (in): x screen coordinate of the point to unproject
13061  * @y: (in): y screen coordinate of the point to unproject
13062  * @x_out: (out): return location for the unprojected x coordinance
13063  * @y_out: (out): return location for the unprojected y coordinance
13064  *
13065  * This function translates screen coordinates (@x, @y) to
13066  * coordinates relative to the actor. For example, it can be used to translate
13067  * screen events from global screen coordinates into actor-local coordinates.
13068  *
13069  * The conversion can fail, notably if the transform stack results in the
13070  * actor being projected on the screen as a mere line.
13071  *
13072  * The conversion should not be expected to be pixel-perfect due to the
13073  * nature of the operation. In general the error grows when the skewing
13074  * of the actor rectangle on screen increases.
13075  *
13076  * <note><para>This function can be computationally intensive.</para></note>
13077  *
13078  * <note><para>This function only works when the allocation is up-to-date,
13079  * i.e. inside of paint().</para></note>
13080  *
13081  * Return value: %TRUE if conversion was successful.
13082  *
13083  * Since: 0.6
13084  */
13085 gboolean
13086 clutter_actor_transform_stage_point (ClutterActor *self,
13087                                      gfloat        x,
13088                                      gfloat        y,
13089                                      gfloat       *x_out,
13090                                      gfloat       *y_out)
13091 {
13092   ClutterVertex v[4];
13093   float ST[3][3];
13094   float RQ[3][3];
13095   int du, dv, xi, yi;
13096   float px, py;
13097   float xf, yf, wf, det;
13098   ClutterActorPrivate *priv;
13099
13100   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13101
13102   priv = self->priv;
13103
13104   /* This implementation is based on the quad -> quad projection algorithm
13105    * described by Paul Heckbert in:
13106    *
13107    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13108    *
13109    * and the sample implementation at:
13110    *
13111    *   http://www.cs.cmu.edu/~ph/src/texfund/
13112    *
13113    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13114    * quad to rectangle only, which significantly simplifies things; the
13115    * function calls have been unrolled, and most of the math is done in fixed
13116    * point.
13117    */
13118
13119   clutter_actor_get_abs_allocation_vertices (self, v);
13120
13121   /* Keeping these as ints simplifies the multiplication (no significant
13122    * loss of precision here).
13123    */
13124   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13125   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13126
13127   if (!du || !dv)
13128     return FALSE;
13129
13130 #define UX2FP(x)        (x)
13131 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13132
13133   /* First, find mapping from unit uv square to xy quadrilateral; this
13134    * equivalent to the pmap_square_quad() functions in the sample
13135    * implementation, which we can simplify, since our target is always
13136    * a rectangle.
13137    */
13138   px = v[0].x - v[1].x + v[3].x - v[2].x;
13139   py = v[0].y - v[1].y + v[3].y - v[2].y;
13140
13141   if (!px && !py)
13142     {
13143       /* affine transform */
13144       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13145       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13146       RQ[2][0] = UX2FP (v[0].x);
13147       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13148       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13149       RQ[2][1] = UX2FP (v[0].y);
13150       RQ[0][2] = 0;
13151       RQ[1][2] = 0;
13152       RQ[2][2] = 1.0;
13153     }
13154   else
13155     {
13156       /* projective transform */
13157       double dx1, dx2, dy1, dy2, del;
13158
13159       dx1 = UX2FP (v[1].x - v[3].x);
13160       dx2 = UX2FP (v[2].x - v[3].x);
13161       dy1 = UX2FP (v[1].y - v[3].y);
13162       dy2 = UX2FP (v[2].y - v[3].y);
13163
13164       del = DET2FP (dx1, dx2, dy1, dy2);
13165       if (!del)
13166         return FALSE;
13167
13168       /*
13169        * The division here needs to be done in floating point for
13170        * precisions reasons.
13171        */
13172       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13173       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13174       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13175       RQ[2][2] = 1.0;
13176       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13177       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13178       RQ[2][0] = UX2FP (v[0].x);
13179       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13180       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13181       RQ[2][1] = UX2FP (v[0].y);
13182     }
13183
13184   /*
13185    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13186    * square. Since our rectangle is based at 0,0 we only need to scale.
13187    */
13188   RQ[0][0] /= du;
13189   RQ[1][0] /= dv;
13190   RQ[0][1] /= du;
13191   RQ[1][1] /= dv;
13192   RQ[0][2] /= du;
13193   RQ[1][2] /= dv;
13194
13195   /*
13196    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13197    * inverse of that.
13198    */
13199   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13200   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13201   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13202   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13203   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13204   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13205   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13206   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13207   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13208
13209   /*
13210    * Check the resulting matrix is OK.
13211    */
13212   det = (RQ[0][0] * ST[0][0])
13213       + (RQ[0][1] * ST[0][1])
13214       + (RQ[0][2] * ST[0][2]);
13215   if (!det)
13216     return FALSE;
13217
13218   /*
13219    * Now transform our point with the ST matrix; the notional w
13220    * coordinate is 1, hence the last part is simply added.
13221    */
13222   xi = (int) x;
13223   yi = (int) y;
13224
13225   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13226   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13227   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13228
13229   if (x_out)
13230     *x_out = xf / wf;
13231
13232   if (y_out)
13233     *y_out = yf / wf;
13234
13235 #undef UX2FP
13236 #undef DET2FP
13237
13238   return TRUE;
13239 }
13240
13241 /*
13242  * ClutterGeometry
13243  */
13244
13245 static ClutterGeometry*
13246 clutter_geometry_copy (const ClutterGeometry *geometry)
13247 {
13248   return g_slice_dup (ClutterGeometry, geometry);
13249 }
13250
13251 static void
13252 clutter_geometry_free (ClutterGeometry *geometry)
13253 {
13254   if (G_LIKELY (geometry != NULL))
13255     g_slice_free (ClutterGeometry, geometry);
13256 }
13257
13258 /**
13259  * clutter_geometry_union:
13260  * @geometry_a: a #ClutterGeometry
13261  * @geometry_b: another #ClutterGeometry
13262  * @result: (out): location to store the result
13263  *
13264  * Find the union of two rectangles represented as #ClutterGeometry.
13265  *
13266  * Since: 1.4
13267  */
13268 void
13269 clutter_geometry_union (const ClutterGeometry *geometry_a,
13270                         const ClutterGeometry *geometry_b,
13271                         ClutterGeometry       *result)
13272 {
13273   /* We don't try to handle rectangles that can't be represented
13274    * as a signed integer box */
13275   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13276   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13277   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13278                   geometry_b->x + (gint)geometry_b->width);
13279   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13280                   geometry_b->y + (gint)geometry_b->height);
13281   result->x = x_1;
13282   result->y = y_1;
13283   result->width = x_2 - x_1;
13284   result->height = y_2 - y_1;
13285 }
13286
13287 /**
13288  * clutter_geometry_intersects:
13289  * @geometry0: The first geometry to test
13290  * @geometry1: The second geometry to test
13291  *
13292  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13293  * they do else %FALSE.
13294  *
13295  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13296  * %FALSE.
13297  *
13298  * Since: 1.4
13299  */
13300 gboolean
13301 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13302                              const ClutterGeometry *geometry1)
13303 {
13304   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13305       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13306       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13307       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13308     return FALSE;
13309   else
13310     return TRUE;
13311 }
13312
13313 static gboolean
13314 clutter_geometry_progress (const GValue *a,
13315                            const GValue *b,
13316                            gdouble       progress,
13317                            GValue       *retval)
13318 {
13319   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13320   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13321   ClutterGeometry res = { 0, };
13322   gint a_width = a_geom->width;
13323   gint b_width = b_geom->width;
13324   gint a_height = a_geom->height;
13325   gint b_height = b_geom->height;
13326
13327   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13328   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13329
13330   res.width = a_width + (b_width - a_width) * progress;
13331   res.height = a_height + (b_height - a_height) * progress;
13332
13333   g_value_set_boxed (retval, &res);
13334
13335   return TRUE;
13336 }
13337
13338 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13339                                clutter_geometry_copy,
13340                                clutter_geometry_free,
13341                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13342
13343 /*
13344  * ClutterVertices
13345  */
13346
13347 /**
13348  * clutter_vertex_new:
13349  * @x: X coordinate
13350  * @y: Y coordinate
13351  * @z: Z coordinate
13352  *
13353  * Creates a new #ClutterVertex for the point in 3D space
13354  * identified by the 3 coordinates @x, @y, @z
13355  *
13356  * Return value: the newly allocate #ClutterVertex. Use
13357  *   clutter_vertex_free() to free the resources
13358  *
13359  * Since: 1.0
13360  */
13361 ClutterVertex *
13362 clutter_vertex_new (gfloat x,
13363                     gfloat y,
13364                     gfloat z)
13365 {
13366   ClutterVertex *vertex;
13367
13368   vertex = g_slice_new (ClutterVertex);
13369   clutter_vertex_init (vertex, x, y, z);
13370
13371   return vertex;
13372 }
13373
13374 /**
13375  * clutter_vertex_init:
13376  * @vertex: a #ClutterVertex
13377  * @x: X coordinate
13378  * @y: Y coordinate
13379  * @z: Z coordinate
13380  *
13381  * Initializes @vertex with the given coordinates.
13382  *
13383  * Since: 1.10
13384  */
13385 void
13386 clutter_vertex_init (ClutterVertex *vertex,
13387                      gfloat         x,
13388                      gfloat         y,
13389                      gfloat         z)
13390 {
13391   g_return_if_fail (vertex != NULL);
13392
13393   vertex->x = x;
13394   vertex->y = y;
13395   vertex->z = z;
13396 }
13397
13398 /**
13399  * clutter_vertex_copy:
13400  * @vertex: a #ClutterVertex
13401  *
13402  * Copies @vertex
13403  *
13404  * Return value: a newly allocated copy of #ClutterVertex. Use
13405  *   clutter_vertex_free() to free the allocated resources
13406  *
13407  * Since: 1.0
13408  */
13409 ClutterVertex *
13410 clutter_vertex_copy (const ClutterVertex *vertex)
13411 {
13412   if (G_LIKELY (vertex != NULL))
13413     return g_slice_dup (ClutterVertex, vertex);
13414
13415   return NULL;
13416 }
13417
13418 /**
13419  * clutter_vertex_free:
13420  * @vertex: a #ClutterVertex
13421  *
13422  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13423  *
13424  * Since: 1.0
13425  */
13426 void
13427 clutter_vertex_free (ClutterVertex *vertex)
13428 {
13429   if (G_UNLIKELY (vertex != NULL))
13430     g_slice_free (ClutterVertex, vertex);
13431 }
13432
13433 /**
13434  * clutter_vertex_equal:
13435  * @vertex_a: a #ClutterVertex
13436  * @vertex_b: a #ClutterVertex
13437  *
13438  * Compares @vertex_a and @vertex_b for equality
13439  *
13440  * Return value: %TRUE if the passed #ClutterVertex are equal
13441  *
13442  * Since: 1.0
13443  */
13444 gboolean
13445 clutter_vertex_equal (const ClutterVertex *vertex_a,
13446                       const ClutterVertex *vertex_b)
13447 {
13448   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13449
13450   if (vertex_a == vertex_b)
13451     return TRUE;
13452
13453   return vertex_a->x == vertex_b->x &&
13454          vertex_a->y == vertex_b->y &&
13455          vertex_a->z == vertex_b->z;
13456 }
13457
13458 static gboolean
13459 clutter_vertex_progress (const GValue *a,
13460                          const GValue *b,
13461                          gdouble       progress,
13462                          GValue       *retval)
13463 {
13464   const ClutterVertex *av = g_value_get_boxed (a);
13465   const ClutterVertex *bv = g_value_get_boxed (b);
13466   ClutterVertex res = { 0, };
13467
13468   res.x = av->x + (bv->x - av->x) * progress;
13469   res.y = av->y + (bv->y - av->y) * progress;
13470   res.z = av->z + (bv->z - av->z) * progress;
13471
13472   g_value_set_boxed (retval, &res);
13473
13474   return TRUE;
13475 }
13476
13477 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13478                                clutter_vertex_copy,
13479                                clutter_vertex_free,
13480                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13481
13482 /**
13483  * clutter_actor_is_rotated:
13484  * @self: a #ClutterActor
13485  *
13486  * Checks whether any rotation is applied to the actor.
13487  *
13488  * Return value: %TRUE if the actor is rotated.
13489  *
13490  * Since: 0.6
13491  */
13492 gboolean
13493 clutter_actor_is_rotated (ClutterActor *self)
13494 {
13495   const ClutterTransformInfo *info;
13496
13497   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13498
13499   info = _clutter_actor_get_transform_info_or_defaults (self);
13500
13501   if (info->rx_angle || info->ry_angle || info->rz_angle)
13502     return TRUE;
13503
13504   return FALSE;
13505 }
13506
13507 /**
13508  * clutter_actor_is_scaled:
13509  * @self: a #ClutterActor
13510  *
13511  * Checks whether the actor is scaled in either dimension.
13512  *
13513  * Return value: %TRUE if the actor is scaled.
13514  *
13515  * Since: 0.6
13516  */
13517 gboolean
13518 clutter_actor_is_scaled (ClutterActor *self)
13519 {
13520   const ClutterTransformInfo *info;
13521
13522   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13523
13524   info = _clutter_actor_get_transform_info_or_defaults (self);
13525
13526   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13527     return TRUE;
13528
13529   return FALSE;
13530 }
13531
13532 ClutterActor *
13533 _clutter_actor_get_stage_internal (ClutterActor *actor)
13534 {
13535   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13536     actor = actor->priv->parent;
13537
13538   return actor;
13539 }
13540
13541 /**
13542  * clutter_actor_get_stage:
13543  * @actor: a #ClutterActor
13544  *
13545  * Retrieves the #ClutterStage where @actor is contained.
13546  *
13547  * Return value: (transfer none) (type Clutter.Stage): the stage
13548  *   containing the actor, or %NULL
13549  *
13550  * Since: 0.8
13551  */
13552 ClutterActor *
13553 clutter_actor_get_stage (ClutterActor *actor)
13554 {
13555   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13556
13557   return _clutter_actor_get_stage_internal (actor);
13558 }
13559
13560 /**
13561  * clutter_actor_allocate_available_size:
13562  * @self: a #ClutterActor
13563  * @x: the actor's X coordinate
13564  * @y: the actor's Y coordinate
13565  * @available_width: the maximum available width, or -1 to use the
13566  *   actor's natural width
13567  * @available_height: the maximum available height, or -1 to use the
13568  *   actor's natural height
13569  * @flags: flags controlling the allocation
13570  *
13571  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13572  * preferred size, but limiting it to the maximum available width
13573  * and height provided.
13574  *
13575  * This function will do the right thing when dealing with the
13576  * actor's request mode.
13577  *
13578  * The implementation of this function is equivalent to:
13579  *
13580  * |[
13581  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13582  *     {
13583  *       clutter_actor_get_preferred_width (self, available_height,
13584  *                                          &amp;min_width,
13585  *                                          &amp;natural_width);
13586  *       width = CLAMP (natural_width, min_width, available_width);
13587  *
13588  *       clutter_actor_get_preferred_height (self, width,
13589  *                                           &amp;min_height,
13590  *                                           &amp;natural_height);
13591  *       height = CLAMP (natural_height, min_height, available_height);
13592  *     }
13593  *   else
13594  *     {
13595  *       clutter_actor_get_preferred_height (self, available_width,
13596  *                                           &amp;min_height,
13597  *                                           &amp;natural_height);
13598  *       height = CLAMP (natural_height, min_height, available_height);
13599  *
13600  *       clutter_actor_get_preferred_width (self, height,
13601  *                                          &amp;min_width,
13602  *                                          &amp;natural_width);
13603  *       width = CLAMP (natural_width, min_width, available_width);
13604  *     }
13605  *
13606  *   box.x1 = x; box.y1 = y;
13607  *   box.x2 = box.x1 + available_width;
13608  *   box.y2 = box.y1 + available_height;
13609  *   clutter_actor_allocate (self, &amp;box, flags);
13610  * ]|
13611  *
13612  * This function can be used by fluid layout managers to allocate
13613  * an actor's preferred size without making it bigger than the area
13614  * available for the container.
13615  *
13616  * Since: 1.0
13617  */
13618 void
13619 clutter_actor_allocate_available_size (ClutterActor           *self,
13620                                        gfloat                  x,
13621                                        gfloat                  y,
13622                                        gfloat                  available_width,
13623                                        gfloat                  available_height,
13624                                        ClutterAllocationFlags  flags)
13625 {
13626   ClutterActorPrivate *priv;
13627   gfloat width, height;
13628   gfloat min_width, min_height;
13629   gfloat natural_width, natural_height;
13630   ClutterActorBox box;
13631
13632   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13633
13634   priv = self->priv;
13635
13636   width = height = 0.0;
13637
13638   switch (priv->request_mode)
13639     {
13640     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13641       clutter_actor_get_preferred_width (self, available_height,
13642                                          &min_width,
13643                                          &natural_width);
13644       width  = CLAMP (natural_width, min_width, available_width);
13645
13646       clutter_actor_get_preferred_height (self, width,
13647                                           &min_height,
13648                                           &natural_height);
13649       height = CLAMP (natural_height, min_height, available_height);
13650       break;
13651
13652     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13653       clutter_actor_get_preferred_height (self, available_width,
13654                                           &min_height,
13655                                           &natural_height);
13656       height = CLAMP (natural_height, min_height, available_height);
13657
13658       clutter_actor_get_preferred_width (self, height,
13659                                          &min_width,
13660                                          &natural_width);
13661       width  = CLAMP (natural_width, min_width, available_width);
13662       break;
13663     }
13664
13665
13666   box.x1 = x;
13667   box.y1 = y;
13668   box.x2 = box.x1 + width;
13669   box.y2 = box.y1 + height;
13670   clutter_actor_allocate (self, &box, flags);
13671 }
13672
13673 /**
13674  * clutter_actor_allocate_preferred_size:
13675  * @self: a #ClutterActor
13676  * @flags: flags controlling the allocation
13677  *
13678  * Allocates the natural size of @self.
13679  *
13680  * This function is a utility call for #ClutterActor implementations
13681  * that allocates the actor's preferred natural size. It can be used
13682  * by fixed layout managers (like #ClutterGroup or so called
13683  * 'composite actors') inside the ClutterActor::allocate
13684  * implementation to give each child exactly how much space it
13685  * requires.
13686  *
13687  * This function is not meant to be used by applications. It is also
13688  * not meant to be used outside the implementation of the
13689  * ClutterActor::allocate virtual function.
13690  *
13691  * Since: 0.8
13692  */
13693 void
13694 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13695                                        ClutterAllocationFlags  flags)
13696 {
13697   gfloat actor_x, actor_y;
13698   gfloat natural_width, natural_height;
13699   ClutterActorBox actor_box;
13700
13701   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13702
13703   actor_x = clutter_actor_get_x (self);
13704   actor_y = clutter_actor_get_y (self);
13705
13706   clutter_actor_get_preferred_size (self,
13707                                     NULL, NULL,
13708                                     &natural_width,
13709                                     &natural_height);
13710
13711   actor_box.x1 = actor_x;
13712   actor_box.y1 = actor_y;
13713   actor_box.x2 = actor_box.x1 + natural_width;
13714   actor_box.y2 = actor_box.y1 + natural_height;
13715
13716   clutter_actor_allocate (self, &actor_box, flags);
13717 }
13718
13719 /**
13720  * clutter_actor_allocate_align_fill:
13721  * @self: a #ClutterActor
13722  * @box: a #ClutterActorBox, containing the available width and height
13723  * @x_align: the horizontal alignment, between 0 and 1
13724  * @y_align: the vertical alignment, between 0 and 1
13725  * @x_fill: whether the actor should fill horizontally
13726  * @y_fill: whether the actor should fill vertically
13727  * @flags: allocation flags to be passed to clutter_actor_allocate()
13728  *
13729  * Allocates @self by taking into consideration the available allocation
13730  * area; an alignment factor on either axis; and whether the actor should
13731  * fill the allocation on either axis.
13732  *
13733  * The @box should contain the available allocation width and height;
13734  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13735  * allocation will be offset by their value.
13736  *
13737  * This function takes into consideration the geometry request specified by
13738  * the #ClutterActor:request-mode property, and the text direction.
13739  *
13740  * This function is useful for fluid layout managers, like #ClutterBinLayout
13741  * or #ClutterTableLayout
13742  *
13743  * Since: 1.4
13744  */
13745 void
13746 clutter_actor_allocate_align_fill (ClutterActor           *self,
13747                                    const ClutterActorBox  *box,
13748                                    gdouble                 x_align,
13749                                    gdouble                 y_align,
13750                                    gboolean                x_fill,
13751                                    gboolean                y_fill,
13752                                    ClutterAllocationFlags  flags)
13753 {
13754   ClutterActorPrivate *priv;
13755   ClutterActorBox allocation = { 0, };
13756   gfloat x_offset, y_offset;
13757   gfloat available_width, available_height;
13758   gfloat child_width, child_height;
13759
13760   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13761   g_return_if_fail (box != NULL);
13762   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13763   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13764
13765   priv = self->priv;
13766
13767   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13768   clutter_actor_box_get_size (box, &available_width, &available_height);
13769
13770   if (available_width < 0)
13771     available_width = 0;
13772
13773   if (available_height < 0)
13774     available_height = 0;
13775
13776   if (x_fill)
13777     {
13778       allocation.x1 = x_offset;
13779       allocation.x2 = allocation.x1 + available_width;
13780     }
13781
13782   if (y_fill)
13783     {
13784       allocation.y1 = y_offset;
13785       allocation.y2 = allocation.y1 + available_height;
13786     }
13787
13788   /* if we are filling horizontally and vertically then we're done */
13789   if (x_fill && y_fill)
13790     goto out;
13791
13792   child_width = child_height = 0.0f;
13793
13794   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13795     {
13796       gfloat min_width, natural_width;
13797       gfloat min_height, natural_height;
13798
13799       clutter_actor_get_preferred_width (self, available_height,
13800                                          &min_width,
13801                                          &natural_width);
13802
13803       child_width = CLAMP (natural_width, min_width, available_width);
13804
13805       if (!y_fill)
13806         {
13807           clutter_actor_get_preferred_height (self, child_width,
13808                                               &min_height,
13809                                               &natural_height);
13810
13811           child_height = CLAMP (natural_height, min_height, available_height);
13812         }
13813     }
13814   else
13815     {
13816       gfloat min_width, natural_width;
13817       gfloat min_height, natural_height;
13818
13819       clutter_actor_get_preferred_height (self, available_width,
13820                                           &min_height,
13821                                           &natural_height);
13822
13823       child_height = CLAMP (natural_height, min_height, available_height);
13824
13825       if (!x_fill)
13826         {
13827           clutter_actor_get_preferred_width (self, child_height,
13828                                              &min_width,
13829                                              &natural_width);
13830
13831           child_width = CLAMP (natural_width, min_width, available_width);
13832         }
13833     }
13834
13835   /* invert the horizontal alignment for RTL languages */
13836   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13837     x_align = 1.0 - x_align;
13838
13839   if (!x_fill)
13840     {
13841       allocation.x1 = x_offset
13842                     + ((available_width - child_width) * x_align);
13843       allocation.x2 = allocation.x1 + child_width;
13844     }
13845
13846   if (!y_fill)
13847     {
13848       allocation.y1 = y_offset
13849                     + ((available_height - child_height) * y_align);
13850       allocation.y2 = allocation.y1 + child_height;
13851     }
13852
13853 out:
13854   clutter_actor_box_clamp_to_pixel (&allocation);
13855   clutter_actor_allocate (self, &allocation, flags);
13856 }
13857
13858 /**
13859  * clutter_actor_grab_key_focus:
13860  * @self: a #ClutterActor
13861  *
13862  * Sets the key focus of the #ClutterStage including @self
13863  * to this #ClutterActor.
13864  *
13865  * Since: 1.0
13866  */
13867 void
13868 clutter_actor_grab_key_focus (ClutterActor *self)
13869 {
13870   ClutterActor *stage;
13871
13872   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13873
13874   stage = _clutter_actor_get_stage_internal (self);
13875   if (stage != NULL)
13876     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13877 }
13878
13879 /**
13880  * clutter_actor_get_pango_context:
13881  * @self: a #ClutterActor
13882  *
13883  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13884  * is already configured using the appropriate font map, resolution
13885  * and font options.
13886  *
13887  * Unlike clutter_actor_create_pango_context(), this context is owend
13888  * by the #ClutterActor and it will be updated each time the options
13889  * stored by the #ClutterBackend change.
13890  *
13891  * You can use the returned #PangoContext to create a #PangoLayout
13892  * and render text using cogl_pango_render_layout() to reuse the
13893  * glyphs cache also used by Clutter.
13894  *
13895  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13896  *   The returned #PangoContext is owned by the actor and should not be
13897  *   unreferenced by the application code
13898  *
13899  * Since: 1.0
13900  */
13901 PangoContext *
13902 clutter_actor_get_pango_context (ClutterActor *self)
13903 {
13904   ClutterActorPrivate *priv;
13905
13906   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13907
13908   priv = self->priv;
13909
13910   if (priv->pango_context != NULL)
13911     return priv->pango_context;
13912
13913   priv->pango_context = _clutter_context_get_pango_context ();
13914   g_object_ref (priv->pango_context);
13915
13916   return priv->pango_context;
13917 }
13918
13919 /**
13920  * clutter_actor_create_pango_context:
13921  * @self: a #ClutterActor
13922  *
13923  * Creates a #PangoContext for the given actor. The #PangoContext
13924  * is already configured using the appropriate font map, resolution
13925  * and font options.
13926  *
13927  * See also clutter_actor_get_pango_context().
13928  *
13929  * Return value: (transfer full): the newly created #PangoContext.
13930  *   Use g_object_unref() on the returned value to deallocate its
13931  *   resources
13932  *
13933  * Since: 1.0
13934  */
13935 PangoContext *
13936 clutter_actor_create_pango_context (ClutterActor *self)
13937 {
13938   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13939
13940   return _clutter_context_create_pango_context ();
13941 }
13942
13943 /**
13944  * clutter_actor_create_pango_layout:
13945  * @self: a #ClutterActor
13946  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13947  *
13948  * Creates a new #PangoLayout from the same #PangoContext used
13949  * by the #ClutterActor. The #PangoLayout is already configured
13950  * with the font map, resolution and font options, and the
13951  * given @text.
13952  *
13953  * If you want to keep around a #PangoLayout created by this
13954  * function you will have to connect to the #ClutterBackend::font-changed
13955  * and #ClutterBackend::resolution-changed signals, and call
13956  * pango_layout_context_changed() in response to them.
13957  *
13958  * Return value: (transfer full): the newly created #PangoLayout.
13959  *   Use g_object_unref() when done
13960  *
13961  * Since: 1.0
13962  */
13963 PangoLayout *
13964 clutter_actor_create_pango_layout (ClutterActor *self,
13965                                    const gchar  *text)
13966 {
13967   PangoContext *context;
13968   PangoLayout *layout;
13969
13970   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13971
13972   context = clutter_actor_get_pango_context (self);
13973   layout = pango_layout_new (context);
13974
13975   if (text)
13976     pango_layout_set_text (layout, text, -1);
13977
13978   return layout;
13979 }
13980
13981 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13982  * ClutterOffscreenEffect.
13983  */
13984 void
13985 _clutter_actor_set_opacity_override (ClutterActor *self,
13986                                      gint          opacity)
13987 {
13988   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13989
13990   self->priv->opacity_override = opacity;
13991 }
13992
13993 gint
13994 _clutter_actor_get_opacity_override (ClutterActor *self)
13995 {
13996   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13997
13998   return self->priv->opacity_override;
13999 }
14000
14001 /* Allows you to disable applying the actors model view transform during
14002  * a paint. Used by ClutterClone. */
14003 void
14004 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14005                                                 gboolean      enable)
14006 {
14007   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14008
14009   self->priv->enable_model_view_transform = enable;
14010 }
14011
14012 void
14013 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14014                                           gboolean      enable)
14015 {
14016   ClutterActorPrivate *priv;
14017
14018   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14019
14020   priv = self->priv;
14021
14022   priv->enable_paint_unmapped = enable;
14023
14024   if (priv->enable_paint_unmapped)
14025     {
14026       /* Make sure that the parents of the widget are realized first;
14027        * otherwise checks in clutter_actor_update_map_state() will
14028        * fail.
14029        */
14030       clutter_actor_realize (self);
14031
14032       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14033     }
14034   else
14035     {
14036       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14037     }
14038 }
14039
14040 static void
14041 clutter_anchor_coord_get_units (ClutterActor      *self,
14042                                 const AnchorCoord *coord,
14043                                 gfloat            *x,
14044                                 gfloat            *y,
14045                                 gfloat            *z)
14046 {
14047   if (coord->is_fractional)
14048     {
14049       gfloat actor_width, actor_height;
14050
14051       clutter_actor_get_size (self, &actor_width, &actor_height);
14052
14053       if (x)
14054         *x = actor_width * coord->v.fraction.x;
14055
14056       if (y)
14057         *y = actor_height * coord->v.fraction.y;
14058
14059       if (z)
14060         *z = 0;
14061     }
14062   else
14063     {
14064       if (x)
14065         *x = coord->v.units.x;
14066
14067       if (y)
14068         *y = coord->v.units.y;
14069
14070       if (z)
14071         *z = coord->v.units.z;
14072     }
14073 }
14074
14075 static void
14076 clutter_anchor_coord_set_units (AnchorCoord *coord,
14077                                 gfloat       x,
14078                                 gfloat       y,
14079                                 gfloat       z)
14080 {
14081   coord->is_fractional = FALSE;
14082   coord->v.units.x = x;
14083   coord->v.units.y = y;
14084   coord->v.units.z = z;
14085 }
14086
14087 static ClutterGravity
14088 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14089 {
14090   if (coord->is_fractional)
14091     {
14092       if (coord->v.fraction.x == 0.0)
14093         {
14094           if (coord->v.fraction.y == 0.0)
14095             return CLUTTER_GRAVITY_NORTH_WEST;
14096           else if (coord->v.fraction.y == 0.5)
14097             return CLUTTER_GRAVITY_WEST;
14098           else if (coord->v.fraction.y == 1.0)
14099             return CLUTTER_GRAVITY_SOUTH_WEST;
14100           else
14101             return CLUTTER_GRAVITY_NONE;
14102         }
14103       else if (coord->v.fraction.x == 0.5)
14104         {
14105           if (coord->v.fraction.y == 0.0)
14106             return CLUTTER_GRAVITY_NORTH;
14107           else if (coord->v.fraction.y == 0.5)
14108             return CLUTTER_GRAVITY_CENTER;
14109           else if (coord->v.fraction.y == 1.0)
14110             return CLUTTER_GRAVITY_SOUTH;
14111           else
14112             return CLUTTER_GRAVITY_NONE;
14113         }
14114       else if (coord->v.fraction.x == 1.0)
14115         {
14116           if (coord->v.fraction.y == 0.0)
14117             return CLUTTER_GRAVITY_NORTH_EAST;
14118           else if (coord->v.fraction.y == 0.5)
14119             return CLUTTER_GRAVITY_EAST;
14120           else if (coord->v.fraction.y == 1.0)
14121             return CLUTTER_GRAVITY_SOUTH_EAST;
14122           else
14123             return CLUTTER_GRAVITY_NONE;
14124         }
14125       else
14126         return CLUTTER_GRAVITY_NONE;
14127     }
14128   else
14129     return CLUTTER_GRAVITY_NONE;
14130 }
14131
14132 static void
14133 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14134                                   ClutterGravity  gravity)
14135 {
14136   switch (gravity)
14137     {
14138     case CLUTTER_GRAVITY_NORTH:
14139       coord->v.fraction.x = 0.5;
14140       coord->v.fraction.y = 0.0;
14141       break;
14142
14143     case CLUTTER_GRAVITY_NORTH_EAST:
14144       coord->v.fraction.x = 1.0;
14145       coord->v.fraction.y = 0.0;
14146       break;
14147
14148     case CLUTTER_GRAVITY_EAST:
14149       coord->v.fraction.x = 1.0;
14150       coord->v.fraction.y = 0.5;
14151       break;
14152
14153     case CLUTTER_GRAVITY_SOUTH_EAST:
14154       coord->v.fraction.x = 1.0;
14155       coord->v.fraction.y = 1.0;
14156       break;
14157
14158     case CLUTTER_GRAVITY_SOUTH:
14159       coord->v.fraction.x = 0.5;
14160       coord->v.fraction.y = 1.0;
14161       break;
14162
14163     case CLUTTER_GRAVITY_SOUTH_WEST:
14164       coord->v.fraction.x = 0.0;
14165       coord->v.fraction.y = 1.0;
14166       break;
14167
14168     case CLUTTER_GRAVITY_WEST:
14169       coord->v.fraction.x = 0.0;
14170       coord->v.fraction.y = 0.5;
14171       break;
14172
14173     case CLUTTER_GRAVITY_NORTH_WEST:
14174       coord->v.fraction.x = 0.0;
14175       coord->v.fraction.y = 0.0;
14176       break;
14177
14178     case CLUTTER_GRAVITY_CENTER:
14179       coord->v.fraction.x = 0.5;
14180       coord->v.fraction.y = 0.5;
14181       break;
14182
14183     default:
14184       coord->v.fraction.x = 0.0;
14185       coord->v.fraction.y = 0.0;
14186       break;
14187     }
14188
14189   coord->is_fractional = TRUE;
14190 }
14191
14192 static gboolean
14193 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14194 {
14195   if (coord->is_fractional)
14196     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14197   else
14198     return (coord->v.units.x == 0.0
14199             && coord->v.units.y == 0.0
14200             && coord->v.units.z == 0.0);
14201 }
14202
14203 /**
14204  * clutter_actor_get_flags:
14205  * @self: a #ClutterActor
14206  *
14207  * Retrieves the flags set on @self
14208  *
14209  * Return value: a bitwise or of #ClutterActorFlags or 0
14210  *
14211  * Since: 1.0
14212  */
14213 ClutterActorFlags
14214 clutter_actor_get_flags (ClutterActor *self)
14215 {
14216   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14217
14218   return self->flags;
14219 }
14220
14221 /**
14222  * clutter_actor_set_flags:
14223  * @self: a #ClutterActor
14224  * @flags: the flags to set
14225  *
14226  * Sets @flags on @self
14227  *
14228  * This function will emit notifications for the changed properties
14229  *
14230  * Since: 1.0
14231  */
14232 void
14233 clutter_actor_set_flags (ClutterActor      *self,
14234                          ClutterActorFlags  flags)
14235 {
14236   ClutterActorFlags old_flags;
14237   GObject *obj;
14238   gboolean was_reactive_set, reactive_set;
14239   gboolean was_realized_set, realized_set;
14240   gboolean was_mapped_set, mapped_set;
14241   gboolean was_visible_set, visible_set;
14242
14243   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14244
14245   if (self->flags == flags)
14246     return;
14247
14248   obj = G_OBJECT (self);
14249   g_object_ref (obj);
14250   g_object_freeze_notify (obj);
14251
14252   old_flags = self->flags;
14253
14254   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14255   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14256   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14257   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14258
14259   self->flags |= flags;
14260
14261   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14262   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14263   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14264   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14265
14266   if (reactive_set != was_reactive_set)
14267     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14268
14269   if (realized_set != was_realized_set)
14270     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14271
14272   if (mapped_set != was_mapped_set)
14273     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14274
14275   if (visible_set != was_visible_set)
14276     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14277
14278   g_object_thaw_notify (obj);
14279   g_object_unref (obj);
14280 }
14281
14282 /**
14283  * clutter_actor_unset_flags:
14284  * @self: a #ClutterActor
14285  * @flags: the flags to unset
14286  *
14287  * Unsets @flags on @self
14288  *
14289  * This function will emit notifications for the changed properties
14290  *
14291  * Since: 1.0
14292  */
14293 void
14294 clutter_actor_unset_flags (ClutterActor      *self,
14295                            ClutterActorFlags  flags)
14296 {
14297   ClutterActorFlags old_flags;
14298   GObject *obj;
14299   gboolean was_reactive_set, reactive_set;
14300   gboolean was_realized_set, realized_set;
14301   gboolean was_mapped_set, mapped_set;
14302   gboolean was_visible_set, visible_set;
14303
14304   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14305
14306   obj = G_OBJECT (self);
14307   g_object_freeze_notify (obj);
14308
14309   old_flags = self->flags;
14310
14311   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14312   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14313   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14314   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14315
14316   self->flags &= ~flags;
14317
14318   if (self->flags == old_flags)
14319     return;
14320
14321   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14322   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14323   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14324   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14325
14326   if (reactive_set != was_reactive_set)
14327     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14328
14329   if (realized_set != was_realized_set)
14330     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14331
14332   if (mapped_set != was_mapped_set)
14333     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14334
14335   if (visible_set != was_visible_set)
14336     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14337
14338   g_object_thaw_notify (obj);
14339 }
14340
14341 /**
14342  * clutter_actor_get_transformation_matrix:
14343  * @self: a #ClutterActor
14344  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14345  *
14346  * Retrieves the transformations applied to @self relative to its
14347  * parent.
14348  *
14349  * Since: 1.0
14350  */
14351 void
14352 clutter_actor_get_transformation_matrix (ClutterActor *self,
14353                                          CoglMatrix   *matrix)
14354 {
14355   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14356
14357   cogl_matrix_init_identity (matrix);
14358
14359   _clutter_actor_apply_modelview_transform (self, matrix);
14360 }
14361
14362 void
14363 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14364                                    gboolean      is_in_clone_paint)
14365 {
14366   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14367   self->priv->in_clone_paint = is_in_clone_paint;
14368 }
14369
14370 /**
14371  * clutter_actor_is_in_clone_paint:
14372  * @self: a #ClutterActor
14373  *
14374  * Checks whether @self is being currently painted by a #ClutterClone
14375  *
14376  * This function is useful only inside the ::paint virtual function
14377  * implementations or within handlers for the #ClutterActor::paint
14378  * signal
14379  *
14380  * This function should not be used by applications
14381  *
14382  * Return value: %TRUE if the #ClutterActor is currently being painted
14383  *   by a #ClutterClone, and %FALSE otherwise
14384  *
14385  * Since: 1.0
14386  */
14387 gboolean
14388 clutter_actor_is_in_clone_paint (ClutterActor *self)
14389 {
14390   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14391
14392   return self->priv->in_clone_paint;
14393 }
14394
14395 static gboolean
14396 set_direction_recursive (ClutterActor *actor,
14397                          gpointer      user_data)
14398 {
14399   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14400
14401   clutter_actor_set_text_direction (actor, text_dir);
14402
14403   return TRUE;
14404 }
14405
14406 /**
14407  * clutter_actor_set_text_direction:
14408  * @self: a #ClutterActor
14409  * @text_dir: the text direction for @self
14410  *
14411  * Sets the #ClutterTextDirection for an actor
14412  *
14413  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14414  *
14415  * If @self implements #ClutterContainer then this function will recurse
14416  * inside all the children of @self (including the internal ones).
14417  *
14418  * Composite actors not implementing #ClutterContainer, or actors requiring
14419  * special handling when the text direction changes, should connect to
14420  * the #GObject::notify signal for the #ClutterActor:text-direction property
14421  *
14422  * Since: 1.2
14423  */
14424 void
14425 clutter_actor_set_text_direction (ClutterActor         *self,
14426                                   ClutterTextDirection  text_dir)
14427 {
14428   ClutterActorPrivate *priv;
14429
14430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14431   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14432
14433   priv = self->priv;
14434
14435   if (priv->text_direction != text_dir)
14436     {
14437       priv->text_direction = text_dir;
14438
14439       /* we need to emit the notify::text-direction first, so that
14440        * the sub-classes can catch that and do specific handling of
14441        * the text direction; see clutter_text_direction_changed_cb()
14442        * inside clutter-text.c
14443        */
14444       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14445
14446       _clutter_actor_foreach_child (self, set_direction_recursive,
14447                                     GINT_TO_POINTER (text_dir));
14448
14449       clutter_actor_queue_relayout (self);
14450     }
14451 }
14452
14453 void
14454 _clutter_actor_set_has_pointer (ClutterActor *self,
14455                                 gboolean      has_pointer)
14456 {
14457   ClutterActorPrivate *priv = self->priv;
14458
14459   if (priv->has_pointer != has_pointer)
14460     {
14461       priv->has_pointer = has_pointer;
14462
14463       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14464     }
14465 }
14466
14467 /**
14468  * clutter_actor_get_text_direction:
14469  * @self: a #ClutterActor
14470  *
14471  * Retrieves the value set using clutter_actor_set_text_direction()
14472  *
14473  * If no text direction has been previously set, the default text
14474  * direction, as returned by clutter_get_default_text_direction(), will
14475  * be returned instead
14476  *
14477  * Return value: the #ClutterTextDirection for the actor
14478  *
14479  * Since: 1.2
14480  */
14481 ClutterTextDirection
14482 clutter_actor_get_text_direction (ClutterActor *self)
14483 {
14484   ClutterActorPrivate *priv;
14485
14486   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14487                         CLUTTER_TEXT_DIRECTION_LTR);
14488
14489   priv = self->priv;
14490
14491   /* if no direction has been set yet use the default */
14492   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14493     priv->text_direction = clutter_get_default_text_direction ();
14494
14495   return priv->text_direction;
14496 }
14497
14498 /**
14499  * clutter_actor_push_internal:
14500  * @self: a #ClutterActor
14501  *
14502  * Should be used by actors implementing the #ClutterContainer and with
14503  * internal children added through clutter_actor_set_parent(), for instance:
14504  *
14505  * |[
14506  *   static void
14507  *   my_actor_init (MyActor *self)
14508  *   {
14509  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14510  *
14511  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14512  *
14513  *     /&ast; calling clutter_actor_set_parent() now will result in
14514  *      &ast; the internal flag being set on a child of MyActor
14515  *      &ast;/
14516  *
14517  *     /&ast; internal child - a background texture &ast;/
14518  *     self->priv->background_tex = clutter_texture_new ();
14519  *     clutter_actor_set_parent (self->priv->background_tex,
14520  *                               CLUTTER_ACTOR (self));
14521  *
14522  *     /&ast; internal child - a label &ast;/
14523  *     self->priv->label = clutter_text_new ();
14524  *     clutter_actor_set_parent (self->priv->label,
14525  *                               CLUTTER_ACTOR (self));
14526  *
14527  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14528  *
14529  *     /&ast; calling clutter_actor_set_parent() now will not result in
14530  *      &ast; the internal flag being set on a child of MyActor
14531  *      &ast;/
14532  *   }
14533  * ]|
14534  *
14535  * This function will be used by Clutter to toggle an "internal child"
14536  * flag whenever clutter_actor_set_parent() is called; internal children
14537  * are handled differently by Clutter, specifically when destroying their
14538  * parent.
14539  *
14540  * Call clutter_actor_pop_internal() when you finished adding internal
14541  * children.
14542  *
14543  * Nested calls to clutter_actor_push_internal() are allowed, but each
14544  * one must by followed by a clutter_actor_pop_internal() call.
14545  *
14546  * Since: 1.2
14547  *
14548  * Deprecated: 1.10: All children of an actor are accessible through
14549  *   the #ClutterActor API, and #ClutterActor implements the
14550  *   #ClutterContainer interface, so this function is only useful
14551  *   for legacy containers overriding the default implementation.
14552  */
14553 void
14554 clutter_actor_push_internal (ClutterActor *self)
14555 {
14556   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14557
14558   self->priv->internal_child += 1;
14559 }
14560
14561 /**
14562  * clutter_actor_pop_internal:
14563  * @self: a #ClutterActor
14564  *
14565  * Disables the effects of clutter_actor_push_internal().
14566  *
14567  * Since: 1.2
14568  *
14569  * Deprecated: 1.10: All children of an actor are accessible through
14570  *   the #ClutterActor API. This function is only useful for legacy
14571  *   containers overriding the default implementation of the
14572  *   #ClutterContainer interface.
14573  */
14574 void
14575 clutter_actor_pop_internal (ClutterActor *self)
14576 {
14577   ClutterActorPrivate *priv;
14578
14579   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14580
14581   priv = self->priv;
14582
14583   if (priv->internal_child == 0)
14584     {
14585       g_warning ("Mismatched %s: you need to call "
14586                  "clutter_actor_push_composite() at least once before "
14587                  "calling this function", G_STRFUNC);
14588       return;
14589     }
14590
14591   priv->internal_child -= 1;
14592 }
14593
14594 /**
14595  * clutter_actor_has_pointer:
14596  * @self: a #ClutterActor
14597  *
14598  * Checks whether an actor contains the pointer of a
14599  * #ClutterInputDevice
14600  *
14601  * Return value: %TRUE if the actor contains the pointer, and
14602  *   %FALSE otherwise
14603  *
14604  * Since: 1.2
14605  */
14606 gboolean
14607 clutter_actor_has_pointer (ClutterActor *self)
14608 {
14609   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14610
14611   return self->priv->has_pointer;
14612 }
14613
14614 /* XXX: This is a workaround for not being able to break the ABI of
14615  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14616  * clutter_actor_queue_clipped_redraw() for details.
14617  */
14618 ClutterPaintVolume *
14619 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14620 {
14621   return g_object_get_data (G_OBJECT (self),
14622                             "-clutter-actor-queue-redraw-clip");
14623 }
14624
14625 void
14626 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14627                                       ClutterPaintVolume *clip)
14628 {
14629   g_object_set_data (G_OBJECT (self),
14630                      "-clutter-actor-queue-redraw-clip",
14631                      clip);
14632 }
14633
14634 /**
14635  * clutter_actor_has_allocation:
14636  * @self: a #ClutterActor
14637  *
14638  * Checks if the actor has an up-to-date allocation assigned to
14639  * it. This means that the actor should have an allocation: it's
14640  * visible and has a parent. It also means that there is no
14641  * outstanding relayout request in progress for the actor or its
14642  * children (There might be other outstanding layout requests in
14643  * progress that will cause the actor to get a new allocation
14644  * when the stage is laid out, however).
14645  *
14646  * If this function returns %FALSE, then the actor will normally
14647  * be allocated before it is next drawn on the screen.
14648  *
14649  * Return value: %TRUE if the actor has an up-to-date allocation
14650  *
14651  * Since: 1.4
14652  */
14653 gboolean
14654 clutter_actor_has_allocation (ClutterActor *self)
14655 {
14656   ClutterActorPrivate *priv;
14657
14658   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14659
14660   priv = self->priv;
14661
14662   return priv->parent != NULL &&
14663          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14664          !priv->needs_allocation;
14665 }
14666
14667 /**
14668  * clutter_actor_add_action:
14669  * @self: a #ClutterActor
14670  * @action: a #ClutterAction
14671  *
14672  * Adds @action to the list of actions applied to @self
14673  *
14674  * A #ClutterAction can only belong to one actor at a time
14675  *
14676  * The #ClutterActor will hold a reference on @action until either
14677  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14678  * is called
14679  *
14680  * Since: 1.4
14681  */
14682 void
14683 clutter_actor_add_action (ClutterActor  *self,
14684                           ClutterAction *action)
14685 {
14686   ClutterActorPrivate *priv;
14687
14688   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14689   g_return_if_fail (CLUTTER_IS_ACTION (action));
14690
14691   priv = self->priv;
14692
14693   if (priv->actions == NULL)
14694     {
14695       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14696       priv->actions->actor = self;
14697     }
14698
14699   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14700
14701   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14702 }
14703
14704 /**
14705  * clutter_actor_add_action_with_name:
14706  * @self: a #ClutterActor
14707  * @name: the name to set on the action
14708  * @action: a #ClutterAction
14709  *
14710  * A convenience function for setting the name of a #ClutterAction
14711  * while adding it to the list of actions applied to @self
14712  *
14713  * This function is the logical equivalent of:
14714  *
14715  * |[
14716  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14717  *   clutter_actor_add_action (self, action);
14718  * ]|
14719  *
14720  * Since: 1.4
14721  */
14722 void
14723 clutter_actor_add_action_with_name (ClutterActor  *self,
14724                                     const gchar   *name,
14725                                     ClutterAction *action)
14726 {
14727   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14728   g_return_if_fail (name != NULL);
14729   g_return_if_fail (CLUTTER_IS_ACTION (action));
14730
14731   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14732   clutter_actor_add_action (self, action);
14733 }
14734
14735 /**
14736  * clutter_actor_remove_action:
14737  * @self: a #ClutterActor
14738  * @action: a #ClutterAction
14739  *
14740  * Removes @action from the list of actions applied to @self
14741  *
14742  * The reference held by @self on the #ClutterAction will be released
14743  *
14744  * Since: 1.4
14745  */
14746 void
14747 clutter_actor_remove_action (ClutterActor  *self,
14748                              ClutterAction *action)
14749 {
14750   ClutterActorPrivate *priv;
14751
14752   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14753   g_return_if_fail (CLUTTER_IS_ACTION (action));
14754
14755   priv = self->priv;
14756
14757   if (priv->actions == NULL)
14758     return;
14759
14760   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14761
14762   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14763 }
14764
14765 /**
14766  * clutter_actor_remove_action_by_name:
14767  * @self: a #ClutterActor
14768  * @name: the name of the action to remove
14769  *
14770  * Removes the #ClutterAction with the given name from the list
14771  * of actions applied to @self
14772  *
14773  * Since: 1.4
14774  */
14775 void
14776 clutter_actor_remove_action_by_name (ClutterActor *self,
14777                                      const gchar  *name)
14778 {
14779   ClutterActorPrivate *priv;
14780   ClutterActorMeta *meta;
14781
14782   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14783   g_return_if_fail (name != NULL);
14784
14785   priv = self->priv;
14786
14787   if (priv->actions == NULL)
14788     return;
14789
14790   meta = _clutter_meta_group_get_meta (priv->actions, name);
14791   if (meta == NULL)
14792     return;
14793
14794   _clutter_meta_group_remove_meta (priv->actions, meta);
14795
14796   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14797 }
14798
14799 /**
14800  * clutter_actor_get_actions:
14801  * @self: a #ClutterActor
14802  *
14803  * Retrieves the list of actions applied to @self
14804  *
14805  * Return value: (transfer container) (element-type Clutter.Action): a copy
14806  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14807  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14808  *   allocated by the returned #GList
14809  *
14810  * Since: 1.4
14811  */
14812 GList *
14813 clutter_actor_get_actions (ClutterActor *self)
14814 {
14815   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14816
14817   if (self->priv->actions == NULL)
14818     return NULL;
14819
14820   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14821 }
14822
14823 /**
14824  * clutter_actor_get_action:
14825  * @self: a #ClutterActor
14826  * @name: the name of the action to retrieve
14827  *
14828  * Retrieves the #ClutterAction with the given name in the list
14829  * of actions applied to @self
14830  *
14831  * Return value: (transfer none): a #ClutterAction for the given
14832  *   name, or %NULL. The returned #ClutterAction is owned by the
14833  *   actor and it should not be unreferenced directly
14834  *
14835  * Since: 1.4
14836  */
14837 ClutterAction *
14838 clutter_actor_get_action (ClutterActor *self,
14839                           const gchar  *name)
14840 {
14841   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14842   g_return_val_if_fail (name != NULL, NULL);
14843
14844   if (self->priv->actions == NULL)
14845     return NULL;
14846
14847   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14848 }
14849
14850 /**
14851  * clutter_actor_clear_actions:
14852  * @self: a #ClutterActor
14853  *
14854  * Clears the list of actions applied to @self
14855  *
14856  * Since: 1.4
14857  */
14858 void
14859 clutter_actor_clear_actions (ClutterActor *self)
14860 {
14861   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14862
14863   if (self->priv->actions == NULL)
14864     return;
14865
14866   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14867 }
14868
14869 /**
14870  * clutter_actor_add_constraint:
14871  * @self: a #ClutterActor
14872  * @constraint: a #ClutterConstraint
14873  *
14874  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14875  * to @self
14876  *
14877  * The #ClutterActor will hold a reference on the @constraint until
14878  * either clutter_actor_remove_constraint() or
14879  * clutter_actor_clear_constraints() is called.
14880  *
14881  * Since: 1.4
14882  */
14883 void
14884 clutter_actor_add_constraint (ClutterActor      *self,
14885                               ClutterConstraint *constraint)
14886 {
14887   ClutterActorPrivate *priv;
14888
14889   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14890   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14891
14892   priv = self->priv;
14893
14894   if (priv->constraints == NULL)
14895     {
14896       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14897       priv->constraints->actor = self;
14898     }
14899
14900   _clutter_meta_group_add_meta (priv->constraints,
14901                                 CLUTTER_ACTOR_META (constraint));
14902   clutter_actor_queue_relayout (self);
14903
14904   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14905 }
14906
14907 /**
14908  * clutter_actor_add_constraint_with_name:
14909  * @self: a #ClutterActor
14910  * @name: the name to set on the constraint
14911  * @constraint: a #ClutterConstraint
14912  *
14913  * A convenience function for setting the name of a #ClutterConstraint
14914  * while adding it to the list of constraints applied to @self
14915  *
14916  * This function is the logical equivalent of:
14917  *
14918  * |[
14919  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14920  *   clutter_actor_add_constraint (self, constraint);
14921  * ]|
14922  *
14923  * Since: 1.4
14924  */
14925 void
14926 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14927                                         const gchar       *name,
14928                                         ClutterConstraint *constraint)
14929 {
14930   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14931   g_return_if_fail (name != NULL);
14932   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14933
14934   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14935   clutter_actor_add_constraint (self, constraint);
14936 }
14937
14938 /**
14939  * clutter_actor_remove_constraint:
14940  * @self: a #ClutterActor
14941  * @constraint: a #ClutterConstraint
14942  *
14943  * Removes @constraint from the list of constraints applied to @self
14944  *
14945  * The reference held by @self on the #ClutterConstraint will be released
14946  *
14947  * Since: 1.4
14948  */
14949 void
14950 clutter_actor_remove_constraint (ClutterActor      *self,
14951                                  ClutterConstraint *constraint)
14952 {
14953   ClutterActorPrivate *priv;
14954
14955   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14956   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14957
14958   priv = self->priv;
14959
14960   if (priv->constraints == NULL)
14961     return;
14962
14963   _clutter_meta_group_remove_meta (priv->constraints,
14964                                    CLUTTER_ACTOR_META (constraint));
14965   clutter_actor_queue_relayout (self);
14966
14967   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14968 }
14969
14970 /**
14971  * clutter_actor_remove_constraint_by_name:
14972  * @self: a #ClutterActor
14973  * @name: the name of the constraint to remove
14974  *
14975  * Removes the #ClutterConstraint with the given name from the list
14976  * of constraints applied to @self
14977  *
14978  * Since: 1.4
14979  */
14980 void
14981 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14982                                          const gchar  *name)
14983 {
14984   ClutterActorPrivate *priv;
14985   ClutterActorMeta *meta;
14986
14987   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14988   g_return_if_fail (name != NULL);
14989
14990   priv = self->priv;
14991
14992   if (priv->constraints == NULL)
14993     return;
14994
14995   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14996   if (meta == NULL)
14997     return;
14998
14999   _clutter_meta_group_remove_meta (priv->constraints, meta);
15000   clutter_actor_queue_relayout (self);
15001 }
15002
15003 /**
15004  * clutter_actor_get_constraints:
15005  * @self: a #ClutterActor
15006  *
15007  * Retrieves the list of constraints applied to @self
15008  *
15009  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15010  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15011  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15012  *   allocated by the returned #GList
15013  *
15014  * Since: 1.4
15015  */
15016 GList *
15017 clutter_actor_get_constraints (ClutterActor *self)
15018 {
15019   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15020
15021   if (self->priv->constraints == NULL)
15022     return NULL;
15023
15024   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15025 }
15026
15027 /**
15028  * clutter_actor_get_constraint:
15029  * @self: a #ClutterActor
15030  * @name: the name of the constraint to retrieve
15031  *
15032  * Retrieves the #ClutterConstraint with the given name in the list
15033  * of constraints applied to @self
15034  *
15035  * Return value: (transfer none): a #ClutterConstraint for the given
15036  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15037  *   actor and it should not be unreferenced directly
15038  *
15039  * Since: 1.4
15040  */
15041 ClutterConstraint *
15042 clutter_actor_get_constraint (ClutterActor *self,
15043                               const gchar  *name)
15044 {
15045   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15046   g_return_val_if_fail (name != NULL, NULL);
15047
15048   if (self->priv->constraints == NULL)
15049     return NULL;
15050
15051   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15052 }
15053
15054 /**
15055  * clutter_actor_clear_constraints:
15056  * @self: a #ClutterActor
15057  *
15058  * Clears the list of constraints applied to @self
15059  *
15060  * Since: 1.4
15061  */
15062 void
15063 clutter_actor_clear_constraints (ClutterActor *self)
15064 {
15065   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15066
15067   if (self->priv->constraints == NULL)
15068     return;
15069
15070   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15071
15072   clutter_actor_queue_relayout (self);
15073 }
15074
15075 /**
15076  * clutter_actor_set_clip_to_allocation:
15077  * @self: a #ClutterActor
15078  * @clip_set: %TRUE to apply a clip tracking the allocation
15079  *
15080  * Sets whether @self should be clipped to the same size as its
15081  * allocation
15082  *
15083  * Since: 1.4
15084  */
15085 void
15086 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15087                                       gboolean      clip_set)
15088 {
15089   ClutterActorPrivate *priv;
15090
15091   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15092
15093   clip_set = !!clip_set;
15094
15095   priv = self->priv;
15096
15097   if (priv->clip_to_allocation != clip_set)
15098     {
15099       priv->clip_to_allocation = clip_set;
15100
15101       clutter_actor_queue_redraw (self);
15102
15103       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15104     }
15105 }
15106
15107 /**
15108  * clutter_actor_get_clip_to_allocation:
15109  * @self: a #ClutterActor
15110  *
15111  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15112  *
15113  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15114  *
15115  * Since: 1.4
15116  */
15117 gboolean
15118 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15119 {
15120   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15121
15122   return self->priv->clip_to_allocation;
15123 }
15124
15125 /**
15126  * clutter_actor_add_effect:
15127  * @self: a #ClutterActor
15128  * @effect: a #ClutterEffect
15129  *
15130  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15131  *
15132  * The #ClutterActor will hold a reference on the @effect until either
15133  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15134  * called.
15135  *
15136  * Since: 1.4
15137  */
15138 void
15139 clutter_actor_add_effect (ClutterActor  *self,
15140                           ClutterEffect *effect)
15141 {
15142   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15143   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15144
15145   _clutter_actor_add_effect_internal (self, effect);
15146
15147   clutter_actor_queue_redraw (self);
15148
15149   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15150 }
15151
15152 /**
15153  * clutter_actor_add_effect_with_name:
15154  * @self: a #ClutterActor
15155  * @name: the name to set on the effect
15156  * @effect: a #ClutterEffect
15157  *
15158  * A convenience function for setting the name of a #ClutterEffect
15159  * while adding it to the list of effectss applied to @self
15160  *
15161  * This function is the logical equivalent of:
15162  *
15163  * |[
15164  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15165  *   clutter_actor_add_effect (self, effect);
15166  * ]|
15167  *
15168  * Since: 1.4
15169  */
15170 void
15171 clutter_actor_add_effect_with_name (ClutterActor  *self,
15172                                     const gchar   *name,
15173                                     ClutterEffect *effect)
15174 {
15175   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15176   g_return_if_fail (name != NULL);
15177   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15178
15179   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15180   clutter_actor_add_effect (self, effect);
15181 }
15182
15183 /**
15184  * clutter_actor_remove_effect:
15185  * @self: a #ClutterActor
15186  * @effect: a #ClutterEffect
15187  *
15188  * Removes @effect from the list of effects applied to @self
15189  *
15190  * The reference held by @self on the #ClutterEffect will be released
15191  *
15192  * Since: 1.4
15193  */
15194 void
15195 clutter_actor_remove_effect (ClutterActor  *self,
15196                              ClutterEffect *effect)
15197 {
15198   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15199   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15200
15201   _clutter_actor_remove_effect_internal (self, effect);
15202
15203   clutter_actor_queue_redraw (self);
15204
15205   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15206 }
15207
15208 /**
15209  * clutter_actor_remove_effect_by_name:
15210  * @self: a #ClutterActor
15211  * @name: the name of the effect to remove
15212  *
15213  * Removes the #ClutterEffect with the given name from the list
15214  * of effects applied to @self
15215  *
15216  * Since: 1.4
15217  */
15218 void
15219 clutter_actor_remove_effect_by_name (ClutterActor *self,
15220                                      const gchar  *name)
15221 {
15222   ClutterActorPrivate *priv;
15223   ClutterActorMeta *meta;
15224
15225   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15226   g_return_if_fail (name != NULL);
15227
15228   priv = self->priv;
15229
15230   if (priv->effects == NULL)
15231     return;
15232
15233   meta = _clutter_meta_group_get_meta (priv->effects, name);
15234   if (meta == NULL)
15235     return;
15236
15237   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15238 }
15239
15240 /**
15241  * clutter_actor_get_effects:
15242  * @self: a #ClutterActor
15243  *
15244  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15245  *
15246  * Return value: (transfer container) (element-type Clutter.Effect): a list
15247  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15248  *   list are owned by Clutter and they should not be freed. You should
15249  *   free the returned list using g_list_free() when done
15250  *
15251  * Since: 1.4
15252  */
15253 GList *
15254 clutter_actor_get_effects (ClutterActor *self)
15255 {
15256   ClutterActorPrivate *priv;
15257
15258   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15259
15260   priv = self->priv;
15261
15262   if (priv->effects == NULL)
15263     return NULL;
15264
15265   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15266 }
15267
15268 /**
15269  * clutter_actor_get_effect:
15270  * @self: a #ClutterActor
15271  * @name: the name of the effect to retrieve
15272  *
15273  * Retrieves the #ClutterEffect with the given name in the list
15274  * of effects applied to @self
15275  *
15276  * Return value: (transfer none): a #ClutterEffect for the given
15277  *   name, or %NULL. The returned #ClutterEffect is owned by the
15278  *   actor and it should not be unreferenced directly
15279  *
15280  * Since: 1.4
15281  */
15282 ClutterEffect *
15283 clutter_actor_get_effect (ClutterActor *self,
15284                           const gchar  *name)
15285 {
15286   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15287   g_return_val_if_fail (name != NULL, NULL);
15288
15289   if (self->priv->effects == NULL)
15290     return NULL;
15291
15292   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15293 }
15294
15295 /**
15296  * clutter_actor_clear_effects:
15297  * @self: a #ClutterActor
15298  *
15299  * Clears the list of effects applied to @self
15300  *
15301  * Since: 1.4
15302  */
15303 void
15304 clutter_actor_clear_effects (ClutterActor *self)
15305 {
15306   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15307
15308   if (self->priv->effects == NULL)
15309     return;
15310
15311   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15312
15313   clutter_actor_queue_redraw (self);
15314 }
15315
15316 /**
15317  * clutter_actor_has_key_focus:
15318  * @self: a #ClutterActor
15319  *
15320  * Checks whether @self is the #ClutterActor that has key focus
15321  *
15322  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15323  *
15324  * Since: 1.4
15325  */
15326 gboolean
15327 clutter_actor_has_key_focus (ClutterActor *self)
15328 {
15329   ClutterActor *stage;
15330
15331   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15332
15333   stage = _clutter_actor_get_stage_internal (self);
15334   if (stage == NULL)
15335     return FALSE;
15336
15337   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15338 }
15339
15340 static gboolean
15341 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15342                                       ClutterPaintVolume *pv)
15343 {
15344   ClutterActorPrivate *priv = self->priv;
15345
15346   /* Actors are only expected to report a valid paint volume
15347    * while they have a valid allocation. */
15348   if (G_UNLIKELY (priv->needs_allocation))
15349     {
15350       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15351                     "Actor needs allocation",
15352                     _clutter_actor_get_debug_name (self));
15353       return FALSE;
15354     }
15355
15356   /* Check if there are any handlers connected to the paint
15357    * signal. If there are then all bets are off for what the paint
15358    * volume for this actor might possibly be!
15359    *
15360    * XXX: It's expected that this is going to end up being quite a
15361    * costly check to have to do here, but we haven't come up with
15362    * another solution that can reliably catch paint signal handlers at
15363    * the right time to either avoid artefacts due to invalid stage
15364    * clipping or due to incorrect culling.
15365    *
15366    * Previously we checked in clutter_actor_paint(), but at that time
15367    * we may already be using a stage clip that could be derived from
15368    * an invalid paint-volume. We used to try and handle that by
15369    * queuing a follow up, unclipped, redraw but still the previous
15370    * checking wasn't enough to catch invalid volumes involved in
15371    * culling (considering that containers may derive their volume from
15372    * children that haven't yet been painted)
15373    *
15374    * Longer term, improved solutions could be:
15375    * - Disallow painting in the paint signal, only allow using it
15376    *   for tracking when paints happen. We can add another API that
15377    *   allows monkey patching the paint of arbitrary actors but in a
15378    *   more controlled way and that also supports modifying the
15379    *   paint-volume.
15380    * - If we could be notified somehow when signal handlers are
15381    *   connected we wouldn't have to poll for handlers like this.
15382    */
15383   if (g_signal_has_handler_pending (self,
15384                                     actor_signals[PAINT],
15385                                     0,
15386                                     TRUE))
15387     {
15388       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15389                     "Actor has \"paint\" signal handlers",
15390                     _clutter_actor_get_debug_name (self));
15391       return FALSE;
15392     }
15393
15394   _clutter_paint_volume_init_static (pv, self);
15395
15396   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15397     {
15398       clutter_paint_volume_free (pv);
15399       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15400                     "Actor failed to report a volume",
15401                     _clutter_actor_get_debug_name (self));
15402       return FALSE;
15403     }
15404
15405   /* since effects can modify the paint volume, we allow them to actually
15406    * do this by making get_paint_volume() "context sensitive"
15407    */
15408   if (priv->effects != NULL)
15409     {
15410       if (priv->current_effect != NULL)
15411         {
15412           const GList *effects, *l;
15413
15414           /* if we are being called from within the paint sequence of
15415            * an actor, get the paint volume up to the current effect
15416            */
15417           effects = _clutter_meta_group_peek_metas (priv->effects);
15418           for (l = effects;
15419                l != NULL || (l != NULL && l->data != priv->current_effect);
15420                l = l->next)
15421             {
15422               if (!_clutter_effect_get_paint_volume (l->data, pv))
15423                 {
15424                   clutter_paint_volume_free (pv);
15425                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15426                                 "Effect (%s) failed to report a volume",
15427                                 _clutter_actor_get_debug_name (self),
15428                                 _clutter_actor_meta_get_debug_name (l->data));
15429                   return FALSE;
15430                 }
15431             }
15432         }
15433       else
15434         {
15435           const GList *effects, *l;
15436
15437           /* otherwise, get the cumulative volume */
15438           effects = _clutter_meta_group_peek_metas (priv->effects);
15439           for (l = effects; l != NULL; l = l->next)
15440             if (!_clutter_effect_get_paint_volume (l->data, pv))
15441               {
15442                 clutter_paint_volume_free (pv);
15443                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15444                               "Effect (%s) failed to report a volume",
15445                               _clutter_actor_get_debug_name (self),
15446                               _clutter_actor_meta_get_debug_name (l->data));
15447                 return FALSE;
15448               }
15449         }
15450     }
15451
15452   return TRUE;
15453 }
15454
15455 /* The public clutter_actor_get_paint_volume API returns a const
15456  * pointer since we return a pointer directly to the cached
15457  * PaintVolume associated with the actor and don't want the user to
15458  * inadvertently modify it, but for internal uses we sometimes need
15459  * access to the same PaintVolume but need to apply some book-keeping
15460  * modifications to it so we don't want a const pointer.
15461  */
15462 static ClutterPaintVolume *
15463 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15464 {
15465   ClutterActorPrivate *priv;
15466
15467   priv = self->priv;
15468
15469   if (priv->paint_volume_valid)
15470     clutter_paint_volume_free (&priv->paint_volume);
15471
15472   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15473     {
15474       priv->paint_volume_valid = TRUE;
15475       return &priv->paint_volume;
15476     }
15477   else
15478     {
15479       priv->paint_volume_valid = FALSE;
15480       return NULL;
15481     }
15482 }
15483
15484 /**
15485  * clutter_actor_get_paint_volume:
15486  * @self: a #ClutterActor
15487  *
15488  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15489  * when a paint volume can't be determined.
15490  *
15491  * The paint volume is defined as the 3D space occupied by an actor
15492  * when being painted.
15493  *
15494  * This function will call the <function>get_paint_volume()</function>
15495  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15496  * should not usually care about overriding the default implementation,
15497  * unless they are, for instance: painting outside their allocation, or
15498  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15499  * 3D depth).
15500  *
15501  * <note>2D actors overriding <function>get_paint_volume()</function>
15502  * ensure their volume has a depth of 0. (This will be true so long as
15503  * you don't call clutter_paint_volume_set_depth().)</note>
15504  *
15505  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15506  *   or %NULL if no volume could be determined. The returned pointer
15507  *   is not guaranteed to be valid across multiple frames; if you want
15508  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15509  *
15510  * Since: 1.6
15511  */
15512 const ClutterPaintVolume *
15513 clutter_actor_get_paint_volume (ClutterActor *self)
15514 {
15515   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15516
15517   return _clutter_actor_get_paint_volume_mutable (self);
15518 }
15519
15520 /**
15521  * clutter_actor_get_transformed_paint_volume:
15522  * @self: a #ClutterActor
15523  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15524  *    (or %NULL for the stage)
15525  *
15526  * Retrieves the 3D paint volume of an actor like
15527  * clutter_actor_get_paint_volume() does (Please refer to the
15528  * documentation of clutter_actor_get_paint_volume() for more
15529  * details.) and it additionally transforms the paint volume into the
15530  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15531  * is passed for @relative_to_ancestor)
15532  *
15533  * This can be used by containers that base their paint volume on
15534  * the volume of their children. Such containers can query the
15535  * transformed paint volume of all of its children and union them
15536  * together using clutter_paint_volume_union().
15537  *
15538  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15539  *   or %NULL if no volume could be determined. The returned pointer is
15540  *   not guaranteed to be valid across multiple frames; if you wish to
15541  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15542  *
15543  * Since: 1.6
15544  */
15545 const ClutterPaintVolume *
15546 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15547                                             ClutterActor *relative_to_ancestor)
15548 {
15549   const ClutterPaintVolume *volume;
15550   ClutterActor *stage;
15551   ClutterPaintVolume *transformed_volume;
15552
15553   stage = _clutter_actor_get_stage_internal (self);
15554   if (G_UNLIKELY (stage == NULL))
15555     return NULL;
15556
15557   if (relative_to_ancestor == NULL)
15558     relative_to_ancestor = stage;
15559
15560   volume = clutter_actor_get_paint_volume (self);
15561   if (volume == NULL)
15562     return NULL;
15563
15564   transformed_volume =
15565     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15566
15567   _clutter_paint_volume_copy_static (volume, transformed_volume);
15568
15569   _clutter_paint_volume_transform_relative (transformed_volume,
15570                                             relative_to_ancestor);
15571
15572   return transformed_volume;
15573 }
15574
15575 /**
15576  * clutter_actor_get_paint_box:
15577  * @self: a #ClutterActor
15578  * @box: (out): return location for a #ClutterActorBox
15579  *
15580  * Retrieves the paint volume of the passed #ClutterActor, and
15581  * transforms it into a 2D bounding box in stage coordinates.
15582  *
15583  * This function is useful to determine the on screen area occupied by
15584  * the actor. The box is only an approximation and may often be
15585  * considerably larger due to the optimizations used to calculate the
15586  * box. The box is never smaller though, so it can reliably be used
15587  * for culling.
15588  *
15589  * There are times when a 2D paint box can't be determined, e.g.
15590  * because the actor isn't yet parented under a stage or because
15591  * the actor is unable to determine a paint volume.
15592  *
15593  * Return value: %TRUE if a 2D paint box could be determined, else
15594  * %FALSE.
15595  *
15596  * Since: 1.6
15597  */
15598 gboolean
15599 clutter_actor_get_paint_box (ClutterActor    *self,
15600                              ClutterActorBox *box)
15601 {
15602   ClutterActor *stage;
15603   ClutterPaintVolume *pv;
15604
15605   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15606   g_return_val_if_fail (box != NULL, FALSE);
15607
15608   stage = _clutter_actor_get_stage_internal (self);
15609   if (G_UNLIKELY (!stage))
15610     return FALSE;
15611
15612   pv = _clutter_actor_get_paint_volume_mutable (self);
15613   if (G_UNLIKELY (!pv))
15614     return FALSE;
15615
15616   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15617
15618   return TRUE;
15619 }
15620
15621 /**
15622  * clutter_actor_has_overlaps:
15623  * @self: A #ClutterActor
15624  *
15625  * Asks the actor's implementation whether it may contain overlapping
15626  * primitives.
15627  *
15628  * For example; Clutter may use this to determine whether the painting
15629  * should be redirected to an offscreen buffer to correctly implement
15630  * the opacity property.
15631  *
15632  * Custom actors can override the default response by implementing the
15633  * #ClutterActor <function>has_overlaps</function> virtual function. See
15634  * clutter_actor_set_offscreen_redirect() for more information.
15635  *
15636  * Return value: %TRUE if the actor may have overlapping primitives, and
15637  *   %FALSE otherwise
15638  *
15639  * Since: 1.8
15640  */
15641 gboolean
15642 clutter_actor_has_overlaps (ClutterActor *self)
15643 {
15644   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15645
15646   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15647 }
15648
15649 /**
15650  * clutter_actor_has_effects:
15651  * @self: A #ClutterActor
15652  *
15653  * Returns whether the actor has any effects applied.
15654  *
15655  * Return value: %TRUE if the actor has any effects,
15656  *   %FALSE otherwise
15657  *
15658  * Since: 1.10
15659  */
15660 gboolean
15661 clutter_actor_has_effects (ClutterActor *self)
15662 {
15663   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15664
15665   if (self->priv->effects == NULL)
15666     return FALSE;
15667
15668   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15669 }
15670
15671 /**
15672  * clutter_actor_has_constraints:
15673  * @self: A #ClutterActor
15674  *
15675  * Returns whether the actor has any constraints applied.
15676  *
15677  * Return value: %TRUE if the actor has any constraints,
15678  *   %FALSE otherwise
15679  *
15680  * Since: 1.10
15681  */
15682 gboolean
15683 clutter_actor_has_constraints (ClutterActor *self)
15684 {
15685   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15686
15687   return self->priv->constraints != NULL;
15688 }
15689
15690 /**
15691  * clutter_actor_has_actions:
15692  * @self: A #ClutterActor
15693  *
15694  * Returns whether the actor has any actions applied.
15695  *
15696  * Return value: %TRUE if the actor has any actions,
15697  *   %FALSE otherwise
15698  *
15699  * Since: 1.10
15700  */
15701 gboolean
15702 clutter_actor_has_actions (ClutterActor *self)
15703 {
15704   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15705
15706   return self->priv->actions != NULL;
15707 }
15708
15709 /**
15710  * clutter_actor_get_n_children:
15711  * @self: a #ClutterActor
15712  *
15713  * Retrieves the number of children of @self.
15714  *
15715  * Return value: the number of children of an actor
15716  *
15717  * Since: 1.10
15718  */
15719 gint
15720 clutter_actor_get_n_children (ClutterActor *self)
15721 {
15722   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15723
15724   return self->priv->n_children;
15725 }
15726
15727 /**
15728  * clutter_actor_get_child_at_index:
15729  * @self: a #ClutterActor
15730  * @index_: the position in the list of children
15731  *
15732  * Retrieves the actor at the given @index_ inside the list of
15733  * children of @self.
15734  *
15735  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15736  *
15737  * Since: 1.10
15738  */
15739 ClutterActor *
15740 clutter_actor_get_child_at_index (ClutterActor *self,
15741                                   gint          index_)
15742 {
15743   ClutterActor *iter;
15744   int i;
15745
15746   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15747   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15748
15749   for (iter = self->priv->first_child, i = 0;
15750        iter != NULL && i < index_;
15751        iter = iter->priv->next_sibling, i += 1)
15752     ;
15753
15754   return iter;
15755 }
15756
15757 /*< private >
15758  * _clutter_actor_foreach_child:
15759  * @actor: The actor whos children you want to iterate
15760  * @callback: The function to call for each child
15761  * @user_data: Private data to pass to @callback
15762  *
15763  * Calls a given @callback once for each child of the specified @actor and
15764  * passing the @user_data pointer each time.
15765  *
15766  * Return value: returns %TRUE if all children were iterated, else
15767  *    %FALSE if a callback broke out of iteration early.
15768  */
15769 gboolean
15770 _clutter_actor_foreach_child (ClutterActor           *self,
15771                               ClutterForeachCallback  callback,
15772                               gpointer                user_data)
15773 {
15774   ClutterActorPrivate *priv = self->priv;
15775   ClutterActor *iter;
15776   gboolean cont;
15777
15778   for (cont = TRUE, iter = priv->first_child;
15779        cont && iter != NULL;
15780        iter = iter->priv->next_sibling)
15781     {
15782       cont = callback (iter, user_data);
15783     }
15784
15785   return cont;
15786 }
15787
15788 #if 0
15789 /* For debugging purposes this gives us a simple way to print out
15790  * the scenegraph e.g in gdb using:
15791  * [|
15792  *   _clutter_actor_traverse (stage,
15793  *                            0,
15794  *                            clutter_debug_print_actor_cb,
15795  *                            NULL,
15796  *                            NULL);
15797  * |]
15798  */
15799 static ClutterActorTraverseVisitFlags
15800 clutter_debug_print_actor_cb (ClutterActor *actor,
15801                               int depth,
15802                               void *user_data)
15803 {
15804   g_print ("%*s%s:%p\n",
15805            depth * 2, "",
15806            _clutter_actor_get_debug_name (actor),
15807            actor);
15808
15809   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15810 }
15811 #endif
15812
15813 static void
15814 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15815                                  ClutterTraverseCallback callback,
15816                                  gpointer                user_data)
15817 {
15818   GQueue *queue = g_queue_new ();
15819   ClutterActor dummy;
15820   int current_depth = 0;
15821
15822   g_queue_push_tail (queue, actor);
15823   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15824
15825   while ((actor = g_queue_pop_head (queue)))
15826     {
15827       ClutterActorTraverseVisitFlags flags;
15828
15829       if (actor == &dummy)
15830         {
15831           current_depth++;
15832           g_queue_push_tail (queue, &dummy);
15833           continue;
15834         }
15835
15836       flags = callback (actor, current_depth, user_data);
15837       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15838         break;
15839       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15840         {
15841           ClutterActor *iter;
15842
15843           for (iter = actor->priv->first_child;
15844                iter != NULL;
15845                iter = iter->priv->next_sibling)
15846             {
15847               g_queue_push_tail (queue, iter);
15848             }
15849         }
15850     }
15851
15852   g_queue_free (queue);
15853 }
15854
15855 static ClutterActorTraverseVisitFlags
15856 _clutter_actor_traverse_depth (ClutterActor           *actor,
15857                                ClutterTraverseCallback before_children_callback,
15858                                ClutterTraverseCallback after_children_callback,
15859                                int                     current_depth,
15860                                gpointer                user_data)
15861 {
15862   ClutterActorTraverseVisitFlags flags;
15863
15864   flags = before_children_callback (actor, current_depth, user_data);
15865   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15866     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15867
15868   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15869     {
15870       ClutterActor *iter;
15871
15872       for (iter = actor->priv->first_child;
15873            iter != NULL;
15874            iter = iter->priv->next_sibling)
15875         {
15876           flags = _clutter_actor_traverse_depth (iter,
15877                                                  before_children_callback,
15878                                                  after_children_callback,
15879                                                  current_depth + 1,
15880                                                  user_data);
15881
15882           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15883             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15884         }
15885     }
15886
15887   if (after_children_callback)
15888     return after_children_callback (actor, current_depth, user_data);
15889   else
15890     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15891 }
15892
15893 /* _clutter_actor_traverse:
15894  * @actor: The actor to start traversing the graph from
15895  * @flags: These flags may affect how the traversal is done
15896  * @before_children_callback: A function to call before visiting the
15897  *   children of the current actor.
15898  * @after_children_callback: A function to call after visiting the
15899  *   children of the current actor. (Ignored if
15900  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15901  * @user_data: The private data to pass to the callbacks
15902  *
15903  * Traverses the scenegraph starting at the specified @actor and
15904  * descending through all its children and its children's children.
15905  * For each actor traversed @before_children_callback and
15906  * @after_children_callback are called with the specified
15907  * @user_data, before and after visiting that actor's children.
15908  *
15909  * The callbacks can return flags that affect the ongoing traversal
15910  * such as by skipping over an actors children or bailing out of
15911  * any further traversing.
15912  */
15913 void
15914 _clutter_actor_traverse (ClutterActor              *actor,
15915                          ClutterActorTraverseFlags  flags,
15916                          ClutterTraverseCallback    before_children_callback,
15917                          ClutterTraverseCallback    after_children_callback,
15918                          gpointer                   user_data)
15919 {
15920   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15921     _clutter_actor_traverse_breadth (actor,
15922                                      before_children_callback,
15923                                      user_data);
15924   else /* DEPTH_FIRST */
15925     _clutter_actor_traverse_depth (actor,
15926                                    before_children_callback,
15927                                    after_children_callback,
15928                                    0, /* start depth */
15929                                    user_data);
15930 }
15931
15932 static void
15933 on_layout_manager_changed (ClutterLayoutManager *manager,
15934                            ClutterActor         *self)
15935 {
15936   clutter_actor_queue_relayout (self);
15937 }
15938
15939 /**
15940  * clutter_actor_set_layout_manager:
15941  * @self: a #ClutterActor
15942  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15943  *
15944  * Sets the #ClutterLayoutManager delegate object that will be used to
15945  * lay out the children of @self.
15946  *
15947  * The #ClutterActor will take a reference on the passed @manager which
15948  * will be released either when the layout manager is removed, or when
15949  * the actor is destroyed.
15950  *
15951  * Since: 1.10
15952  */
15953 void
15954 clutter_actor_set_layout_manager (ClutterActor         *self,
15955                                   ClutterLayoutManager *manager)
15956 {
15957   ClutterActorPrivate *priv;
15958
15959   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15960   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15961
15962   priv = self->priv;
15963
15964   if (priv->layout_manager != NULL)
15965     {
15966       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15967                                             G_CALLBACK (on_layout_manager_changed),
15968                                             self);
15969       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15970       g_clear_object (&priv->layout_manager);
15971     }
15972
15973   priv->layout_manager = manager;
15974
15975   if (priv->layout_manager != NULL)
15976     {
15977       g_object_ref_sink (priv->layout_manager);
15978       clutter_layout_manager_set_container (priv->layout_manager,
15979                                             CLUTTER_CONTAINER (self));
15980       g_signal_connect (priv->layout_manager, "layout-changed",
15981                         G_CALLBACK (on_layout_manager_changed),
15982                         self);
15983     }
15984
15985   clutter_actor_queue_relayout (self);
15986
15987   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15988 }
15989
15990 /**
15991  * clutter_actor_get_layout_manager:
15992  * @self: a #ClutterActor
15993  *
15994  * Retrieves the #ClutterLayoutManager used by @self.
15995  *
15996  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15997  *   or %NULL
15998  *
15999  * Since: 1.10
16000  */
16001 ClutterLayoutManager *
16002 clutter_actor_get_layout_manager (ClutterActor *self)
16003 {
16004   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16005
16006   return self->priv->layout_manager;
16007 }
16008
16009 static const ClutterLayoutInfo default_layout_info = {
16010   0.f,                          /* fixed-x */
16011   0.f,                          /* fixed-y */
16012   { 0, 0, 0, 0 },               /* margin */
16013   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16014   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16015   0.f, 0.f,                     /* min_width, natural_width */
16016   0.f, 0.f,                     /* natual_width, natural_height */
16017 };
16018
16019 static void
16020 layout_info_free (gpointer data)
16021 {
16022   if (G_LIKELY (data != NULL))
16023     g_slice_free (ClutterLayoutInfo, data);
16024 }
16025
16026 /*< private >
16027  * _clutter_actor_get_layout_info:
16028  * @self: a #ClutterActor
16029  *
16030  * Retrieves a pointer to the ClutterLayoutInfo structure.
16031  *
16032  * If the actor does not have a ClutterLayoutInfo associated to it, one
16033  * will be created and initialized to the default values.
16034  *
16035  * This function should be used for setters.
16036  *
16037  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16038  * instead.
16039  *
16040  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16041  */
16042 ClutterLayoutInfo *
16043 _clutter_actor_get_layout_info (ClutterActor *self)
16044 {
16045   ClutterLayoutInfo *retval;
16046
16047   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16048   if (retval == NULL)
16049     {
16050       retval = g_slice_new (ClutterLayoutInfo);
16051
16052       *retval = default_layout_info;
16053
16054       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16055                                retval,
16056                                layout_info_free);
16057     }
16058
16059   return retval;
16060 }
16061
16062 /*< private >
16063  * _clutter_actor_get_layout_info_or_defaults:
16064  * @self: a #ClutterActor
16065  *
16066  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16067  *
16068  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16069  * then the default structure will be returned.
16070  *
16071  * This function should only be used for getters.
16072  *
16073  * Return value: a const pointer to the ClutterLayoutInfo structure
16074  */
16075 const ClutterLayoutInfo *
16076 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16077 {
16078   const ClutterLayoutInfo *info;
16079
16080   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16081   if (info == NULL)
16082     return &default_layout_info;
16083
16084   return info;
16085 }
16086
16087 /**
16088  * clutter_actor_set_x_align:
16089  * @self: a #ClutterActor
16090  * @x_align: the horizontal alignment policy
16091  *
16092  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16093  * actor received extra horizontal space.
16094  *
16095  * See also the #ClutterActor:x-align property.
16096  *
16097  * Since: 1.10
16098  */
16099 void
16100 clutter_actor_set_x_align (ClutterActor      *self,
16101                            ClutterActorAlign  x_align)
16102 {
16103   ClutterLayoutInfo *info;
16104
16105   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16106
16107   info = _clutter_actor_get_layout_info (self);
16108
16109   if (info->x_align != x_align)
16110     {
16111       info->x_align = x_align;
16112
16113       clutter_actor_queue_relayout (self);
16114
16115       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16116     }
16117 }
16118
16119 /**
16120  * clutter_actor_get_x_align:
16121  * @self: a #ClutterActor
16122  *
16123  * Retrieves the horizontal alignment policy set using
16124  * clutter_actor_set_x_align().
16125  *
16126  * Return value: the horizontal alignment policy.
16127  *
16128  * Since: 1.10
16129  */
16130 ClutterActorAlign
16131 clutter_actor_get_x_align (ClutterActor *self)
16132 {
16133   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16134
16135   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16136 }
16137
16138 /**
16139  * clutter_actor_set_y_align:
16140  * @self: a #ClutterActor
16141  * @y_align: the vertical alignment policy
16142  *
16143  * Sets the vertical alignment policy of a #ClutterActor, in case the
16144  * actor received extra vertical space.
16145  *
16146  * See also the #ClutterActor:y-align property.
16147  *
16148  * Since: 1.10
16149  */
16150 void
16151 clutter_actor_set_y_align (ClutterActor      *self,
16152                            ClutterActorAlign  y_align)
16153 {
16154   ClutterLayoutInfo *info;
16155
16156   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16157
16158   info = _clutter_actor_get_layout_info (self);
16159
16160   if (info->y_align != y_align)
16161     {
16162       info->y_align = y_align;
16163
16164       clutter_actor_queue_relayout (self);
16165
16166       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16167     }
16168 }
16169
16170 /**
16171  * clutter_actor_get_y_align:
16172  * @self: a #ClutterActor
16173  *
16174  * Retrieves the vertical alignment policy set using
16175  * clutter_actor_set_y_align().
16176  *
16177  * Return value: the vertical alignment policy.
16178  *
16179  * Since: 1.10
16180  */
16181 ClutterActorAlign
16182 clutter_actor_get_y_align (ClutterActor *self)
16183 {
16184   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16185
16186   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16187 }
16188
16189
16190 /**
16191  * clutter_margin_new:
16192  *
16193  * Creates a new #ClutterMargin.
16194  *
16195  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16196  *   clutter_margin_free() to free the resources associated with it when
16197  *   done.
16198  *
16199  * Since: 1.10
16200  */
16201 ClutterMargin *
16202 clutter_margin_new (void)
16203 {
16204   return g_slice_new0 (ClutterMargin);
16205 }
16206
16207 /**
16208  * clutter_margin_copy:
16209  * @margin_: a #ClutterMargin
16210  *
16211  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16212  * the newly created structure.
16213  *
16214  * Return value: (transfer full): a copy of the #ClutterMargin.
16215  *
16216  * Since: 1.10
16217  */
16218 ClutterMargin *
16219 clutter_margin_copy (const ClutterMargin *margin_)
16220 {
16221   if (G_LIKELY (margin_ != NULL))
16222     return g_slice_dup (ClutterMargin, margin_);
16223
16224   return NULL;
16225 }
16226
16227 /**
16228  * clutter_margin_free:
16229  * @margin_: a #ClutterMargin
16230  *
16231  * Frees the resources allocated by clutter_margin_new() and
16232  * clutter_margin_copy().
16233  *
16234  * Since: 1.10
16235  */
16236 void
16237 clutter_margin_free (ClutterMargin *margin_)
16238 {
16239   if (G_LIKELY (margin_ != NULL))
16240     g_slice_free (ClutterMargin, margin_);
16241 }
16242
16243 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16244                      clutter_margin_copy,
16245                      clutter_margin_free)
16246
16247 /**
16248  * clutter_actor_set_margin:
16249  * @self: a #ClutterActor
16250  * @margin: a #ClutterMargin
16251  *
16252  * Sets all the components of the margin of a #ClutterActor.
16253  *
16254  * Since: 1.10
16255  */
16256 void
16257 clutter_actor_set_margin (ClutterActor        *self,
16258                           const ClutterMargin *margin)
16259 {
16260   ClutterLayoutInfo *info;
16261   gboolean changed;
16262   GObject *obj;
16263
16264   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16265   g_return_if_fail (margin != NULL);
16266
16267   obj = G_OBJECT (self);
16268   changed = FALSE;
16269
16270   g_object_freeze_notify (obj);
16271
16272   info = _clutter_actor_get_layout_info (self);
16273
16274   if (info->margin.top != margin->top)
16275     {
16276       info->margin.top = margin->top;
16277       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16278       changed = TRUE;
16279     }
16280
16281   if (info->margin.right != margin->right)
16282     {
16283       info->margin.right = margin->right;
16284       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16285       changed = TRUE;
16286     }
16287
16288   if (info->margin.bottom != margin->bottom)
16289     {
16290       info->margin.bottom = margin->bottom;
16291       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16292       changed = TRUE;
16293     }
16294
16295   if (info->margin.left != margin->left)
16296     {
16297       info->margin.left = margin->left;
16298       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16299       changed = TRUE;
16300     }
16301
16302   if (changed)
16303     clutter_actor_queue_relayout (self);
16304
16305   g_object_thaw_notify (obj);
16306 }
16307
16308 /**
16309  * clutter_actor_get_margin:
16310  * @self: a #ClutterActor
16311  * @margin: (out caller-allocates): return location for a #ClutterMargin
16312  *
16313  * Retrieves all the components of the margin of a #ClutterActor.
16314  *
16315  * Since: 1.10
16316  */
16317 void
16318 clutter_actor_get_margin (ClutterActor  *self,
16319                           ClutterMargin *margin)
16320 {
16321   const ClutterLayoutInfo *info;
16322
16323   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16324   g_return_if_fail (margin != NULL);
16325
16326   info = _clutter_actor_get_layout_info_or_defaults (self);
16327
16328   *margin = info->margin;
16329 }
16330
16331 /**
16332  * clutter_actor_set_margin_top:
16333  * @self: a #ClutterActor
16334  * @margin: the top margin
16335  *
16336  * Sets the margin from the top of a #ClutterActor.
16337  *
16338  * Since: 1.10
16339  */
16340 void
16341 clutter_actor_set_margin_top (ClutterActor *self,
16342                               gfloat        margin)
16343 {
16344   ClutterLayoutInfo *info;
16345
16346   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16347   g_return_if_fail (margin >= 0.f);
16348
16349   info = _clutter_actor_get_layout_info (self);
16350
16351   if (info->margin.top == margin)
16352     return;
16353
16354   info->margin.top = margin;
16355
16356   clutter_actor_queue_relayout (self);
16357
16358   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16359 }
16360
16361 /**
16362  * clutter_actor_get_margin_top:
16363  * @self: a #ClutterActor
16364  *
16365  * Retrieves the top margin of a #ClutterActor.
16366  *
16367  * Return value: the top margin
16368  *
16369  * Since: 1.10
16370  */
16371 gfloat
16372 clutter_actor_get_margin_top (ClutterActor *self)
16373 {
16374   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16375
16376   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16377 }
16378
16379 /**
16380  * clutter_actor_set_margin_bottom:
16381  * @self: a #ClutterActor
16382  * @margin: the bottom margin
16383  *
16384  * Sets the margin from the bottom of a #ClutterActor.
16385  *
16386  * Since: 1.10
16387  */
16388 void
16389 clutter_actor_set_margin_bottom (ClutterActor *self,
16390                                  gfloat        margin)
16391 {
16392   ClutterLayoutInfo *info;
16393
16394   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16395   g_return_if_fail (margin >= 0.f);
16396
16397   info = _clutter_actor_get_layout_info (self);
16398
16399   if (info->margin.bottom == margin)
16400     return;
16401
16402   info->margin.bottom = margin;
16403
16404   clutter_actor_queue_relayout (self);
16405
16406   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16407 }
16408
16409 /**
16410  * clutter_actor_get_margin_bottom:
16411  * @self: a #ClutterActor
16412  *
16413  * Retrieves the bottom margin of a #ClutterActor.
16414  *
16415  * Return value: the bottom margin
16416  *
16417  * Since: 1.10
16418  */
16419 gfloat
16420 clutter_actor_get_margin_bottom (ClutterActor *self)
16421 {
16422   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16423
16424   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16425 }
16426
16427 /**
16428  * clutter_actor_set_margin_left:
16429  * @self: a #ClutterActor
16430  * @margin: the left margin
16431  *
16432  * Sets the margin from the left of a #ClutterActor.
16433  *
16434  * Since: 1.10
16435  */
16436 void
16437 clutter_actor_set_margin_left (ClutterActor *self,
16438                                gfloat        margin)
16439 {
16440   ClutterLayoutInfo *info;
16441
16442   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16443   g_return_if_fail (margin >= 0.f);
16444
16445   info = _clutter_actor_get_layout_info (self);
16446
16447   if (info->margin.left == margin)
16448     return;
16449
16450   info->margin.left = margin;
16451
16452   clutter_actor_queue_relayout (self);
16453
16454   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16455 }
16456
16457 /**
16458  * clutter_actor_get_margin_left:
16459  * @self: a #ClutterActor
16460  *
16461  * Retrieves the left margin of a #ClutterActor.
16462  *
16463  * Return value: the left margin
16464  *
16465  * Since: 1.10
16466  */
16467 gfloat
16468 clutter_actor_get_margin_left (ClutterActor *self)
16469 {
16470   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16471
16472   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16473 }
16474
16475 /**
16476  * clutter_actor_set_margin_right:
16477  * @self: a #ClutterActor
16478  * @margin: the right margin
16479  *
16480  * Sets the margin from the right of a #ClutterActor.
16481  *
16482  * Since: 1.10
16483  */
16484 void
16485 clutter_actor_set_margin_right (ClutterActor *self,
16486                                 gfloat        margin)
16487 {
16488   ClutterLayoutInfo *info;
16489
16490   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16491   g_return_if_fail (margin >= 0.f);
16492
16493   info = _clutter_actor_get_layout_info (self);
16494
16495   if (info->margin.right == margin)
16496     return;
16497
16498   info->margin.right = margin;
16499
16500   clutter_actor_queue_relayout (self);
16501
16502   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16503 }
16504
16505 /**
16506  * clutter_actor_get_margin_right:
16507  * @self: a #ClutterActor
16508  *
16509  * Retrieves the right margin of a #ClutterActor.
16510  *
16511  * Return value: the right margin
16512  *
16513  * Since: 1.10
16514  */
16515 gfloat
16516 clutter_actor_get_margin_right (ClutterActor *self)
16517 {
16518   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16519
16520   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16521 }
16522
16523 static inline void
16524 clutter_actor_set_background_color_internal (ClutterActor *self,
16525                                              const ClutterColor *color)
16526 {
16527   ClutterActorPrivate *priv = self->priv;
16528   GObject *obj;
16529
16530   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16531     return;
16532
16533   obj = G_OBJECT (self);
16534
16535   priv->bg_color = *color;
16536   priv->bg_color_set = TRUE;
16537
16538   clutter_actor_queue_redraw (self);
16539
16540   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16541   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16542 }
16543
16544 /**
16545  * clutter_actor_set_background_color:
16546  * @self: a #ClutterActor
16547  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16548  *  set color
16549  *
16550  * Sets the background color of a #ClutterActor.
16551  *
16552  * The background color will be used to cover the whole allocation of the
16553  * actor. The default background color of an actor is transparent.
16554  *
16555  * To check whether an actor has a background color, you can use the
16556  * #ClutterActor:background-color-set actor property.
16557  *
16558  * The #ClutterActor:background-color property is animatable.
16559  *
16560  * Since: 1.10
16561  */
16562 void
16563 clutter_actor_set_background_color (ClutterActor       *self,
16564                                     const ClutterColor *color)
16565 {
16566   ClutterActorPrivate *priv;
16567   GObject *obj;
16568   GParamSpec *bg_color_pspec;
16569
16570   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16571
16572   obj = G_OBJECT (self);
16573
16574   priv = self->priv;
16575
16576   if (color == NULL)
16577     {
16578       priv->bg_color_set = FALSE;
16579       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16580       clutter_actor_queue_redraw (self);
16581       return;
16582     }
16583
16584   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16585   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16586     {
16587       _clutter_actor_create_transition (self, bg_color_pspec,
16588                                         &priv->bg_color,
16589                                         color);
16590     }
16591   else
16592     _clutter_actor_update_transition (self, bg_color_pspec, color);
16593
16594   clutter_actor_queue_redraw (self);
16595 }
16596
16597 /**
16598  * clutter_actor_get_background_color:
16599  * @self: a #ClutterActor
16600  * @color: (out caller-allocates): return location for a #ClutterColor
16601  *
16602  * Retrieves the color set using clutter_actor_set_background_color().
16603  *
16604  * Since: 1.10
16605  */
16606 void
16607 clutter_actor_get_background_color (ClutterActor *self,
16608                                     ClutterColor *color)
16609 {
16610   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16611   g_return_if_fail (color != NULL);
16612
16613   *color = self->priv->bg_color;
16614 }
16615
16616 /**
16617  * clutter_actor_get_previous_sibling:
16618  * @self: a #ClutterActor
16619  *
16620  * Retrieves the sibling of @self that comes before it in the list
16621  * of children of @self's parent.
16622  *
16623  * The returned pointer is only valid until the scene graph changes; it
16624  * is not safe to modify the list of children of @self while iterating
16625  * it.
16626  *
16627  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16628  *
16629  * Since: 1.10
16630  */
16631 ClutterActor *
16632 clutter_actor_get_previous_sibling (ClutterActor *self)
16633 {
16634   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16635
16636   return self->priv->prev_sibling;
16637 }
16638
16639 /**
16640  * clutter_actor_get_next_sibling:
16641  * @self: a #ClutterActor
16642  *
16643  * Retrieves the sibling of @self that comes after it in the list
16644  * of children of @self's parent.
16645  *
16646  * The returned pointer is only valid until the scene graph changes; it
16647  * is not safe to modify the list of children of @self while iterating
16648  * it.
16649  *
16650  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16651  *
16652  * Since: 1.10
16653  */
16654 ClutterActor *
16655 clutter_actor_get_next_sibling (ClutterActor *self)
16656 {
16657   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16658
16659   return self->priv->next_sibling;
16660 }
16661
16662 /**
16663  * clutter_actor_get_first_child:
16664  * @self: a #ClutterActor
16665  *
16666  * Retrieves the first child of @self.
16667  *
16668  * The returned pointer is only valid until the scene graph changes; it
16669  * is not safe to modify the list of children of @self while iterating
16670  * it.
16671  *
16672  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16673  *
16674  * Since: 1.10
16675  */
16676 ClutterActor *
16677 clutter_actor_get_first_child (ClutterActor *self)
16678 {
16679   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16680
16681   return self->priv->first_child;
16682 }
16683
16684 /**
16685  * clutter_actor_get_last_child:
16686  * @self: a #ClutterActor
16687  *
16688  * Retrieves the last child of @self.
16689  *
16690  * The returned pointer is only valid until the scene graph changes; it
16691  * is not safe to modify the list of children of @self while iterating
16692  * it.
16693  *
16694  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16695  *
16696  * Since: 1.10
16697  */
16698 ClutterActor *
16699 clutter_actor_get_last_child (ClutterActor *self)
16700 {
16701   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16702
16703   return self->priv->last_child;
16704 }
16705
16706 /* easy way to have properly named fields instead of the dummy ones
16707  * we use in the public structure
16708  */
16709 typedef struct _RealActorIter
16710 {
16711   ClutterActor *root;           /* dummy1 */
16712   ClutterActor *current;        /* dummy2 */
16713   gpointer padding_1;           /* dummy3 */
16714   gint age;                     /* dummy4 */
16715   gpointer padding_2;           /* dummy5 */
16716 } RealActorIter;
16717
16718 /**
16719  * clutter_actor_iter_init:
16720  * @iter: a #ClutterActorIter
16721  * @root: a #ClutterActor
16722  *
16723  * Initializes a #ClutterActorIter, which can then be used to iterate
16724  * efficiently over a section of the scene graph, and associates it
16725  * with @root.
16726  *
16727  * Modifying the scene graph section that contains @root will invalidate
16728  * the iterator.
16729  *
16730  * |[
16731  *   ClutterActorIter iter;
16732  *   ClutterActor *child;
16733  *
16734  *   clutter_actor_iter_init (&iter, container);
16735  *   while (clutter_actor_iter_next (&iter, &child))
16736  *     {
16737  *       /&ast; do something with child &ast;/
16738  *     }
16739  * ]|
16740  *
16741  * Since: 1.10
16742  */
16743 void
16744 clutter_actor_iter_init (ClutterActorIter *iter,
16745                          ClutterActor     *root)
16746 {
16747   RealActorIter *ri = (RealActorIter *) iter;
16748
16749   g_return_if_fail (iter != NULL);
16750   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16751
16752   ri->root = root;
16753   ri->current = NULL;
16754   ri->age = root->priv->age;
16755 }
16756
16757 /**
16758  * clutter_actor_iter_next:
16759  * @iter: a #ClutterActorIter
16760  * @child: (out): return location for a #ClutterActor
16761  *
16762  * Advances the @iter and retrieves the next child of the root #ClutterActor
16763  * that was used to initialize the #ClutterActorIterator.
16764  *
16765  * If the iterator can advance, this function returns %TRUE and sets the
16766  * @child argument.
16767  *
16768  * If the iterator cannot advance, this function returns %FALSE, and
16769  * the contents of @child are undefined.
16770  *
16771  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16772  *
16773  * Since: 1.10
16774  */
16775 gboolean
16776 clutter_actor_iter_next (ClutterActorIter  *iter,
16777                          ClutterActor     **child)
16778 {
16779   RealActorIter *ri = (RealActorIter *) iter;
16780
16781   g_return_val_if_fail (iter != NULL, FALSE);
16782   g_return_val_if_fail (ri->root != NULL, FALSE);
16783 #ifndef G_DISABLE_ASSERT
16784   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16785 #endif
16786
16787   if (ri->current == NULL)
16788     ri->current = ri->root->priv->first_child;
16789   else
16790     ri->current = ri->current->priv->next_sibling;
16791
16792   if (child != NULL)
16793     *child = ri->current;
16794
16795   return ri->current != NULL;
16796 }
16797
16798 /**
16799  * clutter_actor_iter_prev:
16800  * @iter: a #ClutterActorIter
16801  * @child: (out): return location for a #ClutterActor
16802  *
16803  * Advances the @iter and retrieves the previous child of the root
16804  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16805  *
16806  * If the iterator can advance, this function returns %TRUE and sets the
16807  * @child argument.
16808  *
16809  * If the iterator cannot advance, this function returns %FALSE, and
16810  * the contents of @child are undefined.
16811  *
16812  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16813  *
16814  * Since: 1.10
16815  */
16816 gboolean
16817 clutter_actor_iter_prev (ClutterActorIter  *iter,
16818                          ClutterActor     **child)
16819 {
16820   RealActorIter *ri = (RealActorIter *) iter;
16821
16822   g_return_val_if_fail (iter != NULL, FALSE);
16823   g_return_val_if_fail (ri->root != NULL, FALSE);
16824 #ifndef G_DISABLE_ASSERT
16825   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16826 #endif
16827
16828   if (ri->current == NULL)
16829     ri->current = ri->root->priv->last_child;
16830   else
16831     ri->current = ri->current->priv->prev_sibling;
16832
16833   if (child != NULL)
16834     *child = ri->current;
16835
16836   return ri->current != NULL;
16837 }
16838
16839 /**
16840  * clutter_actor_iter_remove:
16841  * @iter: a #ClutterActorIter
16842  *
16843  * Safely removes the #ClutterActor currently pointer to by the iterator
16844  * from its parent.
16845  *
16846  * This function can only be called after clutter_actor_iter_next() or
16847  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16848  * than once for the same actor.
16849  *
16850  * This function will call clutter_actor_remove_child() internally.
16851  *
16852  * Since: 1.10
16853  */
16854 void
16855 clutter_actor_iter_remove (ClutterActorIter *iter)
16856 {
16857   RealActorIter *ri = (RealActorIter *) iter;
16858   ClutterActor *cur;
16859
16860   g_return_if_fail (iter != NULL);
16861   g_return_if_fail (ri->root != NULL);
16862 #ifndef G_DISABLE_ASSERT
16863   g_return_if_fail (ri->age == ri->root->priv->age);
16864 #endif
16865   g_return_if_fail (ri->current != NULL);
16866
16867   cur = ri->current;
16868
16869   if (cur != NULL)
16870     {
16871       ri->current = cur->priv->prev_sibling;
16872
16873       clutter_actor_remove_child_internal (ri->root, cur,
16874                                            REMOVE_CHILD_DEFAULT_FLAGS);
16875
16876       ri->age += 1;
16877     }
16878 }
16879
16880 /**
16881  * clutter_actor_iter_destroy:
16882  * @iter: a #ClutterActorIter
16883  *
16884  * Safely destroys the #ClutterActor currently pointer to by the iterator
16885  * from its parent.
16886  *
16887  * This function can only be called after clutter_actor_iter_next() or
16888  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16889  * than once for the same actor.
16890  *
16891  * This function will call clutter_actor_destroy() internally.
16892  *
16893  * Since: 1.10
16894  */
16895 void
16896 clutter_actor_iter_destroy (ClutterActorIter *iter)
16897 {
16898   RealActorIter *ri = (RealActorIter *) iter;
16899   ClutterActor *cur;
16900
16901   g_return_if_fail (iter != NULL);
16902   g_return_if_fail (ri->root != NULL);
16903 #ifndef G_DISABLE_ASSERT
16904   g_return_if_fail (ri->age == ri->root->priv->age);
16905 #endif
16906   g_return_if_fail (ri->current != NULL);
16907
16908   cur = ri->current;
16909
16910   if (cur != NULL)
16911     {
16912       ri->current = cur->priv->prev_sibling;
16913
16914       clutter_actor_destroy (cur);
16915
16916       ri->age += 1;
16917     }
16918 }
16919
16920 static const ClutterAnimationInfo default_animation_info = {
16921   NULL,         /* transitions */
16922   NULL,         /* states */
16923   NULL,         /* cur_state */
16924 };
16925
16926 static void
16927 clutter_animation_info_free (gpointer data)
16928 {
16929   if (data != NULL)
16930     {
16931       ClutterAnimationInfo *info = data;
16932
16933       if (info->transitions != NULL)
16934         g_hash_table_unref (info->transitions);
16935
16936       if (info->states != NULL)
16937         g_array_unref (info->states);
16938
16939       g_slice_free (ClutterAnimationInfo, info);
16940     }
16941 }
16942
16943 const ClutterAnimationInfo *
16944 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16945 {
16946   const ClutterAnimationInfo *res;
16947   GObject *obj = G_OBJECT (self);
16948
16949   res = g_object_get_qdata (obj, quark_actor_animation_info);
16950   if (res != NULL)
16951     return res;
16952
16953   return &default_animation_info;
16954 }
16955
16956 ClutterAnimationInfo *
16957 _clutter_actor_get_animation_info (ClutterActor *self)
16958 {
16959   GObject *obj = G_OBJECT (self);
16960   ClutterAnimationInfo *res;
16961
16962   res = g_object_get_qdata (obj, quark_actor_animation_info);
16963   if (res == NULL)
16964     {
16965       res = g_slice_new (ClutterAnimationInfo);
16966
16967       *res = default_animation_info;
16968
16969       g_object_set_qdata_full (obj, quark_actor_animation_info,
16970                                res,
16971                                clutter_animation_info_free);
16972     }
16973
16974   return res;
16975 }
16976
16977 ClutterTransition *
16978 _clutter_actor_get_transition (ClutterActor *actor,
16979                                GParamSpec   *pspec)
16980 {
16981   const ClutterAnimationInfo *info;
16982
16983   info = _clutter_actor_get_animation_info_or_defaults (actor);
16984
16985   if (info->transitions == NULL)
16986     return NULL;
16987
16988   return g_hash_table_lookup (info->transitions, pspec->name);
16989 }
16990
16991 typedef struct _TransitionClosure
16992 {
16993   ClutterActor *actor;
16994   ClutterTransition *transition;
16995   gchar *name;
16996   gulong completed_id;
16997 } TransitionClosure;
16998
16999 static void
17000 transition_closure_free (gpointer data)
17001 {
17002   if (G_LIKELY (data != NULL))
17003     {
17004       TransitionClosure *clos = data;
17005
17006       if (clutter_timeline_is_playing (CLUTTER_TIMELINE (clos->transition)))
17007         clutter_timeline_stop (CLUTTER_TIMELINE (clos->transition));
17008
17009       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17010
17011       g_object_unref (clos->transition);
17012       g_free (clos->name);
17013
17014       g_slice_free (TransitionClosure, clos);
17015     }
17016 }
17017
17018 static void
17019 on_transition_completed (ClutterTransition *transition,
17020                          TransitionClosure *clos)
17021 {
17022   ClutterActor *actor = clos->actor;
17023   ClutterAnimationInfo *info;
17024
17025   info = _clutter_actor_get_animation_info (actor);
17026
17027   /* this will take care of cleaning clos for us */
17028   if (clutter_transition_get_remove_on_complete (transition))
17029     {
17030       /* we take a reference here because removing the closure
17031        * will release the reference on the transition, and we
17032        * want the transition to survive the signal emission;
17033        * the master clock will release the laste reference at
17034        * the end of the frame processing.
17035        */
17036       g_object_ref (transition);
17037       g_hash_table_remove (info->transitions, clos->name);
17038     }
17039
17040   /* if it's the last transition then we clean up */
17041   if (g_hash_table_size (info->transitions) == 0)
17042     {
17043       g_hash_table_unref (info->transitions);
17044       info->transitions = NULL;
17045
17046       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17047                     _clutter_actor_get_debug_name (actor));
17048
17049       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17050     }
17051 }
17052
17053 void
17054 _clutter_actor_update_transition (ClutterActor *actor,
17055                                   GParamSpec   *pspec,
17056                                   ...)
17057 {
17058   TransitionClosure *clos;
17059   ClutterTimeline *timeline;
17060   ClutterInterval *interval;
17061   const ClutterAnimationInfo *info;
17062   va_list var_args;
17063   GType ptype;
17064   GValue initial = G_VALUE_INIT;
17065   GValue final = G_VALUE_INIT;
17066   char *error = NULL;
17067
17068   info = _clutter_actor_get_animation_info_or_defaults (actor);
17069
17070   if (info->transitions == NULL)
17071     return;
17072
17073   clos = g_hash_table_lookup (info->transitions, pspec->name);
17074   if (clos == NULL)
17075     return;
17076
17077   timeline = CLUTTER_TIMELINE (clos->transition);
17078
17079   va_start (var_args, pspec);
17080
17081   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17082
17083   g_value_init (&initial, ptype);
17084   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17085                                         pspec->name,
17086                                         &initial);
17087
17088   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17089   if (error != NULL)
17090     {
17091       g_critical ("%s: %s", G_STRLOC, error);
17092       g_free (error);
17093       goto out;
17094     }
17095
17096   interval = clutter_transition_get_interval (clos->transition);
17097   clutter_interval_set_initial_value (interval, &initial);
17098   clutter_interval_set_final_value (interval, &final);
17099
17100   /* if we're updating with an easing duration of zero milliseconds,
17101    * we just jump the timeline to the end and let it run its course
17102    */
17103   if (info->cur_state != NULL &&
17104       info->cur_state->easing_duration != 0)
17105     {
17106       guint cur_duration = clutter_timeline_get_duration (timeline);
17107       ClutterAnimationMode cur_mode =
17108         clutter_timeline_get_progress_mode (timeline);
17109
17110       if (cur_duration != info->cur_state->easing_duration)
17111         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17112
17113       if (cur_mode != info->cur_state->easing_mode)
17114         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17115
17116       clutter_timeline_rewind (timeline);
17117     }
17118   else
17119     {
17120       guint duration = clutter_timeline_get_duration (timeline);
17121
17122       clutter_timeline_advance (timeline, duration);
17123     }
17124
17125 out:
17126   g_value_unset (&initial);
17127   g_value_unset (&final);
17128
17129   va_end (var_args);
17130 }
17131
17132 /*< private >*
17133  * _clutter_actor_create_transition:
17134  * @actor: a #ClutterActor
17135  * @pspec: the property used for the transition
17136  * @...: initial and final state
17137  *
17138  * Creates a #ClutterTransition for the property represented by @pspec.
17139  *
17140  * Return value: a #ClutterTransition
17141  */
17142 ClutterTransition *
17143 _clutter_actor_create_transition (ClutterActor *actor,
17144                                   GParamSpec   *pspec,
17145                                   ...)
17146 {
17147   ClutterAnimationInfo *info;
17148   ClutterTransition *res = NULL;
17149   gboolean call_restore = FALSE;
17150   TransitionClosure *clos;
17151   va_list var_args;
17152
17153   info = _clutter_actor_get_animation_info (actor);
17154
17155   /* XXX - this will go away in 2.0
17156    *
17157    * if no state has been pushed, we assume that the easing state is
17158    * in "compatibility mode": all transitions have a duration of 0
17159    * msecs, which means that they happen immediately. in Clutter 2.0
17160    * this will turn into a g_assert(info->states != NULL), as every
17161    * actor will start with a predefined easing state
17162    */
17163   if (info->states == NULL)
17164     {
17165       clutter_actor_save_easing_state (actor);
17166       clutter_actor_set_easing_duration (actor, 0);
17167       call_restore = TRUE;
17168     }
17169
17170   if (info->transitions == NULL)
17171     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17172                                                NULL,
17173                                                transition_closure_free);
17174
17175   va_start (var_args, pspec);
17176
17177   clos = g_hash_table_lookup (info->transitions, pspec->name);
17178   if (clos == NULL)
17179     {
17180       ClutterInterval *interval;
17181       GValue initial = G_VALUE_INIT;
17182       GValue final = G_VALUE_INIT;
17183       GType ptype;
17184       char *error;
17185
17186       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17187
17188       G_VALUE_COLLECT_INIT (&initial, ptype,
17189                             var_args, 0,
17190                             &error);
17191       if (error != NULL)
17192         {
17193           g_critical ("%s: %s", G_STRLOC, error);
17194           g_free (error);
17195           goto out;
17196         }
17197
17198       G_VALUE_COLLECT_INIT (&final, ptype,
17199                             var_args, 0,
17200                             &error);
17201
17202       if (error != NULL)
17203         {
17204           g_critical ("%s: %s", G_STRLOC, error);
17205           g_value_unset (&initial);
17206           g_free (error);
17207           goto out;
17208         }
17209
17210       /* if the current easing state has a duration of 0, then we don't
17211        * bother to create the transition, and we just set the final value
17212        * directly on the actor; we don't go through the Animatable
17213        * interface because we know we got here through an animatable
17214        * property.
17215        */
17216       if (info->cur_state->easing_duration == 0)
17217         {
17218           clutter_actor_set_animatable_property (actor,
17219                                                  pspec->param_id,
17220                                                  &final,
17221                                                  pspec);
17222           g_value_unset (&initial);
17223           g_value_unset (&final);
17224
17225           goto out;
17226         }
17227
17228       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17229
17230       g_value_unset (&initial);
17231       g_value_unset (&final);
17232
17233       res = clutter_property_transition_new (pspec->name);
17234
17235       clutter_transition_set_interval (res, interval);
17236       clutter_transition_set_remove_on_complete (res, TRUE);
17237
17238       /* this will start the transition as well */
17239       clutter_actor_add_transition (actor, pspec->name, res);
17240
17241       /* the actor now owns the transition */
17242       g_object_unref (res);
17243     }
17244   else
17245     res = clos->transition;
17246
17247 out:
17248   if (call_restore)
17249     clutter_actor_restore_easing_state (actor);
17250
17251   va_end (var_args);
17252
17253   return res;
17254 }
17255
17256 /**
17257  * clutter_actor_add_transition:
17258  * @self: a #ClutterActor
17259  * @name: the name of the transition to add
17260  * @transition: the #ClutterTransition to add
17261  *
17262  * Adds a @transition to the #ClutterActor's list of animations.
17263  *
17264  * The @name string is a per-actor unique identifier of the @transition: only
17265  * one #ClutterTransition can be associated to the specified @name.
17266  *
17267  * The @transition will be given the easing duration, mode, and delay
17268  * associated to the actor's current easing state; it is possible to modify
17269  * these values after calling clutter_actor_add_transition().
17270  *
17271  * The @transition will be started once added.
17272  *
17273  * This function will take a reference on the @transition.
17274  *
17275  * This function is usually called implicitly when modifying an animatable
17276  * property.
17277  *
17278  * Since: 1.10
17279  */
17280 void
17281 clutter_actor_add_transition (ClutterActor      *self,
17282                               const char        *name,
17283                               ClutterTransition *transition)
17284 {
17285   ClutterTimeline *timeline;
17286   TransitionClosure *clos;
17287   ClutterAnimationInfo *info;
17288
17289   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17290   g_return_if_fail (name != NULL);
17291   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17292
17293   info = _clutter_actor_get_animation_info (self);
17294
17295   if (info->cur_state == NULL)
17296     {
17297       g_warning ("No easing state is defined for the actor '%s'; you "
17298                  "must call clutter_actor_save_easing_state() before "
17299                  "calling clutter_actor_add_transition().",
17300                  _clutter_actor_get_debug_name (self));
17301       return;
17302     }
17303
17304   if (info->transitions == NULL)
17305     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17306                                                NULL,
17307                                                transition_closure_free);
17308
17309   if (g_hash_table_lookup (info->transitions, name) != NULL)
17310     {
17311       g_warning ("A transition with name '%s' already exists for "
17312                  "the actor '%s'",
17313                  name,
17314                  _clutter_actor_get_debug_name (self));
17315       return;
17316     }
17317
17318   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17319
17320   timeline = CLUTTER_TIMELINE (transition);
17321
17322   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17323   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17324   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17325
17326   clos = g_slice_new (TransitionClosure);
17327   clos->actor = self;
17328   clos->transition = g_object_ref (transition);
17329   clos->name = g_strdup (name);
17330   clos->completed_id = g_signal_connect (timeline, "completed",
17331                                          G_CALLBACK (on_transition_completed),
17332                                          clos);
17333
17334   CLUTTER_NOTE (ANIMATION,
17335                 "Adding transition '%s' [%p] to actor '%s'",
17336                 clos->name,
17337                 clos->transition,
17338                 _clutter_actor_get_debug_name (self));
17339
17340   g_hash_table_insert (info->transitions, clos->name, clos);
17341   clutter_timeline_start (timeline);
17342 }
17343
17344 /**
17345  * clutter_actor_remove_transition:
17346  * @self: a #ClutterActor
17347  * @name: the name of the transition to remove
17348  *
17349  * Removes the transition stored inside a #ClutterActor using @name
17350  * identifier.
17351  *
17352  * If the transition is currently in progress, it will be stopped.
17353  *
17354  * This function releases the reference acquired when the transition
17355  * was added to the #ClutterActor.
17356  *
17357  * Since: 1.10
17358  */
17359 void
17360 clutter_actor_remove_transition (ClutterActor *self,
17361                                  const char   *name)
17362 {
17363   const ClutterAnimationInfo *info;
17364
17365   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17366   g_return_if_fail (name != NULL);
17367
17368   info = _clutter_actor_get_animation_info_or_defaults (self);
17369
17370   if (info->transitions == NULL)
17371     return;
17372
17373   g_hash_table_remove (info->transitions, name);
17374 }
17375
17376 /**
17377  * clutter_actor_remove_all_transitions:
17378  * @self: a #ClutterActor
17379  *
17380  * Removes all transitions associated to @self.
17381  *
17382  * Since: 1.10
17383  */
17384 void
17385 clutter_actor_remove_all_transitions (ClutterActor *self)
17386 {
17387   const ClutterAnimationInfo *info;
17388
17389   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17390
17391   info = _clutter_actor_get_animation_info_or_defaults (self);
17392   if (info->transitions == NULL)
17393     return;
17394
17395   g_hash_table_remove_all (info->transitions);
17396 }
17397
17398 /**
17399  * clutter_actor_set_easing_duration:
17400  * @self: a #ClutterActor
17401  * @msecs: the duration of the easing, or %NULL
17402  *
17403  * Sets the duration of the tweening for animatable properties
17404  * of @self for the current easing state.
17405  *
17406  * Since: 1.10
17407  */
17408 void
17409 clutter_actor_set_easing_duration (ClutterActor *self,
17410                                    guint         msecs)
17411 {
17412   ClutterAnimationInfo *info;
17413
17414   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17415
17416   info = _clutter_actor_get_animation_info (self);
17417
17418   if (info->cur_state == NULL)
17419     {
17420       g_warning ("You must call clutter_actor_save_easing_state() prior "
17421                  "to calling clutter_actor_set_easing_duration().");
17422       return;
17423     }
17424
17425   if (info->cur_state->easing_duration != msecs)
17426     info->cur_state->easing_duration = msecs;
17427 }
17428
17429 /**
17430  * clutter_actor_get_easing_duration:
17431  * @self: a #ClutterActor
17432  *
17433  * Retrieves the duration of the tweening for animatable
17434  * properties of @self for the current easing state.
17435  *
17436  * Return value: the duration of the tweening, in milliseconds
17437  *
17438  * Since: 1.10
17439  */
17440 guint
17441 clutter_actor_get_easing_duration (ClutterActor *self)
17442 {
17443   const ClutterAnimationInfo *info;
17444
17445   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17446
17447   info = _clutter_actor_get_animation_info_or_defaults (self);
17448
17449   if (info->cur_state != NULL)
17450     return info->cur_state->easing_duration;
17451
17452   return 0;
17453 }
17454
17455 /**
17456  * clutter_actor_set_easing_mode:
17457  * @self: a #ClutterActor
17458  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17459  *
17460  * Sets the easing mode for the tweening of animatable properties
17461  * of @self.
17462  *
17463  * Since: 1.10
17464  */
17465 void
17466 clutter_actor_set_easing_mode (ClutterActor         *self,
17467                                ClutterAnimationMode  mode)
17468 {
17469   ClutterAnimationInfo *info;
17470
17471   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17472   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17473   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17474
17475   info = _clutter_actor_get_animation_info (self);
17476
17477   if (info->cur_state == NULL)
17478     {
17479       g_warning ("You must call clutter_actor_save_easing_state() prior "
17480                  "to calling clutter_actor_set_easing_mode().");
17481       return;
17482     }
17483
17484   if (info->cur_state->easing_mode != mode)
17485     info->cur_state->easing_mode = mode;
17486 }
17487
17488 /**
17489  * clutter_actor_get_easing_mode:
17490  * @self: a #ClutterActor
17491  *
17492  * Retrieves the easing mode for the tweening of animatable properties
17493  * of @self for the current easing state.
17494  *
17495  * Return value: an easing mode
17496  *
17497  * Since: 1.10
17498  */
17499 ClutterAnimationMode
17500 clutter_actor_get_easing_mode (ClutterActor *self)
17501 {
17502   const ClutterAnimationInfo *info;
17503
17504   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17505
17506   info = _clutter_actor_get_animation_info_or_defaults (self);
17507
17508   if (info->cur_state != NULL)
17509     return info->cur_state->easing_mode;
17510
17511   return CLUTTER_EASE_OUT_CUBIC;
17512 }
17513
17514 /**
17515  * clutter_actor_set_easing_delay:
17516  * @self: a #ClutterActor
17517  * @msecs: the delay before the start of the tweening, in milliseconds
17518  *
17519  * Sets the delay that should be applied before tweening animatable
17520  * properties.
17521  *
17522  * Since: 1.10
17523  */
17524 void
17525 clutter_actor_set_easing_delay (ClutterActor *self,
17526                                 guint         msecs)
17527 {
17528   ClutterAnimationInfo *info;
17529
17530   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17531
17532   info = _clutter_actor_get_animation_info (self);
17533
17534   if (info->cur_state == NULL)
17535     {
17536       g_warning ("You must call clutter_actor_save_easing_state() prior "
17537                  "to calling clutter_actor_set_easing_delay().");
17538       return;
17539     }
17540
17541   if (info->cur_state->easing_delay != msecs)
17542     info->cur_state->easing_delay = msecs;
17543 }
17544
17545 /**
17546  * clutter_actor_get_easing_delay:
17547  * @self: a #ClutterActor
17548  *
17549  * Retrieves the delay that should be applied when tweening animatable
17550  * properties.
17551  *
17552  * Return value: a delay, in milliseconds
17553  *
17554  * Since: 1.10
17555  */
17556 guint
17557 clutter_actor_get_easing_delay (ClutterActor *self)
17558 {
17559   const ClutterAnimationInfo *info;
17560
17561   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17562
17563   info = _clutter_actor_get_animation_info_or_defaults (self);
17564
17565   if (info->cur_state != NULL)
17566     return info->cur_state->easing_delay;
17567
17568   return 0;
17569 }
17570
17571 /**
17572  * clutter_actor_get_transition:
17573  * @self: a #ClutterActor
17574  * @name: the name of the transition
17575  *
17576  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17577  * transition @name.
17578  *
17579  * Transitions created for animatable properties use the name of the
17580  * property itself, for instance the code below:
17581  *
17582  * |[
17583  *   clutter_actor_set_easing_duration (actor, 1000);
17584  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17585  *
17586  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17587  *   g_signal_connect (transition, "completed",
17588  *                     G_CALLBACK (on_transition_complete),
17589  *                     actor);
17590  * ]|
17591  *
17592  * will call the <function>on_transition_complete</function> callback when
17593  * the transition is complete.
17594  *
17595  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17596  *   was found to match the passed name; the returned instance is owned
17597  *   by Clutter and it should not be freed
17598  *
17599  * Since: 1.10
17600  */
17601 ClutterTransition *
17602 clutter_actor_get_transition (ClutterActor *self,
17603                               const char   *name)
17604 {
17605   TransitionClosure *clos;
17606   const ClutterAnimationInfo *info;
17607
17608   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17609   g_return_val_if_fail (name != NULL, NULL);
17610
17611   info = _clutter_actor_get_animation_info_or_defaults (self);
17612   if (info->transitions == NULL)
17613     return NULL;
17614
17615   clos = g_hash_table_lookup (info->transitions, name);
17616   if (clos == NULL)
17617     return NULL;
17618
17619   return clos->transition;
17620 }
17621
17622 /**
17623  * clutter_actor_save_easing_state:
17624  * @self: a #ClutterActor
17625  *
17626  * Saves the current easing state for animatable properties, and creates
17627  * a new state with the default values for easing mode and duration.
17628  *
17629  * Since: 1.10
17630  */
17631 void
17632 clutter_actor_save_easing_state (ClutterActor *self)
17633 {
17634   ClutterAnimationInfo *info;
17635   AState new_state;
17636
17637   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17638
17639   info = _clutter_actor_get_animation_info (self);
17640
17641   if (info->states == NULL)
17642     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17643
17644   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17645   new_state.easing_duration = 250;
17646   new_state.easing_delay = 0;
17647
17648   g_array_append_val (info->states, new_state);
17649
17650   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17651 }
17652
17653 /**
17654  * clutter_actor_restore_easing_state:
17655  * @self: a #ClutterActor
17656  *
17657  * Restores the easing state as it was prior to a call to
17658  * clutter_actor_save_easing_state().
17659  *
17660  * Since: 1.10
17661  */
17662 void
17663 clutter_actor_restore_easing_state (ClutterActor *self)
17664 {
17665   ClutterAnimationInfo *info;
17666
17667   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17668
17669   info = _clutter_actor_get_animation_info (self);
17670
17671   if (info->states == NULL)
17672     {
17673       g_critical ("The function clutter_actor_restore_easing_state() has "
17674                   "called without a previous call to "
17675                   "clutter_actor_save_easing_state().");
17676       return;
17677     }
17678
17679   g_array_remove_index (info->states, info->states->len - 1);
17680
17681   if (info->states->len > 0)
17682     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17683   else
17684     {
17685       g_array_unref (info->states);
17686       info->states = NULL;
17687       info->cur_state = NULL;
17688     }
17689 }
17690
17691 /**
17692  * clutter_actor_set_content:
17693  * @self: a #ClutterActor
17694  * @content: (allow-none): a #ClutterContent, or %NULL
17695  *
17696  * Sets the contents of a #ClutterActor.
17697  *
17698  * Since: 1.10
17699  */
17700 void
17701 clutter_actor_set_content (ClutterActor   *self,
17702                            ClutterContent *content)
17703 {
17704   ClutterActorPrivate *priv;
17705
17706   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17707   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17708
17709   priv = self->priv;
17710
17711   if (priv->content != NULL)
17712     {
17713       _clutter_content_detached (priv->content, self);
17714       g_clear_object (&priv->content);
17715     }
17716
17717   priv->content = content;
17718
17719   if (priv->content != NULL)
17720     {
17721       g_object_ref (priv->content);
17722       _clutter_content_attached (priv->content, self);
17723     }
17724
17725   /* given that the content is always painted within the allocation,
17726    * we only need to queue a redraw here
17727    */
17728   clutter_actor_queue_redraw (self);
17729
17730   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17731
17732   /* if the content gravity is not resize-fill, and the new content has a
17733    * different preferred size than the previous one, then the content box
17734    * may have been changed. since we compute that lazily, we just notify
17735    * here, and let whomever watches :content-box do whatever they need to
17736    * do.
17737    */
17738   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17739     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17740 }
17741
17742 /**
17743  * clutter_actor_get_content:
17744  * @self: a #ClutterActor
17745  *
17746  * Retrieves the contents of @self.
17747  *
17748  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17749  *   or %NULL if none was set
17750  *
17751  * Since: 1.10
17752  */
17753 ClutterContent *
17754 clutter_actor_get_content (ClutterActor *self)
17755 {
17756   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17757
17758   return self->priv->content;
17759 }
17760
17761 /**
17762  * clutter_actor_set_content_gravity:
17763  * @self: a #ClutterActor
17764  * @gravity: the #ClutterContentGravity
17765  *
17766  * Sets the gravity of the #ClutterContent used by @self.
17767  *
17768  * See the description of the #ClutterActor:content-gravity property for
17769  * more information.
17770  *
17771  * Since: 1.10
17772  */
17773 void
17774 clutter_actor_set_content_gravity (ClutterActor *self,
17775                                    ClutterContentGravity  gravity)
17776 {
17777   ClutterActorPrivate *priv;
17778
17779   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17780
17781   priv = self->priv;
17782
17783   if (priv->content_gravity == gravity)
17784     return;
17785
17786   priv->content_gravity = gravity;
17787
17788   clutter_actor_queue_redraw (self);
17789
17790   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17791   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17792 }
17793
17794 /**
17795  * clutter_actor_get_content_gravity:
17796  * @self: a #ClutterActor
17797  *
17798  * Retrieves the content gravity as set using
17799  * clutter_actor_get_content_gravity().
17800  *
17801  * Return value: the content gravity
17802  *
17803  * Since: 1.10
17804  */
17805 ClutterContentGravity
17806 clutter_actor_get_content_gravity (ClutterActor *self)
17807 {
17808   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17809                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17810
17811   return self->priv->content_gravity;
17812 }
17813
17814 /**
17815  * clutter_actor_get_content_box:
17816  * @self: a #ClutterActor
17817  * @box: (out caller-allocates): the return location for the bounding
17818  *   box for the #ClutterContent
17819  *
17820  * Retrieves the bounding box for the #ClutterContent of @self.
17821  *
17822  * The bounding box is relative to the actor's allocation.
17823  *
17824  * If no #ClutterContent is set for @self, or if @self has not been
17825  * allocated yet, then the result is undefined.
17826  *
17827  * The content box is guaranteed to be, at most, as big as the allocation
17828  * of the #ClutterActor.
17829  *
17830  * If the #ClutterContent used by the actor has a preferred size, then
17831  * it is possible to modify the content box by using the
17832  * #ClutterActor:content-gravity property.
17833  *
17834  * Since: 1.10
17835  */
17836 void
17837 clutter_actor_get_content_box (ClutterActor    *self,
17838                                ClutterActorBox *box)
17839 {
17840   ClutterActorPrivate *priv;
17841   gfloat content_w, content_h;
17842   gfloat alloc_w, alloc_h;
17843
17844   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17845   g_return_if_fail (box != NULL);
17846
17847   priv = self->priv;
17848
17849   box->x1 = 0.f;
17850   box->y1 = 0.f;
17851   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17852   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17853
17854   if (priv->content == NULL)
17855     return;
17856
17857   /* no need to do any more work */
17858   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17859     return;
17860
17861   /* if the content does not have a preferred size then there is
17862    * no point in computing the content box
17863    */
17864   if (!clutter_content_get_preferred_size (priv->content,
17865                                            &content_w,
17866                                            &content_h))
17867     return;
17868
17869   alloc_w = box->x2;
17870   alloc_h = box->y2;
17871
17872   switch (priv->content_gravity)
17873     {
17874     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17875       box->x2 = box->x1 + MIN (content_w, alloc_w);
17876       box->y2 = box->y1 + MIN (content_h, alloc_h);
17877       break;
17878
17879     case CLUTTER_CONTENT_GRAVITY_TOP:
17880       if (alloc_w > content_w)
17881         {
17882           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17883           box->x2 = box->x1 + content_w;
17884         }
17885       box->y2 = box->y1 + MIN (content_h, alloc_h);
17886       break;
17887
17888     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17889       if (alloc_w > content_w)
17890         {
17891           box->x1 += (alloc_w - content_w);
17892           box->x2 = box->x1 + content_w;
17893         }
17894       box->y2 = box->y1 + MIN (content_h, alloc_h);
17895       break;
17896
17897     case CLUTTER_CONTENT_GRAVITY_LEFT:
17898       box->x2 = box->x1 + MIN (content_w, alloc_w);
17899       if (alloc_h > content_h)
17900         {
17901           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17902           box->y2 = box->y1 + content_h;
17903         }
17904       break;
17905
17906     case CLUTTER_CONTENT_GRAVITY_CENTER:
17907       if (alloc_w > content_w)
17908         {
17909           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17910           box->x2 = box->x1 + content_w;
17911         }
17912       if (alloc_h > content_h)
17913         {
17914           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17915           box->y2 = box->y1 + content_h;
17916         }
17917       break;
17918
17919     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17920       if (alloc_w > content_w)
17921         {
17922           box->x1 += (alloc_w - content_w);
17923           box->x2 = box->x1 + content_w;
17924         }
17925       if (alloc_h > content_h)
17926         {
17927           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17928           box->y2 = box->y1 + content_h;
17929         }
17930       break;
17931
17932     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17933       box->x2 = box->x1 + MIN (content_w, alloc_w);
17934       if (alloc_h > content_h)
17935         {
17936           box->y1 += (alloc_h - content_h);
17937           box->y2 = box->y1 + content_h;
17938         }
17939       break;
17940
17941     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17942       if (alloc_w > content_w)
17943         {
17944           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17945           box->x2 = box->x1 + content_w;
17946         }
17947       if (alloc_h > content_h)
17948         {
17949           box->y1 += (alloc_h - content_h);
17950           box->y2 = box->y1 + content_h;
17951         }
17952       break;
17953
17954     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17955       if (alloc_w > content_w)
17956         {
17957           box->x1 += (alloc_w - content_w);
17958           box->x2 = box->x1 + content_w;
17959         }
17960       if (alloc_h > content_h)
17961         {
17962           box->y1 += (alloc_h - content_h);
17963           box->y2 = box->y1 + content_h;
17964         }
17965       break;
17966
17967     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17968       g_assert_not_reached ();
17969       break;
17970
17971     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17972       {
17973         double r_c = content_w / content_h;
17974         double r_a = alloc_w / alloc_h;
17975
17976         if (r_c >= 1.0)
17977           {
17978             if (r_a >= 1.0)
17979               {
17980                 box->x1 = 0.f;
17981                 box->x2 = alloc_w;
17982
17983                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17984                 box->y2 = box->y1 + (alloc_w * r_c);
17985               }
17986             else
17987               {
17988                 box->y1 = 0.f;
17989                 box->y2 = alloc_h;
17990
17991                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17992                 box->x2 = box->x1 + (alloc_h * r_c);
17993               }
17994           }
17995         else
17996           {
17997             if (r_a >= 1.0)
17998               {
17999                 box->y1 = 0.f;
18000                 box->y2 = alloc_h;
18001
18002                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18003                 box->x2 = box->x1 + (alloc_h * r_c);
18004               }
18005             else
18006               {
18007                 box->x1 = 0.f;
18008                 box->x2 = alloc_w;
18009
18010                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18011                 box->y2 = box->y1 + (alloc_w * r_c);
18012               }
18013           }
18014       }
18015       break;
18016     }
18017 }
18018
18019 /**
18020  * clutter_actor_set_content_scaling_filters:
18021  * @self: a #ClutterActor
18022  * @min_filter: the minification filter for the content
18023  * @mag_filter: the magnification filter for the content
18024  *
18025  * Sets the minification and magnification filter to be applied when
18026  * scaling the #ClutterActor:content of a #ClutterActor.
18027  *
18028  * The #ClutterActor:minification-filter will be used when reducing
18029  * the size of the content; the #ClutterActor:magnification-filter
18030  * will be used when increasing the size of the content.
18031  *
18032  * Since: 1.10
18033  */
18034 void
18035 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18036                                            ClutterScalingFilter  min_filter,
18037                                            ClutterScalingFilter  mag_filter)
18038 {
18039   ClutterActorPrivate *priv;
18040   gboolean changed;
18041   GObject *obj;
18042
18043   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18044
18045   priv = self->priv;
18046   obj = G_OBJECT (self);
18047
18048   g_object_freeze_notify (obj);
18049
18050   changed = FALSE;
18051
18052   if (priv->min_filter != min_filter)
18053     {
18054       priv->min_filter = min_filter;
18055       changed = TRUE;
18056
18057       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18058     }
18059
18060   if (priv->mag_filter != mag_filter)
18061     {
18062       priv->mag_filter = mag_filter;
18063       changed = TRUE;
18064
18065       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18066     }
18067
18068   if (changed)
18069     clutter_actor_queue_redraw (self);
18070
18071   g_object_thaw_notify (obj);
18072 }
18073
18074 /**
18075  * clutter_actor_get_content_scaling_filters:
18076  * @self: a #ClutterActor
18077  * @min_filter: (out) (allow-none): return location for the minification
18078  *   filter, or %NULL
18079  * @mag_filter: (out) (allow-none): return location for the magnification
18080  *   filter, or %NULL
18081  *
18082  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18083  *
18084  * Since: 1.10
18085  */
18086 void
18087 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18088                                            ClutterScalingFilter *min_filter,
18089                                            ClutterScalingFilter *mag_filter)
18090 {
18091   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18092
18093   if (min_filter != NULL)
18094     *min_filter = self->priv->min_filter;
18095
18096   if (mag_filter != NULL)
18097     *mag_filter = self->priv->mag_filter;
18098 }