4 * An OpenGL based 'interactive canvas' library.
6 * Authored By Matthew Allum <mallum@openedhand.com>
8 * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9 * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
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.
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.
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/>.
26 * SECTION:clutter-actor
27 * @short_description: The basic element of the scene graph
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
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>
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>
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>
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 ();
77 * /* set the bounding box of the actor */
78 * clutter_actor_set_position (actor, 0, 0);
79 * clutter_actor_set_size (actor, 480, 640);
81 * /* set the background color of the actor */
82 * clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
84 * /* set the bounding box of the child, relative to the parent */
85 * ClutterActor *child = clutter_actor_new ();
86 * clutter_actor_set_position (child, 20, 20);
87 * clutter_actor_set_size (child, 80, 240);
89 * /* set the background color of the child */
90 * clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
92 * /* add the child to the actor */
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
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>
111 * </programlisting></informalexample>
112 * <figure id="actor-example-image">
113 * <title>Actors</title>
114 * <graphic fileref="actor-example.png" format="PNG"/>
118 * <refsect2 id="ClutterActor-painting">
119 * <title>Painting an actor</title>
120 * <para>There are three ways to paint an actor:</para>
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>
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 ();
139 * /* set the bounding box */
140 * clutter_actor_set_position (actor, 50, 50);
141 * clutter_actor_set_size (actor, 100, 100);
143 * /* set the content; the image_content variable is set elsewhere */
144 * clutter_actor_set_content (actor, image_content);
145 * </programlisting></informalexample>
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>
159 * my_actor_paint_node (ClutterActor *actor,
160 * ClutterPaintNode *root)
162 * ClutterPaintNode *node;
163 * ClutterActorBox box;
165 * /* where the content of the actor should be painted */
166 * clutter_actor_get_allocation_box (actor, &box);
168 * /* the cogl_texture variable is set elsewhere */
169 * node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170 * CLUTTER_SCALING_FILTER_TRILINEAR,
171 * CLUTTER_SCALING_FILTER_LINEAR);
173 * /* paint the content of the node using the allocation */
174 * clutter_paint_node_add_rectangle (node, &box);
176 * /* add the node, and transfer ownership */
177 * clutter_paint_node_add_child (root, node);
178 * clutter_paint_node_unref (node);
180 * </programlisting></informalexample>
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>
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>
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>
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 * /* assume that the actor is currently positioned at (100, 100) */
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 * /* animate the actor's opacity and depth */
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);
251 * /* animate another actor's opacity */
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
266 * <informalexample><programlisting>
267 * clutter_actor_save_easing_state (actor);
268 * clutter_actor_set_x (actor, 200);
269 * clutter_actor_restore_easing_state (actor);
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
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>
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;
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_from (transition, G_TYPE_UINT, 255);
297 * clutter_transition_set_to (transition, G_TYPE_UINT, 0);
299 * clutter_actor_add_transition (actor, "animate-opacity", transition);
300 * </programlisting></informalexample>
301 * <para>The example above will animate the #ClutterActor:opacity property
302 * of an actor between fully opaque and fully transparent, and back, over
303 * a span of 3 seconds. The animation does not begin until it is added to
305 * <para>The explicit animation API should also be used when using custom
306 * animatable properties for #ClutterAction, #ClutterConstraint, and
307 * #ClutterEffect instances associated to an actor; see the section on
308 * <ulink linkend="ClutterActor-custom-animatable-properties">custom
309 * animatable properties below</ulink> for an example.</para>
310 * <para>Finally, explicit animations are useful for creating animations
311 * that run continuously, for instance:</para>
312 * <informalexample><programlisting>
313 * /* this animation will pulse the actor's opacity continuously */
314 * ClutterTransition *transition;
315 * ClutterInterval *interval;
317 * transition = clutter_property_transition_new ("opacity");
319 * /* we want to animate the opacity between 0 and 255 */
320 * clutter_transition_set_from (transition, G_TYPE_UINT, 0);
321 * clutter_transition_set_to (transition, G_TYPE_UINT, 255);
323 * /* over a one second duration, running an infinite amount of times */
324 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
325 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
327 * /* we want to fade in and out, so we need to auto-reverse the transition */
328 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
330 * /* and we want to use an easing function that eases both in and out */
331 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
332 * CLUTTER_EASE_IN_OUT_CUBIC);
334 * /* add the transition to the desired actor; this will
335 * * start the animation.
337 * clutter_actor_add_transition (actor, "opacityAnimation", transition);
338 * </programlisting></informalexample>
342 * <refsect2 id="ClutterActor-subclassing">
343 * <title>Implementing an actor</title>
344 * <para>Careful consideration should be given when deciding to implement
345 * a #ClutterActor sub-class. It is generally recommended to implement a
346 * sub-class of #ClutterActor only for actors that should be used as leaf
347 * nodes of a scene graph.</para>
348 * <para>If your actor should be painted in a custom way, you should
349 * override the #ClutterActor::paint signal class handler. You can either
350 * opt to chain up to the parent class implementation or decide to fully
351 * override the default paint implementation; Clutter will set up the
352 * transformations and clip regions prior to emitting the #ClutterActor::paint
354 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
355 * #ClutterActorClass.get_preferred_height() virtual functions it is
356 * possible to change or provide the preferred size of an actor; similarly,
357 * by overriding the #ClutterActorClass.allocate() virtual function it is
358 * possible to control the layout of the children of an actor. Make sure to
359 * always chain up to the parent implementation of the
360 * #ClutterActorClass.allocate() virtual function.</para>
361 * <para>In general, it is strongly encouraged to use delegation and
362 * composition instead of direct subclassing.</para>
365 * <refsect2 id="ClutterActor-script">
366 * <title>ClutterActor custom properties for #ClutterScript</title>
367 * <para>#ClutterActor defines a custom "rotation" property which
368 * allows a short-hand description of the rotations to be applied
369 * to an actor.</para>
370 * <para>The syntax of the "rotation" property is the following:</para>
374 * { "<axis>" : [ <angle>, [ <center> ] ] }
378 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
379 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
380 * floating point value representing the rotation angle on the given axis,
382 * <para>The <emphasis>center</emphasis> array is optional, and if present
383 * it must contain the center of rotation as described by two coordinates:
384 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
386 * <para>#ClutterActor will also parse every positional and dimensional
387 * property defined as a string through clutter_units_from_string(); you
388 * should read the documentation for the #ClutterUnits parser format for
389 * the valid units and syntax.</para>
392 * <refsect2 id="ClutterActor-custom-animatable-properties">
393 * <title>Custom animatable properties</title>
394 * <para>#ClutterActor allows accessing properties of #ClutterAction,
395 * #ClutterEffect, and #ClutterConstraint instances associated to an actor
396 * instance for animation purposes.</para>
397 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
398 * property it is necessary to set the #ClutterActorMeta:name property on the
399 * given action or constraint.</para>
400 * <para>The property can be accessed using the following syntax:</para>
403 * @<section>.<meta-name>.<property-name>
406 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
407 * <para>The <emphasis>section</emphasis> fragment can be one between
408 * "actions", "constraints" and "effects".</para>
409 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
410 * action or constraint, as specified by the #ClutterActorMeta:name
412 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
413 * action or constraint property to be animated.</para>
414 * <para>The example below animates a #ClutterBindConstraint applied to an
415 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
416 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
417 * its initial state is overlapping the actor to which is bound to.</para>
418 * <informalexample><programlisting>
419 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
420 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
421 * clutter_actor_add_constraint (rect, constraint);
423 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
424 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
425 * clutter_actor_add_constraint (rect, constraint);
427 * clutter_actor_set_reactive (origin, TRUE);
429 * g_signal_connect (origin, "button-press-event",
430 * G_CALLBACK (on_button_press),
432 * </programlisting></informalexample>
433 * <para>On button press, the rectangle "slides" from behind the actor to
434 * which is bound to, using the #ClutterBindConstraint:offset property to
435 * achieve the effect:</para>
436 * <informalexample><programlisting>
438 * on_button_press (ClutterActor *origin,
439 * ClutterEvent *event,
440 * ClutterActor *rect)
442 * ClutterTransition *transition;
443 * ClutterInterval *interval;
445 * /* the offset that we want to apply; this will make the actor
446 * * slide in from behind the origin and rest at the right of
447 * * the origin, plus a padding value.
449 * float new_offset = clutter_actor_get_width (origin) + h_padding;
451 * /* the property we wish to animate; the "@constraints" section
452 * * tells Clutter to check inside the constraints associated
453 * * with the actor; the "bind-x" section is the name of the
454 * * constraint; and the "offset" is the name of the property
455 * * on the constraint.
457 * const char *prop = "@constraints.bind-x.offset";
459 * /* create a new transition for the given property */
460 * transition = clutter_property_transition_new (prop);
462 * /* set the easing mode and duration */
463 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
464 * CLUTTER_EASE_OUT_CUBIC);
465 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
467 * /* create the interval with the initial and final values */
468 * interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
469 * clutter_transition_set_interval (transition, interval);
471 * /* add the transition to the actor; this causes the animation
472 * * to start. the name "offsetAnimation" can be used to retrieve
473 * * the transition later.
475 * clutter_actor_add_transition (rect, "offsetAnimation", transition);
477 * /* we handled the event */
478 * return CLUTTER_EVENT_STOP;
480 * </programlisting></informalexample>
485 * CLUTTER_ACTOR_IS_MAPPED:
486 * @a: a #ClutterActor
488 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
490 * The mapped state is set when the actor is visible and all its parents up
491 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
493 * This check can be used to see if an actor is going to be painted, as only
494 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
496 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
497 * not be checked directly; instead, the recommended usage is to connect a
498 * handler on the #GObject::notify signal for the #ClutterActor:mapped
499 * property of #ClutterActor, and check the presence of
500 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
502 * It is also important to note that Clutter may delay the changes of
503 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
504 * limitations, or during the reparenting of an actor, to optimize
505 * unnecessary (and potentially expensive) state changes.
511 * CLUTTER_ACTOR_IS_REALIZED:
512 * @a: a #ClutterActor
514 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
516 * The realized state has an actor-dependant interpretation. If an
517 * actor wants to delay allocating resources until it is attached to a
518 * stage, it may use the realize state to do so. However it is
519 * perfectly acceptable for an actor to allocate Cogl resources before
520 * being realized because there is only one drawing context used by Clutter
521 * so any resources will work on any stage. If an actor is mapped it
522 * must also be realized, but an actor can be realized and unmapped
523 * (this is so hiding an actor temporarily doesn't do an expensive
524 * unrealize/realize).
526 * To be realized an actor must be inside a stage, and all its parents
533 * CLUTTER_ACTOR_IS_VISIBLE:
534 * @a: a #ClutterActor
536 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
537 * Equivalent to the ClutterActor::visible object property.
539 * Note that an actor is only painted onscreen if it's mapped, which
540 * means it's visible, and all its parents are visible, and one of the
541 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
547 * CLUTTER_ACTOR_IS_REACTIVE:
548 * @a: a #ClutterActor
550 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
552 * Only reactive actors will receive event-related signals.
563 #include <gobject/gvaluecollector.h>
565 #include <cogl/cogl.h>
567 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
568 #define CLUTTER_ENABLE_EXPERIMENTAL_API
570 #include "clutter-actor-private.h"
572 #include "clutter-action.h"
573 #include "clutter-actor-meta-private.h"
574 #include "clutter-animatable.h"
575 #include "clutter-color-static.h"
576 #include "clutter-color.h"
577 #include "clutter-constraint.h"
578 #include "clutter-container.h"
579 #include "clutter-content-private.h"
580 #include "clutter-debug.h"
581 #include "clutter-effect-private.h"
582 #include "clutter-enum-types.h"
583 #include "clutter-fixed-layout.h"
584 #include "clutter-flatten-effect.h"
585 #include "clutter-interval.h"
586 #include "clutter-main.h"
587 #include "clutter-marshal.h"
588 #include "clutter-paint-nodes.h"
589 #include "clutter-paint-node-private.h"
590 #include "clutter-paint-volume-private.h"
591 #include "clutter-private.h"
592 #include "clutter-profile.h"
593 #include "clutter-property-transition.h"
594 #include "clutter-scriptable.h"
595 #include "clutter-script-private.h"
596 #include "clutter-stage-private.h"
597 #include "clutter-timeline.h"
598 #include "clutter-transition.h"
599 #include "clutter-units.h"
601 #include "deprecated/clutter-actor.h"
602 #include "deprecated/clutter-behaviour.h"
603 #include "deprecated/clutter-container.h"
605 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
606 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
608 /* Internal enum used to control mapped state update. This is a hint
609 * which indicates when to do something other than just enforce
613 MAP_STATE_CHECK, /* just enforce invariants. */
614 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
615 * used when about to unparent.
617 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
618 * used to set mapped on toplevels.
620 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
621 * used just before unmapping parent.
625 /* 3 entries should be a good compromise, few layout managers
626 * will ask for 3 different preferred size in each allocation cycle */
627 #define N_CACHED_SIZE_REQUESTS 3
629 struct _ClutterActorPrivate
632 ClutterRequestMode request_mode;
634 /* our cached size requests for different width / height */
635 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
636 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
638 /* An age of 0 means the entry is not set */
639 guint cached_height_age;
640 guint cached_width_age;
642 /* the bounding box of the actor, relative to the parent's
645 ClutterActorBox allocation;
646 ClutterAllocationFlags allocation_flags;
648 /* clip, in actor coordinates */
649 cairo_rectangle_t clip;
651 /* the cached transformation matrix; see apply_transform() */
652 CoglMatrix transform;
655 gint opacity_override;
657 ClutterOffscreenRedirect offscreen_redirect;
659 /* This is an internal effect used to implement the
660 offscreen-redirect property */
661 ClutterEffect *flatten_effect;
664 ClutterActor *parent;
665 ClutterActor *prev_sibling;
666 ClutterActor *next_sibling;
667 ClutterActor *first_child;
668 ClutterActor *last_child;
672 /* tracks whenever the children of an actor are changed; the
673 * age is incremented by 1 whenever an actor is added or
674 * removed. the age is not incremented when the first or the
675 * last child pointers are changed, or when grandchildren of
676 * an actor are changed.
680 gchar *name; /* a non-unique name, used for debugging */
681 guint32 id; /* unique id, used for backward compatibility */
683 gint32 pick_id; /* per-stage unique id, used for picking */
685 /* a back-pointer to the Pango context that we can use
686 * to create pre-configured PangoLayout
688 PangoContext *pango_context;
690 /* the text direction configured for this child - either by
691 * application code, or by the actor's parent
693 ClutterTextDirection text_direction;
695 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
699 ClutterMetaGroup *actions;
700 ClutterMetaGroup *constraints;
701 ClutterMetaGroup *effects;
703 /* delegate object used to allocate the children of this actor */
704 ClutterLayoutManager *layout_manager;
706 /* delegate object used to paint the contents of this actor */
707 ClutterContent *content;
709 ClutterActorBox content_box;
710 ClutterContentGravity content_gravity;
711 ClutterScalingFilter min_filter;
712 ClutterScalingFilter mag_filter;
714 /* used when painting, to update the paint volume */
715 ClutterEffect *current_effect;
717 /* This is used to store an effect which needs to be redrawn. A
718 redraw can be queued to start from a particular effect. This is
719 used by parametrised effects that can cache an image of the
720 actor. If a parameter of the effect changes then it only needs to
721 redraw the cached image, not the actual actor. The pointer is
722 only valid if is_dirty == TRUE. If the pointer is NULL then the
723 whole actor is dirty. */
724 ClutterEffect *effect_to_redraw;
726 /* This is used when painting effects to implement the
727 clutter_actor_continue_paint() function. It points to the node in
728 the list of effects that is next in the chain */
729 const GList *next_effect_to_paint;
731 ClutterPaintVolume paint_volume;
733 /* NB: This volume isn't relative to this actor, it is in eye
734 * coordinates so that it can remain valid after the actor changes.
736 ClutterPaintVolume last_paint_volume;
738 ClutterStageQueueRedrawEntry *queue_redraw_entry;
740 ClutterColor bg_color;
744 /* fixed position and sizes */
745 guint position_set : 1;
746 guint min_width_set : 1;
747 guint min_height_set : 1;
748 guint natural_width_set : 1;
749 guint natural_height_set : 1;
750 /* cached request is invalid (implies allocation is too) */
751 guint needs_width_request : 1;
752 /* cached request is invalid (implies allocation is too) */
753 guint needs_height_request : 1;
754 /* cached allocation is invalid (request has changed, probably) */
755 guint needs_allocation : 1;
756 guint show_on_set_parent : 1;
758 guint clip_to_allocation : 1;
759 guint enable_model_view_transform : 1;
760 guint enable_paint_unmapped : 1;
761 guint has_pointer : 1;
762 guint propagated_one_redraw : 1;
763 guint paint_volume_valid : 1;
764 guint last_paint_volume_valid : 1;
765 guint in_clone_paint : 1;
766 guint transform_valid : 1;
767 /* This is TRUE if anything has queued a redraw since we were last
768 painted. In this case effect_to_redraw will point to an effect
769 the redraw was queued from or it will be NULL if the redraw was
770 queued without an effect. */
772 guint bg_color_set : 1;
773 guint content_box_valid : 1;
774 guint x_expand_set : 1;
775 guint y_expand_set : 1;
776 guint needs_compute_expand : 1;
777 guint needs_x_expand : 1;
778 guint needs_y_expand : 1;
787 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
788 * when set they force a size request, when gotten they
789 * get the allocation if the allocation is valid, and the
800 /* Then the rest of these size-related properties are the "actual"
801 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
806 PROP_FIXED_POSITION_SET,
815 PROP_NATURAL_WIDTH_SET,
818 PROP_NATURAL_HEIGHT_SET,
822 /* Allocation properties are read-only */
829 PROP_CLIP_TO_ALLOCATION,
833 PROP_OFFSCREEN_REDIRECT,
846 PROP_ROTATION_ANGLE_X,
847 PROP_ROTATION_ANGLE_Y,
848 PROP_ROTATION_ANGLE_Z,
849 PROP_ROTATION_CENTER_X,
850 PROP_ROTATION_CENTER_Y,
851 PROP_ROTATION_CENTER_Z,
852 /* This property only makes sense for the z rotation because the
853 others would depend on the actor having a size along the
855 PROP_ROTATION_CENTER_Z_GRAVITY,
861 PROP_SHOW_ON_SET_PARENT,
881 PROP_BACKGROUND_COLOR,
882 PROP_BACKGROUND_COLOR_SET,
888 PROP_CONTENT_GRAVITY,
890 PROP_MINIFICATION_FILTER,
891 PROP_MAGNIFICATION_FILTER,
896 static GParamSpec *obj_props[PROP_LAST];
915 BUTTON_RELEASE_EVENT,
923 TRANSITIONS_COMPLETED,
928 static guint actor_signals[LAST_SIGNAL] = { 0, };
930 static void clutter_container_iface_init (ClutterContainerIface *iface);
931 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
932 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
933 static void atk_implementor_iface_init (AtkImplementorIface *iface);
935 /* These setters are all static for now, maybe they should be in the
936 * public API, but they are perhaps obscure enough to leave only as
939 static void clutter_actor_set_min_width (ClutterActor *self,
941 static void clutter_actor_set_min_height (ClutterActor *self,
943 static void clutter_actor_set_natural_width (ClutterActor *self,
944 gfloat natural_width);
945 static void clutter_actor_set_natural_height (ClutterActor *self,
946 gfloat natural_height);
947 static void clutter_actor_set_min_width_set (ClutterActor *self,
948 gboolean use_min_width);
949 static void clutter_actor_set_min_height_set (ClutterActor *self,
950 gboolean use_min_height);
951 static void clutter_actor_set_natural_width_set (ClutterActor *self,
952 gboolean use_natural_width);
953 static void clutter_actor_set_natural_height_set (ClutterActor *self,
954 gboolean use_natural_height);
955 static void clutter_actor_update_map_state (ClutterActor *self,
956 MapStateChange change);
957 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
959 /* Helper routines for managing anchor coords */
960 static void clutter_anchor_coord_get_units (ClutterActor *self,
961 const AnchorCoord *coord,
965 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
970 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
971 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
972 ClutterGravity gravity);
974 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
976 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
978 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
979 ClutterActor *ancestor,
982 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
984 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
986 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
987 const ClutterColor *color);
989 static void on_layout_manager_changed (ClutterLayoutManager *manager,
992 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
994 /* Helper macro which translates by the anchor coord, applies the
995 given transformation and then translates back */
996 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
997 gfloat _tx, _ty, _tz; \
998 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
999 cogl_matrix_translate ((m), _tx, _ty, _tz); \
1001 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
1003 static GQuark quark_shader_data = 0;
1004 static GQuark quark_actor_layout_info = 0;
1005 static GQuark quark_actor_transform_info = 0;
1006 static GQuark quark_actor_animation_info = 0;
1008 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1010 G_TYPE_INITIALLY_UNOWNED,
1011 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1012 clutter_container_iface_init)
1013 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1014 clutter_scriptable_iface_init)
1015 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1016 clutter_animatable_iface_init)
1017 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1018 atk_implementor_iface_init));
1021 * clutter_actor_get_debug_name:
1022 * @actor: a #ClutterActor
1024 * Retrieves a printable name of @actor for debugging messages
1026 * Return value: a string with a printable name
1029 _clutter_actor_get_debug_name (ClutterActor *actor)
1031 return actor->priv->name != NULL ? actor->priv->name
1032 : G_OBJECT_TYPE_NAME (actor);
1035 #ifdef CLUTTER_ENABLE_DEBUG
1036 /* XXX - this is for debugging only, remove once working (or leave
1037 * in only in some debug mode). Should leave it for a little while
1038 * until we're confident in the new map/realize/visible handling.
1041 clutter_actor_verify_map_state (ClutterActor *self)
1043 ClutterActorPrivate *priv = self->priv;
1045 if (CLUTTER_ACTOR_IS_REALIZED (self))
1047 /* all bets are off during reparent when we're potentially realized,
1048 * but should not be according to invariants
1050 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1052 if (priv->parent == NULL)
1054 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1058 g_warning ("Realized non-toplevel actor '%s' should "
1060 _clutter_actor_get_debug_name (self));
1062 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1064 g_warning ("Realized actor %s has an unrealized parent %s",
1065 _clutter_actor_get_debug_name (self),
1066 _clutter_actor_get_debug_name (priv->parent));
1071 if (CLUTTER_ACTOR_IS_MAPPED (self))
1073 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1074 g_warning ("Actor '%s' is mapped but not realized",
1075 _clutter_actor_get_debug_name (self));
1077 /* remaining bets are off during reparent when we're potentially
1078 * mapped, but should not be according to invariants
1080 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1082 if (priv->parent == NULL)
1084 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1086 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1087 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1089 g_warning ("Toplevel actor '%s' is mapped "
1091 _clutter_actor_get_debug_name (self));
1096 g_warning ("Mapped actor '%s' should have a parent",
1097 _clutter_actor_get_debug_name (self));
1102 ClutterActor *iter = self;
1104 /* check for the enable_paint_unmapped flag on the actor
1105 * and parents; if the flag is enabled at any point of this
1106 * branch of the scene graph then all the later checks
1109 while (iter != NULL)
1111 if (iter->priv->enable_paint_unmapped)
1114 iter = iter->priv->parent;
1117 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1119 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1121 _clutter_actor_get_debug_name (self),
1122 _clutter_actor_get_debug_name (priv->parent));
1125 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1127 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1129 _clutter_actor_get_debug_name (self),
1130 _clutter_actor_get_debug_name (priv->parent));
1133 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1135 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1136 g_warning ("Actor '%s' is mapped but its non-toplevel "
1137 "parent '%s' is not mapped",
1138 _clutter_actor_get_debug_name (self),
1139 _clutter_actor_get_debug_name (priv->parent));
1146 #endif /* CLUTTER_ENABLE_DEBUG */
1149 clutter_actor_set_mapped (ClutterActor *self,
1152 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1157 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1158 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1162 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1163 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1167 /* this function updates the mapped and realized states according to
1168 * invariants, in the appropriate order.
1171 clutter_actor_update_map_state (ClutterActor *self,
1172 MapStateChange change)
1174 gboolean was_mapped;
1176 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1178 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1180 /* the mapped flag on top-level actors must be set by the
1181 * per-backend implementation because it might be asynchronous.
1183 * That is, the MAPPED flag on toplevels currently tracks the X
1184 * server mapped-ness of the window, while the expected behavior
1185 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1186 * This creates some weird complexity by breaking the invariant
1187 * that if we're visible and all ancestors shown then we are
1188 * also mapped - instead, we are mapped if all ancestors
1189 * _possibly excepting_ the stage are mapped. The stage
1190 * will map/unmap for example when it is minimized or
1191 * moved to another workspace.
1193 * So, the only invariant on the stage is that if visible it
1194 * should be realized, and that it has to be visible to be
1197 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1198 clutter_actor_realize (self);
1202 case MAP_STATE_CHECK:
1205 case MAP_STATE_MAKE_MAPPED:
1206 g_assert (!was_mapped);
1207 clutter_actor_set_mapped (self, TRUE);
1210 case MAP_STATE_MAKE_UNMAPPED:
1211 g_assert (was_mapped);
1212 clutter_actor_set_mapped (self, FALSE);
1215 case MAP_STATE_MAKE_UNREALIZED:
1216 /* we only use MAKE_UNREALIZED in unparent,
1217 * and unparenting a stage isn't possible.
1218 * If someone wants to just unrealize a stage
1219 * then clutter_actor_unrealize() doesn't
1220 * go through this codepath.
1222 g_warning ("Trying to force unrealize stage is not allowed");
1226 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1227 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1228 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1230 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1231 "it is somehow still mapped",
1232 _clutter_actor_get_debug_name (self));
1237 ClutterActorPrivate *priv = self->priv;
1238 ClutterActor *parent = priv->parent;
1239 gboolean should_be_mapped;
1240 gboolean may_be_realized;
1241 gboolean must_be_realized;
1243 should_be_mapped = FALSE;
1244 may_be_realized = TRUE;
1245 must_be_realized = FALSE;
1247 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1249 may_be_realized = FALSE;
1253 /* Maintain invariant that if parent is mapped, and we are
1254 * visible, then we are mapped ... unless parent is a
1255 * stage, in which case we map regardless of parent's map
1256 * state but do require stage to be visible and realized.
1258 * If parent is realized, that does not force us to be
1259 * realized; but if parent is unrealized, that does force
1260 * us to be unrealized.
1262 * The reason we don't force children to realize with
1263 * parents is _clutter_actor_rerealize(); if we require that
1264 * a realized parent means children are realized, then to
1265 * unrealize an actor we would have to unrealize its
1266 * parents, which would end up meaning unrealizing and
1267 * hiding the entire stage. So we allow unrealizing a
1268 * child (as long as that child is not mapped) while that
1269 * child still has a realized parent.
1271 * Also, if we unrealize from leaf nodes to root, and
1272 * realize from root to leaf, the invariants are never
1273 * violated if we allow children to be unrealized
1274 * while parents are realized.
1276 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1277 * to force us to unmap, even though parent is still
1278 * mapped. This is because we're unmapping from leaf nodes
1281 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1282 change != MAP_STATE_MAKE_UNMAPPED)
1284 gboolean parent_is_visible_realized_toplevel;
1286 parent_is_visible_realized_toplevel =
1287 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1288 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1289 CLUTTER_ACTOR_IS_REALIZED (parent));
1291 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1292 parent_is_visible_realized_toplevel)
1294 must_be_realized = TRUE;
1295 should_be_mapped = TRUE;
1299 /* if the actor has been set to be painted even if unmapped
1300 * then we should map it and check for realization as well;
1301 * this is an override for the branch of the scene graph
1302 * which begins with this node
1304 if (priv->enable_paint_unmapped)
1306 if (priv->parent == NULL)
1307 g_warning ("Attempting to map an unparented actor '%s'",
1308 _clutter_actor_get_debug_name (self));
1310 should_be_mapped = TRUE;
1311 must_be_realized = TRUE;
1314 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1315 may_be_realized = FALSE;
1318 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1321 g_warning ("Attempting to map a child that does not "
1322 "meet the necessary invariants: the actor '%s' "
1324 _clutter_actor_get_debug_name (self));
1326 g_warning ("Attempting to map a child that does not "
1327 "meet the necessary invariants: the actor '%s' "
1328 "is parented to an unmapped actor '%s'",
1329 _clutter_actor_get_debug_name (self),
1330 _clutter_actor_get_debug_name (priv->parent));
1333 /* If in reparent, we temporarily suspend unmap and unrealize.
1335 * We want to go in the order "realize, map" and "unmap, unrealize"
1339 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1340 clutter_actor_set_mapped (self, FALSE);
1343 if (must_be_realized)
1344 clutter_actor_realize (self);
1346 /* if we must be realized then we may be, presumably */
1347 g_assert (!(must_be_realized && !may_be_realized));
1350 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1351 clutter_actor_unrealize_not_hiding (self);
1354 if (should_be_mapped)
1356 if (!must_be_realized)
1357 g_warning ("Somehow we think actor '%s' should be mapped but "
1358 "not realized, which isn't allowed",
1359 _clutter_actor_get_debug_name (self));
1361 /* realization is allowed to fail (though I don't know what
1362 * an app is supposed to do about that - shouldn't it just
1363 * be a g_error? anyway, we have to avoid mapping if this
1366 if (CLUTTER_ACTOR_IS_REALIZED (self))
1367 clutter_actor_set_mapped (self, TRUE);
1371 #ifdef CLUTTER_ENABLE_DEBUG
1372 /* check all invariants were kept */
1373 clutter_actor_verify_map_state (self);
1378 clutter_actor_real_map (ClutterActor *self)
1380 ClutterActorPrivate *priv = self->priv;
1381 ClutterActor *stage, *iter;
1383 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1385 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1386 _clutter_actor_get_debug_name (self));
1388 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1390 stage = _clutter_actor_get_stage_internal (self);
1391 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1393 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1395 _clutter_actor_get_debug_name (self));
1397 /* notify on parent mapped before potentially mapping
1398 * children, so apps see a top-down notification.
1400 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1402 for (iter = self->priv->first_child;
1404 iter = iter->priv->next_sibling)
1406 clutter_actor_map (iter);
1411 * clutter_actor_map:
1412 * @self: A #ClutterActor
1414 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1415 * and realizes its children if they are visible. Does nothing if the
1416 * actor is not visible.
1418 * Calling this function is strongly disencouraged: the default
1419 * implementation of #ClutterActorClass.map() will map all the children
1420 * of an actor when mapping its parent.
1422 * When overriding map, it is mandatory to chain up to the parent
1428 clutter_actor_map (ClutterActor *self)
1430 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1432 if (CLUTTER_ACTOR_IS_MAPPED (self))
1435 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1438 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1442 clutter_actor_real_unmap (ClutterActor *self)
1444 ClutterActorPrivate *priv = self->priv;
1447 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1449 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1450 _clutter_actor_get_debug_name (self));
1452 for (iter = self->priv->first_child;
1454 iter = iter->priv->next_sibling)
1456 clutter_actor_unmap (iter);
1459 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1461 /* clear the contents of the last paint volume, so that hiding + moving +
1462 * showing will not result in the wrong area being repainted
1464 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1465 priv->last_paint_volume_valid = TRUE;
1467 /* notify on parent mapped after potentially unmapping
1468 * children, so apps see a bottom-up notification.
1470 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1472 /* relinquish keyboard focus if we were unmapped while owning it */
1473 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1475 ClutterStage *stage;
1477 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1480 _clutter_stage_release_pick_id (stage, priv->pick_id);
1484 if (stage != NULL &&
1485 clutter_stage_get_key_focus (stage) == self)
1487 clutter_stage_set_key_focus (stage, NULL);
1493 * clutter_actor_unmap:
1494 * @self: A #ClutterActor
1496 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1497 * unmaps its children if they were mapped.
1499 * Calling this function is not encouraged: the default #ClutterActor
1500 * implementation of #ClutterActorClass.unmap() will also unmap any
1501 * eventual children by default when their parent is unmapped.
1503 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1504 * chain up to the parent implementation.
1506 * <note>It is important to note that the implementation of the
1507 * #ClutterActorClass.unmap() virtual function may be called after
1508 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1509 * implementation, but it is guaranteed to be called before the
1510 * #GObjectClass.finalize() implementation.</note>
1515 clutter_actor_unmap (ClutterActor *self)
1517 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1519 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1522 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1526 clutter_actor_real_show (ClutterActor *self)
1528 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1530 ClutterActorPrivate *priv = self->priv;
1532 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1534 /* we notify on the "visible" flag in the clutter_actor_show()
1535 * wrapper so the entire show signal emission completes first
1538 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1540 /* we queue a relayout unless the actor is inside a
1541 * container that explicitly told us not to
1543 if (priv->parent != NULL &&
1544 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1546 /* While an actor is hidden the parent may not have
1547 * allocated/requested so we need to start from scratch
1548 * and avoid the short-circuiting in
1549 * clutter_actor_queue_relayout().
1551 priv->needs_width_request = FALSE;
1552 priv->needs_height_request = FALSE;
1553 priv->needs_allocation = FALSE;
1554 clutter_actor_queue_relayout (self);
1560 set_show_on_set_parent (ClutterActor *self,
1563 ClutterActorPrivate *priv = self->priv;
1565 set_show = !!set_show;
1567 if (priv->show_on_set_parent == set_show)
1570 if (priv->parent == NULL)
1572 priv->show_on_set_parent = set_show;
1573 g_object_notify_by_pspec (G_OBJECT (self),
1574 obj_props[PROP_SHOW_ON_SET_PARENT]);
1579 * clutter_actor_show:
1580 * @self: A #ClutterActor
1582 * Flags an actor to be displayed. An actor that isn't shown will not
1583 * be rendered on the stage.
1585 * Actors are visible by default.
1587 * If this function is called on an actor without a parent, the
1588 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1592 clutter_actor_show (ClutterActor *self)
1594 ClutterActorPrivate *priv;
1596 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1598 /* simple optimization */
1599 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1601 /* we still need to set the :show-on-set-parent property, in
1602 * case show() is called on an unparented actor
1604 set_show_on_set_parent (self, TRUE);
1608 #ifdef CLUTTER_ENABLE_DEBUG
1609 clutter_actor_verify_map_state (self);
1614 g_object_freeze_notify (G_OBJECT (self));
1616 set_show_on_set_parent (self, TRUE);
1618 /* if we're showing a child that needs to expand, or may
1619 * expand, then we need to recompute the expand flags for
1620 * its parent as well
1622 if (priv->needs_compute_expand ||
1623 priv->needs_x_expand ||
1624 priv->needs_y_expand)
1626 clutter_actor_queue_compute_expand (self);
1629 g_signal_emit (self, actor_signals[SHOW], 0);
1630 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1632 if (priv->parent != NULL)
1633 clutter_actor_queue_redraw (priv->parent);
1635 g_object_thaw_notify (G_OBJECT (self));
1639 * clutter_actor_show_all:
1640 * @self: a #ClutterActor
1642 * Calls clutter_actor_show() on all children of an actor (if any).
1646 * Deprecated: 1.10: Actors are visible by default
1649 clutter_actor_show_all (ClutterActor *self)
1651 ClutterActorClass *klass;
1653 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1655 klass = CLUTTER_ACTOR_GET_CLASS (self);
1656 if (klass->show_all)
1657 klass->show_all (self);
1661 clutter_actor_real_hide (ClutterActor *self)
1663 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1665 ClutterActorPrivate *priv = self->priv;
1667 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1669 /* we notify on the "visible" flag in the clutter_actor_hide()
1670 * wrapper so the entire hide signal emission completes first
1673 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1675 /* we queue a relayout unless the actor is inside a
1676 * container that explicitly told us not to
1678 if (priv->parent != NULL &&
1679 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1680 clutter_actor_queue_relayout (priv->parent);
1685 * clutter_actor_hide:
1686 * @self: A #ClutterActor
1688 * Flags an actor to be hidden. A hidden actor will not be
1689 * rendered on the stage.
1691 * Actors are visible by default.
1693 * If this function is called on an actor without a parent, the
1694 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1698 clutter_actor_hide (ClutterActor *self)
1700 ClutterActorPrivate *priv;
1702 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1704 /* simple optimization */
1705 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1707 /* we still need to set the :show-on-set-parent property, in
1708 * case hide() is called on an unparented actor
1710 set_show_on_set_parent (self, FALSE);
1714 #ifdef CLUTTER_ENABLE_DEBUG
1715 clutter_actor_verify_map_state (self);
1720 g_object_freeze_notify (G_OBJECT (self));
1722 set_show_on_set_parent (self, FALSE);
1724 /* if we're hiding a child that needs to expand, or may
1725 * expand, then we need to recompute the expand flags for
1726 * its parent as well
1728 if (priv->needs_compute_expand ||
1729 priv->needs_x_expand ||
1730 priv->needs_y_expand)
1732 clutter_actor_queue_compute_expand (self);
1735 g_signal_emit (self, actor_signals[HIDE], 0);
1736 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1738 if (priv->parent != NULL)
1739 clutter_actor_queue_redraw (priv->parent);
1741 g_object_thaw_notify (G_OBJECT (self));
1745 * clutter_actor_hide_all:
1746 * @self: a #ClutterActor
1748 * Calls clutter_actor_hide() on all child actors (if any).
1752 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1753 * prevent its children from being painted as well.
1756 clutter_actor_hide_all (ClutterActor *self)
1758 ClutterActorClass *klass;
1760 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1762 klass = CLUTTER_ACTOR_GET_CLASS (self);
1763 if (klass->hide_all)
1764 klass->hide_all (self);
1768 * clutter_actor_realize:
1769 * @self: A #ClutterActor
1771 * Realization informs the actor that it is attached to a stage. It
1772 * can use this to allocate resources if it wanted to delay allocation
1773 * until it would be rendered. However it is perfectly acceptable for
1774 * an actor to create resources before being realized because Clutter
1775 * only ever has a single rendering context so that actor is free to
1776 * be moved from one stage to another.
1778 * This function does nothing if the actor is already realized.
1780 * Because a realized actor must have realized parent actors, calling
1781 * clutter_actor_realize() will also realize all parents of the actor.
1783 * This function does not realize child actors, except in the special
1784 * case that realizing the stage, when the stage is visible, will
1785 * suddenly map (and thus realize) the children of the stage.
1788 clutter_actor_realize (ClutterActor *self)
1790 ClutterActorPrivate *priv;
1792 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1796 #ifdef CLUTTER_ENABLE_DEBUG
1797 clutter_actor_verify_map_state (self);
1800 if (CLUTTER_ACTOR_IS_REALIZED (self))
1803 /* To be realized, our parent actors must be realized first.
1804 * This will only succeed if we're inside a toplevel.
1806 if (priv->parent != NULL)
1807 clutter_actor_realize (priv->parent);
1809 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1811 /* toplevels can be realized at any time */
1815 /* "Fail" the realization if parent is missing or unrealized;
1816 * this should really be a g_warning() not some kind of runtime
1817 * failure; how can an app possibly recover? Instead it's a bug
1818 * in the app and the app should get an explanatory warning so
1819 * someone can fix it. But for now it's too hard to fix this
1820 * because e.g. ClutterTexture needs reworking.
1822 if (priv->parent == NULL ||
1823 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1827 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1829 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1830 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1832 g_signal_emit (self, actor_signals[REALIZE], 0);
1834 /* Stage actor is allowed to unset the realized flag again in its
1835 * default signal handler, though that is a pathological situation.
1838 /* If realization "failed" we'll have to update child state. */
1839 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1843 clutter_actor_real_unrealize (ClutterActor *self)
1845 /* we must be unmapped (implying our children are also unmapped) */
1846 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1850 * clutter_actor_unrealize:
1851 * @self: A #ClutterActor
1853 * Unrealization informs the actor that it may be being destroyed or
1854 * moved to another stage. The actor may want to destroy any
1855 * underlying graphics resources at this point. However it is
1856 * perfectly acceptable for it to retain the resources until the actor
1857 * is destroyed because Clutter only ever uses a single rendering
1858 * context and all of the graphics resources are valid on any stage.
1860 * Because mapped actors must be realized, actors may not be
1861 * unrealized if they are mapped. This function hides the actor to be
1862 * sure it isn't mapped, an application-visible side effect that you
1863 * may not be expecting.
1865 * This function should not be called by application code.
1868 clutter_actor_unrealize (ClutterActor *self)
1870 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1871 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1873 /* This function should not really be in the public API, because
1874 * there isn't a good reason to call it. ClutterActor will already
1875 * unrealize things for you when it's important to do so.
1877 * If you were using clutter_actor_unrealize() in a dispose
1878 * implementation, then don't, just chain up to ClutterActor's
1881 * If you were using clutter_actor_unrealize() to implement
1882 * unrealizing children of your container, then don't, ClutterActor
1883 * will already take care of that.
1885 * If you were using clutter_actor_unrealize() to re-realize to
1886 * create your resources in a different way, then use
1887 * _clutter_actor_rerealize() (inside Clutter) or just call your
1888 * code that recreates your resources directly (outside Clutter).
1891 #ifdef CLUTTER_ENABLE_DEBUG
1892 clutter_actor_verify_map_state (self);
1895 clutter_actor_hide (self);
1897 clutter_actor_unrealize_not_hiding (self);
1900 static ClutterActorTraverseVisitFlags
1901 unrealize_actor_before_children_cb (ClutterActor *self,
1905 /* If an actor is already unrealized we know its children have also
1906 * already been unrealized... */
1907 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1908 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1910 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1912 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1915 static ClutterActorTraverseVisitFlags
1916 unrealize_actor_after_children_cb (ClutterActor *self,
1920 /* We want to unset the realized flag only _after_
1921 * child actors are unrealized, to maintain invariants.
1923 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1924 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1925 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1929 * clutter_actor_unrealize_not_hiding:
1930 * @self: A #ClutterActor
1932 * Unrealization informs the actor that it may be being destroyed or
1933 * moved to another stage. The actor may want to destroy any
1934 * underlying graphics resources at this point. However it is
1935 * perfectly acceptable for it to retain the resources until the actor
1936 * is destroyed because Clutter only ever uses a single rendering
1937 * context and all of the graphics resources are valid on any stage.
1939 * Because mapped actors must be realized, actors may not be
1940 * unrealized if they are mapped. You must hide the actor or one of
1941 * its parents before attempting to unrealize.
1943 * This function is separate from clutter_actor_unrealize() because it
1944 * does not automatically hide the actor.
1945 * Actors need not be hidden to be unrealized, they just need to
1946 * be unmapped. In fact we don't want to mess up the application's
1947 * setting of the "visible" flag, so hiding is very undesirable.
1949 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1950 * backward compatibility.
1953 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1955 _clutter_actor_traverse (self,
1956 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1957 unrealize_actor_before_children_cb,
1958 unrealize_actor_after_children_cb,
1963 * _clutter_actor_rerealize:
1964 * @self: A #ClutterActor
1965 * @callback: Function to call while unrealized
1966 * @data: data for callback
1968 * If an actor is already unrealized, this just calls the callback.
1970 * If it is realized, it unrealizes temporarily, calls the callback,
1971 * and then re-realizes the actor.
1973 * As a side effect, leaves all children of the actor unrealized if
1974 * the actor was realized but not showing. This is because when we
1975 * unrealize the actor temporarily we must unrealize its children
1976 * (e.g. children of a stage can't be realized if stage window is
1977 * gone). And we aren't clever enough to save the realization state of
1978 * all children. In most cases this should not matter, because
1979 * the children will automatically realize when they next become mapped.
1982 _clutter_actor_rerealize (ClutterActor *self,
1983 ClutterCallback callback,
1986 gboolean was_mapped;
1987 gboolean was_showing;
1988 gboolean was_realized;
1990 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1992 #ifdef CLUTTER_ENABLE_DEBUG
1993 clutter_actor_verify_map_state (self);
1996 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1997 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1998 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
2000 /* Must be unmapped to unrealize. Note we only have to hide this
2001 * actor if it was mapped (if all parents were showing). If actor
2002 * is merely visible (but not mapped), then that's fine, we can
2006 clutter_actor_hide (self);
2008 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2010 /* unrealize self and all children */
2011 clutter_actor_unrealize_not_hiding (self);
2013 if (callback != NULL)
2015 (* callback) (self, data);
2019 clutter_actor_show (self); /* will realize only if mapping implies it */
2020 else if (was_realized)
2021 clutter_actor_realize (self); /* realize self and all parents */
2025 clutter_actor_real_pick (ClutterActor *self,
2026 const ClutterColor *color)
2028 /* the default implementation is just to paint a rectangle
2029 * with the same size of the actor using the passed color
2031 if (clutter_actor_should_pick_paint (self))
2033 ClutterActorBox box = { 0, };
2034 float width, height;
2036 clutter_actor_get_allocation_box (self, &box);
2038 width = box.x2 - box.x1;
2039 height = box.y2 - box.y1;
2041 cogl_set_source_color4ub (color->red,
2046 cogl_rectangle (0, 0, width, height);
2049 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2050 * with existing container classes that override the pick() virtual
2051 * and chain up to the default implementation - otherwise we'll end up
2052 * painting our children twice.
2054 * this has to go away for 2.0; hopefully along the pick() itself.
2056 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2060 for (iter = self->priv->first_child;
2062 iter = iter->priv->next_sibling)
2063 clutter_actor_paint (iter);
2068 * clutter_actor_should_pick_paint:
2069 * @self: A #ClutterActor
2071 * Should be called inside the implementation of the
2072 * #ClutterActor::pick virtual function in order to check whether
2073 * the actor should paint itself in pick mode or not.
2075 * This function should never be called directly by applications.
2077 * Return value: %TRUE if the actor should paint its silhouette,
2081 clutter_actor_should_pick_paint (ClutterActor *self)
2083 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2085 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2086 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2087 CLUTTER_ACTOR_IS_REACTIVE (self)))
2094 clutter_actor_real_get_preferred_width (ClutterActor *self,
2096 gfloat *min_width_p,
2097 gfloat *natural_width_p)
2099 ClutterActorPrivate *priv = self->priv;
2101 if (priv->n_children != 0 &&
2102 priv->layout_manager != NULL)
2104 ClutterContainer *container = CLUTTER_CONTAINER (self);
2106 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2107 "for the preferred width",
2108 G_OBJECT_TYPE_NAME (priv->layout_manager),
2109 priv->layout_manager);
2111 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2120 /* Default implementation is always 0x0, usually an actor
2121 * using this default is relying on someone to set the
2124 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2129 if (natural_width_p)
2130 *natural_width_p = 0;
2134 clutter_actor_real_get_preferred_height (ClutterActor *self,
2136 gfloat *min_height_p,
2137 gfloat *natural_height_p)
2139 ClutterActorPrivate *priv = self->priv;
2141 if (priv->n_children != 0 &&
2142 priv->layout_manager != NULL)
2144 ClutterContainer *container = CLUTTER_CONTAINER (self);
2146 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2147 "for the preferred height",
2148 G_OBJECT_TYPE_NAME (priv->layout_manager),
2149 priv->layout_manager);
2151 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2159 /* Default implementation is always 0x0, usually an actor
2160 * using this default is relying on someone to set the
2163 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2168 if (natural_height_p)
2169 *natural_height_p = 0;
2173 clutter_actor_store_old_geometry (ClutterActor *self,
2174 ClutterActorBox *box)
2176 *box = self->priv->allocation;
2180 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2181 const ClutterActorBox *old)
2183 ClutterActorPrivate *priv = self->priv;
2184 GObject *obj = G_OBJECT (self);
2186 g_object_freeze_notify (obj);
2188 /* to avoid excessive requisition or allocation cycles we
2189 * use the cached values.
2191 * - if we don't have an allocation we assume that we need
2193 * - if we don't have a width or a height request we notify
2195 * - if we have a valid allocation then we check the old
2196 * bounding box with the current allocation and we notify
2199 if (priv->needs_allocation)
2201 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2202 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2203 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2204 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2205 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2206 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2208 else if (priv->needs_width_request || priv->needs_height_request)
2210 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2211 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2212 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2217 gfloat width, height;
2219 x = priv->allocation.x1;
2220 y = priv->allocation.y1;
2221 width = priv->allocation.x2 - priv->allocation.x1;
2222 height = priv->allocation.y2 - priv->allocation.y1;
2226 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2227 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2232 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2233 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2236 if (width != (old->x2 - old->x1))
2238 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2239 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2242 if (height != (old->y2 - old->y1))
2244 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2245 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2249 g_object_thaw_notify (obj);
2253 * clutter_actor_set_allocation_internal:
2254 * @self: a #ClutterActor
2255 * @box: a #ClutterActorBox
2256 * @flags: allocation flags
2258 * Stores the allocation of @self.
2260 * This function only performs basic storage and property notification.
2262 * This function should be called by clutter_actor_set_allocation()
2263 * and by the default implementation of #ClutterActorClass.allocate().
2265 * Return value: %TRUE if the allocation of the #ClutterActor has been
2266 * changed, and %FALSE otherwise
2268 static inline gboolean
2269 clutter_actor_set_allocation_internal (ClutterActor *self,
2270 const ClutterActorBox *box,
2271 ClutterAllocationFlags flags)
2273 ClutterActorPrivate *priv = self->priv;
2275 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2276 gboolean flags_changed;
2278 ClutterActorBox old_alloc = { 0, };
2280 obj = G_OBJECT (self);
2282 g_object_freeze_notify (obj);
2284 clutter_actor_store_old_geometry (self, &old_alloc);
2286 x1_changed = priv->allocation.x1 != box->x1;
2287 y1_changed = priv->allocation.y1 != box->y1;
2288 x2_changed = priv->allocation.x2 != box->x2;
2289 y2_changed = priv->allocation.y2 != box->y2;
2291 flags_changed = priv->allocation_flags != flags;
2293 priv->allocation = *box;
2294 priv->allocation_flags = flags;
2296 /* allocation is authoritative */
2297 priv->needs_width_request = FALSE;
2298 priv->needs_height_request = FALSE;
2299 priv->needs_allocation = FALSE;
2301 if (x1_changed || y1_changed ||
2302 x2_changed || y2_changed ||
2305 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2306 _clutter_actor_get_debug_name (self));
2308 priv->transform_valid = FALSE;
2310 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2312 /* if the allocation changes, so does the content box */
2313 if (priv->content != NULL)
2315 priv->content_box_valid = FALSE;
2316 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2324 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2326 g_object_thaw_notify (obj);
2331 static void clutter_actor_real_allocate (ClutterActor *self,
2332 const ClutterActorBox *box,
2333 ClutterAllocationFlags flags);
2336 clutter_actor_maybe_layout_children (ClutterActor *self,
2337 const ClutterActorBox *allocation,
2338 ClutterAllocationFlags flags)
2340 ClutterActorPrivate *priv = self->priv;
2342 /* this is going to be a bit hard to follow, so let's put an explanation
2345 * we want ClutterActor to have a default layout manager if the actor was
2346 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2348 * we also want any subclass of ClutterActor that does not override the
2349 * ::allocate() virtual function to delegate to a layout manager.
2351 * finally, we want to allow people subclassing ClutterActor and overriding
2352 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2354 * on the other hand, we want existing actor subclasses overriding the
2355 * ::allocate() virtual function and chaining up to the parent's
2356 * implementation to continue working without allocating their children
2357 * twice, or without entering an allocation loop.
2359 * for the first two points, we check if the class of the actor is
2360 * overridding the ::allocate() virtual function; if it isn't, then we
2361 * follow through with checking whether we have children and a layout
2362 * manager, and eventually calling clutter_layout_manager_allocate().
2364 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2365 * allocation flags that we got passed, and if it is present, we continue
2366 * with the check above.
2368 * if neither of these two checks yields a positive result, we just
2369 * assume that the ::allocate() virtual function that resulted in this
2370 * function being called will also allocate the children of the actor.
2373 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2376 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2382 if (priv->n_children != 0 &&
2383 priv->layout_manager != NULL)
2385 ClutterContainer *container = CLUTTER_CONTAINER (self);
2386 ClutterAllocationFlags children_flags;
2387 ClutterActorBox children_box;
2389 /* normalize the box passed to the layout manager */
2390 children_box.x1 = children_box.y1 = 0.f;
2391 children_box.x2 = (allocation->x2 - allocation->x1);
2392 children_box.y2 = (allocation->y2 - allocation->y1);
2394 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2395 * the actor's children, since it refers only to the current
2396 * actor's allocation.
2398 children_flags = flags;
2399 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2401 CLUTTER_NOTE (LAYOUT,
2402 "Allocating %d children of %s "
2403 "at { %.2f, %.2f - %.2f x %.2f } "
2406 _clutter_actor_get_debug_name (self),
2409 (allocation->x2 - allocation->x1),
2410 (allocation->y2 - allocation->y1),
2411 G_OBJECT_TYPE_NAME (priv->layout_manager));
2413 clutter_layout_manager_allocate (priv->layout_manager,
2421 clutter_actor_real_allocate (ClutterActor *self,
2422 const ClutterActorBox *box,
2423 ClutterAllocationFlags flags)
2425 ClutterActorPrivate *priv = self->priv;
2428 g_object_freeze_notify (G_OBJECT (self));
2430 changed = clutter_actor_set_allocation_internal (self, box, flags);
2432 /* we allocate our children before we notify changes in our geometry,
2433 * so that people connecting to properties will be able to get valid
2434 * data out of the sub-tree of the scene graph that has this actor at
2437 clutter_actor_maybe_layout_children (self, box, flags);
2441 ClutterActorBox signal_box = priv->allocation;
2442 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2444 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2449 g_object_thaw_notify (G_OBJECT (self));
2453 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2454 ClutterActor *origin)
2456 /* no point in queuing a redraw on a destroyed actor */
2457 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2460 /* NB: We can't bail out early here if the actor is hidden in case
2461 * the actor bas been cloned. In this case the clone will need to
2462 * receive the signal so it can queue its own redraw.
2465 /* calls klass->queue_redraw in default handler */
2466 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2470 clutter_actor_real_queue_redraw (ClutterActor *self,
2471 ClutterActor *origin)
2473 ClutterActor *parent;
2475 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2476 _clutter_actor_get_debug_name (self),
2477 origin != NULL ? _clutter_actor_get_debug_name (origin)
2480 /* no point in queuing a redraw on a destroyed actor */
2481 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2484 /* If the queue redraw is coming from a child then the actor has
2485 become dirty and any queued effect is no longer valid */
2488 self->priv->is_dirty = TRUE;
2489 self->priv->effect_to_redraw = NULL;
2492 /* If the actor isn't visible, we still had to emit the signal
2493 * to allow for a ClutterClone, but the appearance of the parent
2494 * won't change so we don't have to propagate up the hierarchy.
2496 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2499 /* Although we could determine here that a full stage redraw
2500 * has already been queued and immediately bail out, we actually
2501 * guarantee that we will propagate a queue-redraw signal to our
2502 * parent at least once so that it's possible to implement a
2503 * container that tracks which of its children have queued a
2506 if (self->priv->propagated_one_redraw)
2508 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2509 if (stage != NULL &&
2510 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2514 self->priv->propagated_one_redraw = TRUE;
2516 /* notify parents, if they are all visible eventually we'll
2517 * queue redraw on the stage, which queues the redraw idle.
2519 parent = clutter_actor_get_parent (self);
2522 /* this will go up recursively */
2523 _clutter_actor_signal_queue_redraw (parent, origin);
2528 clutter_actor_real_queue_relayout (ClutterActor *self)
2530 ClutterActorPrivate *priv = self->priv;
2532 /* no point in queueing a redraw on a destroyed actor */
2533 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2536 priv->needs_width_request = TRUE;
2537 priv->needs_height_request = TRUE;
2538 priv->needs_allocation = TRUE;
2540 /* reset the cached size requests */
2541 memset (priv->width_requests, 0,
2542 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2543 memset (priv->height_requests, 0,
2544 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2546 /* We need to go all the way up the hierarchy */
2547 if (priv->parent != NULL)
2548 _clutter_actor_queue_only_relayout (priv->parent);
2552 * clutter_actor_apply_relative_transform_to_point:
2553 * @self: A #ClutterActor
2554 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2555 * default #ClutterStage
2556 * @point: A point as #ClutterVertex
2557 * @vertex: (out caller-allocates): The translated #ClutterVertex
2559 * Transforms @point in coordinates relative to the actor into
2560 * ancestor-relative coordinates using the relevant transform
2561 * stack (i.e. scale, rotation, etc).
2563 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2564 * this case, the coordinates returned will be the coordinates on
2565 * the stage before the projection is applied. This is different from
2566 * the behaviour of clutter_actor_apply_transform_to_point().
2571 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2572 ClutterActor *ancestor,
2573 const ClutterVertex *point,
2574 ClutterVertex *vertex)
2579 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2580 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2581 g_return_if_fail (point != NULL);
2582 g_return_if_fail (vertex != NULL);
2587 if (ancestor == NULL)
2588 ancestor = _clutter_actor_get_stage_internal (self);
2590 if (ancestor == NULL)
2596 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2597 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2601 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2602 const ClutterVertex *vertices_in,
2603 ClutterVertex *vertices_out,
2606 ClutterActor *stage;
2607 CoglMatrix modelview;
2608 CoglMatrix projection;
2611 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2613 stage = _clutter_actor_get_stage_internal (self);
2615 /* We really can't do anything meaningful in this case so don't try
2616 * to do any transform */
2620 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2621 * that gets us to stage coordinates, we want to go all the way to eye
2623 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2625 /* Fetch the projection and viewport */
2626 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2627 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2633 _clutter_util_fully_transform_vertices (&modelview,
2644 * clutter_actor_apply_transform_to_point:
2645 * @self: A #ClutterActor
2646 * @point: A point as #ClutterVertex
2647 * @vertex: (out caller-allocates): The translated #ClutterVertex
2649 * Transforms @point in coordinates relative to the actor
2650 * into screen-relative coordinates with the current actor
2651 * transformation (i.e. scale, rotation, etc)
2656 clutter_actor_apply_transform_to_point (ClutterActor *self,
2657 const ClutterVertex *point,
2658 ClutterVertex *vertex)
2660 g_return_if_fail (point != NULL);
2661 g_return_if_fail (vertex != NULL);
2662 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2666 * _clutter_actor_get_relative_transformation_matrix:
2667 * @self: The actor whose coordinate space you want to transform from.
2668 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2669 * or %NULL if you want to transform all the way to eye coordinates.
2670 * @matrix: A #CoglMatrix to store the transformation
2672 * This gets a transformation @matrix that will transform coordinates from the
2673 * coordinate space of @self into the coordinate space of @ancestor.
2675 * For example if you need a matrix that can transform the local actor
2676 * coordinates of @self into stage coordinates you would pass the actor's stage
2677 * pointer as the @ancestor.
2679 * If you pass %NULL then the transformation will take you all the way through
2680 * to eye coordinates. This can be useful if you want to extract the entire
2681 * modelview transform that Clutter applies before applying the projection
2682 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2683 * using cogl_set_modelview_matrix() for example then you would want a matrix
2684 * that transforms into eye coordinates.
2686 * <note><para>This function explicitly initializes the given @matrix. If you just
2687 * want clutter to multiply a relative transformation with an existing matrix
2688 * you can use clutter_actor_apply_relative_transformation_matrix()
2689 * instead.</para></note>
2692 /* XXX: We should consider caching the stage relative modelview along with
2693 * the actor itself */
2695 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2696 ClutterActor *ancestor,
2699 cogl_matrix_init_identity (matrix);
2701 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2704 /* Project the given @box into stage window coordinates, writing the
2705 * transformed vertices to @verts[]. */
2707 _clutter_actor_transform_and_project_box (ClutterActor *self,
2708 const ClutterActorBox *box,
2709 ClutterVertex verts[])
2711 ClutterVertex box_vertices[4];
2713 box_vertices[0].x = box->x1;
2714 box_vertices[0].y = box->y1;
2715 box_vertices[0].z = 0;
2716 box_vertices[1].x = box->x2;
2717 box_vertices[1].y = box->y1;
2718 box_vertices[1].z = 0;
2719 box_vertices[2].x = box->x1;
2720 box_vertices[2].y = box->y2;
2721 box_vertices[2].z = 0;
2722 box_vertices[3].x = box->x2;
2723 box_vertices[3].y = box->y2;
2724 box_vertices[3].z = 0;
2727 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2731 * clutter_actor_get_allocation_vertices:
2732 * @self: A #ClutterActor
2733 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2734 * against, or %NULL to use the #ClutterStage
2735 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2736 * location for an array of 4 #ClutterVertex in which to store the result
2738 * Calculates the transformed coordinates of the four corners of the
2739 * actor in the plane of @ancestor. The returned vertices relate to
2740 * the #ClutterActorBox coordinates as follows:
2742 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2743 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2744 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2745 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2748 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2749 * this case, the coordinates returned will be the coordinates on
2750 * the stage before the projection is applied. This is different from
2751 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2756 clutter_actor_get_allocation_vertices (ClutterActor *self,
2757 ClutterActor *ancestor,
2758 ClutterVertex verts[])
2760 ClutterActorPrivate *priv;
2761 ClutterActorBox box;
2762 ClutterVertex vertices[4];
2763 CoglMatrix modelview;
2765 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2766 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2768 if (ancestor == NULL)
2769 ancestor = _clutter_actor_get_stage_internal (self);
2771 /* Fallback to a NOP transform if the actor isn't parented under a
2773 if (ancestor == NULL)
2778 /* if the actor needs to be allocated we force a relayout, so that
2779 * we will have valid values to use in the transformations */
2780 if (priv->needs_allocation)
2782 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2784 _clutter_stage_maybe_relayout (stage);
2787 box.x1 = box.y1 = 0;
2788 /* The result isn't really meaningful in this case but at
2789 * least try to do something *vaguely* reasonable... */
2790 clutter_actor_get_size (self, &box.x2, &box.y2);
2794 clutter_actor_get_allocation_box (self, &box);
2796 vertices[0].x = box.x1;
2797 vertices[0].y = box.y1;
2799 vertices[1].x = box.x2;
2800 vertices[1].y = box.y1;
2802 vertices[2].x = box.x1;
2803 vertices[2].y = box.y2;
2805 vertices[3].x = box.x2;
2806 vertices[3].y = box.y2;
2809 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2812 cogl_matrix_transform_points (&modelview,
2814 sizeof (ClutterVertex),
2816 sizeof (ClutterVertex),
2822 * clutter_actor_get_abs_allocation_vertices:
2823 * @self: A #ClutterActor
2824 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2825 * of 4 #ClutterVertex where to store the result.
2827 * Calculates the transformed screen coordinates of the four corners of
2828 * the actor; the returned vertices relate to the #ClutterActorBox
2829 * coordinates as follows:
2831 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2832 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2833 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2834 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2840 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2841 ClutterVertex verts[])
2843 ClutterActorPrivate *priv;
2844 ClutterActorBox actor_space_allocation;
2846 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2850 /* if the actor needs to be allocated we force a relayout, so that
2851 * the actor allocation box will be valid for
2852 * _clutter_actor_transform_and_project_box()
2854 if (priv->needs_allocation)
2856 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2857 /* There's nothing meaningful we can do now */
2861 _clutter_stage_maybe_relayout (stage);
2864 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2865 * own coordinate space... */
2866 actor_space_allocation.x1 = 0;
2867 actor_space_allocation.y1 = 0;
2868 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2869 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2870 _clutter_actor_transform_and_project_box (self,
2871 &actor_space_allocation,
2876 clutter_actor_real_apply_transform (ClutterActor *self,
2879 ClutterActorPrivate *priv = self->priv;
2881 if (!priv->transform_valid)
2883 CoglMatrix *transform = &priv->transform;
2884 const ClutterTransformInfo *info;
2886 info = _clutter_actor_get_transform_info_or_defaults (self);
2888 cogl_matrix_init_identity (transform);
2890 cogl_matrix_translate (transform,
2891 priv->allocation.x1,
2892 priv->allocation.y1,
2896 cogl_matrix_translate (transform, 0, 0, info->depth);
2899 * because the rotation involves translations, we must scale
2900 * before applying the rotations (if we apply the scale after
2901 * the rotations, the translations included in the rotation are
2902 * not scaled and so the entire object will move on the screen
2903 * as a result of rotating it).
2905 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2907 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2908 &info->scale_center,
2909 cogl_matrix_scale (transform,
2916 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2918 cogl_matrix_rotate (transform,
2923 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2925 cogl_matrix_rotate (transform,
2930 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2932 cogl_matrix_rotate (transform,
2936 if (!clutter_anchor_coord_is_zero (&info->anchor))
2940 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2941 cogl_matrix_translate (transform, -x, -y, -z);
2944 priv->transform_valid = TRUE;
2947 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2950 /* Applies the transforms associated with this actor to the given
2953 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2956 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2960 * clutter_actor_apply_relative_transformation_matrix:
2961 * @self: The actor whose coordinate space you want to transform from.
2962 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2963 * or %NULL if you want to transform all the way to eye coordinates.
2964 * @matrix: A #CoglMatrix to apply the transformation too.
2966 * This multiplies a transform with @matrix that will transform coordinates
2967 * from the coordinate space of @self into the coordinate space of @ancestor.
2969 * For example if you need a matrix that can transform the local actor
2970 * coordinates of @self into stage coordinates you would pass the actor's stage
2971 * pointer as the @ancestor.
2973 * If you pass %NULL then the transformation will take you all the way through
2974 * to eye coordinates. This can be useful if you want to extract the entire
2975 * modelview transform that Clutter applies before applying the projection
2976 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2977 * using cogl_set_modelview_matrix() for example then you would want a matrix
2978 * that transforms into eye coordinates.
2980 * <note>This function doesn't initialize the given @matrix, it simply
2981 * multiplies the requested transformation matrix with the existing contents of
2982 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2983 * before calling this function, or you can use
2984 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2987 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2988 ClutterActor *ancestor,
2991 ClutterActor *parent;
2993 /* Note we terminate before ever calling stage->apply_transform()
2994 * since that would conceptually be relative to the underlying
2995 * window OpenGL coordinates so we'd need a special @ancestor
2996 * value to represent the fake parent of the stage. */
2997 if (self == ancestor)
3000 parent = clutter_actor_get_parent (self);
3003 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3006 _clutter_actor_apply_modelview_transform (self, matrix);
3010 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3011 ClutterPaintVolume *pv,
3013 const CoglColor *color)
3015 static CoglPipeline *outline = NULL;
3016 CoglPrimitive *prim;
3017 ClutterVertex line_ends[12 * 2];
3020 clutter_backend_get_cogl_context (clutter_get_default_backend ());
3021 /* XXX: at some point we'll query this from the stage but we can't
3022 * do that until the osx backend uses Cogl natively. */
3023 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3025 if (outline == NULL)
3026 outline = cogl_pipeline_new (ctx);
3028 _clutter_paint_volume_complete (pv);
3030 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3033 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3034 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3035 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3036 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3041 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3042 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3043 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3044 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3046 /* Lines connecting front face to back face */
3047 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3048 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3049 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3050 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3053 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3055 (CoglVertexP3 *)line_ends);
3057 cogl_pipeline_set_color (outline, color);
3058 cogl_framebuffer_draw_primitive (fb, outline, prim);
3059 cogl_object_unref (prim);
3063 PangoLayout *layout;
3064 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3065 pango_layout_set_text (layout, label, -1);
3066 cogl_pango_render_layout (layout,
3071 g_object_unref (layout);
3076 _clutter_actor_draw_paint_volume (ClutterActor *self)
3078 ClutterPaintVolume *pv;
3081 pv = _clutter_actor_get_paint_volume_mutable (self);
3084 gfloat width, height;
3085 ClutterPaintVolume fake_pv;
3087 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3088 _clutter_paint_volume_init_static (&fake_pv, stage);
3090 clutter_actor_get_size (self, &width, &height);
3091 clutter_paint_volume_set_width (&fake_pv, width);
3092 clutter_paint_volume_set_height (&fake_pv, height);
3094 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3095 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3096 _clutter_actor_get_debug_name (self),
3099 clutter_paint_volume_free (&fake_pv);
3103 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3104 _clutter_actor_draw_paint_volume_full (self, pv,
3105 _clutter_actor_get_debug_name (self),
3111 _clutter_actor_paint_cull_result (ClutterActor *self,
3113 ClutterCullResult result)
3115 ClutterPaintVolume *pv;
3120 if (result == CLUTTER_CULL_RESULT_IN)
3121 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3122 else if (result == CLUTTER_CULL_RESULT_OUT)
3123 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3125 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3128 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3130 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3131 _clutter_actor_draw_paint_volume_full (self, pv,
3132 _clutter_actor_get_debug_name (self),
3136 PangoLayout *layout;
3138 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3139 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3140 cogl_set_source_color (&color);
3142 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3143 pango_layout_set_text (layout, label, -1);
3144 cogl_pango_render_layout (layout,
3150 g_object_unref (layout);
3154 static int clone_paint_level = 0;
3157 _clutter_actor_push_clone_paint (void)
3159 clone_paint_level++;
3163 _clutter_actor_pop_clone_paint (void)
3165 clone_paint_level--;
3169 in_clone_paint (void)
3171 return clone_paint_level > 0;
3174 /* Returns TRUE if the actor can be ignored */
3175 /* FIXME: we should return a ClutterCullResult, and
3176 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3177 * means there's no point in trying to cull descendants of the current
3180 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3182 ClutterActorPrivate *priv = self->priv;
3183 ClutterActor *stage;
3184 const ClutterPlane *stage_clip;
3186 if (!priv->last_paint_volume_valid)
3188 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3189 "->last_paint_volume_valid == FALSE",
3190 _clutter_actor_get_debug_name (self));
3194 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3197 stage = _clutter_actor_get_stage_internal (self);
3198 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3199 if (G_UNLIKELY (!stage_clip))
3201 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3202 "No stage clip set",
3203 _clutter_actor_get_debug_name (self));
3207 if (cogl_get_draw_framebuffer () !=
3208 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3210 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3211 "Current framebuffer doesn't correspond to stage",
3212 _clutter_actor_get_debug_name (self));
3217 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3222 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3224 ClutterActorPrivate *priv = self->priv;
3225 const ClutterPaintVolume *pv;
3227 if (priv->last_paint_volume_valid)
3229 clutter_paint_volume_free (&priv->last_paint_volume);
3230 priv->last_paint_volume_valid = FALSE;
3233 pv = clutter_actor_get_paint_volume (self);
3236 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3237 "Actor failed to report a paint volume",
3238 _clutter_actor_get_debug_name (self));
3242 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3244 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3245 NULL); /* eye coordinates */
3247 priv->last_paint_volume_valid = TRUE;
3250 static inline gboolean
3251 actor_has_shader_data (ClutterActor *self)
3253 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3257 _clutter_actor_get_pick_id (ClutterActor *self)
3259 if (self->priv->pick_id < 0)
3262 return self->priv->pick_id;
3265 /* This is the same as clutter_actor_add_effect except that it doesn't
3266 queue a redraw and it doesn't notify on the effect property */
3268 _clutter_actor_add_effect_internal (ClutterActor *self,
3269 ClutterEffect *effect)
3271 ClutterActorPrivate *priv = self->priv;
3273 if (priv->effects == NULL)
3275 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3276 priv->effects->actor = self;
3279 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3282 /* This is the same as clutter_actor_remove_effect except that it doesn't
3283 queue a redraw and it doesn't notify on the effect property */
3285 _clutter_actor_remove_effect_internal (ClutterActor *self,
3286 ClutterEffect *effect)
3288 ClutterActorPrivate *priv = self->priv;
3290 if (priv->effects == NULL)
3293 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3295 if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3296 g_clear_object (&priv->effects);
3300 needs_flatten_effect (ClutterActor *self)
3302 ClutterActorPrivate *priv = self->priv;
3304 if (G_UNLIKELY (clutter_paint_debug_flags &
3305 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3308 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3310 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3312 if (clutter_actor_get_paint_opacity (self) < 255 &&
3313 clutter_actor_has_overlaps (self))
3321 add_or_remove_flatten_effect (ClutterActor *self)
3323 ClutterActorPrivate *priv = self->priv;
3325 /* Add or remove the flatten effect depending on the
3326 offscreen-redirect property. */
3327 if (needs_flatten_effect (self))
3329 if (priv->flatten_effect == NULL)
3331 ClutterActorMeta *actor_meta;
3334 priv->flatten_effect = _clutter_flatten_effect_new ();
3335 /* Keep a reference to the effect so that we can queue
3337 g_object_ref_sink (priv->flatten_effect);
3339 /* Set the priority of the effect to high so that it will
3340 always be applied to the actor first. It uses an internal
3341 priority so that it won't be visible to applications */
3342 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3343 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3344 _clutter_actor_meta_set_priority (actor_meta, priority);
3346 /* This will add the effect without queueing a redraw */
3347 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3352 if (priv->flatten_effect != NULL)
3354 /* Destroy the effect so that it will lose its fbo cache of
3356 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3357 g_clear_object (&priv->flatten_effect);
3363 clutter_actor_real_paint (ClutterActor *actor)
3365 ClutterActorPrivate *priv = actor->priv;
3368 for (iter = priv->first_child;
3370 iter = iter->priv->next_sibling)
3372 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3373 _clutter_actor_get_debug_name (iter),
3374 _clutter_actor_get_debug_name (actor),
3375 iter->priv->allocation.x1,
3376 iter->priv->allocation.y1,
3377 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3378 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3380 clutter_actor_paint (iter);
3385 clutter_actor_paint_node (ClutterActor *actor,
3386 ClutterPaintNode *root)
3388 ClutterActorPrivate *priv = actor->priv;
3393 if (priv->bg_color_set &&
3394 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3396 ClutterPaintNode *node;
3397 ClutterColor bg_color;
3398 ClutterActorBox box;
3402 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3403 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3405 bg_color = priv->bg_color;
3406 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3407 * priv->bg_color.alpha
3410 node = clutter_color_node_new (&bg_color);
3411 clutter_paint_node_set_name (node, "backgroundColor");
3412 clutter_paint_node_add_rectangle (node, &box);
3413 clutter_paint_node_add_child (root, node);
3414 clutter_paint_node_unref (node);
3417 if (priv->content != NULL)
3418 _clutter_content_paint_content (priv->content, actor, root);
3420 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3421 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3423 if (clutter_paint_node_get_n_children (root) == 0)
3426 #ifdef CLUTTER_ENABLE_DEBUG
3427 if (CLUTTER_HAS_DEBUG (PAINT))
3429 /* dump the tree only if we have one */
3430 _clutter_paint_node_dump_tree (root);
3432 #endif /* CLUTTER_ENABLE_DEBUG */
3434 _clutter_paint_node_paint (root);
3437 /* XXX: Uncomment this when we disable emitting the paint signal */
3438 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3445 * clutter_actor_paint:
3446 * @self: A #ClutterActor
3448 * Renders the actor to display.
3450 * This function should not be called directly by applications.
3451 * Call clutter_actor_queue_redraw() to queue paints, instead.
3453 * This function is context-aware, and will either cause a
3454 * regular paint or a pick paint.
3456 * This function will emit the #ClutterActor::paint signal or
3457 * the #ClutterActor::pick signal, depending on the context.
3459 * This function does not paint the actor if the actor is set to 0,
3460 * unless it is performing a pick paint.
3463 clutter_actor_paint (ClutterActor *self)
3465 ClutterActorPrivate *priv;
3466 ClutterPickMode pick_mode;
3467 gboolean clip_set = FALSE;
3468 gboolean shader_applied = FALSE;
3470 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3471 "Actor real-paint counter",
3472 "Increments each time any actor is painted",
3473 0 /* no application private data */);
3474 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3475 "Actor pick-paint counter",
3476 "Increments each time any actor is painted "
3478 0 /* no application private data */);
3480 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3482 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3487 pick_mode = _clutter_context_get_pick_mode ();
3489 if (pick_mode == CLUTTER_PICK_NONE)
3490 priv->propagated_one_redraw = FALSE;
3492 /* It's an important optimization that we consider painting of
3493 * actors with 0 opacity to be a NOP... */
3494 if (pick_mode == CLUTTER_PICK_NONE &&
3495 /* ignore top-levels, since they might be transparent */
3496 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3497 /* Use the override opacity if its been set */
3498 ((priv->opacity_override >= 0) ?
3499 priv->opacity_override : priv->opacity) == 0)
3502 /* if we aren't paintable (not in a toplevel with all
3503 * parents paintable) then do nothing.
3505 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3508 /* mark that we are in the paint process */
3509 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3513 if (priv->enable_model_view_transform)
3517 /* XXX: It could be better to cache the modelview with the actor
3518 * instead of progressively building up the transformations on
3519 * the matrix stack every time we paint. */
3520 cogl_get_modelview_matrix (&matrix);
3521 _clutter_actor_apply_modelview_transform (self, &matrix);
3523 #ifdef CLUTTER_ENABLE_DEBUG
3524 /* Catch when out-of-band transforms have been made by actors not as part
3525 * of an apply_transform vfunc... */
3526 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3528 CoglMatrix expected_matrix;
3530 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3533 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3535 GString *buf = g_string_sized_new (1024);
3536 ClutterActor *parent;
3539 while (parent != NULL)
3541 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3543 if (parent->priv->parent != NULL)
3544 g_string_append (buf, "->");
3546 parent = parent->priv->parent;
3549 g_warning ("Unexpected transform found when painting actor "
3550 "\"%s\". This will be caused by one of the actor's "
3551 "ancestors (%s) using the Cogl API directly to transform "
3552 "children instead of using ::apply_transform().",
3553 _clutter_actor_get_debug_name (self),
3556 g_string_free (buf, TRUE);
3559 #endif /* CLUTTER_ENABLE_DEBUG */
3561 cogl_set_modelview_matrix (&matrix);
3566 cogl_clip_push_rectangle (priv->clip.x,
3568 priv->clip.x + priv->clip.width,
3569 priv->clip.y + priv->clip.height);
3572 else if (priv->clip_to_allocation)
3574 gfloat width, height;
3576 width = priv->allocation.x2 - priv->allocation.x1;
3577 height = priv->allocation.y2 - priv->allocation.y1;
3579 cogl_clip_push_rectangle (0, 0, width, height);
3583 if (pick_mode == CLUTTER_PICK_NONE)
3585 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3587 /* We check whether we need to add the flatten effect before
3588 each paint so that we can avoid having a mechanism for
3589 applications to notify when the value of the
3590 has_overlaps virtual changes. */
3591 add_or_remove_flatten_effect (self);
3594 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3596 /* We save the current paint volume so that the next time the
3597 * actor queues a redraw we can constrain the redraw to just
3598 * cover the union of the new bounding box and the old.
3600 * We also fetch the current paint volume to perform culling so
3601 * we can avoid painting actors outside the current clip region.
3603 * If we are painting inside a clone, we should neither update
3604 * the paint volume or use it to cull painting, since the paint
3605 * box represents the location of the source actor on the
3608 * XXX: We are starting to do a lot of vertex transforms on
3609 * the CPU in a typical paint, so at some point we should
3610 * audit these and consider caching some things.
3612 * NB: We don't perform culling while picking at this point because
3613 * clutter-stage.c doesn't setup the clipping planes appropriately.
3615 * NB: We don't want to update the last-paint-volume during picking
3616 * because the last-paint-volume is used to determine the old screen
3617 * space location of an actor that has moved so we can know the
3618 * minimal region to redraw to clear an old view of the actor. If we
3619 * update this during picking then by the time we come around to
3620 * paint then the last-paint-volume would likely represent the new
3621 * actor position not the old.
3623 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3626 /* annoyingly gcc warns if uninitialized even though
3627 * the initialization is redundant :-( */
3628 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3630 if (G_LIKELY ((clutter_paint_debug_flags &
3631 (CLUTTER_DEBUG_DISABLE_CULLING |
3632 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3633 (CLUTTER_DEBUG_DISABLE_CULLING |
3634 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3635 _clutter_actor_update_last_paint_volume (self);
3637 success = cull_actor (self, &result);
3639 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3640 _clutter_actor_paint_cull_result (self, success, result);
3641 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3645 if (priv->effects == NULL)
3647 if (pick_mode == CLUTTER_PICK_NONE &&
3648 actor_has_shader_data (self))
3650 _clutter_actor_shader_pre_paint (self, FALSE);
3651 shader_applied = TRUE;
3654 priv->next_effect_to_paint = NULL;
3657 priv->next_effect_to_paint =
3658 _clutter_meta_group_peek_metas (priv->effects);
3660 clutter_actor_continue_paint (self);
3663 _clutter_actor_shader_post_paint (self);
3665 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3666 pick_mode == CLUTTER_PICK_NONE))
3667 _clutter_actor_draw_paint_volume (self);
3670 /* If we make it here then the actor has run through a complete
3671 paint run including all the effects so it's no longer dirty */
3672 if (pick_mode == CLUTTER_PICK_NONE)
3673 priv->is_dirty = FALSE;
3680 /* paint sequence complete */
3681 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3685 * clutter_actor_continue_paint:
3686 * @self: A #ClutterActor
3688 * Run the next stage of the paint sequence. This function should only
3689 * be called within the implementation of the ‘run’ virtual of a
3690 * #ClutterEffect. It will cause the run method of the next effect to
3691 * be applied, or it will paint the actual actor if the current effect
3692 * is the last effect in the chain.
3697 clutter_actor_continue_paint (ClutterActor *self)
3699 ClutterActorPrivate *priv;
3701 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3702 /* This should only be called from with in the ‘run’ implementation
3703 of a ClutterEffect */
3704 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3708 /* Skip any effects that are disabled */
3709 while (priv->next_effect_to_paint &&
3710 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3711 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3713 /* If this has come from the last effect then we'll just paint the
3715 if (priv->next_effect_to_paint == NULL)
3717 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3719 ClutterPaintNode *dummy;
3721 /* XXX - this will go away in 2.0, when we can get rid of this
3722 * stuff and switch to a pure retained render tree of PaintNodes
3723 * for the entire frame, starting from the Stage; the paint()
3724 * virtual function can then be called directly.
3726 dummy = _clutter_dummy_node_new (self);
3727 clutter_paint_node_set_name (dummy, "Root");
3729 /* XXX - for 1.12, we use the return value of paint_node() to
3730 * decide whether we should emit the ::paint signal.
3732 clutter_actor_paint_node (self, dummy);
3733 clutter_paint_node_unref (dummy);
3735 g_signal_emit (self, actor_signals[PAINT], 0);
3739 ClutterColor col = { 0, };
3741 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3743 /* Actor will then paint silhouette of itself in supplied
3744 * color. See clutter_stage_get_actor_at_pos() for where
3745 * picking is enabled.
3747 g_signal_emit (self, actor_signals[PICK], 0, &col);
3752 ClutterEffect *old_current_effect;
3753 ClutterEffectPaintFlags run_flags = 0;
3755 /* Cache the current effect so that we can put it back before
3757 old_current_effect = priv->current_effect;
3759 priv->current_effect = priv->next_effect_to_paint->data;
3760 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3762 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3766 /* If there's an effect queued with this redraw then all
3767 effects up to that one will be considered dirty. It
3768 is expected the queued effect will paint the cached
3769 image and not call clutter_actor_continue_paint again
3770 (although it should work ok if it does) */
3771 if (priv->effect_to_redraw == NULL ||
3772 priv->current_effect != priv->effect_to_redraw)
3773 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3776 _clutter_effect_paint (priv->current_effect, run_flags);
3780 /* We can't determine when an actor has been modified since
3781 its last pick so lets just assume it has always been
3783 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3785 _clutter_effect_pick (priv->current_effect, run_flags);
3788 priv->current_effect = old_current_effect;
3792 static ClutterActorTraverseVisitFlags
3793 invalidate_queue_redraw_entry (ClutterActor *self,
3797 ClutterActorPrivate *priv = self->priv;
3799 if (priv->queue_redraw_entry != NULL)
3801 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3802 priv->queue_redraw_entry = NULL;
3805 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3809 remove_child (ClutterActor *self,
3810 ClutterActor *child)
3812 ClutterActor *prev_sibling, *next_sibling;
3814 prev_sibling = child->priv->prev_sibling;
3815 next_sibling = child->priv->next_sibling;
3817 if (prev_sibling != NULL)
3818 prev_sibling->priv->next_sibling = next_sibling;
3820 if (next_sibling != NULL)
3821 next_sibling->priv->prev_sibling = prev_sibling;
3823 if (self->priv->first_child == child)
3824 self->priv->first_child = next_sibling;
3826 if (self->priv->last_child == child)
3827 self->priv->last_child = prev_sibling;
3829 child->priv->parent = NULL;
3830 child->priv->prev_sibling = NULL;
3831 child->priv->next_sibling = NULL;
3835 REMOVE_CHILD_DESTROY_META = 1 << 0,
3836 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3837 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3838 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3839 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3840 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3842 /* default flags for public API */
3843 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3844 REMOVE_CHILD_EMIT_PARENT_SET |
3845 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3846 REMOVE_CHILD_CHECK_STATE |
3847 REMOVE_CHILD_FLUSH_QUEUE |
3848 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3850 /* flags for legacy/deprecated API */
3851 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3852 REMOVE_CHILD_FLUSH_QUEUE |
3853 REMOVE_CHILD_EMIT_PARENT_SET |
3854 REMOVE_CHILD_NOTIFY_FIRST_LAST
3855 } ClutterActorRemoveChildFlags;
3858 * clutter_actor_remove_child_internal:
3859 * @self: a #ClutterActor
3860 * @child: the child of @self that has to be removed
3861 * @flags: control the removal operations
3863 * Removes @child from the list of children of @self.
3866 clutter_actor_remove_child_internal (ClutterActor *self,
3867 ClutterActor *child,
3868 ClutterActorRemoveChildFlags flags)
3870 ClutterActor *old_first, *old_last;
3871 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3872 gboolean flush_queue;
3873 gboolean notify_first_last;
3874 gboolean was_mapped;
3876 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3877 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3878 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3879 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3880 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3881 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3883 g_object_freeze_notify (G_OBJECT (self));
3886 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3890 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3892 /* we need to unrealize *before* we set parent_actor to NULL,
3893 * because in an unrealize method actors are dissociating from the
3894 * stage, which means they need to be able to
3895 * clutter_actor_get_stage().
3897 * yhis should unmap and unrealize, unless we're reparenting.
3899 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3906 /* We take this opportunity to invalidate any queue redraw entry
3907 * associated with the actor and descendants since we won't be able to
3908 * determine the appropriate stage after this.
3910 * we do this after we updated the mapped state because actors might
3911 * end up queueing redraws inside their mapped/unmapped virtual
3912 * functions, and if we invalidate the redraw entry we could end up
3913 * with an inconsistent state and weird memory corruption. see
3916 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3917 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3919 _clutter_actor_traverse (child,
3921 invalidate_queue_redraw_entry,
3926 old_first = self->priv->first_child;
3927 old_last = self->priv->last_child;
3929 remove_child (self, child);
3931 self->priv->n_children -= 1;
3933 self->priv->age += 1;
3935 /* if the child that got removed was visible and set to
3936 * expand then we want to reset the parent's state in
3937 * case the child was the only thing that was making it
3940 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
3941 (child->priv->needs_compute_expand ||
3942 child->priv->needs_x_expand ||
3943 child->priv->needs_y_expand))
3945 clutter_actor_queue_compute_expand (self);
3948 /* clutter_actor_reparent() will emit ::parent-set for us */
3949 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3950 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3952 /* if the child was mapped then we need to relayout ourselves to account
3953 * for the removed child
3956 clutter_actor_queue_relayout (self);
3958 /* we need to emit the signal before dropping the reference */
3959 if (emit_actor_removed)
3960 g_signal_emit_by_name (self, "actor-removed", child);
3962 if (notify_first_last)
3964 if (old_first != self->priv->first_child)
3965 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3967 if (old_last != self->priv->last_child)
3968 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3971 g_object_thaw_notify (G_OBJECT (self));
3973 /* remove the reference we acquired in clutter_actor_add_child() */
3974 g_object_unref (child);
3977 static const ClutterTransformInfo default_transform_info = {
3978 0.0, { 0, }, /* rotation-x */
3979 0.0, { 0, }, /* rotation-y */
3980 0.0, { 0, }, /* rotation-z */
3982 1.0, 1.0, { 0, }, /* scale */
3984 { 0, }, /* anchor */
3990 * _clutter_actor_get_transform_info_or_defaults:
3991 * @self: a #ClutterActor
3993 * Retrieves the ClutterTransformInfo structure associated to an actor.
3995 * If the actor does not have a ClutterTransformInfo structure associated
3996 * to it, then the default structure will be returned.
3998 * This function should only be used for getters.
4000 * Return value: a const pointer to the ClutterTransformInfo structure
4002 const ClutterTransformInfo *
4003 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4005 ClutterTransformInfo *info;
4007 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4011 return &default_transform_info;
4015 clutter_transform_info_free (gpointer data)
4018 g_slice_free (ClutterTransformInfo, data);
4022 * _clutter_actor_get_transform_info:
4023 * @self: a #ClutterActor
4025 * Retrieves a pointer to the ClutterTransformInfo structure.
4027 * If the actor does not have a ClutterTransformInfo associated to it, one
4028 * will be created and initialized to the default values.
4030 * This function should be used for setters.
4032 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4035 * Return value: (transfer none): a pointer to the ClutterTransformInfo
4038 ClutterTransformInfo *
4039 _clutter_actor_get_transform_info (ClutterActor *self)
4041 ClutterTransformInfo *info;
4043 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4046 info = g_slice_new (ClutterTransformInfo);
4048 *info = default_transform_info;
4050 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4052 clutter_transform_info_free);
4059 * clutter_actor_set_rotation_angle_internal:
4060 * @self: a #ClutterActor
4061 * @axis: the axis of the angle to change
4062 * @angle: the angle of rotation
4064 * Sets the rotation angle on the given axis without affecting the
4065 * rotation center point.
4068 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4069 ClutterRotateAxis axis,
4072 GObject *obj = G_OBJECT (self);
4073 ClutterTransformInfo *info;
4075 info = _clutter_actor_get_transform_info (self);
4077 g_object_freeze_notify (obj);
4081 case CLUTTER_X_AXIS:
4082 info->rx_angle = angle;
4083 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4086 case CLUTTER_Y_AXIS:
4087 info->ry_angle = angle;
4088 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4091 case CLUTTER_Z_AXIS:
4092 info->rz_angle = angle;
4093 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4097 self->priv->transform_valid = FALSE;
4099 g_object_thaw_notify (obj);
4101 clutter_actor_queue_redraw (self);
4105 clutter_actor_set_rotation_angle (ClutterActor *self,
4106 ClutterRotateAxis axis,
4109 const ClutterTransformInfo *info;
4110 const double *cur_angle_p = NULL;
4111 GParamSpec *pspec = NULL;
4113 info = _clutter_actor_get_transform_info_or_defaults (self);
4117 case CLUTTER_X_AXIS:
4118 cur_angle_p = &info->rx_angle;
4119 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4122 case CLUTTER_Y_AXIS:
4123 cur_angle_p = &info->ry_angle;
4124 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4127 case CLUTTER_Z_AXIS:
4128 cur_angle_p = &info->rz_angle;
4129 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4133 g_assert (pspec != NULL);
4134 g_assert (cur_angle_p != NULL);
4136 if (_clutter_actor_get_transition (self, pspec) == NULL)
4137 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4139 _clutter_actor_update_transition (self, pspec, angle);
4141 clutter_actor_queue_redraw (self);
4145 * clutter_actor_set_rotation_center_internal:
4146 * @self: a #ClutterActor
4147 * @axis: the axis of the center to change
4148 * @center: the coordinates of the rotation center
4150 * Sets the rotation center on the given axis without affecting the
4154 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4155 ClutterRotateAxis axis,
4156 const ClutterVertex *center)
4158 GObject *obj = G_OBJECT (self);
4159 ClutterTransformInfo *info;
4160 ClutterVertex v = { 0, 0, 0 };
4162 info = _clutter_actor_get_transform_info (self);
4167 g_object_freeze_notify (obj);
4171 case CLUTTER_X_AXIS:
4172 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4173 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4176 case CLUTTER_Y_AXIS:
4177 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4178 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4181 case CLUTTER_Z_AXIS:
4182 /* if the previously set rotation center was fractional, then
4183 * setting explicit coordinates will have to notify the
4184 * :rotation-center-z-gravity property as well
4186 if (info->rz_center.is_fractional)
4187 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4189 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4190 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4194 self->priv->transform_valid = FALSE;
4196 g_object_thaw_notify (obj);
4198 clutter_actor_queue_redraw (self);
4202 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4206 GObject *obj = G_OBJECT (self);
4207 ClutterTransformInfo *info;
4209 info = _clutter_actor_get_transform_info (self);
4211 if (pspec == obj_props[PROP_SCALE_X])
4212 info->scale_x = factor;
4214 info->scale_y = factor;
4216 self->priv->transform_valid = FALSE;
4217 clutter_actor_queue_redraw (self);
4218 g_object_notify_by_pspec (obj, pspec);
4222 clutter_actor_set_scale_factor (ClutterActor *self,
4223 ClutterRotateAxis axis,
4226 const ClutterTransformInfo *info;
4227 const double *scale_p = NULL;
4228 GParamSpec *pspec = NULL;
4230 info = _clutter_actor_get_transform_info_or_defaults (self);
4234 case CLUTTER_X_AXIS:
4235 pspec = obj_props[PROP_SCALE_X];
4236 scale_p = &info->scale_x;
4239 case CLUTTER_Y_AXIS:
4240 pspec = obj_props[PROP_SCALE_Y];
4241 scale_p = &info->scale_y;
4244 case CLUTTER_Z_AXIS:
4248 g_assert (pspec != NULL);
4249 g_assert (scale_p != NULL);
4251 if (_clutter_actor_get_transition (self, pspec) == NULL)
4252 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4254 _clutter_actor_update_transition (self, pspec, factor);
4256 clutter_actor_queue_redraw (self);
4260 clutter_actor_set_scale_center (ClutterActor *self,
4261 ClutterRotateAxis axis,
4264 GObject *obj = G_OBJECT (self);
4265 ClutterTransformInfo *info;
4266 gfloat center_x, center_y;
4268 info = _clutter_actor_get_transform_info (self);
4270 g_object_freeze_notify (obj);
4272 /* get the current scale center coordinates */
4273 clutter_anchor_coord_get_units (self, &info->scale_center,
4278 /* we need to notify this too, because setting explicit coordinates will
4279 * change the gravity as a side effect
4281 if (info->scale_center.is_fractional)
4282 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4286 case CLUTTER_X_AXIS:
4287 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4288 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4291 case CLUTTER_Y_AXIS:
4292 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4293 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4297 g_assert_not_reached ();
4300 self->priv->transform_valid = FALSE;
4302 clutter_actor_queue_redraw (self);
4304 g_object_thaw_notify (obj);
4308 clutter_actor_set_scale_gravity (ClutterActor *self,
4309 ClutterGravity gravity)
4311 ClutterTransformInfo *info;
4314 info = _clutter_actor_get_transform_info (self);
4315 obj = G_OBJECT (self);
4317 if (gravity == CLUTTER_GRAVITY_NONE)
4318 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4320 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4322 self->priv->transform_valid = FALSE;
4324 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4325 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4326 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4328 clutter_actor_queue_redraw (self);
4332 clutter_actor_set_anchor_coord (ClutterActor *self,
4333 ClutterRotateAxis axis,
4336 GObject *obj = G_OBJECT (self);
4337 ClutterTransformInfo *info;
4338 gfloat anchor_x, anchor_y;
4340 info = _clutter_actor_get_transform_info (self);
4342 g_object_freeze_notify (obj);
4344 clutter_anchor_coord_get_units (self, &info->anchor,
4349 if (info->anchor.is_fractional)
4350 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4354 case CLUTTER_X_AXIS:
4355 clutter_anchor_coord_set_units (&info->anchor,
4359 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4362 case CLUTTER_Y_AXIS:
4363 clutter_anchor_coord_set_units (&info->anchor,
4367 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4371 g_assert_not_reached ();
4374 self->priv->transform_valid = FALSE;
4376 clutter_actor_queue_redraw (self);
4378 g_object_thaw_notify (obj);
4382 clutter_actor_set_property (GObject *object,
4384 const GValue *value,
4387 ClutterActor *actor = CLUTTER_ACTOR (object);
4388 ClutterActorPrivate *priv = actor->priv;
4393 clutter_actor_set_x (actor, g_value_get_float (value));
4397 clutter_actor_set_y (actor, g_value_get_float (value));
4402 const ClutterPoint *pos = g_value_get_boxed (value);
4405 clutter_actor_set_position (actor, pos->x, pos->y);
4407 clutter_actor_set_fixed_position_set (actor, FALSE);
4412 clutter_actor_set_width (actor, g_value_get_float (value));
4416 clutter_actor_set_height (actor, g_value_get_float (value));
4421 const ClutterSize *size = g_value_get_boxed (value);
4424 clutter_actor_set_size (actor, size->width, size->height);
4426 clutter_actor_set_size (actor, -1, -1);
4431 clutter_actor_set_x (actor, g_value_get_float (value));
4435 clutter_actor_set_y (actor, g_value_get_float (value));
4438 case PROP_FIXED_POSITION_SET:
4439 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4442 case PROP_MIN_WIDTH:
4443 clutter_actor_set_min_width (actor, g_value_get_float (value));
4446 case PROP_MIN_HEIGHT:
4447 clutter_actor_set_min_height (actor, g_value_get_float (value));
4450 case PROP_NATURAL_WIDTH:
4451 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4454 case PROP_NATURAL_HEIGHT:
4455 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4458 case PROP_MIN_WIDTH_SET:
4459 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4462 case PROP_MIN_HEIGHT_SET:
4463 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4466 case PROP_NATURAL_WIDTH_SET:
4467 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4470 case PROP_NATURAL_HEIGHT_SET:
4471 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4474 case PROP_REQUEST_MODE:
4475 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4479 clutter_actor_set_depth (actor, g_value_get_float (value));
4483 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4486 case PROP_OFFSCREEN_REDIRECT:
4487 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4491 clutter_actor_set_name (actor, g_value_get_string (value));
4495 if (g_value_get_boolean (value) == TRUE)
4496 clutter_actor_show (actor);
4498 clutter_actor_hide (actor);
4502 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4503 g_value_get_double (value));
4507 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4508 g_value_get_double (value));
4511 case PROP_SCALE_CENTER_X:
4512 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4513 g_value_get_float (value));
4516 case PROP_SCALE_CENTER_Y:
4517 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4518 g_value_get_float (value));
4521 case PROP_SCALE_GRAVITY:
4522 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4527 const ClutterGeometry *geom = g_value_get_boxed (value);
4529 clutter_actor_set_clip (actor,
4531 geom->width, geom->height);
4535 case PROP_CLIP_TO_ALLOCATION:
4536 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4540 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4543 case PROP_ROTATION_ANGLE_X:
4544 clutter_actor_set_rotation_angle (actor,
4546 g_value_get_double (value));
4549 case PROP_ROTATION_ANGLE_Y:
4550 clutter_actor_set_rotation_angle (actor,
4552 g_value_get_double (value));
4555 case PROP_ROTATION_ANGLE_Z:
4556 clutter_actor_set_rotation_angle (actor,
4558 g_value_get_double (value));
4561 case PROP_ROTATION_CENTER_X:
4562 clutter_actor_set_rotation_center_internal (actor,
4564 g_value_get_boxed (value));
4567 case PROP_ROTATION_CENTER_Y:
4568 clutter_actor_set_rotation_center_internal (actor,
4570 g_value_get_boxed (value));
4573 case PROP_ROTATION_CENTER_Z:
4574 clutter_actor_set_rotation_center_internal (actor,
4576 g_value_get_boxed (value));
4579 case PROP_ROTATION_CENTER_Z_GRAVITY:
4581 const ClutterTransformInfo *info;
4583 info = _clutter_actor_get_transform_info_or_defaults (actor);
4584 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4585 g_value_get_enum (value));
4590 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4591 g_value_get_float (value));
4595 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4596 g_value_get_float (value));
4599 case PROP_ANCHOR_GRAVITY:
4600 clutter_actor_set_anchor_point_from_gravity (actor,
4601 g_value_get_enum (value));
4604 case PROP_SHOW_ON_SET_PARENT:
4605 priv->show_on_set_parent = g_value_get_boolean (value);
4608 case PROP_TEXT_DIRECTION:
4609 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4613 clutter_actor_add_action (actor, g_value_get_object (value));
4616 case PROP_CONSTRAINTS:
4617 clutter_actor_add_constraint (actor, g_value_get_object (value));
4621 clutter_actor_add_effect (actor, g_value_get_object (value));
4624 case PROP_LAYOUT_MANAGER:
4625 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4629 clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4633 clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4637 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4641 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4644 case PROP_MARGIN_TOP:
4645 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4648 case PROP_MARGIN_BOTTOM:
4649 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4652 case PROP_MARGIN_LEFT:
4653 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4656 case PROP_MARGIN_RIGHT:
4657 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4660 case PROP_BACKGROUND_COLOR:
4661 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4665 clutter_actor_set_content (actor, g_value_get_object (value));
4668 case PROP_CONTENT_GRAVITY:
4669 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4672 case PROP_MINIFICATION_FILTER:
4673 clutter_actor_set_content_scaling_filters (actor,
4674 g_value_get_enum (value),
4675 actor->priv->mag_filter);
4678 case PROP_MAGNIFICATION_FILTER:
4679 clutter_actor_set_content_scaling_filters (actor,
4680 actor->priv->min_filter,
4681 g_value_get_enum (value));
4685 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4691 clutter_actor_get_property (GObject *object,
4696 ClutterActor *actor = CLUTTER_ACTOR (object);
4697 ClutterActorPrivate *priv = actor->priv;
4702 g_value_set_float (value, clutter_actor_get_x (actor));
4706 g_value_set_float (value, clutter_actor_get_y (actor));
4711 ClutterPoint position;
4713 clutter_point_init (&position,
4714 clutter_actor_get_x (actor),
4715 clutter_actor_get_y (actor));
4716 g_value_set_boxed (value, &position);
4721 g_value_set_float (value, clutter_actor_get_width (actor));
4725 g_value_set_float (value, clutter_actor_get_height (actor));
4732 clutter_size_init (&size,
4733 clutter_actor_get_width (actor),
4734 clutter_actor_get_height (actor));
4735 g_value_set_boxed (value, &size);
4741 const ClutterLayoutInfo *info;
4743 info = _clutter_actor_get_layout_info_or_defaults (actor);
4744 g_value_set_float (value, info->fixed_pos.x);
4750 const ClutterLayoutInfo *info;
4752 info = _clutter_actor_get_layout_info_or_defaults (actor);
4753 g_value_set_float (value, info->fixed_pos.y);
4757 case PROP_FIXED_POSITION_SET:
4758 g_value_set_boolean (value, priv->position_set);
4761 case PROP_MIN_WIDTH:
4763 const ClutterLayoutInfo *info;
4765 info = _clutter_actor_get_layout_info_or_defaults (actor);
4766 g_value_set_float (value, info->minimum.width);
4770 case PROP_MIN_HEIGHT:
4772 const ClutterLayoutInfo *info;
4774 info = _clutter_actor_get_layout_info_or_defaults (actor);
4775 g_value_set_float (value, info->minimum.height);
4779 case PROP_NATURAL_WIDTH:
4781 const ClutterLayoutInfo *info;
4783 info = _clutter_actor_get_layout_info_or_defaults (actor);
4784 g_value_set_float (value, info->natural.width);
4788 case PROP_NATURAL_HEIGHT:
4790 const ClutterLayoutInfo *info;
4792 info = _clutter_actor_get_layout_info_or_defaults (actor);
4793 g_value_set_float (value, info->natural.height);
4797 case PROP_MIN_WIDTH_SET:
4798 g_value_set_boolean (value, priv->min_width_set);
4801 case PROP_MIN_HEIGHT_SET:
4802 g_value_set_boolean (value, priv->min_height_set);
4805 case PROP_NATURAL_WIDTH_SET:
4806 g_value_set_boolean (value, priv->natural_width_set);
4809 case PROP_NATURAL_HEIGHT_SET:
4810 g_value_set_boolean (value, priv->natural_height_set);
4813 case PROP_REQUEST_MODE:
4814 g_value_set_enum (value, priv->request_mode);
4817 case PROP_ALLOCATION:
4818 g_value_set_boxed (value, &priv->allocation);
4822 g_value_set_float (value, clutter_actor_get_depth (actor));
4826 g_value_set_uint (value, priv->opacity);
4829 case PROP_OFFSCREEN_REDIRECT:
4830 g_value_set_enum (value, priv->offscreen_redirect);
4834 g_value_set_string (value, priv->name);
4838 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4842 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4846 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4850 g_value_set_boolean (value, priv->has_clip);
4855 ClutterGeometry clip;
4857 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4858 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4859 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4860 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4862 g_value_set_boxed (value, &clip);
4866 case PROP_CLIP_TO_ALLOCATION:
4867 g_value_set_boolean (value, priv->clip_to_allocation);
4872 const ClutterTransformInfo *info;
4874 info = _clutter_actor_get_transform_info_or_defaults (actor);
4875 g_value_set_double (value, info->scale_x);
4881 const ClutterTransformInfo *info;
4883 info = _clutter_actor_get_transform_info_or_defaults (actor);
4884 g_value_set_double (value, info->scale_y);
4888 case PROP_SCALE_CENTER_X:
4892 clutter_actor_get_scale_center (actor, ¢er, NULL);
4894 g_value_set_float (value, center);
4898 case PROP_SCALE_CENTER_Y:
4902 clutter_actor_get_scale_center (actor, NULL, ¢er);
4904 g_value_set_float (value, center);
4908 case PROP_SCALE_GRAVITY:
4909 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4913 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4916 case PROP_ROTATION_ANGLE_X:
4918 const ClutterTransformInfo *info;
4920 info = _clutter_actor_get_transform_info_or_defaults (actor);
4921 g_value_set_double (value, info->rx_angle);
4925 case PROP_ROTATION_ANGLE_Y:
4927 const ClutterTransformInfo *info;
4929 info = _clutter_actor_get_transform_info_or_defaults (actor);
4930 g_value_set_double (value, info->ry_angle);
4934 case PROP_ROTATION_ANGLE_Z:
4936 const ClutterTransformInfo *info;
4938 info = _clutter_actor_get_transform_info_or_defaults (actor);
4939 g_value_set_double (value, info->rz_angle);
4943 case PROP_ROTATION_CENTER_X:
4945 ClutterVertex center;
4947 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4952 g_value_set_boxed (value, ¢er);
4956 case PROP_ROTATION_CENTER_Y:
4958 ClutterVertex center;
4960 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4965 g_value_set_boxed (value, ¢er);
4969 case PROP_ROTATION_CENTER_Z:
4971 ClutterVertex center;
4973 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4978 g_value_set_boxed (value, ¢er);
4982 case PROP_ROTATION_CENTER_Z_GRAVITY:
4983 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4988 const ClutterTransformInfo *info;
4991 info = _clutter_actor_get_transform_info_or_defaults (actor);
4992 clutter_anchor_coord_get_units (actor, &info->anchor,
4996 g_value_set_float (value, anchor_x);
5002 const ClutterTransformInfo *info;
5005 info = _clutter_actor_get_transform_info_or_defaults (actor);
5006 clutter_anchor_coord_get_units (actor, &info->anchor,
5010 g_value_set_float (value, anchor_y);
5014 case PROP_ANCHOR_GRAVITY:
5015 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5018 case PROP_SHOW_ON_SET_PARENT:
5019 g_value_set_boolean (value, priv->show_on_set_parent);
5022 case PROP_TEXT_DIRECTION:
5023 g_value_set_enum (value, priv->text_direction);
5026 case PROP_HAS_POINTER:
5027 g_value_set_boolean (value, priv->has_pointer);
5030 case PROP_LAYOUT_MANAGER:
5031 g_value_set_object (value, priv->layout_manager);
5036 const ClutterLayoutInfo *info;
5038 info = _clutter_actor_get_layout_info_or_defaults (actor);
5039 g_value_set_boolean (value, info->x_expand);
5045 const ClutterLayoutInfo *info;
5047 info = _clutter_actor_get_layout_info_or_defaults (actor);
5048 g_value_set_boolean (value, info->y_expand);
5054 const ClutterLayoutInfo *info;
5056 info = _clutter_actor_get_layout_info_or_defaults (actor);
5057 g_value_set_enum (value, info->x_align);
5063 const ClutterLayoutInfo *info;
5065 info = _clutter_actor_get_layout_info_or_defaults (actor);
5066 g_value_set_enum (value, info->y_align);
5070 case PROP_MARGIN_TOP:
5072 const ClutterLayoutInfo *info;
5074 info = _clutter_actor_get_layout_info_or_defaults (actor);
5075 g_value_set_float (value, info->margin.top);
5079 case PROP_MARGIN_BOTTOM:
5081 const ClutterLayoutInfo *info;
5083 info = _clutter_actor_get_layout_info_or_defaults (actor);
5084 g_value_set_float (value, info->margin.bottom);
5088 case PROP_MARGIN_LEFT:
5090 const ClutterLayoutInfo *info;
5092 info = _clutter_actor_get_layout_info_or_defaults (actor);
5093 g_value_set_float (value, info->margin.left);
5097 case PROP_MARGIN_RIGHT:
5099 const ClutterLayoutInfo *info;
5101 info = _clutter_actor_get_layout_info_or_defaults (actor);
5102 g_value_set_float (value, info->margin.right);
5106 case PROP_BACKGROUND_COLOR_SET:
5107 g_value_set_boolean (value, priv->bg_color_set);
5110 case PROP_BACKGROUND_COLOR:
5111 g_value_set_boxed (value, &priv->bg_color);
5114 case PROP_FIRST_CHILD:
5115 g_value_set_object (value, priv->first_child);
5118 case PROP_LAST_CHILD:
5119 g_value_set_object (value, priv->last_child);
5123 g_value_set_object (value, priv->content);
5126 case PROP_CONTENT_GRAVITY:
5127 g_value_set_enum (value, priv->content_gravity);
5130 case PROP_CONTENT_BOX:
5132 ClutterActorBox box = { 0, };
5134 clutter_actor_get_content_box (actor, &box);
5135 g_value_set_boxed (value, &box);
5139 case PROP_MINIFICATION_FILTER:
5140 g_value_set_enum (value, priv->min_filter);
5143 case PROP_MAGNIFICATION_FILTER:
5144 g_value_set_enum (value, priv->mag_filter);
5148 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5154 clutter_actor_dispose (GObject *object)
5156 ClutterActor *self = CLUTTER_ACTOR (object);
5157 ClutterActorPrivate *priv = self->priv;
5159 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5161 g_type_name (G_OBJECT_TYPE (self)),
5164 g_signal_emit (self, actor_signals[DESTROY], 0);
5166 /* avoid recursing when called from clutter_actor_destroy() */
5167 if (priv->parent != NULL)
5169 ClutterActor *parent = priv->parent;
5171 /* go through the Container implementation unless this
5172 * is an internal child and has been marked as such.
5174 * removing the actor from its parent will reset the
5175 * realized and mapped states.
5177 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5178 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5180 clutter_actor_remove_child_internal (parent, self,
5181 REMOVE_CHILD_LEGACY_FLAGS);
5184 /* parent must be gone at this point */
5185 g_assert (priv->parent == NULL);
5187 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5189 /* can't be mapped or realized with no parent */
5190 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5191 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5194 g_clear_object (&priv->pango_context);
5195 g_clear_object (&priv->actions);
5196 g_clear_object (&priv->constraints);
5197 g_clear_object (&priv->effects);
5198 g_clear_object (&priv->flatten_effect);
5200 if (priv->layout_manager != NULL)
5202 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5203 g_clear_object (&priv->layout_manager);
5206 if (priv->content != NULL)
5208 _clutter_content_detached (priv->content, self);
5209 g_clear_object (&priv->content);
5212 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5216 clutter_actor_finalize (GObject *object)
5218 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5220 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5221 priv->name != NULL ? priv->name : "<none>",
5223 g_type_name (G_OBJECT_TYPE (object)));
5225 _clutter_context_release_id (priv->id);
5227 g_free (priv->name);
5229 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5234 * clutter_actor_get_accessible:
5235 * @self: a #ClutterActor
5237 * Returns the accessible object that describes the actor to an
5238 * assistive technology.
5240 * If no class-specific #AtkObject implementation is available for the
5241 * actor instance in question, it will inherit an #AtkObject
5242 * implementation from the first ancestor class for which such an
5243 * implementation is defined.
5245 * The documentation of the <ulink
5246 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5247 * library contains more information about accessible objects and
5250 * Returns: (transfer none): the #AtkObject associated with @actor
5253 clutter_actor_get_accessible (ClutterActor *self)
5255 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5257 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5261 clutter_actor_real_get_accessible (ClutterActor *actor)
5263 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5267 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5269 AtkObject *accessible;
5271 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5272 if (accessible != NULL)
5273 g_object_ref (accessible);
5279 atk_implementor_iface_init (AtkImplementorIface *iface)
5281 iface->ref_accessible = _clutter_actor_ref_accessible;
5285 clutter_actor_update_default_paint_volume (ClutterActor *self,
5286 ClutterPaintVolume *volume)
5288 ClutterActorPrivate *priv = self->priv;
5289 gboolean res = TRUE;
5291 /* we start from the allocation */
5292 clutter_paint_volume_set_width (volume,
5293 priv->allocation.x2 - priv->allocation.x1);
5294 clutter_paint_volume_set_height (volume,
5295 priv->allocation.y2 - priv->allocation.y1);
5297 /* if the actor has a clip set then we have a pretty definite
5298 * size for the paint volume: the actor cannot possibly paint
5299 * outside the clip region.
5301 if (priv->clip_to_allocation)
5303 /* the allocation has already been set, so we just flip the
5310 ClutterActor *child;
5312 if (priv->has_clip &&
5313 priv->clip.width >= 0 &&
5314 priv->clip.height >= 0)
5316 ClutterVertex origin;
5318 origin.x = priv->clip.x;
5319 origin.y = priv->clip.y;
5322 clutter_paint_volume_set_origin (volume, &origin);
5323 clutter_paint_volume_set_width (volume, priv->clip.width);
5324 clutter_paint_volume_set_height (volume, priv->clip.height);
5329 /* if we don't have children we just bail out here... */
5330 if (priv->n_children == 0)
5333 /* ...but if we have children then we ask for their paint volume in
5334 * our coordinates. if any of our children replies that it doesn't
5335 * have a paint volume, we bail out
5337 for (child = priv->first_child;
5339 child = child->priv->next_sibling)
5341 const ClutterPaintVolume *child_volume;
5343 if (!CLUTTER_ACTOR_IS_MAPPED (child))
5346 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5347 if (child_volume == NULL)
5353 clutter_paint_volume_union (volume, child_volume);
5363 clutter_actor_real_get_paint_volume (ClutterActor *self,
5364 ClutterPaintVolume *volume)
5366 ClutterActorClass *klass;
5369 klass = CLUTTER_ACTOR_GET_CLASS (self);
5371 /* XXX - this thoroughly sucks, but we don't want to penalize users
5372 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5373 * redraw. This should go away in 2.0.
5375 if (klass->paint == clutter_actor_real_paint &&
5376 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5382 /* this is the default return value: we cannot know if a class
5383 * is going to paint outside its allocation, so we take the
5384 * conservative approach.
5389 /* update_default_paint_volume() should only fail if one of the children
5390 * reported an invalid, or no, paint volume
5392 if (!clutter_actor_update_default_paint_volume (self, volume))
5399 * clutter_actor_get_default_paint_volume:
5400 * @self: a #ClutterActor
5402 * Retrieves the default paint volume for @self.
5404 * This function provides the same #ClutterPaintVolume that would be
5405 * computed by the default implementation inside #ClutterActor of the
5406 * #ClutterActorClass.get_paint_volume() virtual function.
5408 * This function should only be used by #ClutterActor subclasses that
5409 * cannot chain up to the parent implementation when computing their
5412 * Return value: (transfer none): a pointer to the default
5413 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5414 * the actor could not compute a valid paint volume. The returned value
5415 * is not guaranteed to be stable across multiple frames, so if you
5416 * want to retain it, you will need to copy it using
5417 * clutter_paint_volume_copy().
5421 const ClutterPaintVolume *
5422 clutter_actor_get_default_paint_volume (ClutterActor *self)
5424 ClutterPaintVolume volume;
5425 ClutterPaintVolume *res;
5427 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5430 _clutter_paint_volume_init_static (&volume, self);
5431 if (clutter_actor_update_default_paint_volume (self, &volume))
5433 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5437 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5438 _clutter_paint_volume_copy_static (&volume, res);
5442 clutter_paint_volume_free (&volume);
5448 clutter_actor_real_has_overlaps (ClutterActor *self)
5450 /* By default we'll assume that all actors need an offscreen redirect to get
5451 * the correct opacity. Actors such as ClutterTexture that would never need
5452 * an offscreen redirect can override this to return FALSE. */
5457 clutter_actor_real_destroy (ClutterActor *actor)
5459 ClutterActorIter iter;
5461 g_object_freeze_notify (G_OBJECT (actor));
5463 clutter_actor_iter_init (&iter, actor);
5464 while (clutter_actor_iter_next (&iter, NULL))
5465 clutter_actor_iter_destroy (&iter);
5467 g_object_thaw_notify (G_OBJECT (actor));
5471 clutter_actor_constructor (GType gtype,
5473 GObjectConstructParam *props)
5475 GObjectClass *gobject_class;
5479 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5480 retval = gobject_class->constructor (gtype, n_props, props);
5481 self = CLUTTER_ACTOR (retval);
5483 if (self->priv->layout_manager == NULL)
5485 ClutterLayoutManager *default_layout;
5487 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5489 default_layout = clutter_fixed_layout_new ();
5490 clutter_actor_set_layout_manager (self, default_layout);
5497 clutter_actor_class_init (ClutterActorClass *klass)
5499 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5501 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5502 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5503 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5504 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5506 object_class->constructor = clutter_actor_constructor;
5507 object_class->set_property = clutter_actor_set_property;
5508 object_class->get_property = clutter_actor_get_property;
5509 object_class->dispose = clutter_actor_dispose;
5510 object_class->finalize = clutter_actor_finalize;
5512 klass->show = clutter_actor_real_show;
5513 klass->show_all = clutter_actor_show;
5514 klass->hide = clutter_actor_real_hide;
5515 klass->hide_all = clutter_actor_hide;
5516 klass->map = clutter_actor_real_map;
5517 klass->unmap = clutter_actor_real_unmap;
5518 klass->unrealize = clutter_actor_real_unrealize;
5519 klass->pick = clutter_actor_real_pick;
5520 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5521 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5522 klass->allocate = clutter_actor_real_allocate;
5523 klass->queue_redraw = clutter_actor_real_queue_redraw;
5524 klass->queue_relayout = clutter_actor_real_queue_relayout;
5525 klass->apply_transform = clutter_actor_real_apply_transform;
5526 klass->get_accessible = clutter_actor_real_get_accessible;
5527 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5528 klass->has_overlaps = clutter_actor_real_has_overlaps;
5529 klass->paint = clutter_actor_real_paint;
5530 klass->destroy = clutter_actor_real_destroy;
5532 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5537 * X coordinate of the actor in pixels. If written, forces a fixed
5538 * position for the actor. If read, returns the fixed position if any,
5539 * otherwise the allocation if available, otherwise 0.
5541 * The #ClutterActor:x property is animatable.
5544 g_param_spec_float ("x",
5546 P_("X coordinate of the actor"),
5547 -G_MAXFLOAT, G_MAXFLOAT,
5550 G_PARAM_STATIC_STRINGS |
5551 CLUTTER_PARAM_ANIMATABLE);
5556 * Y coordinate of the actor in pixels. If written, forces a fixed
5557 * position for the actor. If read, returns the fixed position if
5558 * any, otherwise the allocation if available, otherwise 0.
5560 * The #ClutterActor:y property is animatable.
5563 g_param_spec_float ("y",
5565 P_("Y coordinate of the actor"),
5566 -G_MAXFLOAT, G_MAXFLOAT,
5569 G_PARAM_STATIC_STRINGS |
5570 CLUTTER_PARAM_ANIMATABLE);
5573 * ClutterActor:position:
5575 * The position of the origin of the actor.
5577 * This property is a shorthand for setting and getting the
5578 * #ClutterActor:x and #ClutterActor:y properties at the same
5581 * The #ClutterActor:position property is animatable.
5585 obj_props[PROP_POSITION] =
5586 g_param_spec_boxed ("position",
5588 P_("The position of the origin of the actor"),
5591 G_PARAM_STATIC_STRINGS |
5592 CLUTTER_PARAM_ANIMATABLE);
5595 * ClutterActor:width:
5597 * Width of the actor (in pixels). If written, forces the minimum and
5598 * natural size request of the actor to the given width. If read, returns
5599 * the allocated width if available, otherwise the width request.
5601 * The #ClutterActor:width property is animatable.
5603 obj_props[PROP_WIDTH] =
5604 g_param_spec_float ("width",
5606 P_("Width of the actor"),
5610 G_PARAM_STATIC_STRINGS |
5611 CLUTTER_PARAM_ANIMATABLE);
5614 * ClutterActor:height:
5616 * Height of the actor (in pixels). If written, forces the minimum and
5617 * natural size request of the actor to the given height. If read, returns
5618 * the allocated height if available, otherwise the height request.
5620 * The #ClutterActor:height property is animatable.
5622 obj_props[PROP_HEIGHT] =
5623 g_param_spec_float ("height",
5625 P_("Height of the actor"),
5629 G_PARAM_STATIC_STRINGS |
5630 CLUTTER_PARAM_ANIMATABLE);
5633 * ClutterActor:size:
5635 * The size of the actor.
5637 * This property is a shorthand for setting and getting the
5638 * #ClutterActor:width and #ClutterActor:height at the same time.
5640 * The #ClutterActor:size property is animatable.
5644 obj_props[PROP_SIZE] =
5645 g_param_spec_boxed ("size",
5647 P_("The size of the actor"),
5650 G_PARAM_STATIC_STRINGS |
5651 CLUTTER_PARAM_ANIMATABLE);
5654 * ClutterActor:fixed-x:
5656 * The fixed X position of the actor in pixels.
5658 * Writing this property sets #ClutterActor:fixed-position-set
5659 * property as well, as a side effect
5663 obj_props[PROP_FIXED_X] =
5664 g_param_spec_float ("fixed-x",
5666 P_("Forced X position of the actor"),
5667 -G_MAXFLOAT, G_MAXFLOAT,
5669 CLUTTER_PARAM_READWRITE);
5672 * ClutterActor:fixed-y:
5674 * The fixed Y position of the actor in pixels.
5676 * Writing this property sets the #ClutterActor:fixed-position-set
5677 * property as well, as a side effect
5681 obj_props[PROP_FIXED_Y] =
5682 g_param_spec_float ("fixed-y",
5684 P_("Forced Y position of the actor"),
5685 -G_MAXFLOAT, G_MAXFLOAT,
5687 CLUTTER_PARAM_READWRITE);
5690 * ClutterActor:fixed-position-set:
5692 * This flag controls whether the #ClutterActor:fixed-x and
5693 * #ClutterActor:fixed-y properties are used
5697 obj_props[PROP_FIXED_POSITION_SET] =
5698 g_param_spec_boolean ("fixed-position-set",
5699 P_("Fixed position set"),
5700 P_("Whether to use fixed positioning for the actor"),
5702 CLUTTER_PARAM_READWRITE);
5705 * ClutterActor:min-width:
5707 * A forced minimum width request for the actor, in pixels
5709 * Writing this property sets the #ClutterActor:min-width-set property
5710 * as well, as a side effect.
5712 *This property overrides the usual width request of the actor.
5716 obj_props[PROP_MIN_WIDTH] =
5717 g_param_spec_float ("min-width",
5719 P_("Forced minimum width request for the actor"),
5722 CLUTTER_PARAM_READWRITE);
5725 * ClutterActor:min-height:
5727 * A forced minimum height request for the actor, in pixels
5729 * Writing this property sets the #ClutterActor:min-height-set property
5730 * as well, as a side effect. This property overrides the usual height
5731 * request of the actor.
5735 obj_props[PROP_MIN_HEIGHT] =
5736 g_param_spec_float ("min-height",
5738 P_("Forced minimum height request for the actor"),
5741 CLUTTER_PARAM_READWRITE);
5744 * ClutterActor:natural-width:
5746 * A forced natural width request for the actor, in pixels
5748 * Writing this property sets the #ClutterActor:natural-width-set
5749 * property as well, as a side effect. This property overrides the
5750 * usual width request of the actor
5754 obj_props[PROP_NATURAL_WIDTH] =
5755 g_param_spec_float ("natural-width",
5756 P_("Natural Width"),
5757 P_("Forced natural width request for the actor"),
5760 CLUTTER_PARAM_READWRITE);
5763 * ClutterActor:natural-height:
5765 * A forced natural height request for the actor, in pixels
5767 * Writing this property sets the #ClutterActor:natural-height-set
5768 * property as well, as a side effect. This property overrides the
5769 * usual height request of the actor
5773 obj_props[PROP_NATURAL_HEIGHT] =
5774 g_param_spec_float ("natural-height",
5775 P_("Natural Height"),
5776 P_("Forced natural height request for the actor"),
5779 CLUTTER_PARAM_READWRITE);
5782 * ClutterActor:min-width-set:
5784 * This flag controls whether the #ClutterActor:min-width property
5789 obj_props[PROP_MIN_WIDTH_SET] =
5790 g_param_spec_boolean ("min-width-set",
5791 P_("Minimum width set"),
5792 P_("Whether to use the min-width property"),
5794 CLUTTER_PARAM_READWRITE);
5797 * ClutterActor:min-height-set:
5799 * This flag controls whether the #ClutterActor:min-height property
5804 obj_props[PROP_MIN_HEIGHT_SET] =
5805 g_param_spec_boolean ("min-height-set",
5806 P_("Minimum height set"),
5807 P_("Whether to use the min-height property"),
5809 CLUTTER_PARAM_READWRITE);
5812 * ClutterActor:natural-width-set:
5814 * This flag controls whether the #ClutterActor:natural-width property
5819 obj_props[PROP_NATURAL_WIDTH_SET] =
5820 g_param_spec_boolean ("natural-width-set",
5821 P_("Natural width set"),
5822 P_("Whether to use the natural-width property"),
5824 CLUTTER_PARAM_READWRITE);
5827 * ClutterActor:natural-height-set:
5829 * This flag controls whether the #ClutterActor:natural-height property
5834 obj_props[PROP_NATURAL_HEIGHT_SET] =
5835 g_param_spec_boolean ("natural-height-set",
5836 P_("Natural height set"),
5837 P_("Whether to use the natural-height property"),
5839 CLUTTER_PARAM_READWRITE);
5842 * ClutterActor:allocation:
5844 * The allocation for the actor, in pixels
5846 * This is property is read-only, but you might monitor it to know when an
5847 * actor moves or resizes
5851 obj_props[PROP_ALLOCATION] =
5852 g_param_spec_boxed ("allocation",
5854 P_("The actor's allocation"),
5855 CLUTTER_TYPE_ACTOR_BOX,
5856 CLUTTER_PARAM_READABLE);
5859 * ClutterActor:request-mode:
5861 * Request mode for the #ClutterActor. The request mode determines the
5862 * type of geometry management used by the actor, either height for width
5863 * (the default) or width for height.
5865 * For actors implementing height for width, the parent container should get
5866 * the preferred width first, and then the preferred height for that width.
5868 * For actors implementing width for height, the parent container should get
5869 * the preferred height first, and then the preferred width for that height.
5874 * ClutterRequestMode mode;
5875 * gfloat natural_width, min_width;
5876 * gfloat natural_height, min_height;
5878 * mode = clutter_actor_get_request_mode (child);
5879 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5881 * clutter_actor_get_preferred_width (child, -1,
5883 * &natural_width);
5884 * clutter_actor_get_preferred_height (child, natural_width,
5886 * &natural_height);
5890 * clutter_actor_get_preferred_height (child, -1,
5892 * &natural_height);
5893 * clutter_actor_get_preferred_width (child, natural_height,
5895 * &natural_width);
5899 * will retrieve the minimum and natural width and height depending on the
5900 * preferred request mode of the #ClutterActor "child".
5902 * The clutter_actor_get_preferred_size() function will implement this
5907 obj_props[PROP_REQUEST_MODE] =
5908 g_param_spec_enum ("request-mode",
5910 P_("The actor's request mode"),
5911 CLUTTER_TYPE_REQUEST_MODE,
5912 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5913 CLUTTER_PARAM_READWRITE);
5916 * ClutterActor:depth:
5918 * The position of the actor on the Z axis.
5920 * The #ClutterActor:depth property is relative to the parent's
5923 * The #ClutterActor:depth property is animatable.
5927 obj_props[PROP_DEPTH] =
5928 g_param_spec_float ("depth",
5930 P_("Position on the Z axis"),
5931 -G_MAXFLOAT, G_MAXFLOAT,
5934 G_PARAM_STATIC_STRINGS |
5935 CLUTTER_PARAM_ANIMATABLE);
5938 * ClutterActor:opacity:
5940 * Opacity of an actor, between 0 (fully transparent) and
5941 * 255 (fully opaque)
5943 * The #ClutterActor:opacity property is animatable.
5945 obj_props[PROP_OPACITY] =
5946 g_param_spec_uint ("opacity",
5948 P_("Opacity of an actor"),
5952 G_PARAM_STATIC_STRINGS |
5953 CLUTTER_PARAM_ANIMATABLE);
5956 * ClutterActor:offscreen-redirect:
5958 * Determines the conditions in which the actor will be redirected
5959 * to an offscreen framebuffer while being painted. For example this
5960 * can be used to cache an actor in a framebuffer or for improved
5961 * handling of transparent actors. See
5962 * clutter_actor_set_offscreen_redirect() for details.
5966 obj_props[PROP_OFFSCREEN_REDIRECT] =
5967 g_param_spec_flags ("offscreen-redirect",
5968 P_("Offscreen redirect"),
5969 P_("Flags controlling when to flatten the actor into a single image"),
5970 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5972 CLUTTER_PARAM_READWRITE);
5975 * ClutterActor:visible:
5977 * Whether the actor is set to be visible or not
5979 * See also #ClutterActor:mapped
5981 obj_props[PROP_VISIBLE] =
5982 g_param_spec_boolean ("visible",
5984 P_("Whether the actor is visible or not"),
5986 CLUTTER_PARAM_READWRITE);
5989 * ClutterActor:mapped:
5991 * Whether the actor is mapped (will be painted when the stage
5992 * to which it belongs is mapped)
5996 obj_props[PROP_MAPPED] =
5997 g_param_spec_boolean ("mapped",
5999 P_("Whether the actor will be painted"),
6001 CLUTTER_PARAM_READABLE);
6004 * ClutterActor:realized:
6006 * Whether the actor has been realized
6010 obj_props[PROP_REALIZED] =
6011 g_param_spec_boolean ("realized",
6013 P_("Whether the actor has been realized"),
6015 CLUTTER_PARAM_READABLE);
6018 * ClutterActor:reactive:
6020 * Whether the actor is reactive to events or not
6022 * Only reactive actors will emit event-related signals
6026 obj_props[PROP_REACTIVE] =
6027 g_param_spec_boolean ("reactive",
6029 P_("Whether the actor is reactive to events"),
6031 CLUTTER_PARAM_READWRITE);
6034 * ClutterActor:has-clip:
6036 * Whether the actor has the #ClutterActor:clip property set or not
6038 obj_props[PROP_HAS_CLIP] =
6039 g_param_spec_boolean ("has-clip",
6041 P_("Whether the actor has a clip set"),
6043 CLUTTER_PARAM_READABLE);
6046 * ClutterActor:clip:
6048 * The clip region for the actor, in actor-relative coordinates
6050 * Every part of the actor outside the clip region will not be
6053 obj_props[PROP_CLIP] =
6054 g_param_spec_boxed ("clip",
6056 P_("The clip region for the actor"),
6057 CLUTTER_TYPE_GEOMETRY,
6058 CLUTTER_PARAM_READWRITE);
6061 * ClutterActor:name:
6063 * The name of the actor
6067 obj_props[PROP_NAME] =
6068 g_param_spec_string ("name",
6070 P_("Name of the actor"),
6072 CLUTTER_PARAM_READWRITE);
6075 * ClutterActor:scale-x:
6077 * The horizontal scale of the actor.
6079 * The #ClutterActor:scale-x property is animatable.
6083 obj_props[PROP_SCALE_X] =
6084 g_param_spec_double ("scale-x",
6086 P_("Scale factor on the X axis"),
6090 G_PARAM_STATIC_STRINGS |
6091 CLUTTER_PARAM_ANIMATABLE);
6094 * ClutterActor:scale-y:
6096 * The vertical scale of the actor.
6098 * The #ClutterActor:scale-y property is animatable.
6102 obj_props[PROP_SCALE_Y] =
6103 g_param_spec_double ("scale-y",
6105 P_("Scale factor on the Y axis"),
6109 G_PARAM_STATIC_STRINGS |
6110 CLUTTER_PARAM_ANIMATABLE);
6113 * ClutterActor:scale-center-x:
6115 * The horizontal center point for scaling
6119 obj_props[PROP_SCALE_CENTER_X] =
6120 g_param_spec_float ("scale-center-x",
6121 P_("Scale Center X"),
6122 P_("Horizontal scale center"),
6123 -G_MAXFLOAT, G_MAXFLOAT,
6125 CLUTTER_PARAM_READWRITE);
6128 * ClutterActor:scale-center-y:
6130 * The vertical center point for scaling
6134 obj_props[PROP_SCALE_CENTER_Y] =
6135 g_param_spec_float ("scale-center-y",
6136 P_("Scale Center Y"),
6137 P_("Vertical scale center"),
6138 -G_MAXFLOAT, G_MAXFLOAT,
6140 CLUTTER_PARAM_READWRITE);
6143 * ClutterActor:scale-gravity:
6145 * The center point for scaling expressed as a #ClutterGravity
6149 obj_props[PROP_SCALE_GRAVITY] =
6150 g_param_spec_enum ("scale-gravity",
6151 P_("Scale Gravity"),
6152 P_("The center of scaling"),
6153 CLUTTER_TYPE_GRAVITY,
6154 CLUTTER_GRAVITY_NONE,
6155 CLUTTER_PARAM_READWRITE);
6158 * ClutterActor:rotation-angle-x:
6160 * The rotation angle on the X axis.
6162 * The #ClutterActor:rotation-angle-x property is animatable.
6166 obj_props[PROP_ROTATION_ANGLE_X] =
6167 g_param_spec_double ("rotation-angle-x",
6168 P_("Rotation Angle X"),
6169 P_("The rotation angle on the X axis"),
6170 -G_MAXDOUBLE, G_MAXDOUBLE,
6173 G_PARAM_STATIC_STRINGS |
6174 CLUTTER_PARAM_ANIMATABLE);
6177 * ClutterActor:rotation-angle-y:
6179 * The rotation angle on the Y axis
6181 * The #ClutterActor:rotation-angle-y property is animatable.
6185 obj_props[PROP_ROTATION_ANGLE_Y] =
6186 g_param_spec_double ("rotation-angle-y",
6187 P_("Rotation Angle Y"),
6188 P_("The rotation angle on the Y axis"),
6189 -G_MAXDOUBLE, G_MAXDOUBLE,
6192 G_PARAM_STATIC_STRINGS |
6193 CLUTTER_PARAM_ANIMATABLE);
6196 * ClutterActor:rotation-angle-z:
6198 * The rotation angle on the Z axis
6200 * The #ClutterActor:rotation-angle-z property is animatable.
6204 obj_props[PROP_ROTATION_ANGLE_Z] =
6205 g_param_spec_double ("rotation-angle-z",
6206 P_("Rotation Angle Z"),
6207 P_("The rotation angle on the Z axis"),
6208 -G_MAXDOUBLE, G_MAXDOUBLE,
6211 G_PARAM_STATIC_STRINGS |
6212 CLUTTER_PARAM_ANIMATABLE);
6215 * ClutterActor:rotation-center-x:
6217 * The rotation center on the X axis.
6221 obj_props[PROP_ROTATION_CENTER_X] =
6222 g_param_spec_boxed ("rotation-center-x",
6223 P_("Rotation Center X"),
6224 P_("The rotation center on the X axis"),
6225 CLUTTER_TYPE_VERTEX,
6226 CLUTTER_PARAM_READWRITE);
6229 * ClutterActor:rotation-center-y:
6231 * The rotation center on the Y axis.
6235 obj_props[PROP_ROTATION_CENTER_Y] =
6236 g_param_spec_boxed ("rotation-center-y",
6237 P_("Rotation Center Y"),
6238 P_("The rotation center on the Y axis"),
6239 CLUTTER_TYPE_VERTEX,
6240 CLUTTER_PARAM_READWRITE);
6243 * ClutterActor:rotation-center-z:
6245 * The rotation center on the Z axis.
6249 obj_props[PROP_ROTATION_CENTER_Z] =
6250 g_param_spec_boxed ("rotation-center-z",
6251 P_("Rotation Center Z"),
6252 P_("The rotation center on the Z axis"),
6253 CLUTTER_TYPE_VERTEX,
6254 CLUTTER_PARAM_READWRITE);
6257 * ClutterActor:rotation-center-z-gravity:
6259 * The rotation center on the Z axis expressed as a #ClutterGravity.
6263 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6264 g_param_spec_enum ("rotation-center-z-gravity",
6265 P_("Rotation Center Z Gravity"),
6266 P_("Center point for rotation around the Z axis"),
6267 CLUTTER_TYPE_GRAVITY,
6268 CLUTTER_GRAVITY_NONE,
6269 CLUTTER_PARAM_READWRITE);
6272 * ClutterActor:anchor-x:
6274 * The X coordinate of an actor's anchor point, relative to
6275 * the actor coordinate space, in pixels
6279 obj_props[PROP_ANCHOR_X] =
6280 g_param_spec_float ("anchor-x",
6282 P_("X coordinate of the anchor point"),
6283 -G_MAXFLOAT, G_MAXFLOAT,
6285 CLUTTER_PARAM_READWRITE);
6288 * ClutterActor:anchor-y:
6290 * The Y coordinate of an actor's anchor point, relative to
6291 * the actor coordinate space, in pixels
6295 obj_props[PROP_ANCHOR_Y] =
6296 g_param_spec_float ("anchor-y",
6298 P_("Y coordinate of the anchor point"),
6299 -G_MAXFLOAT, G_MAXFLOAT,
6301 CLUTTER_PARAM_READWRITE);
6304 * ClutterActor:anchor-gravity:
6306 * The anchor point expressed as a #ClutterGravity
6310 obj_props[PROP_ANCHOR_GRAVITY] =
6311 g_param_spec_enum ("anchor-gravity",
6312 P_("Anchor Gravity"),
6313 P_("The anchor point as a ClutterGravity"),
6314 CLUTTER_TYPE_GRAVITY,
6315 CLUTTER_GRAVITY_NONE,
6316 CLUTTER_PARAM_READWRITE);
6319 * ClutterActor:show-on-set-parent:
6321 * If %TRUE, the actor is automatically shown when parented.
6323 * Calling clutter_actor_hide() on an actor which has not been
6324 * parented will set this property to %FALSE as a side effect.
6328 obj_props[PROP_SHOW_ON_SET_PARENT] =
6329 g_param_spec_boolean ("show-on-set-parent",
6330 P_("Show on set parent"),
6331 P_("Whether the actor is shown when parented"),
6333 CLUTTER_PARAM_READWRITE);
6336 * ClutterActor:clip-to-allocation:
6338 * Whether the clip region should track the allocated area
6341 * This property is ignored if a clip area has been explicitly
6342 * set using clutter_actor_set_clip().
6346 obj_props[PROP_CLIP_TO_ALLOCATION] =
6347 g_param_spec_boolean ("clip-to-allocation",
6348 P_("Clip to Allocation"),
6349 P_("Sets the clip region to track the actor's allocation"),
6351 CLUTTER_PARAM_READWRITE);
6354 * ClutterActor:text-direction:
6356 * The direction of the text inside a #ClutterActor.
6360 obj_props[PROP_TEXT_DIRECTION] =
6361 g_param_spec_enum ("text-direction",
6362 P_("Text Direction"),
6363 P_("Direction of the text"),
6364 CLUTTER_TYPE_TEXT_DIRECTION,
6365 CLUTTER_TEXT_DIRECTION_LTR,
6366 CLUTTER_PARAM_READWRITE);
6369 * ClutterActor:has-pointer:
6371 * Whether the actor contains the pointer of a #ClutterInputDevice
6376 obj_props[PROP_HAS_POINTER] =
6377 g_param_spec_boolean ("has-pointer",
6379 P_("Whether the actor contains the pointer of an input device"),
6381 CLUTTER_PARAM_READABLE);
6384 * ClutterActor:actions:
6386 * Adds a #ClutterAction to the actor
6390 obj_props[PROP_ACTIONS] =
6391 g_param_spec_object ("actions",
6393 P_("Adds an action to the actor"),
6394 CLUTTER_TYPE_ACTION,
6395 CLUTTER_PARAM_WRITABLE);
6398 * ClutterActor:constraints:
6400 * Adds a #ClutterConstraint to the actor
6404 obj_props[PROP_CONSTRAINTS] =
6405 g_param_spec_object ("constraints",
6407 P_("Adds a constraint to the actor"),
6408 CLUTTER_TYPE_CONSTRAINT,
6409 CLUTTER_PARAM_WRITABLE);
6412 * ClutterActor:effect:
6414 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6418 obj_props[PROP_EFFECT] =
6419 g_param_spec_object ("effect",
6421 P_("Add an effect to be applied on the actor"),
6422 CLUTTER_TYPE_EFFECT,
6423 CLUTTER_PARAM_WRITABLE);
6426 * ClutterActor:layout-manager:
6428 * A delegate object for controlling the layout of the children of
6433 obj_props[PROP_LAYOUT_MANAGER] =
6434 g_param_spec_object ("layout-manager",
6435 P_("Layout Manager"),
6436 P_("The object controlling the layout of an actor's children"),
6437 CLUTTER_TYPE_LAYOUT_MANAGER,
6438 CLUTTER_PARAM_READWRITE);
6441 * ClutterActor:x-expand:
6443 * Whether a layout manager should assign more space to the actor on
6448 obj_props[PROP_X_EXPAND] =
6449 g_param_spec_boolean ("x-expand",
6451 P_("Whether extra horizontal space should be assigned to the actor"),
6454 G_PARAM_STATIC_STRINGS);
6457 * ClutterActor:y-expand:
6459 * Whether a layout manager should assign more space to the actor on
6464 obj_props[PROP_Y_EXPAND] =
6465 g_param_spec_boolean ("y-expand",
6467 P_("Whether extra vertical space should be assigned to the actor"),
6470 G_PARAM_STATIC_STRINGS);
6473 * ClutterActor:x-align:
6475 * The alignment of an actor on the X axis, if the actor has been given
6476 * extra space for its allocation. See also the #ClutterActor:x-expand
6481 obj_props[PROP_X_ALIGN] =
6482 g_param_spec_enum ("x-align",
6484 P_("The alignment of the actor on the X axis within its allocation"),
6485 CLUTTER_TYPE_ACTOR_ALIGN,
6486 CLUTTER_ACTOR_ALIGN_FILL,
6487 CLUTTER_PARAM_READWRITE);
6490 * ClutterActor:y-align:
6492 * The alignment of an actor on the Y axis, if the actor has been given
6493 * extra space for its allocation.
6497 obj_props[PROP_Y_ALIGN] =
6498 g_param_spec_enum ("y-align",
6500 P_("The alignment of the actor on the Y axis within its allocation"),
6501 CLUTTER_TYPE_ACTOR_ALIGN,
6502 CLUTTER_ACTOR_ALIGN_FILL,
6503 CLUTTER_PARAM_READWRITE);
6506 * ClutterActor:margin-top:
6508 * The margin (in pixels) from the top of the actor.
6510 * This property adds a margin to the actor's preferred size; the margin
6511 * will be automatically taken into account when allocating the actor.
6515 obj_props[PROP_MARGIN_TOP] =
6516 g_param_spec_float ("margin-top",
6518 P_("Extra space at the top"),
6521 CLUTTER_PARAM_READWRITE);
6524 * ClutterActor:margin-bottom:
6526 * The margin (in pixels) from the bottom of the actor.
6528 * This property adds a margin to the actor's preferred size; the margin
6529 * will be automatically taken into account when allocating the actor.
6533 obj_props[PROP_MARGIN_BOTTOM] =
6534 g_param_spec_float ("margin-bottom",
6535 P_("Margin Bottom"),
6536 P_("Extra space at the bottom"),
6539 CLUTTER_PARAM_READWRITE);
6542 * ClutterActor:margin-left:
6544 * The margin (in pixels) from the left of the actor.
6546 * This property adds a margin to the actor's preferred size; the margin
6547 * will be automatically taken into account when allocating the actor.
6551 obj_props[PROP_MARGIN_LEFT] =
6552 g_param_spec_float ("margin-left",
6554 P_("Extra space at the left"),
6557 CLUTTER_PARAM_READWRITE);
6560 * ClutterActor:margin-right:
6562 * The margin (in pixels) from the right of the actor.
6564 * This property adds a margin to the actor's preferred size; the margin
6565 * will be automatically taken into account when allocating the actor.
6569 obj_props[PROP_MARGIN_RIGHT] =
6570 g_param_spec_float ("margin-right",
6572 P_("Extra space at the right"),
6575 CLUTTER_PARAM_READWRITE);
6578 * ClutterActor:background-color-set:
6580 * Whether the #ClutterActor:background-color property has been set.
6584 obj_props[PROP_BACKGROUND_COLOR_SET] =
6585 g_param_spec_boolean ("background-color-set",
6586 P_("Background Color Set"),
6587 P_("Whether the background color is set"),
6589 CLUTTER_PARAM_READABLE);
6592 * ClutterActor:background-color:
6594 * Paints a solid fill of the actor's allocation using the specified
6597 * The #ClutterActor:background-color property is animatable.
6601 obj_props[PROP_BACKGROUND_COLOR] =
6602 clutter_param_spec_color ("background-color",
6603 P_("Background color"),
6604 P_("The actor's background color"),
6605 CLUTTER_COLOR_Transparent,
6607 G_PARAM_STATIC_STRINGS |
6608 CLUTTER_PARAM_ANIMATABLE);
6611 * ClutterActor:first-child:
6613 * The actor's first child.
6617 obj_props[PROP_FIRST_CHILD] =
6618 g_param_spec_object ("first-child",
6620 P_("The actor's first child"),
6622 CLUTTER_PARAM_READABLE);
6625 * ClutterActor:last-child:
6627 * The actor's last child.
6631 obj_props[PROP_LAST_CHILD] =
6632 g_param_spec_object ("last-child",
6634 P_("The actor's last child"),
6636 CLUTTER_PARAM_READABLE);
6639 * ClutterActor:content:
6641 * The #ClutterContent implementation that controls the content
6646 obj_props[PROP_CONTENT] =
6647 g_param_spec_object ("content",
6649 P_("Delegate object for painting the actor's content"),
6650 CLUTTER_TYPE_CONTENT,
6651 CLUTTER_PARAM_READWRITE);
6654 * ClutterActor:content-gravity:
6656 * The alignment that should be honoured by the #ClutterContent
6657 * set with the #ClutterActor:content property.
6659 * Changing the value of this property will change the bounding box of
6660 * the content; you can use the #ClutterActor:content-box property to
6661 * get the position and size of the content within the actor's
6664 * This property is meaningful only for #ClutterContent implementations
6665 * that have a preferred size, and if the preferred size is smaller than
6666 * the actor's allocation.
6668 * The #ClutterActor:content-gravity property is animatable.
6672 obj_props[PROP_CONTENT_GRAVITY] =
6673 g_param_spec_enum ("content-gravity",
6674 P_("Content Gravity"),
6675 P_("Alignment of the actor's content"),
6676 CLUTTER_TYPE_CONTENT_GRAVITY,
6677 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6678 CLUTTER_PARAM_READWRITE);
6681 * ClutterActor:content-box:
6683 * The bounding box for the #ClutterContent used by the actor.
6685 * The value of this property is controlled by the #ClutterActor:allocation
6686 * and #ClutterActor:content-gravity properties of #ClutterActor.
6688 * The bounding box for the content is guaranteed to never exceed the
6689 * allocation's of the actor.
6693 obj_props[PROP_CONTENT_BOX] =
6694 g_param_spec_boxed ("content-box",
6696 P_("The bounding box of the actor's content"),
6697 CLUTTER_TYPE_ACTOR_BOX,
6699 G_PARAM_STATIC_STRINGS |
6700 CLUTTER_PARAM_ANIMATABLE);
6702 obj_props[PROP_MINIFICATION_FILTER] =
6703 g_param_spec_enum ("minification-filter",
6704 P_("Minification Filter"),
6705 P_("The filter used when reducing the size of the content"),
6706 CLUTTER_TYPE_SCALING_FILTER,
6707 CLUTTER_SCALING_FILTER_LINEAR,
6708 CLUTTER_PARAM_READWRITE);
6710 obj_props[PROP_MAGNIFICATION_FILTER] =
6711 g_param_spec_enum ("magnification-filter",
6712 P_("Magnification Filter"),
6713 P_("The filter used when increasing the size of the content"),
6714 CLUTTER_TYPE_SCALING_FILTER,
6715 CLUTTER_SCALING_FILTER_LINEAR,
6716 CLUTTER_PARAM_READWRITE);
6718 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6721 * ClutterActor::destroy:
6722 * @actor: the #ClutterActor which emitted the signal
6724 * The ::destroy signal notifies that all references held on the
6725 * actor which emitted it should be released.
6727 * The ::destroy signal should be used by all holders of a reference
6730 * This signal might result in the finalization of the #ClutterActor
6731 * if all references are released.
6733 * Composite actors and actors implementing the #ClutterContainer
6734 * interface should override the default implementation of the
6735 * class handler of this signal and call clutter_actor_destroy() on
6736 * their children. When overriding the default class handler, it is
6737 * required to chain up to the parent's implementation.
6741 actor_signals[DESTROY] =
6742 g_signal_new (I_("destroy"),
6743 G_TYPE_FROM_CLASS (object_class),
6744 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6745 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6747 _clutter_marshal_VOID__VOID,
6750 * ClutterActor::show:
6751 * @actor: the object which received the signal
6753 * The ::show signal is emitted when an actor is visible and
6754 * rendered on the stage.
6758 actor_signals[SHOW] =
6759 g_signal_new (I_("show"),
6760 G_TYPE_FROM_CLASS (object_class),
6762 G_STRUCT_OFFSET (ClutterActorClass, show),
6764 _clutter_marshal_VOID__VOID,
6767 * ClutterActor::hide:
6768 * @actor: the object which received the signal
6770 * The ::hide signal is emitted when an actor is no longer rendered
6775 actor_signals[HIDE] =
6776 g_signal_new (I_("hide"),
6777 G_TYPE_FROM_CLASS (object_class),
6779 G_STRUCT_OFFSET (ClutterActorClass, hide),
6781 _clutter_marshal_VOID__VOID,
6784 * ClutterActor::parent-set:
6785 * @actor: the object which received the signal
6786 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6788 * This signal is emitted when the parent of the actor changes.
6792 actor_signals[PARENT_SET] =
6793 g_signal_new (I_("parent-set"),
6794 G_TYPE_FROM_CLASS (object_class),
6796 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6798 _clutter_marshal_VOID__OBJECT,
6800 CLUTTER_TYPE_ACTOR);
6803 * ClutterActor::queue-redraw:
6804 * @actor: the actor we're bubbling the redraw request through
6805 * @origin: the actor which initiated the redraw request
6807 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6808 * is called on @origin.
6810 * The default implementation for #ClutterActor chains up to the
6811 * parent actor and queues a redraw on the parent, thus "bubbling"
6812 * the redraw queue up through the actor graph. The default
6813 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6814 * in a main loop idle handler.
6816 * Note that the @origin actor may be the stage, or a container; it
6817 * does not have to be a leaf node in the actor graph.
6819 * Toolkits embedding a #ClutterStage which require a redraw and
6820 * relayout cycle can stop the emission of this signal using the
6821 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6826 * on_redraw_complete (gpointer data)
6828 * ClutterStage *stage = data;
6830 * /* execute the Clutter drawing pipeline */
6831 * clutter_stage_ensure_redraw (stage);
6835 * on_stage_queue_redraw (ClutterStage *stage)
6837 * /* this prevents the default handler to run */
6838 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6840 * /* queue a redraw with the host toolkit and call
6841 * * a function when the redraw has been completed
6843 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6847 * <note><para>This signal is emitted before the Clutter paint
6848 * pipeline is executed. If you want to know when the pipeline has
6849 * been completed you should connect to the ::paint signal on the
6850 * Stage with g_signal_connect_after().</para></note>
6854 actor_signals[QUEUE_REDRAW] =
6855 g_signal_new (I_("queue-redraw"),
6856 G_TYPE_FROM_CLASS (object_class),
6859 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6861 _clutter_marshal_VOID__OBJECT,
6863 CLUTTER_TYPE_ACTOR);
6866 * ClutterActor::queue-relayout
6867 * @actor: the actor being queued for relayout
6869 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6870 * is called on an actor.
6872 * The default implementation for #ClutterActor chains up to the
6873 * parent actor and queues a relayout on the parent, thus "bubbling"
6874 * the relayout queue up through the actor graph.
6876 * The main purpose of this signal is to allow relayout to be propagated
6877 * properly in the procense of #ClutterClone actors. Applications will
6878 * not normally need to connect to this signal.
6882 actor_signals[QUEUE_RELAYOUT] =
6883 g_signal_new (I_("queue-relayout"),
6884 G_TYPE_FROM_CLASS (object_class),
6887 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6889 _clutter_marshal_VOID__VOID,
6893 * ClutterActor::event:
6894 * @actor: the actor which received the event
6895 * @event: a #ClutterEvent
6897 * The ::event signal is emitted each time an event is received
6898 * by the @actor. This signal will be emitted on every actor,
6899 * following the hierarchy chain, until it reaches the top-level
6900 * container (the #ClutterStage).
6902 * Return value: %TRUE if the event has been handled by the actor,
6903 * or %FALSE to continue the emission.
6907 actor_signals[EVENT] =
6908 g_signal_new (I_("event"),
6909 G_TYPE_FROM_CLASS (object_class),
6911 G_STRUCT_OFFSET (ClutterActorClass, event),
6912 _clutter_boolean_handled_accumulator, NULL,
6913 _clutter_marshal_BOOLEAN__BOXED,
6915 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6917 * ClutterActor::button-press-event:
6918 * @actor: the actor which received the event
6919 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6921 * The ::button-press-event signal is emitted each time a mouse button
6922 * is pressed on @actor.
6924 * Return value: %TRUE if the event has been handled by the actor,
6925 * or %FALSE to continue the emission.
6929 actor_signals[BUTTON_PRESS_EVENT] =
6930 g_signal_new (I_("button-press-event"),
6931 G_TYPE_FROM_CLASS (object_class),
6933 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6934 _clutter_boolean_handled_accumulator, NULL,
6935 _clutter_marshal_BOOLEAN__BOXED,
6937 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6939 * ClutterActor::button-release-event:
6940 * @actor: the actor which received the event
6941 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6943 * The ::button-release-event signal is emitted each time a mouse button
6944 * is released on @actor.
6946 * Return value: %TRUE if the event has been handled by the actor,
6947 * or %FALSE to continue the emission.
6951 actor_signals[BUTTON_RELEASE_EVENT] =
6952 g_signal_new (I_("button-release-event"),
6953 G_TYPE_FROM_CLASS (object_class),
6955 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6956 _clutter_boolean_handled_accumulator, NULL,
6957 _clutter_marshal_BOOLEAN__BOXED,
6959 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6961 * ClutterActor::scroll-event:
6962 * @actor: the actor which received the event
6963 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6965 * The ::scroll-event signal is emitted each time the mouse is
6966 * scrolled on @actor
6968 * Return value: %TRUE if the event has been handled by the actor,
6969 * or %FALSE to continue the emission.
6973 actor_signals[SCROLL_EVENT] =
6974 g_signal_new (I_("scroll-event"),
6975 G_TYPE_FROM_CLASS (object_class),
6977 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6978 _clutter_boolean_handled_accumulator, NULL,
6979 _clutter_marshal_BOOLEAN__BOXED,
6981 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6983 * ClutterActor::key-press-event:
6984 * @actor: the actor which received the event
6985 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6987 * The ::key-press-event signal is emitted each time a keyboard button
6988 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6990 * Return value: %TRUE if the event has been handled by the actor,
6991 * or %FALSE to continue the emission.
6995 actor_signals[KEY_PRESS_EVENT] =
6996 g_signal_new (I_("key-press-event"),
6997 G_TYPE_FROM_CLASS (object_class),
6999 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7000 _clutter_boolean_handled_accumulator, NULL,
7001 _clutter_marshal_BOOLEAN__BOXED,
7003 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7005 * ClutterActor::key-release-event:
7006 * @actor: the actor which received the event
7007 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7009 * The ::key-release-event signal is emitted each time a keyboard button
7010 * is released while @actor has key focus (see
7011 * clutter_stage_set_key_focus()).
7013 * Return value: %TRUE if the event has been handled by the actor,
7014 * or %FALSE to continue the emission.
7018 actor_signals[KEY_RELEASE_EVENT] =
7019 g_signal_new (I_("key-release-event"),
7020 G_TYPE_FROM_CLASS (object_class),
7022 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7023 _clutter_boolean_handled_accumulator, NULL,
7024 _clutter_marshal_BOOLEAN__BOXED,
7026 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7028 * ClutterActor::motion-event:
7029 * @actor: the actor which received the event
7030 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7032 * The ::motion-event signal is emitted each time the mouse pointer is
7033 * moved over @actor.
7035 * Return value: %TRUE if the event has been handled by the actor,
7036 * or %FALSE to continue the emission.
7040 actor_signals[MOTION_EVENT] =
7041 g_signal_new (I_("motion-event"),
7042 G_TYPE_FROM_CLASS (object_class),
7044 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7045 _clutter_boolean_handled_accumulator, NULL,
7046 _clutter_marshal_BOOLEAN__BOXED,
7048 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7051 * ClutterActor::key-focus-in:
7052 * @actor: the actor which now has key focus
7054 * The ::key-focus-in signal is emitted when @actor receives key focus.
7058 actor_signals[KEY_FOCUS_IN] =
7059 g_signal_new (I_("key-focus-in"),
7060 G_TYPE_FROM_CLASS (object_class),
7062 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7064 _clutter_marshal_VOID__VOID,
7068 * ClutterActor::key-focus-out:
7069 * @actor: the actor which now has key focus
7071 * The ::key-focus-out signal is emitted when @actor loses key focus.
7075 actor_signals[KEY_FOCUS_OUT] =
7076 g_signal_new (I_("key-focus-out"),
7077 G_TYPE_FROM_CLASS (object_class),
7079 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7081 _clutter_marshal_VOID__VOID,
7085 * ClutterActor::enter-event:
7086 * @actor: the actor which the pointer has entered.
7087 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7089 * The ::enter-event signal is emitted when the pointer enters the @actor
7091 * Return value: %TRUE if the event has been handled by the actor,
7092 * or %FALSE to continue the emission.
7096 actor_signals[ENTER_EVENT] =
7097 g_signal_new (I_("enter-event"),
7098 G_TYPE_FROM_CLASS (object_class),
7100 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7101 _clutter_boolean_handled_accumulator, NULL,
7102 _clutter_marshal_BOOLEAN__BOXED,
7104 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7107 * ClutterActor::leave-event:
7108 * @actor: the actor which the pointer has left
7109 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7111 * The ::leave-event signal is emitted when the pointer leaves the @actor.
7113 * Return value: %TRUE if the event has been handled by the actor,
7114 * or %FALSE to continue the emission.
7118 actor_signals[LEAVE_EVENT] =
7119 g_signal_new (I_("leave-event"),
7120 G_TYPE_FROM_CLASS (object_class),
7122 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7123 _clutter_boolean_handled_accumulator, NULL,
7124 _clutter_marshal_BOOLEAN__BOXED,
7126 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7129 * ClutterActor::captured-event:
7130 * @actor: the actor which received the signal
7131 * @event: a #ClutterEvent
7133 * The ::captured-event signal is emitted when an event is captured
7134 * by Clutter. This signal will be emitted starting from the top-level
7135 * container (the #ClutterStage) to the actor which received the event
7136 * going down the hierarchy. This signal can be used to intercept every
7137 * event before the specialized events (like
7138 * ClutterActor::button-press-event or ::key-released-event) are
7141 * Return value: %TRUE if the event has been handled by the actor,
7142 * or %FALSE to continue the emission.
7146 actor_signals[CAPTURED_EVENT] =
7147 g_signal_new (I_("captured-event"),
7148 G_TYPE_FROM_CLASS (object_class),
7150 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7151 _clutter_boolean_handled_accumulator, NULL,
7152 _clutter_marshal_BOOLEAN__BOXED,
7154 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7157 * ClutterActor::paint:
7158 * @actor: the #ClutterActor that received the signal
7160 * The ::paint signal is emitted each time an actor is being painted.
7162 * Subclasses of #ClutterActor should override the class signal handler
7163 * and paint themselves in that function.
7165 * It is possible to connect a handler to the ::paint signal in order
7166 * to set up some custom aspect of a paint.
7170 actor_signals[PAINT] =
7171 g_signal_new (I_("paint"),
7172 G_TYPE_FROM_CLASS (object_class),
7175 G_STRUCT_OFFSET (ClutterActorClass, paint),
7177 _clutter_marshal_VOID__VOID,
7180 * ClutterActor::realize:
7181 * @actor: the #ClutterActor that received the signal
7183 * The ::realize signal is emitted each time an actor is being
7188 actor_signals[REALIZE] =
7189 g_signal_new (I_("realize"),
7190 G_TYPE_FROM_CLASS (object_class),
7192 G_STRUCT_OFFSET (ClutterActorClass, realize),
7194 _clutter_marshal_VOID__VOID,
7197 * ClutterActor::unrealize:
7198 * @actor: the #ClutterActor that received the signal
7200 * The ::unrealize signal is emitted each time an actor is being
7205 actor_signals[UNREALIZE] =
7206 g_signal_new (I_("unrealize"),
7207 G_TYPE_FROM_CLASS (object_class),
7209 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7211 _clutter_marshal_VOID__VOID,
7215 * ClutterActor::pick:
7216 * @actor: the #ClutterActor that received the signal
7217 * @color: the #ClutterColor to be used when picking
7219 * The ::pick signal is emitted each time an actor is being painted
7220 * in "pick mode". The pick mode is used to identify the actor during
7221 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7222 * The actor should paint its shape using the passed @pick_color.
7224 * Subclasses of #ClutterActor should override the class signal handler
7225 * and paint themselves in that function.
7227 * It is possible to connect a handler to the ::pick signal in order
7228 * to set up some custom aspect of a paint in pick mode.
7232 actor_signals[PICK] =
7233 g_signal_new (I_("pick"),
7234 G_TYPE_FROM_CLASS (object_class),
7236 G_STRUCT_OFFSET (ClutterActorClass, pick),
7238 _clutter_marshal_VOID__BOXED,
7240 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7243 * ClutterActor::allocation-changed:
7244 * @actor: the #ClutterActor that emitted the signal
7245 * @box: a #ClutterActorBox with the new allocation
7246 * @flags: #ClutterAllocationFlags for the allocation
7248 * The ::allocation-changed signal is emitted when the
7249 * #ClutterActor:allocation property changes. Usually, application
7250 * code should just use the notifications for the :allocation property
7251 * but if you want to track the allocation flags as well, for instance
7252 * to know whether the absolute origin of @actor changed, then you might
7253 * want use this signal instead.
7257 actor_signals[ALLOCATION_CHANGED] =
7258 g_signal_new (I_("allocation-changed"),
7259 G_TYPE_FROM_CLASS (object_class),
7263 _clutter_marshal_VOID__BOXED_FLAGS,
7265 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7266 CLUTTER_TYPE_ALLOCATION_FLAGS);
7269 * ClutterActor::transitions-completed:
7270 * @actor: a #ClutterActor
7272 * The ::transitions-completed signal is emitted once all transitions
7273 * involving @actor are complete.
7277 actor_signals[TRANSITIONS_COMPLETED] =
7278 g_signal_new (I_("transitions-completed"),
7279 G_TYPE_FROM_CLASS (object_class),
7283 _clutter_marshal_VOID__VOID,
7288 clutter_actor_init (ClutterActor *self)
7290 ClutterActorPrivate *priv;
7292 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7294 priv->id = _clutter_context_acquire_id (self);
7297 priv->opacity = 0xff;
7298 priv->show_on_set_parent = TRUE;
7300 priv->needs_width_request = TRUE;
7301 priv->needs_height_request = TRUE;
7302 priv->needs_allocation = TRUE;
7304 priv->cached_width_age = 1;
7305 priv->cached_height_age = 1;
7307 priv->opacity_override = -1;
7308 priv->enable_model_view_transform = TRUE;
7310 /* Initialize an empty paint volume to start with */
7311 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7312 priv->last_paint_volume_valid = TRUE;
7314 priv->transform_valid = FALSE;
7316 /* the default is to stretch the content, to match the
7317 * current behaviour of basically all actors. also, it's
7318 * the easiest thing to compute.
7320 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7321 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7322 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7324 /* this flag will be set to TRUE if the actor gets a child
7325 * or if the [xy]-expand flags are explicitly set; until
7326 * then, the actor does not need to expand.
7328 * this also allows us to avoid computing the expand flag
7329 * when building up a scene.
7331 priv->needs_compute_expand = FALSE;
7335 * clutter_actor_new:
7337 * Creates a new #ClutterActor.
7339 * A newly created actor has a floating reference, which will be sunk
7340 * when it is added to another actor.
7342 * Return value: (transfer full): the newly created #ClutterActor
7347 clutter_actor_new (void)
7349 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7353 * clutter_actor_destroy:
7354 * @self: a #ClutterActor
7356 * Destroys an actor. When an actor is destroyed, it will break any
7357 * references it holds to other objects. If the actor is inside a
7358 * container, the actor will be removed.
7360 * When you destroy a container, its children will be destroyed as well.
7362 * Note: you cannot destroy the #ClutterStage returned by
7363 * clutter_stage_get_default().
7366 clutter_actor_destroy (ClutterActor *self)
7368 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7370 g_object_ref (self);
7372 /* avoid recursion while destroying */
7373 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7375 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7377 g_object_run_dispose (G_OBJECT (self));
7379 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7382 g_object_unref (self);
7386 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7387 ClutterPaintVolume *clip)
7389 ClutterActorPrivate *priv = self->priv;
7390 ClutterPaintVolume *pv;
7393 /* Remove queue entry early in the process, otherwise a new
7394 queue_redraw() during signal handling could put back this
7395 object in the stage redraw list (but the entry is freed as
7396 soon as we return from this function, causing a segfault
7399 priv->queue_redraw_entry = NULL;
7401 /* If we've been explicitly passed a clip volume then there's
7402 * nothing more to calculate, but otherwise the only thing we know
7403 * is that the change is constrained to the given actor.
7405 * The idea is that if we know the paint volume for where the actor
7406 * was last drawn (in eye coordinates) and we also have the paint
7407 * volume for where it will be drawn next (in actor coordinates)
7408 * then if we queue a redraw for both these volumes that will cover
7409 * everything that needs to be redrawn to clear the old view and
7410 * show the latest view of the actor.
7412 * Don't clip this redraw if we don't know what position we had for
7413 * the previous redraw since we don't know where to set the clip so
7414 * it will clear the actor as it is currently.
7418 _clutter_actor_set_queue_redraw_clip (self, clip);
7421 else if (G_LIKELY (priv->last_paint_volume_valid))
7423 pv = _clutter_actor_get_paint_volume_mutable (self);
7426 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7428 /* make sure we redraw the actors old position... */
7429 _clutter_actor_set_queue_redraw_clip (stage,
7430 &priv->last_paint_volume);
7431 _clutter_actor_signal_queue_redraw (stage, stage);
7432 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7434 /* XXX: Ideally the redraw signal would take a clip volume
7435 * argument, but that would be an ABI break. Until we can
7436 * break the ABI we pass the argument out-of-band
7439 /* setup the clip for the actors new position... */
7440 _clutter_actor_set_queue_redraw_clip (self, pv);
7449 _clutter_actor_signal_queue_redraw (self, self);
7451 /* Just in case anyone is manually firing redraw signals without
7452 * using the public queue_redraw() API we are careful to ensure that
7453 * our out-of-band clip member is cleared before returning...
7455 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7457 if (G_LIKELY (clipped))
7458 _clutter_actor_set_queue_redraw_clip (self, NULL);
7462 _clutter_actor_get_allocation_clip (ClutterActor *self,
7463 ClutterActorBox *clip)
7465 ClutterActorBox allocation;
7467 /* XXX: we don't care if we get an out of date allocation here
7468 * because clutter_actor_queue_redraw_with_clip knows to ignore
7469 * the clip if the actor's allocation is invalid.
7471 * This is noted because clutter_actor_get_allocation_box does some
7472 * unnecessary work to support buggy code with a comment suggesting
7473 * that it could be changed later which would be good for this use
7476 clutter_actor_get_allocation_box (self, &allocation);
7478 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7479 * actor's own coordinate space but the allocation is in parent
7483 clip->x2 = allocation.x2 - allocation.x1;
7484 clip->y2 = allocation.y2 - allocation.y1;
7488 _clutter_actor_queue_redraw_full (ClutterActor *self,
7489 ClutterRedrawFlags flags,
7490 ClutterPaintVolume *volume,
7491 ClutterEffect *effect)
7493 ClutterActorPrivate *priv = self->priv;
7494 ClutterPaintVolume allocation_pv;
7495 ClutterPaintVolume *pv;
7496 gboolean should_free_pv;
7497 ClutterActor *stage;
7499 /* Here's an outline of the actor queue redraw mechanism:
7501 * The process starts in one of the following two functions which
7502 * are wrappers for this function:
7503 * clutter_actor_queue_redraw
7504 * _clutter_actor_queue_redraw_with_clip
7506 * additionally, an effect can queue a redraw by wrapping this
7507 * function in clutter_effect_queue_rerun
7509 * This functions queues an entry in a list associated with the
7510 * stage which is a list of actors that queued a redraw while
7511 * updating the timelines, performing layouting and processing other
7512 * mainloop sources before the next paint starts.
7514 * We aim to minimize the processing done at this point because
7515 * there is a good chance other events will happen while updating
7516 * the scenegraph that would invalidate any expensive work we might
7517 * otherwise try to do here. For example we don't try and resolve
7518 * the screen space bounding box of an actor at this stage so as to
7519 * minimize how much of the screen redraw because it's possible
7520 * something else will happen which will force a full redraw anyway.
7522 * When all updates are complete and we come to paint the stage then
7523 * we iterate this list and actually emit the "queue-redraw" signals
7524 * for each of the listed actors which will bubble up to the stage
7525 * for each actor and at that point we will transform the actors
7526 * paint volume into screen coordinates to determine the clip region
7527 * for what needs to be redrawn in the next paint.
7529 * Besides minimizing redundant work another reason for this
7530 * deferred design is that it's more likely we will be able to
7531 * determine the paint volume of an actor once we've finished
7532 * updating the scenegraph because its allocation should be up to
7533 * date. NB: If we can't determine an actors paint volume then we
7534 * can't automatically queue a clipped redraw which can make a big
7535 * difference to performance.
7537 * So the control flow goes like this:
7538 * One of clutter_actor_queue_redraw,
7539 * _clutter_actor_queue_redraw_with_clip
7540 * or clutter_effect_queue_rerun
7542 * then control moves to:
7543 * _clutter_stage_queue_actor_redraw
7545 * later during _clutter_stage_do_update, once relayouting is done
7546 * and the scenegraph has been updated we will call:
7547 * _clutter_stage_finish_queue_redraws
7549 * _clutter_stage_finish_queue_redraws will call
7550 * _clutter_actor_finish_queue_redraw for each listed actor.
7551 * Note: actors *are* allowed to queue further redraws during this
7552 * process (considering clone actors or texture_new_from_actor which
7553 * respond to their source queueing a redraw by queuing a redraw
7554 * themselves). We repeat the process until the list is empty.
7556 * This will result in the "queue-redraw" signal being fired for
7557 * each actor which will pass control to the default signal handler:
7558 * clutter_actor_real_queue_redraw
7560 * This will bubble up to the stages handler:
7561 * clutter_stage_real_queue_redraw
7563 * clutter_stage_real_queue_redraw will transform the actors paint
7564 * volume into screen space and add it as a clip region for the next
7568 /* ignore queueing a redraw for actors being destroyed */
7569 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7572 stage = _clutter_actor_get_stage_internal (self);
7574 /* Ignore queueing a redraw for actors not descended from a stage */
7578 /* ignore queueing a redraw on stages that are being destroyed */
7579 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7582 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7584 ClutterActorBox allocation_clip;
7585 ClutterVertex origin;
7587 /* If the actor doesn't have a valid allocation then we will
7588 * queue a full stage redraw. */
7589 if (priv->needs_allocation)
7591 /* NB: NULL denotes an undefined clip which will result in a
7593 _clutter_actor_set_queue_redraw_clip (self, NULL);
7594 _clutter_actor_signal_queue_redraw (self, self);
7598 _clutter_paint_volume_init_static (&allocation_pv, self);
7599 pv = &allocation_pv;
7601 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7603 origin.x = allocation_clip.x1;
7604 origin.y = allocation_clip.y1;
7606 clutter_paint_volume_set_origin (pv, &origin);
7607 clutter_paint_volume_set_width (pv,
7608 allocation_clip.x2 - allocation_clip.x1);
7609 clutter_paint_volume_set_height (pv,
7610 allocation_clip.y2 -
7611 allocation_clip.y1);
7612 should_free_pv = TRUE;
7617 should_free_pv = FALSE;
7620 self->priv->queue_redraw_entry =
7621 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7622 priv->queue_redraw_entry,
7627 clutter_paint_volume_free (pv);
7629 /* If this is the first redraw queued then we can directly use the
7631 if (!priv->is_dirty)
7632 priv->effect_to_redraw = effect;
7633 /* Otherwise we need to merge it with the existing effect parameter */
7634 else if (effect != NULL)
7636 /* If there's already an effect then we need to use whichever is
7637 later in the chain of actors. Otherwise a full redraw has
7638 already been queued on the actor so we need to ignore the
7640 if (priv->effect_to_redraw != NULL)
7642 if (priv->effects == NULL)
7643 g_warning ("Redraw queued with an effect that is "
7644 "not applied to the actor");
7649 for (l = _clutter_meta_group_peek_metas (priv->effects);
7653 if (l->data == priv->effect_to_redraw ||
7655 priv->effect_to_redraw = l->data;
7662 /* If no effect is specified then we need to redraw the whole
7664 priv->effect_to_redraw = NULL;
7667 priv->is_dirty = TRUE;
7671 * clutter_actor_queue_redraw:
7672 * @self: A #ClutterActor
7674 * Queues up a redraw of an actor and any children. The redraw occurs
7675 * once the main loop becomes idle (after the current batch of events
7676 * has been processed, roughly).
7678 * Applications rarely need to call this, as redraws are handled
7679 * automatically by modification functions.
7681 * This function will not do anything if @self is not visible, or
7682 * if the actor is inside an invisible part of the scenegraph.
7684 * Also be aware that painting is a NOP for actors with an opacity of
7687 * When you are implementing a custom actor you must queue a redraw
7688 * whenever some private state changes that will affect painting or
7689 * picking of your actor.
7692 clutter_actor_queue_redraw (ClutterActor *self)
7694 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7696 _clutter_actor_queue_redraw_full (self,
7698 NULL, /* clip volume */
7703 * _clutter_actor_queue_redraw_with_clip:
7704 * @self: A #ClutterActor
7705 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7706 * this queue redraw.
7707 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7708 * redrawn or %NULL if you are just using a @flag to state your
7711 * Queues up a clipped redraw of an actor and any children. The redraw
7712 * occurs once the main loop becomes idle (after the current batch of
7713 * events has been processed, roughly).
7715 * If no flags are given the clip volume is defined by @volume
7716 * specified in actor coordinates and tells Clutter that only content
7717 * within this volume has been changed so Clutter can optionally
7718 * optimize the redraw.
7720 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7721 * should be %NULL and this tells Clutter to use the actor's current
7722 * allocation as a clip box. This flag can only be used for 2D actors,
7723 * because any actor with depth may be projected outside its
7726 * Applications rarely need to call this, as redraws are handled
7727 * automatically by modification functions.
7729 * This function will not do anything if @self is not visible, or if
7730 * the actor is inside an invisible part of the scenegraph.
7732 * Also be aware that painting is a NOP for actors with an opacity of
7735 * When you are implementing a custom actor you must queue a redraw
7736 * whenever some private state changes that will affect painting or
7737 * picking of your actor.
7740 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7741 ClutterRedrawFlags flags,
7742 ClutterPaintVolume *volume)
7744 _clutter_actor_queue_redraw_full (self,
7746 volume, /* clip volume */
7751 _clutter_actor_queue_only_relayout (ClutterActor *self)
7753 ClutterActorPrivate *priv = self->priv;
7755 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7758 if (priv->needs_width_request &&
7759 priv->needs_height_request &&
7760 priv->needs_allocation)
7761 return; /* save some cpu cycles */
7763 #if CLUTTER_ENABLE_DEBUG
7764 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7766 g_warning ("The actor '%s' is currently inside an allocation "
7767 "cycle; calling clutter_actor_queue_relayout() is "
7769 _clutter_actor_get_debug_name (self));
7771 #endif /* CLUTTER_ENABLE_DEBUG */
7773 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7777 * clutter_actor_queue_redraw_with_clip:
7778 * @self: a #ClutterActor
7779 * @clip: (allow-none): a rectangular clip region, or %NULL
7781 * Queues a redraw on @self limited to a specific, actor-relative
7784 * If @clip is %NULL this function is equivalent to
7785 * clutter_actor_queue_redraw().
7790 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7791 const cairo_rectangle_int_t *clip)
7793 ClutterPaintVolume volume;
7794 ClutterVertex origin;
7796 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7800 clutter_actor_queue_redraw (self);
7804 _clutter_paint_volume_init_static (&volume, self);
7810 clutter_paint_volume_set_origin (&volume, &origin);
7811 clutter_paint_volume_set_width (&volume, clip->width);
7812 clutter_paint_volume_set_height (&volume, clip->height);
7814 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7816 clutter_paint_volume_free (&volume);
7820 * clutter_actor_queue_relayout:
7821 * @self: A #ClutterActor
7823 * Indicates that the actor's size request or other layout-affecting
7824 * properties may have changed. This function is used inside #ClutterActor
7825 * subclass implementations, not by applications directly.
7827 * Queueing a new layout automatically queues a redraw as well.
7832 clutter_actor_queue_relayout (ClutterActor *self)
7834 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7836 _clutter_actor_queue_only_relayout (self);
7837 clutter_actor_queue_redraw (self);
7841 * clutter_actor_get_preferred_size:
7842 * @self: a #ClutterActor
7843 * @min_width_p: (out) (allow-none): return location for the minimum
7845 * @min_height_p: (out) (allow-none): return location for the minimum
7847 * @natural_width_p: (out) (allow-none): return location for the natural
7849 * @natural_height_p: (out) (allow-none): return location for the natural
7852 * Computes the preferred minimum and natural size of an actor, taking into
7853 * account the actor's geometry management (either height-for-width
7854 * or width-for-height).
7856 * The width and height used to compute the preferred height and preferred
7857 * width are the actor's natural ones.
7859 * If you need to control the height for the preferred width, or the width for
7860 * the preferred height, you should use clutter_actor_get_preferred_width()
7861 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7862 * geometry management using the #ClutterActor:request-mode property.
7867 clutter_actor_get_preferred_size (ClutterActor *self,
7868 gfloat *min_width_p,
7869 gfloat *min_height_p,
7870 gfloat *natural_width_p,
7871 gfloat *natural_height_p)
7873 ClutterActorPrivate *priv;
7874 gfloat min_width, min_height;
7875 gfloat natural_width, natural_height;
7877 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7881 min_width = min_height = 0;
7882 natural_width = natural_height = 0;
7884 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7886 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7887 clutter_actor_get_preferred_width (self, -1,
7890 clutter_actor_get_preferred_height (self, natural_width,
7896 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7897 clutter_actor_get_preferred_height (self, -1,
7900 clutter_actor_get_preferred_width (self, natural_height,
7906 *min_width_p = min_width;
7909 *min_height_p = min_height;
7911 if (natural_width_p)
7912 *natural_width_p = natural_width;
7914 if (natural_height_p)
7915 *natural_height_p = natural_height;
7920 * @align: a #ClutterActorAlign
7921 * @direction: a #ClutterTextDirection
7923 * Retrieves the correct alignment depending on the text direction
7925 * Return value: the effective alignment
7927 static ClutterActorAlign
7928 effective_align (ClutterActorAlign align,
7929 ClutterTextDirection direction)
7931 ClutterActorAlign res;
7935 case CLUTTER_ACTOR_ALIGN_START:
7936 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7937 ? CLUTTER_ACTOR_ALIGN_END
7938 : CLUTTER_ACTOR_ALIGN_START;
7941 case CLUTTER_ACTOR_ALIGN_END:
7942 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7943 ? CLUTTER_ACTOR_ALIGN_START
7944 : CLUTTER_ACTOR_ALIGN_END;
7956 adjust_for_margin (float margin_start,
7958 float *minimum_size,
7959 float *natural_size,
7960 float *allocated_start,
7961 float *allocated_end)
7963 *minimum_size -= (margin_start + margin_end);
7964 *natural_size -= (margin_start + margin_end);
7965 *allocated_start += margin_start;
7966 *allocated_end -= margin_end;
7970 adjust_for_alignment (ClutterActorAlign alignment,
7972 float *allocated_start,
7973 float *allocated_end)
7975 float allocated_size = *allocated_end - *allocated_start;
7979 case CLUTTER_ACTOR_ALIGN_FILL:
7983 case CLUTTER_ACTOR_ALIGN_START:
7985 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7988 case CLUTTER_ACTOR_ALIGN_END:
7989 if (allocated_size > natural_size)
7991 *allocated_start += (allocated_size - natural_size);
7992 *allocated_end = *allocated_start + natural_size;
7996 case CLUTTER_ACTOR_ALIGN_CENTER:
7997 if (allocated_size > natural_size)
7999 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8000 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8007 * clutter_actor_adjust_width:
8008 * @self: a #ClutterActor
8009 * @minimum_width: (inout): the actor's preferred minimum width, which
8010 * will be adjusted depending on the margin
8011 * @natural_width: (inout): the actor's preferred natural width, which
8012 * will be adjusted depending on the margin
8013 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8014 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8016 * Adjusts the preferred and allocated position and size of an actor,
8017 * depending on the margin and alignment properties.
8020 clutter_actor_adjust_width (ClutterActor *self,
8021 gfloat *minimum_width,
8022 gfloat *natural_width,
8023 gfloat *adjusted_x1,
8024 gfloat *adjusted_x2)
8026 ClutterTextDirection text_dir;
8027 const ClutterLayoutInfo *info;
8029 info = _clutter_actor_get_layout_info_or_defaults (self);
8030 text_dir = clutter_actor_get_text_direction (self);
8032 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8034 /* this will tweak natural_width to remove the margin, so that
8035 * adjust_for_alignment() will use the correct size
8037 adjust_for_margin (info->margin.left, info->margin.right,
8038 minimum_width, natural_width,
8039 adjusted_x1, adjusted_x2);
8041 adjust_for_alignment (effective_align (info->x_align, text_dir),
8043 adjusted_x1, adjusted_x2);
8047 * clutter_actor_adjust_height:
8048 * @self: a #ClutterActor
8049 * @minimum_height: (inout): the actor's preferred minimum height, which
8050 * will be adjusted depending on the margin
8051 * @natural_height: (inout): the actor's preferred natural height, which
8052 * will be adjusted depending on the margin
8053 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8054 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8056 * Adjusts the preferred and allocated position and size of an actor,
8057 * depending on the margin and alignment properties.
8060 clutter_actor_adjust_height (ClutterActor *self,
8061 gfloat *minimum_height,
8062 gfloat *natural_height,
8063 gfloat *adjusted_y1,
8064 gfloat *adjusted_y2)
8066 const ClutterLayoutInfo *info;
8068 info = _clutter_actor_get_layout_info_or_defaults (self);
8070 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8072 /* this will tweak natural_height to remove the margin, so that
8073 * adjust_for_alignment() will use the correct size
8075 adjust_for_margin (info->margin.top, info->margin.bottom,
8076 minimum_height, natural_height,
8080 /* we don't use effective_align() here, because text direction
8081 * only affects the horizontal axis
8083 adjust_for_alignment (info->y_align,
8090 /* looks for a cached size request for this for_size. If not
8091 * found, returns the oldest entry so it can be overwritten */
8093 _clutter_actor_get_cached_size_request (gfloat for_size,
8094 SizeRequest *cached_size_requests,
8095 SizeRequest **result)
8099 *result = &cached_size_requests[0];
8101 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8105 sr = &cached_size_requests[i];
8108 sr->for_size == for_size)
8110 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8114 else if (sr->age < (*result)->age)
8120 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8126 * clutter_actor_get_preferred_width:
8127 * @self: A #ClutterActor
8128 * @for_height: available height when computing the preferred width,
8129 * or a negative value to indicate that no height is defined
8130 * @min_width_p: (out) (allow-none): return location for minimum width,
8132 * @natural_width_p: (out) (allow-none): return location for the natural
8135 * Computes the requested minimum and natural widths for an actor,
8136 * optionally depending on the specified height, or if they are
8137 * already computed, returns the cached values.
8139 * An actor may not get its request - depending on the layout
8140 * manager that's in effect.
8142 * A request should not incorporate the actor's scale or anchor point;
8143 * those transformations do not affect layout, only rendering.
8148 clutter_actor_get_preferred_width (ClutterActor *self,
8150 gfloat *min_width_p,
8151 gfloat *natural_width_p)
8153 float request_min_width, request_natural_width;
8154 SizeRequest *cached_size_request;
8155 const ClutterLayoutInfo *info;
8156 ClutterActorPrivate *priv;
8157 gboolean found_in_cache;
8159 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8163 info = _clutter_actor_get_layout_info_or_defaults (self);
8165 /* we shortcircuit the case of a fixed size set using set_width() */
8166 if (priv->min_width_set && priv->natural_width_set)
8168 if (min_width_p != NULL)
8169 *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8171 if (natural_width_p != NULL)
8172 *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8177 /* the remaining cases are:
8179 * - either min_width or natural_width have been set
8180 * - neither min_width or natural_width have been set
8182 * in both cases, we go through the cache (and through the actor in case
8183 * of cache misses) and determine the authoritative value depending on
8187 if (!priv->needs_width_request)
8190 _clutter_actor_get_cached_size_request (for_height,
8191 priv->width_requests,
8192 &cached_size_request);
8196 /* if the actor needs a width request we use the first slot */
8197 found_in_cache = FALSE;
8198 cached_size_request = &priv->width_requests[0];
8201 if (!found_in_cache)
8203 gfloat minimum_width, natural_width;
8204 ClutterActorClass *klass;
8206 minimum_width = natural_width = 0;
8208 /* adjust for the margin */
8209 if (for_height >= 0)
8211 for_height -= (info->margin.top + info->margin.bottom);
8216 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8218 klass = CLUTTER_ACTOR_GET_CLASS (self);
8219 klass->get_preferred_width (self, for_height,
8223 /* adjust for the margin */
8224 minimum_width += (info->margin.left + info->margin.right);
8225 natural_width += (info->margin.left + info->margin.right);
8227 /* Due to accumulated float errors, it's better not to warn
8228 * on this, but just fix it.
8230 if (natural_width < minimum_width)
8231 natural_width = minimum_width;
8233 cached_size_request->min_size = minimum_width;
8234 cached_size_request->natural_size = natural_width;
8235 cached_size_request->for_size = for_height;
8236 cached_size_request->age = priv->cached_width_age;
8238 priv->cached_width_age += 1;
8239 priv->needs_width_request = FALSE;
8242 if (!priv->min_width_set)
8243 request_min_width = cached_size_request->min_size;
8245 request_min_width = info->minimum.width;
8247 if (!priv->natural_width_set)
8248 request_natural_width = cached_size_request->natural_size;
8250 request_natural_width = info->natural.width;
8253 *min_width_p = request_min_width;
8255 if (natural_width_p)
8256 *natural_width_p = request_natural_width;
8260 * clutter_actor_get_preferred_height:
8261 * @self: A #ClutterActor
8262 * @for_width: available width to assume in computing desired height,
8263 * or a negative value to indicate that no width is defined
8264 * @min_height_p: (out) (allow-none): return location for minimum height,
8266 * @natural_height_p: (out) (allow-none): return location for natural
8269 * Computes the requested minimum and natural heights for an actor,
8270 * or if they are already computed, returns the cached values.
8272 * An actor may not get its request - depending on the layout
8273 * manager that's in effect.
8275 * A request should not incorporate the actor's scale or anchor point;
8276 * those transformations do not affect layout, only rendering.
8281 clutter_actor_get_preferred_height (ClutterActor *self,
8283 gfloat *min_height_p,
8284 gfloat *natural_height_p)
8286 float request_min_height, request_natural_height;
8287 SizeRequest *cached_size_request;
8288 const ClutterLayoutInfo *info;
8289 ClutterActorPrivate *priv;
8290 gboolean found_in_cache;
8292 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8296 info = _clutter_actor_get_layout_info_or_defaults (self);
8298 /* we shortcircuit the case of a fixed size set using set_height() */
8299 if (priv->min_height_set && priv->natural_height_set)
8301 if (min_height_p != NULL)
8302 *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8304 if (natural_height_p != NULL)
8305 *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8310 /* the remaining cases are:
8312 * - either min_height or natural_height have been set
8313 * - neither min_height or natural_height have been set
8315 * in both cases, we go through the cache (and through the actor in case
8316 * of cache misses) and determine the authoritative value depending on
8320 if (!priv->needs_height_request)
8323 _clutter_actor_get_cached_size_request (for_width,
8324 priv->height_requests,
8325 &cached_size_request);
8329 found_in_cache = FALSE;
8330 cached_size_request = &priv->height_requests[0];
8333 if (!found_in_cache)
8335 gfloat minimum_height, natural_height;
8336 ClutterActorClass *klass;
8338 minimum_height = natural_height = 0;
8340 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8342 /* adjust for margin */
8345 for_width -= (info->margin.left + info->margin.right);
8350 klass = CLUTTER_ACTOR_GET_CLASS (self);
8351 klass->get_preferred_height (self, for_width,
8355 /* adjust for margin */
8356 minimum_height += (info->margin.top + info->margin.bottom);
8357 natural_height += (info->margin.top + info->margin.bottom);
8359 /* Due to accumulated float errors, it's better not to warn
8360 * on this, but just fix it.
8362 if (natural_height < minimum_height)
8363 natural_height = minimum_height;
8365 cached_size_request->min_size = minimum_height;
8366 cached_size_request->natural_size = natural_height;
8367 cached_size_request->for_size = for_width;
8368 cached_size_request->age = priv->cached_height_age;
8370 priv->cached_height_age += 1;
8371 priv->needs_height_request = FALSE;
8374 if (!priv->min_height_set)
8375 request_min_height = cached_size_request->min_size;
8377 request_min_height = info->minimum.height;
8379 if (!priv->natural_height_set)
8380 request_natural_height = cached_size_request->natural_size;
8382 request_natural_height = info->natural.height;
8385 *min_height_p = request_min_height;
8387 if (natural_height_p)
8388 *natural_height_p = request_natural_height;
8392 * clutter_actor_get_allocation_box:
8393 * @self: A #ClutterActor
8394 * @box: (out): the function fills this in with the actor's allocation
8396 * Gets the layout box an actor has been assigned. The allocation can
8397 * only be assumed valid inside a paint() method; anywhere else, it
8398 * may be out-of-date.
8400 * An allocation does not incorporate the actor's scale or anchor point;
8401 * those transformations do not affect layout, only rendering.
8403 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8404 * of functions inside the implementation of the get_preferred_width()
8405 * or get_preferred_height() virtual functions.</note>
8410 clutter_actor_get_allocation_box (ClutterActor *self,
8411 ClutterActorBox *box)
8413 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8415 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8416 * which limits calling get_allocation to inside paint() basically; or
8417 * we can 2) force a layout, which could be expensive if someone calls
8418 * get_allocation somewhere silly; or we can 3) just return the latest
8419 * value, allowing it to be out-of-date, and assume people know what
8422 * The least-surprises approach that keeps existing code working is
8423 * likely to be 2). People can end up doing some inefficient things,
8424 * though, and in general code that requires 2) is probably broken.
8427 /* this implements 2) */
8428 if (G_UNLIKELY (self->priv->needs_allocation))
8430 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8432 /* do not queue a relayout on an unparented actor */
8434 _clutter_stage_maybe_relayout (stage);
8437 /* commenting out the code above and just keeping this assigment
8440 *box = self->priv->allocation;
8444 * clutter_actor_get_allocation_geometry:
8445 * @self: A #ClutterActor
8446 * @geom: (out): allocation geometry in pixels
8448 * Gets the layout box an actor has been assigned. The allocation can
8449 * only be assumed valid inside a paint() method; anywhere else, it
8450 * may be out-of-date.
8452 * An allocation does not incorporate the actor's scale or anchor point;
8453 * those transformations do not affect layout, only rendering.
8455 * The returned rectangle is in pixels.
8460 clutter_actor_get_allocation_geometry (ClutterActor *self,
8461 ClutterGeometry *geom)
8463 ClutterActorBox box;
8465 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8466 g_return_if_fail (geom != NULL);
8468 clutter_actor_get_allocation_box (self, &box);
8470 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8471 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8472 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8473 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8477 clutter_actor_update_constraints (ClutterActor *self,
8478 ClutterActorBox *allocation)
8480 ClutterActorPrivate *priv = self->priv;
8481 const GList *constraints, *l;
8483 if (priv->constraints == NULL)
8486 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8487 for (l = constraints; l != NULL; l = l->next)
8489 ClutterConstraint *constraint = l->data;
8490 ClutterActorMeta *meta = l->data;
8492 if (clutter_actor_meta_get_enabled (meta))
8494 _clutter_constraint_update_allocation (constraint,
8498 CLUTTER_NOTE (LAYOUT,
8499 "Allocation of '%s' after constraint '%s': "
8500 "{ %.2f, %.2f, %.2f, %.2f }",
8501 _clutter_actor_get_debug_name (self),
8502 _clutter_actor_meta_get_debug_name (meta),
8512 * clutter_actor_adjust_allocation:
8513 * @self: a #ClutterActor
8514 * @allocation: (inout): the allocation to adjust
8516 * Adjusts the passed allocation box taking into account the actor's
8517 * layout information, like alignment, expansion, and margin.
8520 clutter_actor_adjust_allocation (ClutterActor *self,
8521 ClutterActorBox *allocation)
8523 ClutterActorBox adj_allocation;
8524 float alloc_width, alloc_height;
8525 float min_width, min_height;
8526 float nat_width, nat_height;
8527 ClutterRequestMode req_mode;
8529 adj_allocation = *allocation;
8531 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8533 /* we want to hit the cache, so we use the public API */
8534 req_mode = clutter_actor_get_request_mode (self);
8536 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8538 clutter_actor_get_preferred_width (self, -1,
8541 clutter_actor_get_preferred_height (self, alloc_width,
8545 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8547 clutter_actor_get_preferred_height (self, -1,
8550 clutter_actor_get_preferred_height (self, alloc_height,
8555 #ifdef CLUTTER_ENABLE_DEBUG
8556 /* warn about underallocations */
8557 if (_clutter_diagnostic_enabled () &&
8558 (floorf (min_width - alloc_width) > 0 ||
8559 floorf (min_height - alloc_height) > 0))
8561 ClutterActor *parent = clutter_actor_get_parent (self);
8563 /* the only actors that are allowed to be underallocated are the Stage,
8564 * as it doesn't have an implicit size, and Actors that specifically
8565 * told us that they want to opt-out from layout control mechanisms
8566 * through the NO_LAYOUT escape hatch.
8568 if (parent != NULL &&
8569 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8571 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8572 "of %.2f x %.2f from its parent actor '%s', but its "
8573 "requested minimum size is of %.2f x %.2f",
8574 _clutter_actor_get_debug_name (self),
8575 alloc_width, alloc_height,
8576 _clutter_actor_get_debug_name (parent),
8577 min_width, min_height);
8582 clutter_actor_adjust_width (self,
8586 &adj_allocation.x2);
8588 clutter_actor_adjust_height (self,
8592 &adj_allocation.y2);
8594 /* we maintain the invariant that an allocation cannot be adjusted
8595 * to be outside the parent-given box
8597 if (adj_allocation.x1 < allocation->x1 ||
8598 adj_allocation.y1 < allocation->y1 ||
8599 adj_allocation.x2 > allocation->x2 ||
8600 adj_allocation.y2 > allocation->y2)
8602 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8603 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8604 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8605 _clutter_actor_get_debug_name (self),
8606 adj_allocation.x1, adj_allocation.y1,
8607 adj_allocation.x2 - adj_allocation.x1,
8608 adj_allocation.y2 - adj_allocation.y1,
8609 allocation->x1, allocation->y1,
8610 allocation->x2 - allocation->x1,
8611 allocation->y2 - allocation->y1);
8615 *allocation = adj_allocation;
8619 * clutter_actor_allocate:
8620 * @self: A #ClutterActor
8621 * @box: new allocation of the actor, in parent-relative coordinates
8622 * @flags: flags that control the allocation
8624 * Called by the parent of an actor to assign the actor its size.
8625 * Should never be called by applications (except when implementing
8626 * a container or layout manager).
8628 * Actors can know from their allocation box whether they have moved
8629 * with respect to their parent actor. The @flags parameter describes
8630 * additional information about the allocation, for instance whether
8631 * the parent has moved with respect to the stage, for example because
8632 * a grandparent's origin has moved.
8637 clutter_actor_allocate (ClutterActor *self,
8638 const ClutterActorBox *box,
8639 ClutterAllocationFlags flags)
8641 ClutterActorPrivate *priv;
8642 ClutterActorClass *klass;
8643 ClutterActorBox old_allocation, real_allocation;
8644 gboolean origin_changed, child_moved, size_changed;
8645 gboolean stage_allocation_changed;
8647 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8648 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8650 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8651 "which isn't a descendent of the stage!\n",
8652 self, _clutter_actor_get_debug_name (self));
8658 old_allocation = priv->allocation;
8659 real_allocation = *box;
8661 /* constraints are allowed to modify the allocation only here; we do
8662 * this prior to all the other checks so that we can bail out if the
8663 * allocation did not change
8665 clutter_actor_update_constraints (self, &real_allocation);
8667 /* adjust the allocation depending on the align/margin properties */
8668 clutter_actor_adjust_allocation (self, &real_allocation);
8670 if (real_allocation.x2 < real_allocation.x1 ||
8671 real_allocation.y2 < real_allocation.y1)
8673 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8674 _clutter_actor_get_debug_name (self),
8675 real_allocation.x2 - real_allocation.x1,
8676 real_allocation.y2 - real_allocation.y1);
8679 /* we allow 0-sized actors, but not negative-sized ones */
8680 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8681 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8683 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8685 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8686 real_allocation.y1 != old_allocation.y1);
8688 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8689 real_allocation.y2 != old_allocation.y2);
8691 if (origin_changed || child_moved || size_changed)
8692 stage_allocation_changed = TRUE;
8694 stage_allocation_changed = FALSE;
8696 /* If we get an allocation "out of the blue"
8697 * (we did not queue relayout), then we want to
8698 * ignore it. But if we have needs_allocation set,
8699 * we want to guarantee that allocate() virtual
8700 * method is always called, i.e. that queue_relayout()
8701 * always results in an allocate() invocation on
8704 * The optimization here is to avoid re-allocating
8705 * actors that did not queue relayout and were
8708 if (!priv->needs_allocation && !stage_allocation_changed)
8710 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8714 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8715 * clutter_actor_allocate(), it indicates whether the parent has its
8716 * absolute origin moved; when passed in to ClutterActor::allocate()
8717 * virtual method though, it indicates whether the child has its
8718 * absolute origin moved. So we set it when child_moved is TRUE
8721 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8723 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8725 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8726 _clutter_actor_get_debug_name (self));
8728 klass = CLUTTER_ACTOR_GET_CLASS (self);
8729 klass->allocate (self, &real_allocation, flags);
8731 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8733 if (stage_allocation_changed)
8734 clutter_actor_queue_redraw (self);
8738 * clutter_actor_set_allocation:
8739 * @self: a #ClutterActor
8740 * @box: a #ClutterActorBox
8741 * @flags: allocation flags
8743 * Stores the allocation of @self as defined by @box.
8745 * This function can only be called from within the implementation of
8746 * the #ClutterActorClass.allocate() virtual function.
8748 * The allocation should have been adjusted to take into account constraints,
8749 * alignment, and margin properties. If you are implementing a #ClutterActor
8750 * subclass that provides its own layout management policy for its children
8751 * instead of using a #ClutterLayoutManager delegate, you should not call
8752 * this function on the children of @self; instead, you should call
8753 * clutter_actor_allocate(), which will adjust the allocation box for
8756 * This function should only be used by subclasses of #ClutterActor
8757 * that wish to store their allocation but cannot chain up to the
8758 * parent's implementation; the default implementation of the
8759 * #ClutterActorClass.allocate() virtual function will call this
8762 * It is important to note that, while chaining up was the recommended
8763 * behaviour for #ClutterActor subclasses prior to the introduction of
8764 * this function, it is recommended to call clutter_actor_set_allocation()
8767 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8768 * to handle the allocation of its children, this function will call
8769 * the clutter_layout_manager_allocate() function only if the
8770 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8771 * expected that the subclass will call clutter_layout_manager_allocate()
8772 * by itself. For instance, the following code:
8776 * my_actor_allocate (ClutterActor *actor,
8777 * const ClutterActorBox *allocation,
8778 * ClutterAllocationFlags flags)
8780 * ClutterActorBox new_alloc;
8781 * ClutterAllocationFlags new_flags;
8783 * adjust_allocation (allocation, &new_alloc);
8785 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8787 * /* this will use the layout manager set on the actor */
8788 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8792 * is equivalent to this:
8796 * my_actor_allocate (ClutterActor *actor,
8797 * const ClutterActorBox *allocation,
8798 * ClutterAllocationFlags flags)
8800 * ClutterLayoutManager *layout;
8801 * ClutterActorBox new_alloc;
8803 * adjust_allocation (allocation, &new_alloc);
8805 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8807 * layout = clutter_actor_get_layout_manager (actor);
8808 * clutter_layout_manager_allocate (layout,
8809 * CLUTTER_CONTAINER (actor),
8818 clutter_actor_set_allocation (ClutterActor *self,
8819 const ClutterActorBox *box,
8820 ClutterAllocationFlags flags)
8822 ClutterActorPrivate *priv;
8825 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8826 g_return_if_fail (box != NULL);
8828 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8830 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8831 "can only be called from within the implementation of "
8832 "the ClutterActor::allocate() virtual function.");
8838 g_object_freeze_notify (G_OBJECT (self));
8840 changed = clutter_actor_set_allocation_internal (self, box, flags);
8842 /* we allocate our children before we notify changes in our geometry,
8843 * so that people connecting to properties will be able to get valid
8844 * data out of the sub-tree of the scene graph that has this actor at
8847 clutter_actor_maybe_layout_children (self, box, flags);
8851 ClutterActorBox signal_box = priv->allocation;
8852 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8854 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8859 g_object_thaw_notify (G_OBJECT (self));
8863 * clutter_actor_set_geometry:
8864 * @self: A #ClutterActor
8865 * @geometry: A #ClutterGeometry
8867 * Sets the actor's fixed position and forces its minimum and natural
8868 * size, in pixels. This means the untransformed actor will have the
8869 * given geometry. This is the same as calling clutter_actor_set_position()
8870 * and clutter_actor_set_size().
8872 * Deprecated: 1.10: Use clutter_actor_set_position() and
8873 * clutter_actor_set_size() instead.
8876 clutter_actor_set_geometry (ClutterActor *self,
8877 const ClutterGeometry *geometry)
8879 g_object_freeze_notify (G_OBJECT (self));
8881 clutter_actor_set_position (self, geometry->x, geometry->y);
8882 clutter_actor_set_size (self, geometry->width, geometry->height);
8884 g_object_thaw_notify (G_OBJECT (self));
8888 * clutter_actor_get_geometry:
8889 * @self: A #ClutterActor
8890 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8892 * Gets the size and position of an actor relative to its parent
8893 * actor. This is the same as calling clutter_actor_get_position() and
8894 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8895 * requested size and position if the actor's allocation is invalid.
8897 * Deprecated: 1.10: Use clutter_actor_get_position() and
8898 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8902 clutter_actor_get_geometry (ClutterActor *self,
8903 ClutterGeometry *geometry)
8905 gfloat x, y, width, height;
8907 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8908 g_return_if_fail (geometry != NULL);
8910 clutter_actor_get_position (self, &x, &y);
8911 clutter_actor_get_size (self, &width, &height);
8913 geometry->x = (int) x;
8914 geometry->y = (int) y;
8915 geometry->width = (int) width;
8916 geometry->height = (int) height;
8920 * clutter_actor_set_position:
8921 * @self: A #ClutterActor
8922 * @x: New left position of actor in pixels.
8923 * @y: New top position of actor in pixels.
8925 * Sets the actor's fixed position in pixels relative to any parent
8928 * If a layout manager is in use, this position will override the
8929 * layout manager and force a fixed position.
8932 clutter_actor_set_position (ClutterActor *self,
8936 ClutterPoint new_position;
8938 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8940 clutter_point_init (&new_position, x, y);
8942 if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
8944 ClutterPoint cur_position;
8946 cur_position.x = clutter_actor_get_x (self);
8947 cur_position.y = clutter_actor_get_y (self);
8949 _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
8954 _clutter_actor_update_transition (self,
8955 obj_props[PROP_POSITION],
8958 clutter_actor_queue_relayout (self);
8962 * clutter_actor_get_fixed_position_set:
8963 * @self: A #ClutterActor
8965 * Checks whether an actor has a fixed position set (and will thus be
8966 * unaffected by any layout manager).
8968 * Return value: %TRUE if the fixed position is set on the actor
8973 clutter_actor_get_fixed_position_set (ClutterActor *self)
8975 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8977 return self->priv->position_set;
8981 * clutter_actor_set_fixed_position_set:
8982 * @self: A #ClutterActor
8983 * @is_set: whether to use fixed position
8985 * Sets whether an actor has a fixed position set (and will thus be
8986 * unaffected by any layout manager).
8991 clutter_actor_set_fixed_position_set (ClutterActor *self,
8994 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8996 if (self->priv->position_set == (is_set != FALSE))
8999 self->priv->position_set = is_set != FALSE;
9000 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9002 clutter_actor_queue_relayout (self);
9006 * clutter_actor_move_by:
9007 * @self: A #ClutterActor
9008 * @dx: Distance to move Actor on X axis.
9009 * @dy: Distance to move Actor on Y axis.
9011 * Moves an actor by the specified distance relative to its current
9012 * position in pixels.
9014 * This function modifies the fixed position of an actor and thus removes
9015 * it from any layout management. Another way to move an actor is with an
9016 * anchor point, see clutter_actor_set_anchor_point().
9021 clutter_actor_move_by (ClutterActor *self,
9025 const ClutterLayoutInfo *info;
9028 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9030 info = _clutter_actor_get_layout_info_or_defaults (self);
9031 x = info->fixed_pos.x;
9032 y = info->fixed_pos.y;
9034 clutter_actor_set_position (self, x + dx, y + dy);
9038 clutter_actor_set_min_width (ClutterActor *self,
9041 ClutterActorPrivate *priv = self->priv;
9042 ClutterActorBox old = { 0, };
9043 ClutterLayoutInfo *info;
9045 /* if we are setting the size on a top-level actor and the
9046 * backend only supports static top-levels (e.g. framebuffers)
9047 * then we ignore the passed value and we override it with
9048 * the stage implementation's preferred size.
9050 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9051 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9054 info = _clutter_actor_get_layout_info (self);
9056 if (priv->min_width_set && min_width == info->minimum.width)
9059 g_object_freeze_notify (G_OBJECT (self));
9061 clutter_actor_store_old_geometry (self, &old);
9063 info->minimum.width = min_width;
9064 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9065 clutter_actor_set_min_width_set (self, TRUE);
9067 clutter_actor_notify_if_geometry_changed (self, &old);
9069 g_object_thaw_notify (G_OBJECT (self));
9071 clutter_actor_queue_relayout (self);
9075 clutter_actor_set_min_height (ClutterActor *self,
9079 ClutterActorPrivate *priv = self->priv;
9080 ClutterActorBox old = { 0, };
9081 ClutterLayoutInfo *info;
9083 /* if we are setting the size on a top-level actor and the
9084 * backend only supports static top-levels (e.g. framebuffers)
9085 * then we ignore the passed value and we override it with
9086 * the stage implementation's preferred size.
9088 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9089 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9092 info = _clutter_actor_get_layout_info (self);
9094 if (priv->min_height_set && min_height == info->minimum.height)
9097 g_object_freeze_notify (G_OBJECT (self));
9099 clutter_actor_store_old_geometry (self, &old);
9101 info->minimum.height = min_height;
9102 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9103 clutter_actor_set_min_height_set (self, TRUE);
9105 clutter_actor_notify_if_geometry_changed (self, &old);
9107 g_object_thaw_notify (G_OBJECT (self));
9109 clutter_actor_queue_relayout (self);
9113 clutter_actor_set_natural_width (ClutterActor *self,
9114 gfloat natural_width)
9116 ClutterActorPrivate *priv = self->priv;
9117 ClutterActorBox old = { 0, };
9118 ClutterLayoutInfo *info;
9120 /* if we are setting the size on a top-level actor and the
9121 * backend only supports static top-levels (e.g. framebuffers)
9122 * then we ignore the passed value and we override it with
9123 * the stage implementation's preferred size.
9125 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9126 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9129 info = _clutter_actor_get_layout_info (self);
9131 if (priv->natural_width_set && natural_width == info->natural.width)
9134 g_object_freeze_notify (G_OBJECT (self));
9136 clutter_actor_store_old_geometry (self, &old);
9138 info->natural.width = natural_width;
9139 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9140 clutter_actor_set_natural_width_set (self, TRUE);
9142 clutter_actor_notify_if_geometry_changed (self, &old);
9144 g_object_thaw_notify (G_OBJECT (self));
9146 clutter_actor_queue_relayout (self);
9150 clutter_actor_set_natural_height (ClutterActor *self,
9151 gfloat natural_height)
9153 ClutterActorPrivate *priv = self->priv;
9154 ClutterActorBox old = { 0, };
9155 ClutterLayoutInfo *info;
9157 /* if we are setting the size on a top-level actor and the
9158 * backend only supports static top-levels (e.g. framebuffers)
9159 * then we ignore the passed value and we override it with
9160 * the stage implementation's preferred size.
9162 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9163 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9166 info = _clutter_actor_get_layout_info (self);
9168 if (priv->natural_height_set && natural_height == info->natural.height)
9171 g_object_freeze_notify (G_OBJECT (self));
9173 clutter_actor_store_old_geometry (self, &old);
9175 info->natural.height = natural_height;
9176 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9177 clutter_actor_set_natural_height_set (self, TRUE);
9179 clutter_actor_notify_if_geometry_changed (self, &old);
9181 g_object_thaw_notify (G_OBJECT (self));
9183 clutter_actor_queue_relayout (self);
9187 clutter_actor_set_min_width_set (ClutterActor *self,
9188 gboolean use_min_width)
9190 ClutterActorPrivate *priv = self->priv;
9191 ClutterActorBox old = { 0, };
9193 if (priv->min_width_set == (use_min_width != FALSE))
9196 clutter_actor_store_old_geometry (self, &old);
9198 priv->min_width_set = use_min_width != FALSE;
9199 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9201 clutter_actor_notify_if_geometry_changed (self, &old);
9203 clutter_actor_queue_relayout (self);
9207 clutter_actor_set_min_height_set (ClutterActor *self,
9208 gboolean use_min_height)
9210 ClutterActorPrivate *priv = self->priv;
9211 ClutterActorBox old = { 0, };
9213 if (priv->min_height_set == (use_min_height != FALSE))
9216 clutter_actor_store_old_geometry (self, &old);
9218 priv->min_height_set = use_min_height != FALSE;
9219 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9221 clutter_actor_notify_if_geometry_changed (self, &old);
9223 clutter_actor_queue_relayout (self);
9227 clutter_actor_set_natural_width_set (ClutterActor *self,
9228 gboolean use_natural_width)
9230 ClutterActorPrivate *priv = self->priv;
9231 ClutterActorBox old = { 0, };
9233 if (priv->natural_width_set == (use_natural_width != FALSE))
9236 clutter_actor_store_old_geometry (self, &old);
9238 priv->natural_width_set = use_natural_width != FALSE;
9239 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9241 clutter_actor_notify_if_geometry_changed (self, &old);
9243 clutter_actor_queue_relayout (self);
9247 clutter_actor_set_natural_height_set (ClutterActor *self,
9248 gboolean use_natural_height)
9250 ClutterActorPrivate *priv = self->priv;
9251 ClutterActorBox old = { 0, };
9253 if (priv->natural_height_set == (use_natural_height != FALSE))
9256 clutter_actor_store_old_geometry (self, &old);
9258 priv->natural_height_set = use_natural_height != FALSE;
9259 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9261 clutter_actor_notify_if_geometry_changed (self, &old);
9263 clutter_actor_queue_relayout (self);
9267 * clutter_actor_set_request_mode:
9268 * @self: a #ClutterActor
9269 * @mode: the request mode
9271 * Sets the geometry request mode of @self.
9273 * The @mode determines the order for invoking
9274 * clutter_actor_get_preferred_width() and
9275 * clutter_actor_get_preferred_height()
9280 clutter_actor_set_request_mode (ClutterActor *self,
9281 ClutterRequestMode mode)
9283 ClutterActorPrivate *priv;
9285 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9289 if (priv->request_mode == mode)
9292 priv->request_mode = mode;
9294 priv->needs_width_request = TRUE;
9295 priv->needs_height_request = TRUE;
9297 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9299 clutter_actor_queue_relayout (self);
9303 * clutter_actor_get_request_mode:
9304 * @self: a #ClutterActor
9306 * Retrieves the geometry request mode of @self
9308 * Return value: the request mode for the actor
9313 clutter_actor_get_request_mode (ClutterActor *self)
9315 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9316 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9318 return self->priv->request_mode;
9321 /* variant of set_width() without checks and without notification
9322 * freeze+thaw, for internal usage only
9325 clutter_actor_set_width_internal (ClutterActor *self,
9330 /* the Stage will use the :min-width to control the minimum
9331 * width to be resized to, so we should not be setting it
9332 * along with the :natural-width
9334 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9335 clutter_actor_set_min_width (self, width);
9337 clutter_actor_set_natural_width (self, width);
9341 /* we only unset the :natural-width for the Stage */
9342 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9343 clutter_actor_set_min_width_set (self, FALSE);
9345 clutter_actor_set_natural_width_set (self, FALSE);
9349 /* variant of set_height() without checks and without notification
9350 * freeze+thaw, for internal usage only
9353 clutter_actor_set_height_internal (ClutterActor *self,
9358 /* see the comment above in set_width_internal() */
9359 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9360 clutter_actor_set_min_height (self, height);
9362 clutter_actor_set_natural_height (self, height);
9366 /* see the comment above in set_width_internal() */
9367 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9368 clutter_actor_set_min_height_set (self, FALSE);
9370 clutter_actor_set_natural_height_set (self, FALSE);
9375 clutter_actor_set_size_internal (ClutterActor *self,
9376 const ClutterSize *size)
9380 clutter_actor_set_width_internal (self, size->width);
9381 clutter_actor_set_height_internal (self, size->height);
9385 clutter_actor_set_width_internal (self, -1);
9386 clutter_actor_set_height_internal (self, -1);
9391 * clutter_actor_set_size:
9392 * @self: A #ClutterActor
9393 * @width: New width of actor in pixels, or -1
9394 * @height: New height of actor in pixels, or -1
9396 * Sets the actor's size request in pixels. This overrides any
9397 * "normal" size request the actor would have. For example
9398 * a text actor might normally request the size of the text;
9399 * this function would force a specific size instead.
9401 * If @width and/or @height are -1 the actor will use its
9402 * "normal" size request instead of overriding it, i.e.
9403 * you can "unset" the size with -1.
9405 * This function sets or unsets both the minimum and natural size.
9408 clutter_actor_set_size (ClutterActor *self,
9412 ClutterSize new_size;
9414 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9416 clutter_size_init (&new_size, width, height);
9418 if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9420 /* minor optimization: if we don't have a duration then we can
9421 * skip the get_size() below, to avoid the chance of going through
9422 * get_preferred_width() and get_preferred_height() just to jump to
9423 * a new desired size
9425 if (clutter_actor_get_easing_duration (self) == 0)
9427 g_object_freeze_notify (G_OBJECT (self));
9429 clutter_actor_set_size_internal (self, &new_size);
9431 g_object_thaw_notify (G_OBJECT (self));
9437 ClutterSize cur_size;
9439 clutter_size_init (&cur_size,
9440 clutter_actor_get_width (self),
9441 clutter_actor_get_height (self));
9443 _clutter_actor_create_transition (self,
9444 obj_props[PROP_SIZE],
9450 _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9452 clutter_actor_queue_relayout (self);
9456 * clutter_actor_get_size:
9457 * @self: A #ClutterActor
9458 * @width: (out) (allow-none): return location for the width, or %NULL.
9459 * @height: (out) (allow-none): return location for the height, or %NULL.
9461 * This function tries to "do what you mean" and return
9462 * the size an actor will have. If the actor has a valid
9463 * allocation, the allocation will be returned; otherwise,
9464 * the actors natural size request will be returned.
9466 * If you care whether you get the request vs. the allocation, you
9467 * should probably call a different function like
9468 * clutter_actor_get_allocation_box() or
9469 * clutter_actor_get_preferred_width().
9474 clutter_actor_get_size (ClutterActor *self,
9478 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9481 *width = clutter_actor_get_width (self);
9484 *height = clutter_actor_get_height (self);
9488 * clutter_actor_get_position:
9489 * @self: a #ClutterActor
9490 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9491 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9493 * This function tries to "do what you mean" and tell you where the
9494 * actor is, prior to any transformations. Retrieves the fixed
9495 * position of an actor in pixels, if one has been set; otherwise, if
9496 * the allocation is valid, returns the actor's allocated position;
9497 * otherwise, returns 0,0.
9499 * The returned position is in pixels.
9504 clutter_actor_get_position (ClutterActor *self,
9508 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9511 *x = clutter_actor_get_x (self);
9514 *y = clutter_actor_get_y (self);
9518 * clutter_actor_get_transformed_position:
9519 * @self: A #ClutterActor
9520 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9521 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9523 * Gets the absolute position of an actor, in pixels relative to the stage.
9528 clutter_actor_get_transformed_position (ClutterActor *self,
9535 v1.x = v1.y = v1.z = 0;
9536 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9546 * clutter_actor_get_transformed_size:
9547 * @self: A #ClutterActor
9548 * @width: (out) (allow-none): return location for the width, or %NULL
9549 * @height: (out) (allow-none): return location for the height, or %NULL
9551 * Gets the absolute size of an actor in pixels, taking into account the
9554 * If the actor has a valid allocation, the allocated size will be used.
9555 * If the actor has not a valid allocation then the preferred size will
9556 * be transformed and returned.
9558 * If you want the transformed allocation, see
9559 * clutter_actor_get_abs_allocation_vertices() instead.
9561 * <note>When the actor (or one of its ancestors) is rotated around the
9562 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9563 * as a generic quadrangle; in that case this function returns the size
9564 * of the smallest rectangle that encapsulates the entire quad. Please
9565 * note that in this case no assumptions can be made about the relative
9566 * position of this envelope to the absolute position of the actor, as
9567 * returned by clutter_actor_get_transformed_position(); if you need this
9568 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9569 * to get the coords of the actual quadrangle.</note>
9574 clutter_actor_get_transformed_size (ClutterActor *self,
9578 ClutterActorPrivate *priv;
9580 gfloat x_min, x_max, y_min, y_max;
9583 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9587 /* if the actor hasn't been allocated yet, get the preferred
9588 * size and transform that
9590 if (priv->needs_allocation)
9592 gfloat natural_width, natural_height;
9593 ClutterActorBox box;
9595 /* Make a fake allocation to transform.
9597 * NB: _clutter_actor_transform_and_project_box expects a box in
9598 * the actor's coordinate space... */
9603 natural_width = natural_height = 0;
9604 clutter_actor_get_preferred_size (self, NULL, NULL,
9608 box.x2 = natural_width;
9609 box.y2 = natural_height;
9611 _clutter_actor_transform_and_project_box (self, &box, v);
9614 clutter_actor_get_abs_allocation_vertices (self, v);
9616 x_min = x_max = v[0].x;
9617 y_min = y_max = v[0].y;
9619 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9635 *width = x_max - x_min;
9638 *height = y_max - y_min;
9642 * clutter_actor_get_width:
9643 * @self: A #ClutterActor
9645 * Retrieves the width of a #ClutterActor.
9647 * If the actor has a valid allocation, this function will return the
9648 * width of the allocated area given to the actor.
9650 * If the actor does not have a valid allocation, this function will
9651 * return the actor's natural width, that is the preferred width of
9654 * If you care whether you get the preferred width or the width that
9655 * has been assigned to the actor, you should probably call a different
9656 * function like clutter_actor_get_allocation_box() to retrieve the
9657 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9660 * If an actor has a fixed width, for instance a width that has been
9661 * assigned using clutter_actor_set_width(), the width returned will
9662 * be the same value.
9664 * Return value: the width of the actor, in pixels
9667 clutter_actor_get_width (ClutterActor *self)
9669 ClutterActorPrivate *priv;
9671 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9675 if (priv->needs_allocation)
9677 gfloat natural_width = 0;
9679 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9680 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9683 gfloat natural_height = 0;
9685 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9686 clutter_actor_get_preferred_width (self, natural_height,
9691 return natural_width;
9694 return priv->allocation.x2 - priv->allocation.x1;
9698 * clutter_actor_get_height:
9699 * @self: A #ClutterActor
9701 * Retrieves the height of a #ClutterActor.
9703 * If the actor has a valid allocation, this function will return the
9704 * height of the allocated area given to the actor.
9706 * If the actor does not have a valid allocation, this function will
9707 * return the actor's natural height, that is the preferred height of
9710 * If you care whether you get the preferred height or the height that
9711 * has been assigned to the actor, you should probably call a different
9712 * function like clutter_actor_get_allocation_box() to retrieve the
9713 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9716 * If an actor has a fixed height, for instance a height that has been
9717 * assigned using clutter_actor_set_height(), the height returned will
9718 * be the same value.
9720 * Return value: the height of the actor, in pixels
9723 clutter_actor_get_height (ClutterActor *self)
9725 ClutterActorPrivate *priv;
9727 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9731 if (priv->needs_allocation)
9733 gfloat natural_height = 0;
9735 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9737 gfloat natural_width = 0;
9739 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9740 clutter_actor_get_preferred_height (self, natural_width,
9741 NULL, &natural_height);
9744 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9746 return natural_height;
9749 return priv->allocation.y2 - priv->allocation.y1;
9753 * clutter_actor_set_width:
9754 * @self: A #ClutterActor
9755 * @width: Requested new width for the actor, in pixels, or -1
9757 * Forces a width on an actor, causing the actor's preferred width
9758 * and height (if any) to be ignored.
9760 * If @width is -1 the actor will use its preferred width request
9761 * instead of overriding it, i.e. you can "unset" the width with -1.
9763 * This function sets both the minimum and natural size of the actor.
9768 clutter_actor_set_width (ClutterActor *self,
9771 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9773 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9777 /* minor optimization: if we don't have a duration
9778 * then we can skip the get_width() below, to avoid
9779 * the chance of going through get_preferred_width()
9780 * just to jump to a new desired width.
9782 if (clutter_actor_get_easing_duration (self) == 0)
9784 g_object_freeze_notify (G_OBJECT (self));
9786 clutter_actor_set_width_internal (self, width);
9788 g_object_thaw_notify (G_OBJECT (self));
9793 cur_size = clutter_actor_get_width (self);
9795 _clutter_actor_create_transition (self,
9796 obj_props[PROP_WIDTH],
9801 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9805 * clutter_actor_set_height:
9806 * @self: A #ClutterActor
9807 * @height: Requested new height for the actor, in pixels, or -1
9809 * Forces a height on an actor, causing the actor's preferred width
9810 * and height (if any) to be ignored.
9812 * If @height is -1 the actor will use its preferred height instead of
9813 * overriding it, i.e. you can "unset" the height with -1.
9815 * This function sets both the minimum and natural size of the actor.
9820 clutter_actor_set_height (ClutterActor *self,
9823 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9825 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9829 /* see the comment in clutter_actor_set_width() above */
9830 if (clutter_actor_get_easing_duration (self) == 0)
9832 g_object_freeze_notify (G_OBJECT (self));
9834 clutter_actor_set_height_internal (self, height);
9836 g_object_thaw_notify (G_OBJECT (self));
9841 cur_size = clutter_actor_get_height (self);
9843 _clutter_actor_create_transition (self,
9844 obj_props[PROP_HEIGHT],
9849 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9853 clutter_actor_set_x_internal (ClutterActor *self,
9856 ClutterActorPrivate *priv = self->priv;
9857 ClutterLayoutInfo *linfo;
9858 ClutterActorBox old = { 0, };
9860 linfo = _clutter_actor_get_layout_info (self);
9862 if (priv->position_set && linfo->fixed_pos.x == x)
9865 clutter_actor_store_old_geometry (self, &old);
9867 linfo->fixed_pos.x = x;
9868 clutter_actor_set_fixed_position_set (self, TRUE);
9870 clutter_actor_notify_if_geometry_changed (self, &old);
9872 clutter_actor_queue_relayout (self);
9876 clutter_actor_set_y_internal (ClutterActor *self,
9879 ClutterActorPrivate *priv = self->priv;
9880 ClutterLayoutInfo *linfo;
9881 ClutterActorBox old = { 0, };
9883 linfo = _clutter_actor_get_layout_info (self);
9885 if (priv->position_set && linfo->fixed_pos.y == y)
9888 clutter_actor_store_old_geometry (self, &old);
9890 linfo->fixed_pos.y = y;
9891 clutter_actor_set_fixed_position_set (self, TRUE);
9893 clutter_actor_notify_if_geometry_changed (self, &old);
9895 clutter_actor_queue_relayout (self);
9899 clutter_actor_set_position_internal (ClutterActor *self,
9900 const ClutterPoint *position)
9902 ClutterActorPrivate *priv = self->priv;
9903 ClutterLayoutInfo *linfo;
9904 ClutterActorBox old = { 0, };
9906 linfo = _clutter_actor_get_layout_info (self);
9908 if (priv->position_set &&
9909 clutter_point_equals (position, &linfo->fixed_pos))
9912 clutter_actor_store_old_geometry (self, &old);
9914 if (position != NULL)
9916 linfo->fixed_pos = *position;
9917 clutter_actor_set_fixed_position_set (self, TRUE);
9920 clutter_actor_set_fixed_position_set (self, FALSE);
9922 clutter_actor_notify_if_geometry_changed (self, &old);
9924 clutter_actor_queue_relayout (self);
9928 * clutter_actor_set_x:
9929 * @self: a #ClutterActor
9930 * @x: the actor's position on the X axis
9932 * Sets the actor's X coordinate, relative to its parent, in pixels.
9934 * Overrides any layout manager and forces a fixed position for
9937 * The #ClutterActor:x property is animatable.
9942 clutter_actor_set_x (ClutterActor *self,
9945 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9947 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9949 float cur_position = clutter_actor_get_x (self);
9951 _clutter_actor_create_transition (self, obj_props[PROP_X],
9956 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9960 * clutter_actor_set_y:
9961 * @self: a #ClutterActor
9962 * @y: the actor's position on the Y axis
9964 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9966 * Overrides any layout manager and forces a fixed position for
9969 * The #ClutterActor:y property is animatable.
9974 clutter_actor_set_y (ClutterActor *self,
9977 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9979 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9981 float cur_position = clutter_actor_get_y (self);
9983 _clutter_actor_create_transition (self, obj_props[PROP_Y],
9988 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9992 * clutter_actor_get_x:
9993 * @self: A #ClutterActor
9995 * Retrieves the X coordinate of a #ClutterActor.
9997 * This function tries to "do what you mean", by returning the
9998 * correct value depending on the actor's state.
10000 * If the actor has a valid allocation, this function will return
10001 * the X coordinate of the origin of the allocation box.
10003 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10004 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10005 * function will return that coordinate.
10007 * If both the allocation and a fixed position are missing, this function
10010 * Return value: the X coordinate, in pixels, ignoring any
10011 * transformation (i.e. scaling, rotation)
10014 clutter_actor_get_x (ClutterActor *self)
10016 ClutterActorPrivate *priv;
10018 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10022 if (priv->needs_allocation)
10024 if (priv->position_set)
10026 const ClutterLayoutInfo *info;
10028 info = _clutter_actor_get_layout_info_or_defaults (self);
10030 return info->fixed_pos.x;
10036 return priv->allocation.x1;
10040 * clutter_actor_get_y:
10041 * @self: A #ClutterActor
10043 * Retrieves the Y coordinate of a #ClutterActor.
10045 * This function tries to "do what you mean", by returning the
10046 * correct value depending on the actor's state.
10048 * If the actor has a valid allocation, this function will return
10049 * the Y coordinate of the origin of the allocation box.
10051 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10052 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10053 * function will return that coordinate.
10055 * If both the allocation and a fixed position are missing, this function
10058 * Return value: the Y coordinate, in pixels, ignoring any
10059 * transformation (i.e. scaling, rotation)
10062 clutter_actor_get_y (ClutterActor *self)
10064 ClutterActorPrivate *priv;
10066 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10070 if (priv->needs_allocation)
10072 if (priv->position_set)
10074 const ClutterLayoutInfo *info;
10076 info = _clutter_actor_get_layout_info_or_defaults (self);
10078 return info->fixed_pos.y;
10084 return priv->allocation.y1;
10088 * clutter_actor_set_scale:
10089 * @self: A #ClutterActor
10090 * @scale_x: double factor to scale actor by horizontally.
10091 * @scale_y: double factor to scale actor by vertically.
10093 * Scales an actor with the given factors. The scaling is relative to
10094 * the scale center and the anchor point. The scale center is
10095 * unchanged by this function and defaults to 0,0.
10097 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10103 clutter_actor_set_scale (ClutterActor *self,
10107 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10109 g_object_freeze_notify (G_OBJECT (self));
10111 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10112 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10114 g_object_thaw_notify (G_OBJECT (self));
10118 * clutter_actor_set_scale_full:
10119 * @self: A #ClutterActor
10120 * @scale_x: double factor to scale actor by horizontally.
10121 * @scale_y: double factor to scale actor by vertically.
10122 * @center_x: X coordinate of the center of the scale.
10123 * @center_y: Y coordinate of the center of the scale
10125 * Scales an actor with the given factors around the given center
10126 * point. The center point is specified in pixels relative to the
10127 * anchor point (usually the top left corner of the actor).
10129 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10135 clutter_actor_set_scale_full (ClutterActor *self,
10141 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10143 g_object_freeze_notify (G_OBJECT (self));
10145 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10146 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10147 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10148 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10150 g_object_thaw_notify (G_OBJECT (self));
10154 * clutter_actor_set_scale_with_gravity:
10155 * @self: A #ClutterActor
10156 * @scale_x: double factor to scale actor by horizontally.
10157 * @scale_y: double factor to scale actor by vertically.
10158 * @gravity: the location of the scale center expressed as a compass
10161 * Scales an actor with the given factors around the given
10162 * center point. The center point is specified as one of the compass
10163 * directions in #ClutterGravity. For example, setting it to north
10164 * will cause the top of the actor to remain unchanged and the rest of
10165 * the actor to expand left, right and downwards.
10167 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10173 clutter_actor_set_scale_with_gravity (ClutterActor *self,
10176 ClutterGravity gravity)
10178 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10180 g_object_freeze_notify (G_OBJECT (self));
10182 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10183 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10184 clutter_actor_set_scale_gravity (self, gravity);
10186 g_object_thaw_notify (G_OBJECT (self));
10190 * clutter_actor_get_scale:
10191 * @self: A #ClutterActor
10192 * @scale_x: (out) (allow-none): Location to store horizonal
10193 * scale factor, or %NULL.
10194 * @scale_y: (out) (allow-none): Location to store vertical
10195 * scale factor, or %NULL.
10197 * Retrieves an actors scale factors.
10202 clutter_actor_get_scale (ClutterActor *self,
10206 const ClutterTransformInfo *info;
10208 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10210 info = _clutter_actor_get_transform_info_or_defaults (self);
10213 *scale_x = info->scale_x;
10216 *scale_y = info->scale_y;
10220 * clutter_actor_get_scale_center:
10221 * @self: A #ClutterActor
10222 * @center_x: (out) (allow-none): Location to store the X position
10223 * of the scale center, or %NULL.
10224 * @center_y: (out) (allow-none): Location to store the Y position
10225 * of the scale center, or %NULL.
10227 * Retrieves the scale center coordinate in pixels relative to the top
10228 * left corner of the actor. If the scale center was specified using a
10229 * #ClutterGravity this will calculate the pixel offset using the
10230 * current size of the actor.
10235 clutter_actor_get_scale_center (ClutterActor *self,
10239 const ClutterTransformInfo *info;
10241 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10243 info = _clutter_actor_get_transform_info_or_defaults (self);
10245 clutter_anchor_coord_get_units (self, &info->scale_center,
10252 * clutter_actor_get_scale_gravity:
10253 * @self: A #ClutterActor
10255 * Retrieves the scale center as a compass direction. If the scale
10256 * center was specified in pixels or units this will return
10257 * %CLUTTER_GRAVITY_NONE.
10259 * Return value: the scale gravity
10264 clutter_actor_get_scale_gravity (ClutterActor *self)
10266 const ClutterTransformInfo *info;
10268 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10270 info = _clutter_actor_get_transform_info_or_defaults (self);
10272 return clutter_anchor_coord_get_gravity (&info->scale_center);
10276 clutter_actor_set_opacity_internal (ClutterActor *self,
10279 ClutterActorPrivate *priv = self->priv;
10281 if (priv->opacity != opacity)
10283 priv->opacity = opacity;
10285 /* Queue a redraw from the flatten effect so that it can use
10286 its cached image if available instead of having to redraw the
10287 actual actor. If it doesn't end up using the FBO then the
10288 effect is still able to continue the paint anyway. If there
10289 is no flatten effect yet then this is equivalent to queueing
10291 _clutter_actor_queue_redraw_full (self,
10294 priv->flatten_effect);
10296 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10301 * clutter_actor_set_opacity:
10302 * @self: A #ClutterActor
10303 * @opacity: New opacity value for the actor.
10305 * Sets the actor's opacity, with zero being completely transparent and
10306 * 255 (0xff) being fully opaque.
10308 * The #ClutterActor:opacity property is animatable.
10311 clutter_actor_set_opacity (ClutterActor *self,
10314 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10316 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10318 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10319 self->priv->opacity,
10323 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10327 * clutter_actor_get_paint_opacity_internal:
10328 * @self: a #ClutterActor
10330 * Retrieves the absolute opacity of the actor, as it appears on the stage
10332 * This function does not do type checks
10334 * Return value: the absolute opacity of the actor
10337 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10339 ClutterActorPrivate *priv = self->priv;
10340 ClutterActor *parent;
10342 /* override the top-level opacity to always be 255; even in
10343 * case of ClutterStage:use-alpha being TRUE we want the rest
10344 * of the scene to be painted
10346 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10349 if (priv->opacity_override >= 0)
10350 return priv->opacity_override;
10352 parent = priv->parent;
10354 /* Factor in the actual actors opacity with parents */
10355 if (parent != NULL)
10357 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10359 if (opacity != 0xff)
10360 return (opacity * priv->opacity) / 0xff;
10363 return priv->opacity;
10368 * clutter_actor_get_paint_opacity:
10369 * @self: A #ClutterActor
10371 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10373 * This function traverses the hierarchy chain and composites the opacity of
10374 * the actor with that of its parents.
10376 * This function is intended for subclasses to use in the paint virtual
10377 * function, to paint themselves with the correct opacity.
10379 * Return value: The actor opacity value.
10384 clutter_actor_get_paint_opacity (ClutterActor *self)
10386 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10388 return clutter_actor_get_paint_opacity_internal (self);
10392 * clutter_actor_get_opacity:
10393 * @self: a #ClutterActor
10395 * Retrieves the opacity value of an actor, as set by
10396 * clutter_actor_set_opacity().
10398 * For retrieving the absolute opacity of the actor inside a paint
10399 * virtual function, see clutter_actor_get_paint_opacity().
10401 * Return value: the opacity of the actor
10404 clutter_actor_get_opacity (ClutterActor *self)
10406 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10408 return self->priv->opacity;
10412 * clutter_actor_set_offscreen_redirect:
10413 * @self: A #ClutterActor
10414 * @redirect: New offscreen redirect flags for the actor.
10416 * Defines the circumstances where the actor should be redirected into
10417 * an offscreen image. The offscreen image is used to flatten the
10418 * actor into a single image while painting for two main reasons.
10419 * Firstly, when the actor is painted a second time without any of its
10420 * contents changing it can simply repaint the cached image without
10421 * descending further down the actor hierarchy. Secondly, it will make
10422 * the opacity look correct even if there are overlapping primitives
10425 * Caching the actor could in some cases be a performance win and in
10426 * some cases be a performance lose so it is important to determine
10427 * which value is right for an actor before modifying this value. For
10428 * example, there is never any reason to flatten an actor that is just
10429 * a single texture (such as a #ClutterTexture) because it is
10430 * effectively already cached in an image so the offscreen would be
10431 * redundant. Also if the actor contains primitives that are far apart
10432 * with a large transparent area in the middle (such as a large
10433 * CluterGroup with a small actor in the top left and a small actor in
10434 * the bottom right) then the cached image will contain the entire
10435 * image of the large area and the paint will waste time blending all
10436 * of the transparent pixels in the middle.
10438 * The default method of implementing opacity on a container simply
10439 * forwards on the opacity to all of the children. If the children are
10440 * overlapping then it will appear as if they are two separate glassy
10441 * objects and there will be a break in the color where they
10442 * overlap. By redirecting to an offscreen buffer it will be as if the
10443 * two opaque objects are combined into one and then made transparent
10444 * which is usually what is expected.
10446 * The image below demonstrates the difference between redirecting and
10447 * not. The image shows two Clutter groups, each containing a red and
10448 * a green rectangle which overlap. The opacity on the group is set to
10449 * 128 (which is 50%). When the offscreen redirect is not used, the
10450 * red rectangle can be seen through the blue rectangle as if the two
10451 * rectangles were separately transparent. When the redirect is used
10452 * the group as a whole is transparent instead so the red rectangle is
10453 * not visible where they overlap.
10455 * <figure id="offscreen-redirect">
10456 * <title>Sample of using an offscreen redirect for transparency</title>
10457 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10460 * The default value for this property is 0, so we effectively will
10461 * never redirect an actor offscreen by default. This means that there
10462 * are times that transparent actors may look glassy as described
10463 * above. The reason this is the default is because there is a
10464 * performance trade off between quality and performance here. In many
10465 * cases the default form of glassy opacity looks good enough, but if
10466 * it's not you will need to set the
10467 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10468 * redirection for opacity.
10470 * Custom actors that don't contain any overlapping primitives are
10471 * recommended to override the has_overlaps() virtual to return %FALSE
10472 * for maximum efficiency.
10477 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10478 ClutterOffscreenRedirect redirect)
10480 ClutterActorPrivate *priv;
10482 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10486 if (priv->offscreen_redirect != redirect)
10488 priv->offscreen_redirect = redirect;
10490 /* Queue a redraw from the effect so that it can use its cached
10491 image if available instead of having to redraw the actual
10492 actor. If it doesn't end up using the FBO then the effect is
10493 still able to continue the paint anyway. If there is no
10494 effect then this is equivalent to queuing a full redraw */
10495 _clutter_actor_queue_redraw_full (self,
10498 priv->flatten_effect);
10500 g_object_notify_by_pspec (G_OBJECT (self),
10501 obj_props[PROP_OFFSCREEN_REDIRECT]);
10506 * clutter_actor_get_offscreen_redirect:
10507 * @self: a #ClutterActor
10509 * Retrieves whether to redirect the actor to an offscreen buffer, as
10510 * set by clutter_actor_set_offscreen_redirect().
10512 * Return value: the value of the offscreen-redirect property of the actor
10516 ClutterOffscreenRedirect
10517 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10519 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10521 return self->priv->offscreen_redirect;
10525 * clutter_actor_set_name:
10526 * @self: A #ClutterActor
10527 * @name: Textual tag to apply to actor
10529 * Sets the given name to @self. The name can be used to identify
10533 clutter_actor_set_name (ClutterActor *self,
10536 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10538 g_free (self->priv->name);
10539 self->priv->name = g_strdup (name);
10541 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10545 * clutter_actor_get_name:
10546 * @self: A #ClutterActor
10548 * Retrieves the name of @self.
10550 * Return value: the name of the actor, or %NULL. The returned string is
10551 * owned by the actor and should not be modified or freed.
10554 clutter_actor_get_name (ClutterActor *self)
10556 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10558 return self->priv->name;
10562 * clutter_actor_get_gid:
10563 * @self: A #ClutterActor
10565 * Retrieves the unique id for @self.
10567 * Return value: Globally unique value for this object instance.
10571 * Deprecated: 1.8: The id is not used any longer.
10574 clutter_actor_get_gid (ClutterActor *self)
10576 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10578 return self->priv->id;
10582 clutter_actor_set_depth_internal (ClutterActor *self,
10585 ClutterTransformInfo *info;
10587 info = _clutter_actor_get_transform_info (self);
10589 if (info->depth != depth)
10591 /* Sets Z value - XXX 2.0: should we invert? */
10592 info->depth = depth;
10594 self->priv->transform_valid = FALSE;
10596 /* FIXME - remove this crap; sadly, there are still containers
10597 * in Clutter that depend on this utter brain damage
10599 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10601 clutter_actor_queue_redraw (self);
10603 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10608 * clutter_actor_set_depth:
10609 * @self: a #ClutterActor
10612 * Sets the Z coordinate of @self to @depth.
10614 * The unit used by @depth is dependant on the perspective setup. See
10615 * also clutter_stage_set_perspective().
10618 clutter_actor_set_depth (ClutterActor *self,
10621 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10623 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10625 const ClutterTransformInfo *info;
10627 info = _clutter_actor_get_transform_info_or_defaults (self);
10629 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10634 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10636 clutter_actor_queue_redraw (self);
10640 * clutter_actor_get_depth:
10641 * @self: a #ClutterActor
10643 * Retrieves the depth of @self.
10645 * Return value: the depth of the actor
10648 clutter_actor_get_depth (ClutterActor *self)
10650 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10652 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10656 * clutter_actor_set_rotation:
10657 * @self: a #ClutterActor
10658 * @axis: the axis of rotation
10659 * @angle: the angle of rotation
10660 * @x: X coordinate of the rotation center
10661 * @y: Y coordinate of the rotation center
10662 * @z: Z coordinate of the rotation center
10664 * Sets the rotation angle of @self around the given axis.
10666 * The rotation center coordinates used depend on the value of @axis:
10668 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10669 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10670 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10673 * The rotation coordinates are relative to the anchor point of the
10674 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10675 * point is set, the upper left corner is assumed as the origin.
10680 clutter_actor_set_rotation (ClutterActor *self,
10681 ClutterRotateAxis axis,
10689 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10695 g_object_freeze_notify (G_OBJECT (self));
10697 clutter_actor_set_rotation_angle (self, axis, angle);
10698 clutter_actor_set_rotation_center_internal (self, axis, &v);
10700 g_object_thaw_notify (G_OBJECT (self));
10704 * clutter_actor_set_z_rotation_from_gravity:
10705 * @self: a #ClutterActor
10706 * @angle: the angle of rotation
10707 * @gravity: the center point of the rotation
10709 * Sets the rotation angle of @self around the Z axis using the center
10710 * point specified as a compass point. For example to rotate such that
10711 * the center of the actor remains static you can use
10712 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10713 * will move accordingly.
10718 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10720 ClutterGravity gravity)
10722 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10724 if (gravity == CLUTTER_GRAVITY_NONE)
10725 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10728 GObject *obj = G_OBJECT (self);
10729 ClutterTransformInfo *info;
10731 info = _clutter_actor_get_transform_info (self);
10733 g_object_freeze_notify (obj);
10735 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10737 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10738 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10739 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10741 g_object_thaw_notify (obj);
10746 * clutter_actor_get_rotation:
10747 * @self: a #ClutterActor
10748 * @axis: the axis of rotation
10749 * @x: (out): return value for the X coordinate of the center of rotation
10750 * @y: (out): return value for the Y coordinate of the center of rotation
10751 * @z: (out): return value for the Z coordinate of the center of rotation
10753 * Retrieves the angle and center of rotation on the given axis,
10754 * set using clutter_actor_set_rotation().
10756 * Return value: the angle of rotation
10761 clutter_actor_get_rotation (ClutterActor *self,
10762 ClutterRotateAxis axis,
10767 const ClutterTransformInfo *info;
10768 const AnchorCoord *anchor_coord;
10769 gdouble retval = 0;
10771 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10773 info = _clutter_actor_get_transform_info_or_defaults (self);
10777 case CLUTTER_X_AXIS:
10778 anchor_coord = &info->rx_center;
10779 retval = info->rx_angle;
10782 case CLUTTER_Y_AXIS:
10783 anchor_coord = &info->ry_center;
10784 retval = info->ry_angle;
10787 case CLUTTER_Z_AXIS:
10788 anchor_coord = &info->rz_center;
10789 retval = info->rz_angle;
10793 anchor_coord = NULL;
10798 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10804 * clutter_actor_get_z_rotation_gravity:
10805 * @self: A #ClutterActor
10807 * Retrieves the center for the rotation around the Z axis as a
10808 * compass direction. If the center was specified in pixels or units
10809 * this will return %CLUTTER_GRAVITY_NONE.
10811 * Return value: the Z rotation center
10816 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10818 const ClutterTransformInfo *info;
10820 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10822 info = _clutter_actor_get_transform_info_or_defaults (self);
10824 return clutter_anchor_coord_get_gravity (&info->rz_center);
10828 * clutter_actor_set_clip:
10829 * @self: A #ClutterActor
10830 * @xoff: X offset of the clip rectangle
10831 * @yoff: Y offset of the clip rectangle
10832 * @width: Width of the clip rectangle
10833 * @height: Height of the clip rectangle
10835 * Sets clip area for @self. The clip area is always computed from the
10836 * upper left corner of the actor, even if the anchor point is set
10842 clutter_actor_set_clip (ClutterActor *self,
10848 ClutterActorPrivate *priv;
10850 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10854 if (priv->has_clip &&
10855 priv->clip.x == xoff &&
10856 priv->clip.y == yoff &&
10857 priv->clip.width == width &&
10858 priv->clip.height == height)
10861 priv->clip.x = xoff;
10862 priv->clip.y = yoff;
10863 priv->clip.width = width;
10864 priv->clip.height = height;
10866 priv->has_clip = TRUE;
10868 clutter_actor_queue_redraw (self);
10870 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10871 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10875 * clutter_actor_remove_clip:
10876 * @self: A #ClutterActor
10878 * Removes clip area from @self.
10881 clutter_actor_remove_clip (ClutterActor *self)
10883 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10885 if (!self->priv->has_clip)
10888 self->priv->has_clip = FALSE;
10890 clutter_actor_queue_redraw (self);
10892 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10896 * clutter_actor_has_clip:
10897 * @self: a #ClutterActor
10899 * Determines whether the actor has a clip area set or not.
10901 * Return value: %TRUE if the actor has a clip area set.
10906 clutter_actor_has_clip (ClutterActor *self)
10908 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10910 return self->priv->has_clip;
10914 * clutter_actor_get_clip:
10915 * @self: a #ClutterActor
10916 * @xoff: (out) (allow-none): return location for the X offset of
10917 * the clip rectangle, or %NULL
10918 * @yoff: (out) (allow-none): return location for the Y offset of
10919 * the clip rectangle, or %NULL
10920 * @width: (out) (allow-none): return location for the width of
10921 * the clip rectangle, or %NULL
10922 * @height: (out) (allow-none): return location for the height of
10923 * the clip rectangle, or %NULL
10925 * Gets the clip area for @self, if any is set
10930 clutter_actor_get_clip (ClutterActor *self,
10936 ClutterActorPrivate *priv;
10938 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10942 if (!priv->has_clip)
10946 *xoff = priv->clip.x;
10949 *yoff = priv->clip.y;
10952 *width = priv->clip.width;
10954 if (height != NULL)
10955 *height = priv->clip.height;
10959 * clutter_actor_get_children:
10960 * @self: a #ClutterActor
10962 * Retrieves the list of children of @self.
10964 * Return value: (transfer container) (element-type ClutterActor): A newly
10965 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10971 clutter_actor_get_children (ClutterActor *self)
10973 ClutterActor *iter;
10976 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10978 /* we walk the list backward so that we can use prepend(),
10981 for (iter = self->priv->last_child, res = NULL;
10983 iter = iter->priv->prev_sibling)
10985 res = g_list_prepend (res, iter);
10992 * insert_child_at_depth:
10993 * @self: a #ClutterActor
10994 * @child: a #ClutterActor
10996 * Inserts @child inside the list of children held by @self, using
10997 * the depth as the insertion criteria.
10999 * This sadly makes the insertion not O(1), but we can keep the
11000 * list sorted so that the painters algorithm we use for painting
11001 * the children will work correctly.
11004 insert_child_at_depth (ClutterActor *self,
11005 ClutterActor *child,
11006 gpointer dummy G_GNUC_UNUSED)
11008 ClutterActor *iter;
11011 child->priv->parent = self;
11014 _clutter_actor_get_transform_info_or_defaults (child)->depth;
11016 /* special-case the first child */
11017 if (self->priv->n_children == 0)
11019 self->priv->first_child = child;
11020 self->priv->last_child = child;
11022 child->priv->next_sibling = NULL;
11023 child->priv->prev_sibling = NULL;
11028 /* Find the right place to insert the child so that it will still be
11029 sorted and the child will be after all of the actors at the same
11031 for (iter = self->priv->first_child;
11033 iter = iter->priv->next_sibling)
11038 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11040 if (iter_depth > child_depth)
11046 ClutterActor *tmp = iter->priv->prev_sibling;
11049 tmp->priv->next_sibling = child;
11051 /* Insert the node before the found one */
11052 child->priv->prev_sibling = iter->priv->prev_sibling;
11053 child->priv->next_sibling = iter;
11054 iter->priv->prev_sibling = child;
11058 ClutterActor *tmp = self->priv->last_child;
11061 tmp->priv->next_sibling = child;
11063 /* insert the node at the end of the list */
11064 child->priv->prev_sibling = self->priv->last_child;
11065 child->priv->next_sibling = NULL;
11068 if (child->priv->prev_sibling == NULL)
11069 self->priv->first_child = child;
11071 if (child->priv->next_sibling == NULL)
11072 self->priv->last_child = child;
11076 insert_child_at_index (ClutterActor *self,
11077 ClutterActor *child,
11080 gint index_ = GPOINTER_TO_INT (data_);
11082 child->priv->parent = self;
11086 ClutterActor *tmp = self->priv->first_child;
11089 tmp->priv->prev_sibling = child;
11091 child->priv->prev_sibling = NULL;
11092 child->priv->next_sibling = tmp;
11094 else if (index_ < 0 || index_ >= self->priv->n_children)
11096 ClutterActor *tmp = self->priv->last_child;
11099 tmp->priv->next_sibling = child;
11101 child->priv->prev_sibling = tmp;
11102 child->priv->next_sibling = NULL;
11106 ClutterActor *iter;
11109 for (iter = self->priv->first_child, i = 0;
11111 iter = iter->priv->next_sibling, i += 1)
11115 ClutterActor *tmp = iter->priv->prev_sibling;
11117 child->priv->prev_sibling = tmp;
11118 child->priv->next_sibling = iter;
11120 iter->priv->prev_sibling = child;
11123 tmp->priv->next_sibling = child;
11130 if (child->priv->prev_sibling == NULL)
11131 self->priv->first_child = child;
11133 if (child->priv->next_sibling == NULL)
11134 self->priv->last_child = child;
11138 insert_child_above (ClutterActor *self,
11139 ClutterActor *child,
11142 ClutterActor *sibling = data;
11144 child->priv->parent = self;
11146 if (sibling == NULL)
11147 sibling = self->priv->last_child;
11149 child->priv->prev_sibling = sibling;
11151 if (sibling != NULL)
11153 ClutterActor *tmp = sibling->priv->next_sibling;
11155 child->priv->next_sibling = tmp;
11158 tmp->priv->prev_sibling = child;
11160 sibling->priv->next_sibling = child;
11163 child->priv->next_sibling = NULL;
11165 if (child->priv->prev_sibling == NULL)
11166 self->priv->first_child = child;
11168 if (child->priv->next_sibling == NULL)
11169 self->priv->last_child = child;
11173 insert_child_below (ClutterActor *self,
11174 ClutterActor *child,
11177 ClutterActor *sibling = data;
11179 child->priv->parent = self;
11181 if (sibling == NULL)
11182 sibling = self->priv->first_child;
11184 child->priv->next_sibling = sibling;
11186 if (sibling != NULL)
11188 ClutterActor *tmp = sibling->priv->prev_sibling;
11190 child->priv->prev_sibling = tmp;
11193 tmp->priv->next_sibling = child;
11195 sibling->priv->prev_sibling = child;
11198 child->priv->prev_sibling = NULL;
11200 if (child->priv->prev_sibling == NULL)
11201 self->priv->first_child = child;
11203 if (child->priv->next_sibling == NULL)
11204 self->priv->last_child = child;
11207 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11208 ClutterActor *child,
11212 ADD_CHILD_CREATE_META = 1 << 0,
11213 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
11214 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
11215 ADD_CHILD_CHECK_STATE = 1 << 3,
11216 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
11217 ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11219 /* default flags for public API */
11220 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
11221 ADD_CHILD_EMIT_PARENT_SET |
11222 ADD_CHILD_EMIT_ACTOR_ADDED |
11223 ADD_CHILD_CHECK_STATE |
11224 ADD_CHILD_NOTIFY_FIRST_LAST |
11225 ADD_CHILD_SHOW_ON_SET_PARENT,
11227 /* flags for legacy/deprecated API */
11228 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
11229 ADD_CHILD_CHECK_STATE |
11230 ADD_CHILD_NOTIFY_FIRST_LAST |
11231 ADD_CHILD_SHOW_ON_SET_PARENT
11232 } ClutterActorAddChildFlags;
11235 * clutter_actor_add_child_internal:
11236 * @self: a #ClutterActor
11237 * @child: a #ClutterActor
11238 * @flags: control flags for actions
11239 * @add_func: delegate function
11240 * @data: (closure): data to pass to @add_func
11242 * Adds @child to the list of children of @self.
11244 * The actual insertion inside the list is delegated to @add_func: this
11245 * function will just set up the state, perform basic checks, and emit
11248 * The @flags argument is used to perform additional operations.
11251 clutter_actor_add_child_internal (ClutterActor *self,
11252 ClutterActor *child,
11253 ClutterActorAddChildFlags flags,
11254 ClutterActorAddChildFunc add_func,
11257 ClutterTextDirection text_dir;
11258 gboolean create_meta;
11259 gboolean emit_parent_set, emit_actor_added;
11260 gboolean check_state;
11261 gboolean notify_first_last;
11262 gboolean show_on_set_parent;
11263 ClutterActor *old_first_child, *old_last_child;
11265 if (child->priv->parent != NULL)
11267 g_warning ("The actor '%s' already has a parent, '%s'. You must "
11268 "use clutter_actor_remove_child() first.",
11269 _clutter_actor_get_debug_name (child),
11270 _clutter_actor_get_debug_name (child->priv->parent));
11274 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11276 g_warning ("The actor '%s' is a top-level actor, and cannot be "
11277 "a child of another actor.",
11278 _clutter_actor_get_debug_name (child));
11283 /* XXX - this check disallows calling methods that change the stacking
11284 * order within the destruction sequence, by triggering a critical
11285 * warning first, and leaving the actor in an undefined state, which
11286 * then ends up being caught by an assertion.
11288 * the reproducible sequence is:
11290 * - actor gets destroyed;
11291 * - another actor, linked to the first, will try to change the
11292 * stacking order of the first actor;
11293 * - changing the stacking order is a composite operation composed
11294 * by the following steps:
11295 * 1. ref() the child;
11296 * 2. remove_child_internal(), which removes the reference;
11297 * 3. add_child_internal(), which adds a reference;
11298 * - the state of the actor is not changed between (2) and (3), as
11299 * it could be an expensive recomputation;
11300 * - if (3) bails out, then the actor is in an undefined state, but
11302 * - the destruction sequence terminates, but the actor is unparented
11303 * while its state indicates being parented instead.
11304 * - assertion failure.
11306 * the obvious fix would be to decompose each set_child_*_sibling()
11307 * method into proper remove_child()/add_child(), with state validation;
11308 * this may cause excessive work, though, and trigger a cascade of other
11309 * bugs in code that assumes that a change in the stacking order is an
11310 * atomic operation.
11312 * another potential fix is to just remove this check here, and let
11313 * code doing stacking order changes inside the destruction sequence
11314 * of an actor continue doing the work.
11316 * the third fix is to silently bail out early from every
11317 * set_child_*_sibling() and set_child_at_index() method, and avoid
11320 * I have a preference for the second solution, since it involves the
11321 * least amount of work, and the least amount of code duplication.
11323 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11325 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11327 g_warning ("The actor '%s' is currently being destroyed, and "
11328 "cannot be added as a child of another actor.",
11329 _clutter_actor_get_debug_name (child));
11334 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11335 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11336 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11337 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11338 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11339 show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11341 old_first_child = self->priv->first_child;
11342 old_last_child = self->priv->last_child;
11344 g_object_freeze_notify (G_OBJECT (self));
11347 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11349 g_object_ref_sink (child);
11350 child->priv->parent = NULL;
11351 child->priv->next_sibling = NULL;
11352 child->priv->prev_sibling = NULL;
11354 /* delegate the actual insertion */
11355 add_func (self, child, data);
11357 g_assert (child->priv->parent == self);
11359 self->priv->n_children += 1;
11361 self->priv->age += 1;
11363 /* if push_internal() has been called then we automatically set
11364 * the flag on the actor
11366 if (self->priv->internal_child)
11367 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11369 /* children may cause their parent to expand, if they are set
11370 * to expand; if a child is not expanded then it cannot change
11371 * its parent's state. any further change later on will queue
11372 * an expand state check.
11374 * this check, with the initial state of the needs_compute_expand
11375 * flag set to FALSE, should avoid recomputing the expand flags
11376 * state while building the actor tree.
11378 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11379 (child->priv->needs_compute_expand ||
11380 child->priv->needs_x_expand ||
11381 child->priv->needs_y_expand))
11383 clutter_actor_queue_compute_expand (self);
11386 /* clutter_actor_reparent() will emit ::parent-set for us */
11387 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11388 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11392 /* If parent is mapped or realized, we need to also be mapped or
11393 * realized once we're inside the parent.
11395 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11397 /* propagate the parent's text direction to the child */
11398 text_dir = clutter_actor_get_text_direction (self);
11399 clutter_actor_set_text_direction (child, text_dir);
11402 if (show_on_set_parent && child->priv->show_on_set_parent)
11403 clutter_actor_show (child);
11405 if (CLUTTER_ACTOR_IS_MAPPED (child))
11406 clutter_actor_queue_redraw (child);
11408 /* maintain the invariant that if an actor needs layout,
11409 * its parents do as well
11411 if (child->priv->needs_width_request ||
11412 child->priv->needs_height_request ||
11413 child->priv->needs_allocation)
11415 /* we work around the short-circuiting we do
11416 * in clutter_actor_queue_relayout() since we
11417 * want to force a relayout
11419 child->priv->needs_width_request = TRUE;
11420 child->priv->needs_height_request = TRUE;
11421 child->priv->needs_allocation = TRUE;
11423 clutter_actor_queue_relayout (child->priv->parent);
11426 if (emit_actor_added)
11427 g_signal_emit_by_name (self, "actor-added", child);
11429 if (notify_first_last)
11431 if (old_first_child != self->priv->first_child)
11432 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11434 if (old_last_child != self->priv->last_child)
11435 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11438 g_object_thaw_notify (G_OBJECT (self));
11442 * clutter_actor_add_child:
11443 * @self: a #ClutterActor
11444 * @child: a #ClutterActor
11446 * Adds @child to the children of @self.
11448 * This function will acquire a reference on @child that will only
11449 * be released when calling clutter_actor_remove_child().
11451 * This function will take into consideration the #ClutterActor:depth
11452 * of @child, and will keep the list of children sorted.
11454 * This function will emit the #ClutterContainer::actor-added signal
11460 clutter_actor_add_child (ClutterActor *self,
11461 ClutterActor *child)
11463 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11464 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11465 g_return_if_fail (self != child);
11466 g_return_if_fail (child->priv->parent == NULL);
11468 clutter_actor_add_child_internal (self, child,
11469 ADD_CHILD_DEFAULT_FLAGS,
11470 insert_child_at_depth,
11475 * clutter_actor_insert_child_at_index:
11476 * @self: a #ClutterActor
11477 * @child: a #ClutterActor
11478 * @index_: the index
11480 * Inserts @child into the list of children of @self, using the
11481 * given @index_. If @index_ is greater than the number of children
11482 * in @self, or is less than 0, then the new child is added at the end.
11484 * This function will acquire a reference on @child that will only
11485 * be released when calling clutter_actor_remove_child().
11487 * This function will not take into consideration the #ClutterActor:depth
11490 * This function will emit the #ClutterContainer::actor-added signal
11496 clutter_actor_insert_child_at_index (ClutterActor *self,
11497 ClutterActor *child,
11500 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11501 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11502 g_return_if_fail (self != child);
11503 g_return_if_fail (child->priv->parent == NULL);
11505 clutter_actor_add_child_internal (self, child,
11506 ADD_CHILD_DEFAULT_FLAGS,
11507 insert_child_at_index,
11508 GINT_TO_POINTER (index_));
11512 * clutter_actor_insert_child_above:
11513 * @self: a #ClutterActor
11514 * @child: a #ClutterActor
11515 * @sibling: (allow-none): a child of @self, or %NULL
11517 * Inserts @child into the list of children of @self, above another
11518 * child of @self or, if @sibling is %NULL, above all the children
11521 * This function will acquire a reference on @child that will only
11522 * be released when calling clutter_actor_remove_child().
11524 * This function will not take into consideration the #ClutterActor:depth
11527 * This function will emit the #ClutterContainer::actor-added signal
11533 clutter_actor_insert_child_above (ClutterActor *self,
11534 ClutterActor *child,
11535 ClutterActor *sibling)
11537 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11538 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11539 g_return_if_fail (self != child);
11540 g_return_if_fail (child != sibling);
11541 g_return_if_fail (child->priv->parent == NULL);
11542 g_return_if_fail (sibling == NULL ||
11543 (CLUTTER_IS_ACTOR (sibling) &&
11544 sibling->priv->parent == self));
11546 clutter_actor_add_child_internal (self, child,
11547 ADD_CHILD_DEFAULT_FLAGS,
11548 insert_child_above,
11553 * clutter_actor_insert_child_below:
11554 * @self: a #ClutterActor
11555 * @child: a #ClutterActor
11556 * @sibling: (allow-none): a child of @self, or %NULL
11558 * Inserts @child into the list of children of @self, below another
11559 * child of @self or, if @sibling is %NULL, below all the children
11562 * This function will acquire a reference on @child that will only
11563 * be released when calling clutter_actor_remove_child().
11565 * This function will not take into consideration the #ClutterActor:depth
11568 * This function will emit the #ClutterContainer::actor-added signal
11574 clutter_actor_insert_child_below (ClutterActor *self,
11575 ClutterActor *child,
11576 ClutterActor *sibling)
11578 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11579 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11580 g_return_if_fail (self != child);
11581 g_return_if_fail (child != sibling);
11582 g_return_if_fail (child->priv->parent == NULL);
11583 g_return_if_fail (sibling == NULL ||
11584 (CLUTTER_IS_ACTOR (sibling) &&
11585 sibling->priv->parent == self));
11587 clutter_actor_add_child_internal (self, child,
11588 ADD_CHILD_DEFAULT_FLAGS,
11589 insert_child_below,
11594 * clutter_actor_set_parent:
11595 * @self: A #ClutterActor
11596 * @parent: A new #ClutterActor parent
11598 * Sets the parent of @self to @parent.
11600 * This function will result in @parent acquiring a reference on @self,
11601 * eventually by sinking its floating reference first. The reference
11602 * will be released by clutter_actor_unparent().
11604 * This function should only be called by legacy #ClutterActor<!-- -->s
11605 * implementing the #ClutterContainer interface.
11607 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11610 clutter_actor_set_parent (ClutterActor *self,
11611 ClutterActor *parent)
11613 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11614 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11615 g_return_if_fail (self != parent);
11616 g_return_if_fail (self->priv->parent == NULL);
11618 /* as this function will be called inside ClutterContainer::add
11619 * implementations or when building up a composite actor, we have
11620 * to preserve the old behaviour, and not create child meta or
11621 * emit the ::actor-added signal, to avoid recursion or double
11624 clutter_actor_add_child_internal (parent, self,
11625 ADD_CHILD_LEGACY_FLAGS,
11626 insert_child_at_depth,
11631 * clutter_actor_get_parent:
11632 * @self: A #ClutterActor
11634 * Retrieves the parent of @self.
11636 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11637 * if no parent is set
11640 clutter_actor_get_parent (ClutterActor *self)
11642 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11644 return self->priv->parent;
11648 * clutter_actor_get_paint_visibility:
11649 * @self: A #ClutterActor
11651 * Retrieves the 'paint' visibility of an actor recursively checking for non
11654 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11656 * Return Value: %TRUE if the actor is visibile and will be painted.
11661 clutter_actor_get_paint_visibility (ClutterActor *actor)
11663 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11665 return CLUTTER_ACTOR_IS_MAPPED (actor);
11669 * clutter_actor_remove_child:
11670 * @self: a #ClutterActor
11671 * @child: a #ClutterActor
11673 * Removes @child from the children of @self.
11675 * This function will release the reference added by
11676 * clutter_actor_add_child(), so if you want to keep using @child
11677 * you will have to acquire a referenced on it before calling this
11680 * This function will emit the #ClutterContainer::actor-removed
11686 clutter_actor_remove_child (ClutterActor *self,
11687 ClutterActor *child)
11689 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11690 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11691 g_return_if_fail (self != child);
11692 g_return_if_fail (child->priv->parent != NULL);
11693 g_return_if_fail (child->priv->parent == self);
11695 clutter_actor_remove_child_internal (self, child,
11696 REMOVE_CHILD_DEFAULT_FLAGS);
11700 * clutter_actor_remove_all_children:
11701 * @self: a #ClutterActor
11703 * Removes all children of @self.
11705 * This function releases the reference added by inserting a child actor
11706 * in the list of children of @self.
11708 * If the reference count of a child drops to zero, the child will be
11709 * destroyed. If you want to ensure the destruction of all the children
11710 * of @self, use clutter_actor_destroy_all_children().
11715 clutter_actor_remove_all_children (ClutterActor *self)
11717 ClutterActorIter iter;
11719 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11721 if (self->priv->n_children == 0)
11724 g_object_freeze_notify (G_OBJECT (self));
11726 clutter_actor_iter_init (&iter, self);
11727 while (clutter_actor_iter_next (&iter, NULL))
11728 clutter_actor_iter_remove (&iter);
11730 g_object_thaw_notify (G_OBJECT (self));
11733 g_assert (self->priv->first_child == NULL);
11734 g_assert (self->priv->last_child == NULL);
11735 g_assert (self->priv->n_children == 0);
11739 * clutter_actor_destroy_all_children:
11740 * @self: a #ClutterActor
11742 * Destroys all children of @self.
11744 * This function releases the reference added by inserting a child
11745 * actor in the list of children of @self, and ensures that the
11746 * #ClutterActor::destroy signal is emitted on each child of the
11749 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11750 * when its reference count drops to 0; the default handler of the
11751 * #ClutterActor::destroy signal will destroy all the children of an
11752 * actor. This function ensures that all children are destroyed, instead
11753 * of just removed from @self, unlike clutter_actor_remove_all_children()
11754 * which will merely release the reference and remove each child.
11756 * Unless you acquired an additional reference on each child of @self
11757 * prior to calling clutter_actor_remove_all_children() and want to reuse
11758 * the actors, you should use clutter_actor_destroy_all_children() in
11759 * order to make sure that children are destroyed and signal handlers
11760 * are disconnected even in cases where circular references prevent this
11761 * from automatically happening through reference counting alone.
11766 clutter_actor_destroy_all_children (ClutterActor *self)
11768 ClutterActorIter iter;
11770 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11772 if (self->priv->n_children == 0)
11775 g_object_freeze_notify (G_OBJECT (self));
11777 clutter_actor_iter_init (&iter, self);
11778 while (clutter_actor_iter_next (&iter, NULL))
11779 clutter_actor_iter_destroy (&iter);
11781 g_object_thaw_notify (G_OBJECT (self));
11784 g_assert (self->priv->first_child == NULL);
11785 g_assert (self->priv->last_child == NULL);
11786 g_assert (self->priv->n_children == 0);
11789 typedef struct _InsertBetweenData {
11790 ClutterActor *prev_sibling;
11791 ClutterActor *next_sibling;
11792 } InsertBetweenData;
11795 insert_child_between (ClutterActor *self,
11796 ClutterActor *child,
11799 InsertBetweenData *data = data_;
11800 ClutterActor *prev_sibling = data->prev_sibling;
11801 ClutterActor *next_sibling = data->next_sibling;
11803 child->priv->parent = self;
11804 child->priv->prev_sibling = prev_sibling;
11805 child->priv->next_sibling = next_sibling;
11807 if (prev_sibling != NULL)
11808 prev_sibling->priv->next_sibling = child;
11810 if (next_sibling != NULL)
11811 next_sibling->priv->prev_sibling = child;
11813 if (child->priv->prev_sibling == NULL)
11814 self->priv->first_child = child;
11816 if (child->priv->next_sibling == NULL)
11817 self->priv->last_child = child;
11821 * clutter_actor_replace_child:
11822 * @self: a #ClutterActor
11823 * @old_child: the child of @self to replace
11824 * @new_child: the #ClutterActor to replace @old_child
11826 * Replaces @old_child with @new_child in the list of children of @self.
11831 clutter_actor_replace_child (ClutterActor *self,
11832 ClutterActor *old_child,
11833 ClutterActor *new_child)
11835 ClutterActor *prev_sibling, *next_sibling;
11836 InsertBetweenData clos;
11838 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11839 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11840 g_return_if_fail (old_child->priv->parent == self);
11841 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11842 g_return_if_fail (old_child != new_child);
11843 g_return_if_fail (new_child != self);
11844 g_return_if_fail (new_child->priv->parent == NULL);
11846 prev_sibling = old_child->priv->prev_sibling;
11847 next_sibling = old_child->priv->next_sibling;
11848 clutter_actor_remove_child_internal (self, old_child,
11849 REMOVE_CHILD_DEFAULT_FLAGS);
11851 clos.prev_sibling = prev_sibling;
11852 clos.next_sibling = next_sibling;
11853 clutter_actor_add_child_internal (self, new_child,
11854 ADD_CHILD_DEFAULT_FLAGS,
11855 insert_child_between,
11860 * clutter_actor_unparent:
11861 * @self: a #ClutterActor
11863 * Removes the parent of @self.
11865 * This will cause the parent of @self to release the reference
11866 * acquired when calling clutter_actor_set_parent(), so if you
11867 * want to keep @self you will have to acquire a reference of
11868 * your own, through g_object_ref().
11870 * This function should only be called by legacy #ClutterActor<!-- -->s
11871 * implementing the #ClutterContainer interface.
11875 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11878 clutter_actor_unparent (ClutterActor *self)
11880 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11882 if (self->priv->parent == NULL)
11885 clutter_actor_remove_child_internal (self->priv->parent, self,
11886 REMOVE_CHILD_LEGACY_FLAGS);
11890 * clutter_actor_reparent:
11891 * @self: a #ClutterActor
11892 * @new_parent: the new #ClutterActor parent
11894 * Resets the parent actor of @self.
11896 * This function is logically equivalent to calling clutter_actor_unparent()
11897 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11898 * ensures the child is not finalized when unparented, and emits the
11899 * #ClutterActor::parent-set signal only once.
11901 * In reality, calling this function is less useful than it sounds, as some
11902 * application code may rely on changes in the intermediate state between
11903 * removal and addition of the actor from its old parent to the @new_parent.
11904 * Thus, it is strongly encouraged to avoid using this function in application
11909 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11910 * clutter_actor_add_child() instead; remember to take a reference on
11911 * the actor being removed before calling clutter_actor_remove_child()
11912 * to avoid the reference count dropping to zero and the actor being
11916 clutter_actor_reparent (ClutterActor *self,
11917 ClutterActor *new_parent)
11919 ClutterActorPrivate *priv;
11921 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11922 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11923 g_return_if_fail (self != new_parent);
11925 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11927 g_warning ("Cannot set a parent on a toplevel actor");
11931 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11933 g_warning ("Cannot set a parent currently being destroyed");
11939 if (priv->parent != new_parent)
11941 ClutterActor *old_parent;
11943 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11945 old_parent = priv->parent;
11947 g_object_ref (self);
11949 if (old_parent != NULL)
11951 /* go through the Container implementation if this is a regular
11952 * child and not an internal one
11954 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11956 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11958 /* this will have to call unparent() */
11959 clutter_container_remove_actor (parent, self);
11962 clutter_actor_remove_child_internal (old_parent, self,
11963 REMOVE_CHILD_LEGACY_FLAGS);
11966 /* Note, will call set_parent() */
11967 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11968 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11970 clutter_actor_add_child_internal (new_parent, self,
11971 ADD_CHILD_LEGACY_FLAGS,
11972 insert_child_at_depth,
11975 /* we emit the ::parent-set signal once */
11976 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11978 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11980 /* the IN_REPARENT flag suspends state updates */
11981 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11983 g_object_unref (self);
11988 * clutter_actor_contains:
11989 * @self: A #ClutterActor
11990 * @descendant: A #ClutterActor, possibly contained in @self
11992 * Determines if @descendant is contained inside @self (either as an
11993 * immediate child, or as a deeper descendant). If @self and
11994 * @descendant point to the same actor then it will also return %TRUE.
11996 * Return value: whether @descendent is contained within @self
12001 clutter_actor_contains (ClutterActor *self,
12002 ClutterActor *descendant)
12004 ClutterActor *actor;
12006 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12007 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12009 for (actor = descendant; actor; actor = actor->priv->parent)
12017 * clutter_actor_set_child_above_sibling:
12018 * @self: a #ClutterActor
12019 * @child: a #ClutterActor child of @self
12020 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12022 * Sets @child to be above @sibling in the list of children of @self.
12024 * If @sibling is %NULL, @child will be the new last child of @self.
12026 * This function is logically equivalent to removing @child and using
12027 * clutter_actor_insert_child_above(), but it will not emit signals
12028 * or change state on @child.
12033 clutter_actor_set_child_above_sibling (ClutterActor *self,
12034 ClutterActor *child,
12035 ClutterActor *sibling)
12037 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12038 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12039 g_return_if_fail (child->priv->parent == self);
12040 g_return_if_fail (child != sibling);
12041 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12043 if (sibling != NULL)
12044 g_return_if_fail (sibling->priv->parent == self);
12046 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12047 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12048 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12051 /* we don't want to change the state of child, or emit signals, or
12052 * regenerate ChildMeta instances here, but we still want to follow
12053 * the correct sequence of steps encoded in remove_child() and
12054 * add_child(), so that correctness is ensured, and we only go
12055 * through one known code path.
12057 g_object_ref (child);
12058 clutter_actor_remove_child_internal (self, child, 0);
12059 clutter_actor_add_child_internal (self, child,
12060 ADD_CHILD_NOTIFY_FIRST_LAST,
12061 insert_child_above,
12064 clutter_actor_queue_relayout (self);
12068 * clutter_actor_set_child_below_sibling:
12069 * @self: a #ClutterActor
12070 * @child: a #ClutterActor child of @self
12071 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12073 * Sets @child to be below @sibling in the list of children of @self.
12075 * If @sibling is %NULL, @child will be the new first child of @self.
12077 * This function is logically equivalent to removing @self and using
12078 * clutter_actor_insert_child_below(), but it will not emit signals
12079 * or change state on @child.
12084 clutter_actor_set_child_below_sibling (ClutterActor *self,
12085 ClutterActor *child,
12086 ClutterActor *sibling)
12088 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12089 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12090 g_return_if_fail (child->priv->parent == self);
12091 g_return_if_fail (child != sibling);
12092 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12094 if (sibling != NULL)
12095 g_return_if_fail (sibling->priv->parent == self);
12097 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12098 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12099 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12102 /* see the comment in set_child_above_sibling() */
12103 g_object_ref (child);
12104 clutter_actor_remove_child_internal (self, child, 0);
12105 clutter_actor_add_child_internal (self, child,
12106 ADD_CHILD_NOTIFY_FIRST_LAST,
12107 insert_child_below,
12110 clutter_actor_queue_relayout (self);
12114 * clutter_actor_set_child_at_index:
12115 * @self: a #ClutterActor
12116 * @child: a #ClutterActor child of @self
12117 * @index_: the new index for @child
12119 * Changes the index of @child in the list of children of @self.
12121 * This function is logically equivalent to removing @child and
12122 * calling clutter_actor_insert_child_at_index(), but it will not
12123 * emit signals or change state on @child.
12128 clutter_actor_set_child_at_index (ClutterActor *self,
12129 ClutterActor *child,
12132 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12133 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12134 g_return_if_fail (child->priv->parent == self);
12135 g_return_if_fail (index_ <= self->priv->n_children);
12137 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12138 CLUTTER_ACTOR_IN_DESTRUCTION (child))
12141 g_object_ref (child);
12142 clutter_actor_remove_child_internal (self, child, 0);
12143 clutter_actor_add_child_internal (self, child,
12144 ADD_CHILD_NOTIFY_FIRST_LAST,
12145 insert_child_at_index,
12146 GINT_TO_POINTER (index_));
12148 clutter_actor_queue_relayout (self);
12152 * clutter_actor_raise:
12153 * @self: A #ClutterActor
12154 * @below: (allow-none): A #ClutterActor to raise above.
12156 * Puts @self above @below.
12158 * Both actors must have the same parent, and the parent must implement
12159 * the #ClutterContainer interface
12161 * This function calls clutter_container_raise_child() internally.
12163 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12166 clutter_actor_raise (ClutterActor *self,
12167 ClutterActor *below)
12169 ClutterActor *parent;
12171 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12173 parent = clutter_actor_get_parent (self);
12174 if (parent == NULL)
12176 g_warning ("%s: Actor '%s' is not inside a container",
12178 _clutter_actor_get_debug_name (self));
12184 if (parent != clutter_actor_get_parent (below))
12186 g_warning ("%s Actor '%s' is not in the same container as "
12189 _clutter_actor_get_debug_name (self),
12190 _clutter_actor_get_debug_name (below));
12195 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12199 * clutter_actor_lower:
12200 * @self: A #ClutterActor
12201 * @above: (allow-none): A #ClutterActor to lower below
12203 * Puts @self below @above.
12205 * Both actors must have the same parent, and the parent must implement
12206 * the #ClutterContainer interface.
12208 * This function calls clutter_container_lower_child() internally.
12210 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12213 clutter_actor_lower (ClutterActor *self,
12214 ClutterActor *above)
12216 ClutterActor *parent;
12218 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12220 parent = clutter_actor_get_parent (self);
12221 if (parent == NULL)
12223 g_warning ("%s: Actor of type %s is not inside a container",
12225 _clutter_actor_get_debug_name (self));
12231 if (parent != clutter_actor_get_parent (above))
12233 g_warning ("%s: Actor '%s' is not in the same container as "
12236 _clutter_actor_get_debug_name (self),
12237 _clutter_actor_get_debug_name (above));
12242 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12246 * clutter_actor_raise_top:
12247 * @self: A #ClutterActor
12249 * Raises @self to the top.
12251 * This function calls clutter_actor_raise() internally.
12253 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12254 * a %NULL sibling, instead.
12257 clutter_actor_raise_top (ClutterActor *self)
12259 clutter_actor_raise (self, NULL);
12263 * clutter_actor_lower_bottom:
12264 * @self: A #ClutterActor
12266 * Lowers @self to the bottom.
12268 * This function calls clutter_actor_lower() internally.
12270 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12271 * a %NULL sibling, instead.
12274 clutter_actor_lower_bottom (ClutterActor *self)
12276 clutter_actor_lower (self, NULL);
12284 * clutter_actor_event:
12285 * @actor: a #ClutterActor
12286 * @event: a #ClutterEvent
12287 * @capture: TRUE if event in in capture phase, FALSE otherwise.
12289 * This function is used to emit an event on the main stage.
12290 * You should rarely need to use this function, except for
12291 * synthetising events.
12293 * Return value: the return value from the signal emission: %TRUE
12294 * if the actor handled the event, or %FALSE if the event was
12300 clutter_actor_event (ClutterActor *actor,
12301 ClutterEvent *event,
12304 gboolean retval = FALSE;
12305 gint signal_num = -1;
12307 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12308 g_return_val_if_fail (event != NULL, FALSE);
12310 g_object_ref (actor);
12314 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12320 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12324 switch (event->type)
12326 case CLUTTER_NOTHING:
12328 case CLUTTER_BUTTON_PRESS:
12329 signal_num = BUTTON_PRESS_EVENT;
12331 case CLUTTER_BUTTON_RELEASE:
12332 signal_num = BUTTON_RELEASE_EVENT;
12334 case CLUTTER_SCROLL:
12335 signal_num = SCROLL_EVENT;
12337 case CLUTTER_KEY_PRESS:
12338 signal_num = KEY_PRESS_EVENT;
12340 case CLUTTER_KEY_RELEASE:
12341 signal_num = KEY_RELEASE_EVENT;
12343 case CLUTTER_MOTION:
12344 signal_num = MOTION_EVENT;
12346 case CLUTTER_ENTER:
12347 signal_num = ENTER_EVENT;
12349 case CLUTTER_LEAVE:
12350 signal_num = LEAVE_EVENT;
12352 case CLUTTER_DELETE:
12353 case CLUTTER_DESTROY_NOTIFY:
12354 case CLUTTER_CLIENT_MESSAGE:
12360 if (signal_num != -1)
12361 g_signal_emit (actor, actor_signals[signal_num], 0,
12366 g_object_unref (actor);
12372 * clutter_actor_set_reactive:
12373 * @actor: a #ClutterActor
12374 * @reactive: whether the actor should be reactive to events
12376 * Sets @actor as reactive. Reactive actors will receive events.
12381 clutter_actor_set_reactive (ClutterActor *actor,
12384 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12386 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12390 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12392 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12394 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12398 * clutter_actor_get_reactive:
12399 * @actor: a #ClutterActor
12401 * Checks whether @actor is marked as reactive.
12403 * Return value: %TRUE if the actor is reactive
12408 clutter_actor_get_reactive (ClutterActor *actor)
12410 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12412 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12416 * clutter_actor_get_anchor_point:
12417 * @self: a #ClutterActor
12418 * @anchor_x: (out): return location for the X coordinate of the anchor point
12419 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12421 * Gets the current anchor point of the @actor in pixels.
12426 clutter_actor_get_anchor_point (ClutterActor *self,
12430 const ClutterTransformInfo *info;
12432 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12434 info = _clutter_actor_get_transform_info_or_defaults (self);
12435 clutter_anchor_coord_get_units (self, &info->anchor,
12442 * clutter_actor_set_anchor_point:
12443 * @self: a #ClutterActor
12444 * @anchor_x: X coordinate of the anchor point
12445 * @anchor_y: Y coordinate of the anchor point
12447 * Sets an anchor point for @self. The anchor point is a point in the
12448 * coordinate space of an actor to which the actor position within its
12449 * parent is relative; the default is (0, 0), i.e. the top-left corner
12455 clutter_actor_set_anchor_point (ClutterActor *self,
12459 ClutterTransformInfo *info;
12460 ClutterActorPrivate *priv;
12461 gboolean changed = FALSE;
12462 gfloat old_anchor_x, old_anchor_y;
12465 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12467 obj = G_OBJECT (self);
12469 info = _clutter_actor_get_transform_info (self);
12471 g_object_freeze_notify (obj);
12473 clutter_anchor_coord_get_units (self, &info->anchor,
12478 if (info->anchor.is_fractional)
12479 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12481 if (old_anchor_x != anchor_x)
12483 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12487 if (old_anchor_y != anchor_y)
12489 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12493 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12497 priv->transform_valid = FALSE;
12498 clutter_actor_queue_redraw (self);
12501 g_object_thaw_notify (obj);
12505 * clutter_actor_get_anchor_point_gravity:
12506 * @self: a #ClutterActor
12508 * Retrieves the anchor position expressed as a #ClutterGravity. If
12509 * the anchor point was specified using pixels or units this will
12510 * return %CLUTTER_GRAVITY_NONE.
12512 * Return value: the #ClutterGravity used by the anchor point
12517 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12519 const ClutterTransformInfo *info;
12521 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12523 info = _clutter_actor_get_transform_info_or_defaults (self);
12525 return clutter_anchor_coord_get_gravity (&info->anchor);
12529 * clutter_actor_move_anchor_point:
12530 * @self: a #ClutterActor
12531 * @anchor_x: X coordinate of the anchor point
12532 * @anchor_y: Y coordinate of the anchor point
12534 * Sets an anchor point for the actor, and adjusts the actor postion so that
12535 * the relative position of the actor toward its parent remains the same.
12540 clutter_actor_move_anchor_point (ClutterActor *self,
12544 gfloat old_anchor_x, old_anchor_y;
12545 const ClutterTransformInfo *info;
12547 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12549 info = _clutter_actor_get_transform_info (self);
12550 clutter_anchor_coord_get_units (self, &info->anchor,
12555 g_object_freeze_notify (G_OBJECT (self));
12557 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12559 if (self->priv->position_set)
12560 clutter_actor_move_by (self,
12561 anchor_x - old_anchor_x,
12562 anchor_y - old_anchor_y);
12564 g_object_thaw_notify (G_OBJECT (self));
12568 * clutter_actor_move_anchor_point_from_gravity:
12569 * @self: a #ClutterActor
12570 * @gravity: #ClutterGravity.
12572 * Sets an anchor point on the actor based on the given gravity, adjusting the
12573 * actor postion so that its relative position within its parent remains
12576 * Since version 1.0 the anchor point will be stored as a gravity so
12577 * that if the actor changes size then the anchor point will move. For
12578 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12579 * and later double the size of the actor, the anchor point will move
12580 * to the bottom right.
12585 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12586 ClutterGravity gravity)
12588 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12589 const ClutterTransformInfo *info;
12590 ClutterActorPrivate *priv;
12592 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12595 info = _clutter_actor_get_transform_info (self);
12597 g_object_freeze_notify (G_OBJECT (self));
12599 clutter_anchor_coord_get_units (self, &info->anchor,
12603 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12604 clutter_anchor_coord_get_units (self, &info->anchor,
12609 if (priv->position_set)
12610 clutter_actor_move_by (self,
12611 new_anchor_x - old_anchor_x,
12612 new_anchor_y - old_anchor_y);
12614 g_object_thaw_notify (G_OBJECT (self));
12618 * clutter_actor_set_anchor_point_from_gravity:
12619 * @self: a #ClutterActor
12620 * @gravity: #ClutterGravity.
12622 * Sets an anchor point on the actor, based on the given gravity (this is a
12623 * convenience function wrapping clutter_actor_set_anchor_point()).
12625 * Since version 1.0 the anchor point will be stored as a gravity so
12626 * that if the actor changes size then the anchor point will move. For
12627 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12628 * and later double the size of the actor, the anchor point will move
12629 * to the bottom right.
12634 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12635 ClutterGravity gravity)
12637 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12639 if (gravity == CLUTTER_GRAVITY_NONE)
12640 clutter_actor_set_anchor_point (self, 0, 0);
12643 GObject *obj = G_OBJECT (self);
12644 ClutterTransformInfo *info;
12646 g_object_freeze_notify (obj);
12648 info = _clutter_actor_get_transform_info (self);
12649 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12651 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12652 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12653 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12655 self->priv->transform_valid = FALSE;
12657 clutter_actor_queue_redraw (self);
12659 g_object_thaw_notify (obj);
12664 clutter_actor_store_content_box (ClutterActor *self,
12665 const ClutterActorBox *box)
12669 self->priv->content_box = *box;
12670 self->priv->content_box_valid = TRUE;
12673 self->priv->content_box_valid = FALSE;
12675 clutter_actor_queue_redraw (self);
12677 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12681 clutter_container_iface_init (ClutterContainerIface *iface)
12683 /* we don't override anything, as ClutterContainer already has a default
12684 * implementation that we can use, and which calls into our own API.
12699 parse_units (ClutterActor *self,
12700 ParseDimension dimension,
12703 GValue value = G_VALUE_INIT;
12706 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12709 json_node_get_value (node, &value);
12711 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12713 retval = (gfloat) g_value_get_int64 (&value);
12715 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12717 retval = g_value_get_double (&value);
12719 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12721 ClutterUnits units;
12724 res = clutter_units_from_string (&units, g_value_get_string (&value));
12726 retval = clutter_units_to_pixels (&units);
12729 g_warning ("Invalid value '%s': integers, strings or floating point "
12730 "values can be used for the x, y, width and height "
12731 "properties. Valid modifiers for strings are 'px', 'mm', "
12733 g_value_get_string (&value));
12739 g_warning ("Invalid value of type '%s': integers, strings of floating "
12740 "point values can be used for the x, y, width, height "
12741 "anchor-x and anchor-y properties.",
12742 g_type_name (G_VALUE_TYPE (&value)));
12745 g_value_unset (&value);
12751 ClutterRotateAxis axis;
12760 static inline gboolean
12761 parse_rotation_array (ClutterActor *actor,
12763 RotationInfo *info)
12767 if (json_array_get_length (array) != 2)
12771 element = json_array_get_element (array, 0);
12772 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12773 info->angle = json_node_get_double (element);
12778 element = json_array_get_element (array, 1);
12779 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12781 JsonArray *center = json_node_get_array (element);
12783 if (json_array_get_length (center) != 2)
12786 switch (info->axis)
12788 case CLUTTER_X_AXIS:
12789 info->center_y = parse_units (actor, PARSE_Y,
12790 json_array_get_element (center, 0));
12791 info->center_z = parse_units (actor, PARSE_Y,
12792 json_array_get_element (center, 1));
12795 case CLUTTER_Y_AXIS:
12796 info->center_x = parse_units (actor, PARSE_X,
12797 json_array_get_element (center, 0));
12798 info->center_z = parse_units (actor, PARSE_X,
12799 json_array_get_element (center, 1));
12802 case CLUTTER_Z_AXIS:
12803 info->center_x = parse_units (actor, PARSE_X,
12804 json_array_get_element (center, 0));
12805 info->center_y = parse_units (actor, PARSE_Y,
12806 json_array_get_element (center, 1));
12815 parse_rotation (ClutterActor *actor,
12817 RotationInfo *info)
12821 gboolean retval = FALSE;
12823 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12825 g_warning ("Invalid node of type '%s' found, expecting an array",
12826 json_node_type_name (node));
12830 array = json_node_get_array (node);
12831 len = json_array_get_length (array);
12833 for (i = 0; i < len; i++)
12835 JsonNode *element = json_array_get_element (array, i);
12836 JsonObject *object;
12839 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12841 g_warning ("Invalid node of type '%s' found, expecting an object",
12842 json_node_type_name (element));
12846 object = json_node_get_object (element);
12848 if (json_object_has_member (object, "x-axis"))
12850 member = json_object_get_member (object, "x-axis");
12852 info->axis = CLUTTER_X_AXIS;
12854 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12856 info->angle = json_node_get_double (member);
12859 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12860 retval = parse_rotation_array (actor,
12861 json_node_get_array (member),
12866 else if (json_object_has_member (object, "y-axis"))
12868 member = json_object_get_member (object, "y-axis");
12870 info->axis = CLUTTER_Y_AXIS;
12872 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12874 info->angle = json_node_get_double (member);
12877 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12878 retval = parse_rotation_array (actor,
12879 json_node_get_array (member),
12884 else if (json_object_has_member (object, "z-axis"))
12886 member = json_object_get_member (object, "z-axis");
12888 info->axis = CLUTTER_Z_AXIS;
12890 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12892 info->angle = json_node_get_double (member);
12895 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12896 retval = parse_rotation_array (actor,
12897 json_node_get_array (member),
12908 parse_actor_metas (ClutterScript *script,
12909 ClutterActor *actor,
12912 GList *elements, *l;
12913 GSList *retval = NULL;
12915 if (!JSON_NODE_HOLDS_ARRAY (node))
12918 elements = json_array_get_elements (json_node_get_array (node));
12920 for (l = elements; l != NULL; l = l->next)
12922 JsonNode *element = l->data;
12923 const gchar *id_ = _clutter_script_get_id_from_node (element);
12926 if (id_ == NULL || *id_ == '\0')
12929 meta = clutter_script_get_object (script, id_);
12933 retval = g_slist_prepend (retval, meta);
12936 g_list_free (elements);
12938 return g_slist_reverse (retval);
12942 parse_behaviours (ClutterScript *script,
12943 ClutterActor *actor,
12946 GList *elements, *l;
12947 GSList *retval = NULL;
12949 if (!JSON_NODE_HOLDS_ARRAY (node))
12952 elements = json_array_get_elements (json_node_get_array (node));
12954 for (l = elements; l != NULL; l = l->next)
12956 JsonNode *element = l->data;
12957 const gchar *id_ = _clutter_script_get_id_from_node (element);
12958 GObject *behaviour;
12960 if (id_ == NULL || *id_ == '\0')
12963 behaviour = clutter_script_get_object (script, id_);
12964 if (behaviour == NULL)
12967 retval = g_slist_prepend (retval, behaviour);
12970 g_list_free (elements);
12972 return g_slist_reverse (retval);
12976 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12977 ClutterScript *script,
12982 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12983 gboolean retval = FALSE;
12985 if ((name[0] == 'x' && name[1] == '\0') ||
12986 (name[0] == 'y' && name[1] == '\0') ||
12987 (strcmp (name, "width") == 0) ||
12988 (strcmp (name, "height") == 0) ||
12989 (strcmp (name, "anchor_x") == 0) ||
12990 (strcmp (name, "anchor_y") == 0))
12992 ParseDimension dimension;
12995 if (name[0] == 'x')
12996 dimension = PARSE_X;
12997 else if (name[0] == 'y')
12998 dimension = PARSE_Y;
12999 else if (name[0] == 'w')
13000 dimension = PARSE_WIDTH;
13001 else if (name[0] == 'h')
13002 dimension = PARSE_HEIGHT;
13003 else if (name[0] == 'a' && name[7] == 'x')
13004 dimension = PARSE_ANCHOR_X;
13005 else if (name[0] == 'a' && name[7] == 'y')
13006 dimension = PARSE_ANCHOR_Y;
13010 units = parse_units (actor, dimension, node);
13012 /* convert back to pixels: all properties are pixel-based */
13013 g_value_init (value, G_TYPE_FLOAT);
13014 g_value_set_float (value, units);
13018 else if (strcmp (name, "rotation") == 0)
13020 RotationInfo *info;
13022 info = g_slice_new0 (RotationInfo);
13023 retval = parse_rotation (actor, node, info);
13027 g_value_init (value, G_TYPE_POINTER);
13028 g_value_set_pointer (value, info);
13031 g_slice_free (RotationInfo, info);
13033 else if (strcmp (name, "behaviours") == 0)
13037 #ifdef CLUTTER_ENABLE_DEBUG
13038 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13039 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13040 "and it should not be used in newly "
13041 "written ClutterScript definitions.");
13044 l = parse_behaviours (script, actor, node);
13046 g_value_init (value, G_TYPE_POINTER);
13047 g_value_set_pointer (value, l);
13051 else if (strcmp (name, "actions") == 0 ||
13052 strcmp (name, "constraints") == 0 ||
13053 strcmp (name, "effects") == 0)
13057 l = parse_actor_metas (script, actor, node);
13059 g_value_init (value, G_TYPE_POINTER);
13060 g_value_set_pointer (value, l);
13069 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13070 ClutterScript *script,
13072 const GValue *value)
13074 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13076 #ifdef CLUTTER_ENABLE_DEBUG
13077 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13079 gchar *tmp = g_strdup_value_contents (value);
13081 CLUTTER_NOTE (SCRIPT,
13082 "in ClutterActor::set_custom_property('%s') = %s",
13088 #endif /* CLUTTER_ENABLE_DEBUG */
13090 if (strcmp (name, "rotation") == 0)
13092 RotationInfo *info;
13094 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13097 info = g_value_get_pointer (value);
13099 clutter_actor_set_rotation (actor,
13100 info->axis, info->angle,
13105 g_slice_free (RotationInfo, info);
13110 if (strcmp (name, "behaviours") == 0)
13112 GSList *behaviours, *l;
13114 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13117 behaviours = g_value_get_pointer (value);
13118 for (l = behaviours; l != NULL; l = l->next)
13120 ClutterBehaviour *behaviour = l->data;
13122 clutter_behaviour_apply (behaviour, actor);
13125 g_slist_free (behaviours);
13130 if (strcmp (name, "actions") == 0 ||
13131 strcmp (name, "constraints") == 0 ||
13132 strcmp (name, "effects") == 0)
13136 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13139 metas = g_value_get_pointer (value);
13140 for (l = metas; l != NULL; l = l->next)
13142 if (name[0] == 'a')
13143 clutter_actor_add_action (actor, l->data);
13145 if (name[0] == 'c')
13146 clutter_actor_add_constraint (actor, l->data);
13148 if (name[0] == 'e')
13149 clutter_actor_add_effect (actor, l->data);
13152 g_slist_free (metas);
13157 g_object_set_property (G_OBJECT (scriptable), name, value);
13161 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13163 iface->parse_custom_node = clutter_actor_parse_custom_node;
13164 iface->set_custom_property = clutter_actor_set_custom_property;
13167 static ClutterActorMeta *
13168 get_meta_from_animation_property (ClutterActor *actor,
13172 ClutterActorPrivate *priv = actor->priv;
13173 ClutterActorMeta *meta = NULL;
13176 /* if this is not a special property, fall through */
13177 if (name[0] != '@')
13180 /* detect the properties named using the following spec:
13182 * @<section>.<meta-name>.<property-name>
13184 * where <section> can be one of the following:
13190 * and <meta-name> is the name set on a specific ActorMeta
13193 tokens = g_strsplit (name + 1, ".", -1);
13194 if (tokens == NULL || g_strv_length (tokens) != 3)
13196 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13198 g_strfreev (tokens);
13202 if (strcmp (tokens[0], "actions") == 0)
13203 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13205 if (strcmp (tokens[0], "constraints") == 0)
13206 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13208 if (strcmp (tokens[0], "effects") == 0)
13209 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13211 if (name_p != NULL)
13212 *name_p = g_strdup (tokens[2]);
13214 CLUTTER_NOTE (ANIMATION,
13215 "Looking for property '%s' of object '%s' in section '%s'",
13220 g_strfreev (tokens);
13225 static GParamSpec *
13226 clutter_actor_find_property (ClutterAnimatable *animatable,
13227 const gchar *property_name)
13229 ClutterActorMeta *meta = NULL;
13230 GObjectClass *klass = NULL;
13231 GParamSpec *pspec = NULL;
13232 gchar *p_name = NULL;
13234 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13240 klass = G_OBJECT_GET_CLASS (meta);
13242 pspec = g_object_class_find_property (klass, p_name);
13246 klass = G_OBJECT_GET_CLASS (animatable);
13248 pspec = g_object_class_find_property (klass, property_name);
13257 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13258 const gchar *property_name,
13261 ClutterActorMeta *meta = NULL;
13262 gchar *p_name = NULL;
13264 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13269 g_object_get_property (G_OBJECT (meta), p_name, initial);
13271 g_object_get_property (G_OBJECT (animatable), property_name, initial);
13277 * clutter_actor_set_animatable_property:
13278 * @actor: a #ClutterActor
13279 * @prop_id: the paramspec id
13280 * @value: the value to set
13281 * @pspec: the paramspec
13283 * Sets values of animatable properties.
13285 * This is a variant of clutter_actor_set_property() that gets called
13286 * by the #ClutterAnimatable implementation of #ClutterActor for the
13287 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13290 * Unlike the implementation of #GObjectClass.set_property(), this
13291 * function will not update the interval if a transition involving an
13292 * animatable property is in progress - this avoids cycles with the
13293 * transition API calling the public API.
13296 clutter_actor_set_animatable_property (ClutterActor *actor,
13298 const GValue *value,
13301 GObject *obj = G_OBJECT (actor);
13303 g_object_freeze_notify (obj);
13308 clutter_actor_set_x_internal (actor, g_value_get_float (value));
13312 clutter_actor_set_y_internal (actor, g_value_get_float (value));
13315 case PROP_POSITION:
13316 clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13320 clutter_actor_set_width_internal (actor, g_value_get_float (value));
13324 clutter_actor_set_height_internal (actor, g_value_get_float (value));
13328 clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13332 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13336 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13339 case PROP_BACKGROUND_COLOR:
13340 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13344 clutter_actor_set_scale_factor_internal (actor,
13345 g_value_get_double (value),
13350 clutter_actor_set_scale_factor_internal (actor,
13351 g_value_get_double (value),
13355 case PROP_ROTATION_ANGLE_X:
13356 clutter_actor_set_rotation_angle_internal (actor,
13358 g_value_get_double (value));
13361 case PROP_ROTATION_ANGLE_Y:
13362 clutter_actor_set_rotation_angle_internal (actor,
13364 g_value_get_double (value));
13367 case PROP_ROTATION_ANGLE_Z:
13368 clutter_actor_set_rotation_angle_internal (actor,
13370 g_value_get_double (value));
13373 case PROP_CONTENT_BOX:
13374 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13378 g_object_set_property (obj, pspec->name, value);
13382 g_object_thaw_notify (obj);
13386 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13387 const gchar *property_name,
13388 const GValue *final)
13390 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13391 ClutterActorMeta *meta = NULL;
13392 gchar *p_name = NULL;
13394 meta = get_meta_from_animation_property (actor,
13398 g_object_set_property (G_OBJECT (meta), p_name, final);
13401 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13404 pspec = g_object_class_find_property (obj_class, property_name);
13406 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13408 /* XXX - I'm going to the special hell for this */
13409 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13412 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13419 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13421 iface->find_property = clutter_actor_find_property;
13422 iface->get_initial_state = clutter_actor_get_initial_state;
13423 iface->set_final_state = clutter_actor_set_final_state;
13427 * clutter_actor_transform_stage_point:
13428 * @self: A #ClutterActor
13429 * @x: (in): x screen coordinate of the point to unproject
13430 * @y: (in): y screen coordinate of the point to unproject
13431 * @x_out: (out): return location for the unprojected x coordinance
13432 * @y_out: (out): return location for the unprojected y coordinance
13434 * This function translates screen coordinates (@x, @y) to
13435 * coordinates relative to the actor. For example, it can be used to translate
13436 * screen events from global screen coordinates into actor-local coordinates.
13438 * The conversion can fail, notably if the transform stack results in the
13439 * actor being projected on the screen as a mere line.
13441 * The conversion should not be expected to be pixel-perfect due to the
13442 * nature of the operation. In general the error grows when the skewing
13443 * of the actor rectangle on screen increases.
13445 * <note><para>This function can be computationally intensive.</para></note>
13447 * <note><para>This function only works when the allocation is up-to-date,
13448 * i.e. inside of paint().</para></note>
13450 * Return value: %TRUE if conversion was successful.
13455 clutter_actor_transform_stage_point (ClutterActor *self,
13461 ClutterVertex v[4];
13464 int du, dv, xi, yi;
13466 float xf, yf, wf, det;
13467 ClutterActorPrivate *priv;
13469 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13473 /* This implementation is based on the quad -> quad projection algorithm
13474 * described by Paul Heckbert in:
13476 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13478 * and the sample implementation at:
13480 * http://www.cs.cmu.edu/~ph/src/texfund/
13482 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13483 * quad to rectangle only, which significantly simplifies things; the
13484 * function calls have been unrolled, and most of the math is done in fixed
13488 clutter_actor_get_abs_allocation_vertices (self, v);
13490 /* Keeping these as ints simplifies the multiplication (no significant
13491 * loss of precision here).
13493 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13494 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13499 #define UX2FP(x) (x)
13500 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13502 /* First, find mapping from unit uv square to xy quadrilateral; this
13503 * equivalent to the pmap_square_quad() functions in the sample
13504 * implementation, which we can simplify, since our target is always
13507 px = v[0].x - v[1].x + v[3].x - v[2].x;
13508 py = v[0].y - v[1].y + v[3].y - v[2].y;
13512 /* affine transform */
13513 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13514 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13515 RQ[2][0] = UX2FP (v[0].x);
13516 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13517 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13518 RQ[2][1] = UX2FP (v[0].y);
13525 /* projective transform */
13526 double dx1, dx2, dy1, dy2, del;
13528 dx1 = UX2FP (v[1].x - v[3].x);
13529 dx2 = UX2FP (v[2].x - v[3].x);
13530 dy1 = UX2FP (v[1].y - v[3].y);
13531 dy2 = UX2FP (v[2].y - v[3].y);
13533 del = DET2FP (dx1, dx2, dy1, dy2);
13538 * The division here needs to be done in floating point for
13539 * precisions reasons.
13541 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13542 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13543 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13545 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13546 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13547 RQ[2][0] = UX2FP (v[0].x);
13548 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13549 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13550 RQ[2][1] = UX2FP (v[0].y);
13554 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13555 * square. Since our rectangle is based at 0,0 we only need to scale.
13565 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13568 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13569 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13570 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13571 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13572 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13573 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13574 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13575 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13576 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13579 * Check the resulting matrix is OK.
13581 det = (RQ[0][0] * ST[0][0])
13582 + (RQ[0][1] * ST[0][1])
13583 + (RQ[0][2] * ST[0][2]);
13588 * Now transform our point with the ST matrix; the notional w
13589 * coordinate is 1, hence the last part is simply added.
13594 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13595 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13596 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13611 * clutter_actor_is_rotated:
13612 * @self: a #ClutterActor
13614 * Checks whether any rotation is applied to the actor.
13616 * Return value: %TRUE if the actor is rotated.
13621 clutter_actor_is_rotated (ClutterActor *self)
13623 const ClutterTransformInfo *info;
13625 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13627 info = _clutter_actor_get_transform_info_or_defaults (self);
13629 if (info->rx_angle || info->ry_angle || info->rz_angle)
13636 * clutter_actor_is_scaled:
13637 * @self: a #ClutterActor
13639 * Checks whether the actor is scaled in either dimension.
13641 * Return value: %TRUE if the actor is scaled.
13646 clutter_actor_is_scaled (ClutterActor *self)
13648 const ClutterTransformInfo *info;
13650 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13652 info = _clutter_actor_get_transform_info_or_defaults (self);
13654 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13661 _clutter_actor_get_stage_internal (ClutterActor *actor)
13663 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13664 actor = actor->priv->parent;
13670 * clutter_actor_get_stage:
13671 * @actor: a #ClutterActor
13673 * Retrieves the #ClutterStage where @actor is contained.
13675 * Return value: (transfer none) (type Clutter.Stage): the stage
13676 * containing the actor, or %NULL
13681 clutter_actor_get_stage (ClutterActor *actor)
13683 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13685 return _clutter_actor_get_stage_internal (actor);
13689 * clutter_actor_allocate_available_size:
13690 * @self: a #ClutterActor
13691 * @x: the actor's X coordinate
13692 * @y: the actor's Y coordinate
13693 * @available_width: the maximum available width, or -1 to use the
13694 * actor's natural width
13695 * @available_height: the maximum available height, or -1 to use the
13696 * actor's natural height
13697 * @flags: flags controlling the allocation
13699 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13700 * preferred size, but limiting it to the maximum available width
13701 * and height provided.
13703 * This function will do the right thing when dealing with the
13704 * actor's request mode.
13706 * The implementation of this function is equivalent to:
13709 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13711 * clutter_actor_get_preferred_width (self, available_height,
13713 * &natural_width);
13714 * width = CLAMP (natural_width, min_width, available_width);
13716 * clutter_actor_get_preferred_height (self, width,
13718 * &natural_height);
13719 * height = CLAMP (natural_height, min_height, available_height);
13723 * clutter_actor_get_preferred_height (self, available_width,
13725 * &natural_height);
13726 * height = CLAMP (natural_height, min_height, available_height);
13728 * clutter_actor_get_preferred_width (self, height,
13730 * &natural_width);
13731 * width = CLAMP (natural_width, min_width, available_width);
13734 * box.x1 = x; box.y1 = y;
13735 * box.x2 = box.x1 + available_width;
13736 * box.y2 = box.y1 + available_height;
13737 * clutter_actor_allocate (self, &box, flags);
13740 * This function can be used by fluid layout managers to allocate
13741 * an actor's preferred size without making it bigger than the area
13742 * available for the container.
13747 clutter_actor_allocate_available_size (ClutterActor *self,
13750 gfloat available_width,
13751 gfloat available_height,
13752 ClutterAllocationFlags flags)
13754 ClutterActorPrivate *priv;
13755 gfloat width, height;
13756 gfloat min_width, min_height;
13757 gfloat natural_width, natural_height;
13758 ClutterActorBox box;
13760 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13764 width = height = 0.0;
13766 switch (priv->request_mode)
13768 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13769 clutter_actor_get_preferred_width (self, available_height,
13772 width = CLAMP (natural_width, min_width, available_width);
13774 clutter_actor_get_preferred_height (self, width,
13777 height = CLAMP (natural_height, min_height, available_height);
13780 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13781 clutter_actor_get_preferred_height (self, available_width,
13784 height = CLAMP (natural_height, min_height, available_height);
13786 clutter_actor_get_preferred_width (self, height,
13789 width = CLAMP (natural_width, min_width, available_width);
13796 box.x2 = box.x1 + width;
13797 box.y2 = box.y1 + height;
13798 clutter_actor_allocate (self, &box, flags);
13802 * clutter_actor_allocate_preferred_size:
13803 * @self: a #ClutterActor
13804 * @flags: flags controlling the allocation
13806 * Allocates the natural size of @self.
13808 * This function is a utility call for #ClutterActor implementations
13809 * that allocates the actor's preferred natural size. It can be used
13810 * by fixed layout managers (like #ClutterGroup or so called
13811 * 'composite actors') inside the ClutterActor::allocate
13812 * implementation to give each child exactly how much space it
13815 * This function is not meant to be used by applications. It is also
13816 * not meant to be used outside the implementation of the
13817 * ClutterActor::allocate virtual function.
13822 clutter_actor_allocate_preferred_size (ClutterActor *self,
13823 ClutterAllocationFlags flags)
13825 gfloat actor_x, actor_y;
13826 gfloat natural_width, natural_height;
13827 ClutterActorBox actor_box;
13829 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13831 actor_x = clutter_actor_get_x (self);
13832 actor_y = clutter_actor_get_y (self);
13834 clutter_actor_get_preferred_size (self,
13839 actor_box.x1 = actor_x;
13840 actor_box.y1 = actor_y;
13841 actor_box.x2 = actor_box.x1 + natural_width;
13842 actor_box.y2 = actor_box.y1 + natural_height;
13844 clutter_actor_allocate (self, &actor_box, flags);
13848 * clutter_actor_allocate_align_fill:
13849 * @self: a #ClutterActor
13850 * @box: a #ClutterActorBox, containing the available width and height
13851 * @x_align: the horizontal alignment, between 0 and 1
13852 * @y_align: the vertical alignment, between 0 and 1
13853 * @x_fill: whether the actor should fill horizontally
13854 * @y_fill: whether the actor should fill vertically
13855 * @flags: allocation flags to be passed to clutter_actor_allocate()
13857 * Allocates @self by taking into consideration the available allocation
13858 * area; an alignment factor on either axis; and whether the actor should
13859 * fill the allocation on either axis.
13861 * The @box should contain the available allocation width and height;
13862 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13863 * allocation will be offset by their value.
13865 * This function takes into consideration the geometry request specified by
13866 * the #ClutterActor:request-mode property, and the text direction.
13868 * This function is useful for fluid layout managers, like #ClutterBinLayout
13869 * or #ClutterTableLayout
13874 clutter_actor_allocate_align_fill (ClutterActor *self,
13875 const ClutterActorBox *box,
13880 ClutterAllocationFlags flags)
13882 ClutterActorPrivate *priv;
13883 ClutterActorBox allocation = { 0, };
13884 gfloat x_offset, y_offset;
13885 gfloat available_width, available_height;
13886 gfloat child_width, child_height;
13888 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13889 g_return_if_fail (box != NULL);
13890 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13891 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13895 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13896 clutter_actor_box_get_size (box, &available_width, &available_height);
13898 if (available_width < 0)
13899 available_width = 0;
13901 if (available_height < 0)
13902 available_height = 0;
13906 allocation.x1 = x_offset;
13907 allocation.x2 = allocation.x1 + available_width;
13912 allocation.y1 = y_offset;
13913 allocation.y2 = allocation.y1 + available_height;
13916 /* if we are filling horizontally and vertically then we're done */
13917 if (x_fill && y_fill)
13920 child_width = child_height = 0.0f;
13922 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13924 gfloat min_width, natural_width;
13925 gfloat min_height, natural_height;
13927 clutter_actor_get_preferred_width (self, available_height,
13931 child_width = CLAMP (natural_width, min_width, available_width);
13935 clutter_actor_get_preferred_height (self, child_width,
13939 child_height = CLAMP (natural_height, min_height, available_height);
13944 gfloat min_width, natural_width;
13945 gfloat min_height, natural_height;
13947 clutter_actor_get_preferred_height (self, available_width,
13951 child_height = CLAMP (natural_height, min_height, available_height);
13955 clutter_actor_get_preferred_width (self, child_height,
13959 child_width = CLAMP (natural_width, min_width, available_width);
13963 /* invert the horizontal alignment for RTL languages */
13964 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13965 x_align = 1.0 - x_align;
13969 allocation.x1 = x_offset
13970 + ((available_width - child_width) * x_align);
13971 allocation.x2 = allocation.x1 + child_width;
13976 allocation.y1 = y_offset
13977 + ((available_height - child_height) * y_align);
13978 allocation.y2 = allocation.y1 + child_height;
13982 clutter_actor_box_clamp_to_pixel (&allocation);
13983 clutter_actor_allocate (self, &allocation, flags);
13987 * clutter_actor_grab_key_focus:
13988 * @self: a #ClutterActor
13990 * Sets the key focus of the #ClutterStage including @self
13991 * to this #ClutterActor.
13996 clutter_actor_grab_key_focus (ClutterActor *self)
13998 ClutterActor *stage;
14000 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14002 stage = _clutter_actor_get_stage_internal (self);
14004 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14008 * clutter_actor_get_pango_context:
14009 * @self: a #ClutterActor
14011 * Retrieves the #PangoContext for @self. The actor's #PangoContext
14012 * is already configured using the appropriate font map, resolution
14013 * and font options.
14015 * Unlike clutter_actor_create_pango_context(), this context is owend
14016 * by the #ClutterActor and it will be updated each time the options
14017 * stored by the #ClutterBackend change.
14019 * You can use the returned #PangoContext to create a #PangoLayout
14020 * and render text using cogl_pango_render_layout() to reuse the
14021 * glyphs cache also used by Clutter.
14023 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14024 * The returned #PangoContext is owned by the actor and should not be
14025 * unreferenced by the application code
14030 clutter_actor_get_pango_context (ClutterActor *self)
14032 ClutterActorPrivate *priv;
14034 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14038 if (priv->pango_context != NULL)
14039 return priv->pango_context;
14041 priv->pango_context = _clutter_context_get_pango_context ();
14042 g_object_ref (priv->pango_context);
14044 return priv->pango_context;
14048 * clutter_actor_create_pango_context:
14049 * @self: a #ClutterActor
14051 * Creates a #PangoContext for the given actor. The #PangoContext
14052 * is already configured using the appropriate font map, resolution
14053 * and font options.
14055 * See also clutter_actor_get_pango_context().
14057 * Return value: (transfer full): the newly created #PangoContext.
14058 * Use g_object_unref() on the returned value to deallocate its
14064 clutter_actor_create_pango_context (ClutterActor *self)
14066 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14068 return _clutter_context_create_pango_context ();
14072 * clutter_actor_create_pango_layout:
14073 * @self: a #ClutterActor
14074 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14076 * Creates a new #PangoLayout from the same #PangoContext used
14077 * by the #ClutterActor. The #PangoLayout is already configured
14078 * with the font map, resolution and font options, and the
14081 * If you want to keep around a #PangoLayout created by this
14082 * function you will have to connect to the #ClutterBackend::font-changed
14083 * and #ClutterBackend::resolution-changed signals, and call
14084 * pango_layout_context_changed() in response to them.
14086 * Return value: (transfer full): the newly created #PangoLayout.
14087 * Use g_object_unref() when done
14092 clutter_actor_create_pango_layout (ClutterActor *self,
14095 PangoContext *context;
14096 PangoLayout *layout;
14098 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14100 context = clutter_actor_get_pango_context (self);
14101 layout = pango_layout_new (context);
14104 pango_layout_set_text (layout, text, -1);
14109 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14110 * ClutterOffscreenEffect.
14113 _clutter_actor_set_opacity_override (ClutterActor *self,
14116 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14118 self->priv->opacity_override = opacity;
14122 _clutter_actor_get_opacity_override (ClutterActor *self)
14124 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14126 return self->priv->opacity_override;
14129 /* Allows you to disable applying the actors model view transform during
14130 * a paint. Used by ClutterClone. */
14132 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14135 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14137 self->priv->enable_model_view_transform = enable;
14141 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14144 ClutterActorPrivate *priv;
14146 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14150 priv->enable_paint_unmapped = enable;
14152 if (priv->enable_paint_unmapped)
14154 /* Make sure that the parents of the widget are realized first;
14155 * otherwise checks in clutter_actor_update_map_state() will
14158 clutter_actor_realize (self);
14160 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14164 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14169 clutter_anchor_coord_get_units (ClutterActor *self,
14170 const AnchorCoord *coord,
14175 if (coord->is_fractional)
14177 gfloat actor_width, actor_height;
14179 clutter_actor_get_size (self, &actor_width, &actor_height);
14182 *x = actor_width * coord->v.fraction.x;
14185 *y = actor_height * coord->v.fraction.y;
14193 *x = coord->v.units.x;
14196 *y = coord->v.units.y;
14199 *z = coord->v.units.z;
14204 clutter_anchor_coord_set_units (AnchorCoord *coord,
14209 coord->is_fractional = FALSE;
14210 coord->v.units.x = x;
14211 coord->v.units.y = y;
14212 coord->v.units.z = z;
14215 static ClutterGravity
14216 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14218 if (coord->is_fractional)
14220 if (coord->v.fraction.x == 0.0)
14222 if (coord->v.fraction.y == 0.0)
14223 return CLUTTER_GRAVITY_NORTH_WEST;
14224 else if (coord->v.fraction.y == 0.5)
14225 return CLUTTER_GRAVITY_WEST;
14226 else if (coord->v.fraction.y == 1.0)
14227 return CLUTTER_GRAVITY_SOUTH_WEST;
14229 return CLUTTER_GRAVITY_NONE;
14231 else if (coord->v.fraction.x == 0.5)
14233 if (coord->v.fraction.y == 0.0)
14234 return CLUTTER_GRAVITY_NORTH;
14235 else if (coord->v.fraction.y == 0.5)
14236 return CLUTTER_GRAVITY_CENTER;
14237 else if (coord->v.fraction.y == 1.0)
14238 return CLUTTER_GRAVITY_SOUTH;
14240 return CLUTTER_GRAVITY_NONE;
14242 else if (coord->v.fraction.x == 1.0)
14244 if (coord->v.fraction.y == 0.0)
14245 return CLUTTER_GRAVITY_NORTH_EAST;
14246 else if (coord->v.fraction.y == 0.5)
14247 return CLUTTER_GRAVITY_EAST;
14248 else if (coord->v.fraction.y == 1.0)
14249 return CLUTTER_GRAVITY_SOUTH_EAST;
14251 return CLUTTER_GRAVITY_NONE;
14254 return CLUTTER_GRAVITY_NONE;
14257 return CLUTTER_GRAVITY_NONE;
14261 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14262 ClutterGravity gravity)
14266 case CLUTTER_GRAVITY_NORTH:
14267 coord->v.fraction.x = 0.5;
14268 coord->v.fraction.y = 0.0;
14271 case CLUTTER_GRAVITY_NORTH_EAST:
14272 coord->v.fraction.x = 1.0;
14273 coord->v.fraction.y = 0.0;
14276 case CLUTTER_GRAVITY_EAST:
14277 coord->v.fraction.x = 1.0;
14278 coord->v.fraction.y = 0.5;
14281 case CLUTTER_GRAVITY_SOUTH_EAST:
14282 coord->v.fraction.x = 1.0;
14283 coord->v.fraction.y = 1.0;
14286 case CLUTTER_GRAVITY_SOUTH:
14287 coord->v.fraction.x = 0.5;
14288 coord->v.fraction.y = 1.0;
14291 case CLUTTER_GRAVITY_SOUTH_WEST:
14292 coord->v.fraction.x = 0.0;
14293 coord->v.fraction.y = 1.0;
14296 case CLUTTER_GRAVITY_WEST:
14297 coord->v.fraction.x = 0.0;
14298 coord->v.fraction.y = 0.5;
14301 case CLUTTER_GRAVITY_NORTH_WEST:
14302 coord->v.fraction.x = 0.0;
14303 coord->v.fraction.y = 0.0;
14306 case CLUTTER_GRAVITY_CENTER:
14307 coord->v.fraction.x = 0.5;
14308 coord->v.fraction.y = 0.5;
14312 coord->v.fraction.x = 0.0;
14313 coord->v.fraction.y = 0.0;
14317 coord->is_fractional = TRUE;
14321 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14323 if (coord->is_fractional)
14324 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14326 return (coord->v.units.x == 0.0
14327 && coord->v.units.y == 0.0
14328 && coord->v.units.z == 0.0);
14332 * clutter_actor_get_flags:
14333 * @self: a #ClutterActor
14335 * Retrieves the flags set on @self
14337 * Return value: a bitwise or of #ClutterActorFlags or 0
14342 clutter_actor_get_flags (ClutterActor *self)
14344 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14346 return self->flags;
14350 * clutter_actor_set_flags:
14351 * @self: a #ClutterActor
14352 * @flags: the flags to set
14354 * Sets @flags on @self
14356 * This function will emit notifications for the changed properties
14361 clutter_actor_set_flags (ClutterActor *self,
14362 ClutterActorFlags flags)
14364 ClutterActorFlags old_flags;
14366 gboolean was_reactive_set, reactive_set;
14367 gboolean was_realized_set, realized_set;
14368 gboolean was_mapped_set, mapped_set;
14369 gboolean was_visible_set, visible_set;
14371 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14373 if (self->flags == flags)
14376 obj = G_OBJECT (self);
14377 g_object_ref (obj);
14378 g_object_freeze_notify (obj);
14380 old_flags = self->flags;
14382 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14383 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14384 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14385 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14387 self->flags |= flags;
14389 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14390 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14391 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14392 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14394 if (reactive_set != was_reactive_set)
14395 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14397 if (realized_set != was_realized_set)
14398 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14400 if (mapped_set != was_mapped_set)
14401 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14403 if (visible_set != was_visible_set)
14404 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14406 g_object_thaw_notify (obj);
14407 g_object_unref (obj);
14411 * clutter_actor_unset_flags:
14412 * @self: a #ClutterActor
14413 * @flags: the flags to unset
14415 * Unsets @flags on @self
14417 * This function will emit notifications for the changed properties
14422 clutter_actor_unset_flags (ClutterActor *self,
14423 ClutterActorFlags flags)
14425 ClutterActorFlags old_flags;
14427 gboolean was_reactive_set, reactive_set;
14428 gboolean was_realized_set, realized_set;
14429 gboolean was_mapped_set, mapped_set;
14430 gboolean was_visible_set, visible_set;
14432 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14434 obj = G_OBJECT (self);
14435 g_object_freeze_notify (obj);
14437 old_flags = self->flags;
14439 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14440 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14441 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14442 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14444 self->flags &= ~flags;
14446 if (self->flags == old_flags)
14449 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14450 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14451 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14452 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14454 if (reactive_set != was_reactive_set)
14455 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14457 if (realized_set != was_realized_set)
14458 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14460 if (mapped_set != was_mapped_set)
14461 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14463 if (visible_set != was_visible_set)
14464 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14466 g_object_thaw_notify (obj);
14470 * clutter_actor_get_transformation_matrix:
14471 * @self: a #ClutterActor
14472 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14474 * Retrieves the transformations applied to @self relative to its
14480 clutter_actor_get_transformation_matrix (ClutterActor *self,
14481 CoglMatrix *matrix)
14483 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14485 cogl_matrix_init_identity (matrix);
14487 _clutter_actor_apply_modelview_transform (self, matrix);
14491 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14492 gboolean is_in_clone_paint)
14494 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14495 self->priv->in_clone_paint = is_in_clone_paint;
14499 * clutter_actor_is_in_clone_paint:
14500 * @self: a #ClutterActor
14502 * Checks whether @self is being currently painted by a #ClutterClone
14504 * This function is useful only inside the ::paint virtual function
14505 * implementations or within handlers for the #ClutterActor::paint
14508 * This function should not be used by applications
14510 * Return value: %TRUE if the #ClutterActor is currently being painted
14511 * by a #ClutterClone, and %FALSE otherwise
14516 clutter_actor_is_in_clone_paint (ClutterActor *self)
14518 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14520 return self->priv->in_clone_paint;
14524 set_direction_recursive (ClutterActor *actor,
14525 gpointer user_data)
14527 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14529 clutter_actor_set_text_direction (actor, text_dir);
14535 * clutter_actor_set_text_direction:
14536 * @self: a #ClutterActor
14537 * @text_dir: the text direction for @self
14539 * Sets the #ClutterTextDirection for an actor
14541 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14543 * If @self implements #ClutterContainer then this function will recurse
14544 * inside all the children of @self (including the internal ones).
14546 * Composite actors not implementing #ClutterContainer, or actors requiring
14547 * special handling when the text direction changes, should connect to
14548 * the #GObject::notify signal for the #ClutterActor:text-direction property
14553 clutter_actor_set_text_direction (ClutterActor *self,
14554 ClutterTextDirection text_dir)
14556 ClutterActorPrivate *priv;
14558 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14559 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14563 if (priv->text_direction != text_dir)
14565 priv->text_direction = text_dir;
14567 /* we need to emit the notify::text-direction first, so that
14568 * the sub-classes can catch that and do specific handling of
14569 * the text direction; see clutter_text_direction_changed_cb()
14570 * inside clutter-text.c
14572 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14574 _clutter_actor_foreach_child (self, set_direction_recursive,
14575 GINT_TO_POINTER (text_dir));
14577 clutter_actor_queue_relayout (self);
14582 _clutter_actor_set_has_pointer (ClutterActor *self,
14583 gboolean has_pointer)
14585 ClutterActorPrivate *priv = self->priv;
14587 if (priv->has_pointer != has_pointer)
14589 priv->has_pointer = has_pointer;
14591 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14596 * clutter_actor_get_text_direction:
14597 * @self: a #ClutterActor
14599 * Retrieves the value set using clutter_actor_set_text_direction()
14601 * If no text direction has been previously set, the default text
14602 * direction, as returned by clutter_get_default_text_direction(), will
14603 * be returned instead
14605 * Return value: the #ClutterTextDirection for the actor
14609 ClutterTextDirection
14610 clutter_actor_get_text_direction (ClutterActor *self)
14612 ClutterActorPrivate *priv;
14614 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14615 CLUTTER_TEXT_DIRECTION_LTR);
14619 /* if no direction has been set yet use the default */
14620 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14621 priv->text_direction = clutter_get_default_text_direction ();
14623 return priv->text_direction;
14627 * clutter_actor_push_internal:
14628 * @self: a #ClutterActor
14630 * Should be used by actors implementing the #ClutterContainer and with
14631 * internal children added through clutter_actor_set_parent(), for instance:
14635 * my_actor_init (MyActor *self)
14637 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14639 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14641 * /* calling clutter_actor_set_parent() now will result in
14642 * * the internal flag being set on a child of MyActor
14645 * /* internal child - a background texture */
14646 * self->priv->background_tex = clutter_texture_new ();
14647 * clutter_actor_set_parent (self->priv->background_tex,
14648 * CLUTTER_ACTOR (self));
14650 * /* internal child - a label */
14651 * self->priv->label = clutter_text_new ();
14652 * clutter_actor_set_parent (self->priv->label,
14653 * CLUTTER_ACTOR (self));
14655 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14657 * /* calling clutter_actor_set_parent() now will not result in
14658 * * the internal flag being set on a child of MyActor
14663 * This function will be used by Clutter to toggle an "internal child"
14664 * flag whenever clutter_actor_set_parent() is called; internal children
14665 * are handled differently by Clutter, specifically when destroying their
14668 * Call clutter_actor_pop_internal() when you finished adding internal
14671 * Nested calls to clutter_actor_push_internal() are allowed, but each
14672 * one must by followed by a clutter_actor_pop_internal() call.
14676 * Deprecated: 1.10: All children of an actor are accessible through
14677 * the #ClutterActor API, and #ClutterActor implements the
14678 * #ClutterContainer interface, so this function is only useful
14679 * for legacy containers overriding the default implementation.
14682 clutter_actor_push_internal (ClutterActor *self)
14684 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14686 self->priv->internal_child += 1;
14690 * clutter_actor_pop_internal:
14691 * @self: a #ClutterActor
14693 * Disables the effects of clutter_actor_push_internal().
14697 * Deprecated: 1.10: All children of an actor are accessible through
14698 * the #ClutterActor API. This function is only useful for legacy
14699 * containers overriding the default implementation of the
14700 * #ClutterContainer interface.
14703 clutter_actor_pop_internal (ClutterActor *self)
14705 ClutterActorPrivate *priv;
14707 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14711 if (priv->internal_child == 0)
14713 g_warning ("Mismatched %s: you need to call "
14714 "clutter_actor_push_composite() at least once before "
14715 "calling this function", G_STRFUNC);
14719 priv->internal_child -= 1;
14723 * clutter_actor_has_pointer:
14724 * @self: a #ClutterActor
14726 * Checks whether an actor contains the pointer of a
14727 * #ClutterInputDevice
14729 * Return value: %TRUE if the actor contains the pointer, and
14735 clutter_actor_has_pointer (ClutterActor *self)
14737 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14739 return self->priv->has_pointer;
14742 /* XXX: This is a workaround for not being able to break the ABI of
14743 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14744 * clutter_actor_queue_clipped_redraw() for details.
14746 ClutterPaintVolume *
14747 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14749 return g_object_get_data (G_OBJECT (self),
14750 "-clutter-actor-queue-redraw-clip");
14754 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14755 ClutterPaintVolume *clip)
14757 g_object_set_data (G_OBJECT (self),
14758 "-clutter-actor-queue-redraw-clip",
14763 * clutter_actor_has_allocation:
14764 * @self: a #ClutterActor
14766 * Checks if the actor has an up-to-date allocation assigned to
14767 * it. This means that the actor should have an allocation: it's
14768 * visible and has a parent. It also means that there is no
14769 * outstanding relayout request in progress for the actor or its
14770 * children (There might be other outstanding layout requests in
14771 * progress that will cause the actor to get a new allocation
14772 * when the stage is laid out, however).
14774 * If this function returns %FALSE, then the actor will normally
14775 * be allocated before it is next drawn on the screen.
14777 * Return value: %TRUE if the actor has an up-to-date allocation
14782 clutter_actor_has_allocation (ClutterActor *self)
14784 ClutterActorPrivate *priv;
14786 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14790 return priv->parent != NULL &&
14791 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14792 !priv->needs_allocation;
14796 * clutter_actor_add_action:
14797 * @self: a #ClutterActor
14798 * @action: a #ClutterAction
14800 * Adds @action to the list of actions applied to @self
14802 * A #ClutterAction can only belong to one actor at a time
14804 * The #ClutterActor will hold a reference on @action until either
14805 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14811 clutter_actor_add_action (ClutterActor *self,
14812 ClutterAction *action)
14814 ClutterActorPrivate *priv;
14816 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14817 g_return_if_fail (CLUTTER_IS_ACTION (action));
14821 if (priv->actions == NULL)
14823 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14824 priv->actions->actor = self;
14827 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14829 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14833 * clutter_actor_add_action_with_name:
14834 * @self: a #ClutterActor
14835 * @name: the name to set on the action
14836 * @action: a #ClutterAction
14838 * A convenience function for setting the name of a #ClutterAction
14839 * while adding it to the list of actions applied to @self
14841 * This function is the logical equivalent of:
14844 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14845 * clutter_actor_add_action (self, action);
14851 clutter_actor_add_action_with_name (ClutterActor *self,
14853 ClutterAction *action)
14855 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14856 g_return_if_fail (name != NULL);
14857 g_return_if_fail (CLUTTER_IS_ACTION (action));
14859 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14860 clutter_actor_add_action (self, action);
14864 * clutter_actor_remove_action:
14865 * @self: a #ClutterActor
14866 * @action: a #ClutterAction
14868 * Removes @action from the list of actions applied to @self
14870 * The reference held by @self on the #ClutterAction will be released
14875 clutter_actor_remove_action (ClutterActor *self,
14876 ClutterAction *action)
14878 ClutterActorPrivate *priv;
14880 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14881 g_return_if_fail (CLUTTER_IS_ACTION (action));
14885 if (priv->actions == NULL)
14888 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14890 if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14891 g_clear_object (&priv->actions);
14893 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14897 * clutter_actor_remove_action_by_name:
14898 * @self: a #ClutterActor
14899 * @name: the name of the action to remove
14901 * Removes the #ClutterAction with the given name from the list
14902 * of actions applied to @self
14907 clutter_actor_remove_action_by_name (ClutterActor *self,
14910 ClutterActorPrivate *priv;
14911 ClutterActorMeta *meta;
14913 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14914 g_return_if_fail (name != NULL);
14918 if (priv->actions == NULL)
14921 meta = _clutter_meta_group_get_meta (priv->actions, name);
14925 _clutter_meta_group_remove_meta (priv->actions, meta);
14927 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14931 * clutter_actor_get_actions:
14932 * @self: a #ClutterActor
14934 * Retrieves the list of actions applied to @self
14936 * Return value: (transfer container) (element-type Clutter.Action): a copy
14937 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14938 * owned by the #ClutterActor. Use g_list_free() to free the resources
14939 * allocated by the returned #GList
14944 clutter_actor_get_actions (ClutterActor *self)
14946 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14948 if (self->priv->actions == NULL)
14951 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14955 * clutter_actor_get_action:
14956 * @self: a #ClutterActor
14957 * @name: the name of the action to retrieve
14959 * Retrieves the #ClutterAction with the given name in the list
14960 * of actions applied to @self
14962 * Return value: (transfer none): a #ClutterAction for the given
14963 * name, or %NULL. The returned #ClutterAction is owned by the
14964 * actor and it should not be unreferenced directly
14969 clutter_actor_get_action (ClutterActor *self,
14972 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14973 g_return_val_if_fail (name != NULL, NULL);
14975 if (self->priv->actions == NULL)
14978 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14982 * clutter_actor_clear_actions:
14983 * @self: a #ClutterActor
14985 * Clears the list of actions applied to @self
14990 clutter_actor_clear_actions (ClutterActor *self)
14992 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14994 if (self->priv->actions == NULL)
14997 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15001 * clutter_actor_add_constraint:
15002 * @self: a #ClutterActor
15003 * @constraint: a #ClutterConstraint
15005 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15008 * The #ClutterActor will hold a reference on the @constraint until
15009 * either clutter_actor_remove_constraint() or
15010 * clutter_actor_clear_constraints() is called.
15015 clutter_actor_add_constraint (ClutterActor *self,
15016 ClutterConstraint *constraint)
15018 ClutterActorPrivate *priv;
15020 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15021 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15025 if (priv->constraints == NULL)
15027 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15028 priv->constraints->actor = self;
15031 _clutter_meta_group_add_meta (priv->constraints,
15032 CLUTTER_ACTOR_META (constraint));
15033 clutter_actor_queue_relayout (self);
15035 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15039 * clutter_actor_add_constraint_with_name:
15040 * @self: a #ClutterActor
15041 * @name: the name to set on the constraint
15042 * @constraint: a #ClutterConstraint
15044 * A convenience function for setting the name of a #ClutterConstraint
15045 * while adding it to the list of constraints applied to @self
15047 * This function is the logical equivalent of:
15050 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15051 * clutter_actor_add_constraint (self, constraint);
15057 clutter_actor_add_constraint_with_name (ClutterActor *self,
15059 ClutterConstraint *constraint)
15061 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15062 g_return_if_fail (name != NULL);
15063 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15065 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15066 clutter_actor_add_constraint (self, constraint);
15070 * clutter_actor_remove_constraint:
15071 * @self: a #ClutterActor
15072 * @constraint: a #ClutterConstraint
15074 * Removes @constraint from the list of constraints applied to @self
15076 * The reference held by @self on the #ClutterConstraint will be released
15081 clutter_actor_remove_constraint (ClutterActor *self,
15082 ClutterConstraint *constraint)
15084 ClutterActorPrivate *priv;
15086 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15087 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15091 if (priv->constraints == NULL)
15094 _clutter_meta_group_remove_meta (priv->constraints,
15095 CLUTTER_ACTOR_META (constraint));
15097 if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15098 g_clear_object (&priv->constraints);
15100 clutter_actor_queue_relayout (self);
15102 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15106 * clutter_actor_remove_constraint_by_name:
15107 * @self: a #ClutterActor
15108 * @name: the name of the constraint to remove
15110 * Removes the #ClutterConstraint with the given name from the list
15111 * of constraints applied to @self
15116 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15119 ClutterActorPrivate *priv;
15120 ClutterActorMeta *meta;
15122 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15123 g_return_if_fail (name != NULL);
15127 if (priv->constraints == NULL)
15130 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15134 _clutter_meta_group_remove_meta (priv->constraints, meta);
15135 clutter_actor_queue_relayout (self);
15139 * clutter_actor_get_constraints:
15140 * @self: a #ClutterActor
15142 * Retrieves the list of constraints applied to @self
15144 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15145 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15146 * owned by the #ClutterActor. Use g_list_free() to free the resources
15147 * allocated by the returned #GList
15152 clutter_actor_get_constraints (ClutterActor *self)
15154 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15156 if (self->priv->constraints == NULL)
15159 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15163 * clutter_actor_get_constraint:
15164 * @self: a #ClutterActor
15165 * @name: the name of the constraint to retrieve
15167 * Retrieves the #ClutterConstraint with the given name in the list
15168 * of constraints applied to @self
15170 * Return value: (transfer none): a #ClutterConstraint for the given
15171 * name, or %NULL. The returned #ClutterConstraint is owned by the
15172 * actor and it should not be unreferenced directly
15176 ClutterConstraint *
15177 clutter_actor_get_constraint (ClutterActor *self,
15180 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15181 g_return_val_if_fail (name != NULL, NULL);
15183 if (self->priv->constraints == NULL)
15186 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15190 * clutter_actor_clear_constraints:
15191 * @self: a #ClutterActor
15193 * Clears the list of constraints applied to @self
15198 clutter_actor_clear_constraints (ClutterActor *self)
15200 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15202 if (self->priv->constraints == NULL)
15205 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15207 clutter_actor_queue_relayout (self);
15211 * clutter_actor_set_clip_to_allocation:
15212 * @self: a #ClutterActor
15213 * @clip_set: %TRUE to apply a clip tracking the allocation
15215 * Sets whether @self should be clipped to the same size as its
15221 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15224 ClutterActorPrivate *priv;
15226 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15228 clip_set = !!clip_set;
15232 if (priv->clip_to_allocation != clip_set)
15234 priv->clip_to_allocation = clip_set;
15236 clutter_actor_queue_redraw (self);
15238 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15243 * clutter_actor_get_clip_to_allocation:
15244 * @self: a #ClutterActor
15246 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15248 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15253 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15255 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15257 return self->priv->clip_to_allocation;
15261 * clutter_actor_add_effect:
15262 * @self: a #ClutterActor
15263 * @effect: a #ClutterEffect
15265 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15267 * The #ClutterActor will hold a reference on the @effect until either
15268 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15274 clutter_actor_add_effect (ClutterActor *self,
15275 ClutterEffect *effect)
15277 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15278 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15280 _clutter_actor_add_effect_internal (self, effect);
15282 clutter_actor_queue_redraw (self);
15284 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15288 * clutter_actor_add_effect_with_name:
15289 * @self: a #ClutterActor
15290 * @name: the name to set on the effect
15291 * @effect: a #ClutterEffect
15293 * A convenience function for setting the name of a #ClutterEffect
15294 * while adding it to the list of effectss applied to @self
15296 * This function is the logical equivalent of:
15299 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15300 * clutter_actor_add_effect (self, effect);
15306 clutter_actor_add_effect_with_name (ClutterActor *self,
15308 ClutterEffect *effect)
15310 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15311 g_return_if_fail (name != NULL);
15312 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15314 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15315 clutter_actor_add_effect (self, effect);
15319 * clutter_actor_remove_effect:
15320 * @self: a #ClutterActor
15321 * @effect: a #ClutterEffect
15323 * Removes @effect from the list of effects applied to @self
15325 * The reference held by @self on the #ClutterEffect will be released
15330 clutter_actor_remove_effect (ClutterActor *self,
15331 ClutterEffect *effect)
15333 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15334 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15336 _clutter_actor_remove_effect_internal (self, effect);
15338 clutter_actor_queue_redraw (self);
15340 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15344 * clutter_actor_remove_effect_by_name:
15345 * @self: a #ClutterActor
15346 * @name: the name of the effect to remove
15348 * Removes the #ClutterEffect with the given name from the list
15349 * of effects applied to @self
15354 clutter_actor_remove_effect_by_name (ClutterActor *self,
15357 ClutterActorPrivate *priv;
15358 ClutterActorMeta *meta;
15360 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15361 g_return_if_fail (name != NULL);
15365 if (priv->effects == NULL)
15368 meta = _clutter_meta_group_get_meta (priv->effects, name);
15372 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15376 * clutter_actor_get_effects:
15377 * @self: a #ClutterActor
15379 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15381 * Return value: (transfer container) (element-type Clutter.Effect): a list
15382 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15383 * list are owned by Clutter and they should not be freed. You should
15384 * free the returned list using g_list_free() when done
15389 clutter_actor_get_effects (ClutterActor *self)
15391 ClutterActorPrivate *priv;
15393 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15397 if (priv->effects == NULL)
15400 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15404 * clutter_actor_get_effect:
15405 * @self: a #ClutterActor
15406 * @name: the name of the effect to retrieve
15408 * Retrieves the #ClutterEffect with the given name in the list
15409 * of effects applied to @self
15411 * Return value: (transfer none): a #ClutterEffect for the given
15412 * name, or %NULL. The returned #ClutterEffect is owned by the
15413 * actor and it should not be unreferenced directly
15418 clutter_actor_get_effect (ClutterActor *self,
15421 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15422 g_return_val_if_fail (name != NULL, NULL);
15424 if (self->priv->effects == NULL)
15427 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15431 * clutter_actor_clear_effects:
15432 * @self: a #ClutterActor
15434 * Clears the list of effects applied to @self
15439 clutter_actor_clear_effects (ClutterActor *self)
15441 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15443 if (self->priv->effects == NULL)
15446 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15448 clutter_actor_queue_redraw (self);
15452 * clutter_actor_has_key_focus:
15453 * @self: a #ClutterActor
15455 * Checks whether @self is the #ClutterActor that has key focus
15457 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15462 clutter_actor_has_key_focus (ClutterActor *self)
15464 ClutterActor *stage;
15466 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15468 stage = _clutter_actor_get_stage_internal (self);
15472 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15476 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15477 ClutterPaintVolume *pv)
15479 ClutterActorPrivate *priv = self->priv;
15481 /* Actors are only expected to report a valid paint volume
15482 * while they have a valid allocation. */
15483 if (G_UNLIKELY (priv->needs_allocation))
15485 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15486 "Actor needs allocation",
15487 _clutter_actor_get_debug_name (self));
15491 /* Check if there are any handlers connected to the paint
15492 * signal. If there are then all bets are off for what the paint
15493 * volume for this actor might possibly be!
15495 * XXX: It's expected that this is going to end up being quite a
15496 * costly check to have to do here, but we haven't come up with
15497 * another solution that can reliably catch paint signal handlers at
15498 * the right time to either avoid artefacts due to invalid stage
15499 * clipping or due to incorrect culling.
15501 * Previously we checked in clutter_actor_paint(), but at that time
15502 * we may already be using a stage clip that could be derived from
15503 * an invalid paint-volume. We used to try and handle that by
15504 * queuing a follow up, unclipped, redraw but still the previous
15505 * checking wasn't enough to catch invalid volumes involved in
15506 * culling (considering that containers may derive their volume from
15507 * children that haven't yet been painted)
15509 * Longer term, improved solutions could be:
15510 * - Disallow painting in the paint signal, only allow using it
15511 * for tracking when paints happen. We can add another API that
15512 * allows monkey patching the paint of arbitrary actors but in a
15513 * more controlled way and that also supports modifying the
15515 * - If we could be notified somehow when signal handlers are
15516 * connected we wouldn't have to poll for handlers like this.
15518 if (g_signal_has_handler_pending (self,
15519 actor_signals[PAINT],
15523 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15524 "Actor has \"paint\" signal handlers",
15525 _clutter_actor_get_debug_name (self));
15529 _clutter_paint_volume_init_static (pv, self);
15531 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15533 clutter_paint_volume_free (pv);
15534 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15535 "Actor failed to report a volume",
15536 _clutter_actor_get_debug_name (self));
15540 /* since effects can modify the paint volume, we allow them to actually
15541 * do this by making get_paint_volume() "context sensitive"
15543 if (priv->effects != NULL)
15545 if (priv->current_effect != NULL)
15547 const GList *effects, *l;
15549 /* if we are being called from within the paint sequence of
15550 * an actor, get the paint volume up to the current effect
15552 effects = _clutter_meta_group_peek_metas (priv->effects);
15554 l != NULL || (l != NULL && l->data != priv->current_effect);
15557 if (!_clutter_effect_get_paint_volume (l->data, pv))
15559 clutter_paint_volume_free (pv);
15560 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15561 "Effect (%s) failed to report a volume",
15562 _clutter_actor_get_debug_name (self),
15563 _clutter_actor_meta_get_debug_name (l->data));
15570 const GList *effects, *l;
15572 /* otherwise, get the cumulative volume */
15573 effects = _clutter_meta_group_peek_metas (priv->effects);
15574 for (l = effects; l != NULL; l = l->next)
15575 if (!_clutter_effect_get_paint_volume (l->data, pv))
15577 clutter_paint_volume_free (pv);
15578 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15579 "Effect (%s) failed to report a volume",
15580 _clutter_actor_get_debug_name (self),
15581 _clutter_actor_meta_get_debug_name (l->data));
15590 /* The public clutter_actor_get_paint_volume API returns a const
15591 * pointer since we return a pointer directly to the cached
15592 * PaintVolume associated with the actor and don't want the user to
15593 * inadvertently modify it, but for internal uses we sometimes need
15594 * access to the same PaintVolume but need to apply some book-keeping
15595 * modifications to it so we don't want a const pointer.
15597 static ClutterPaintVolume *
15598 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15600 ClutterActorPrivate *priv;
15604 if (priv->paint_volume_valid)
15605 clutter_paint_volume_free (&priv->paint_volume);
15607 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15609 priv->paint_volume_valid = TRUE;
15610 return &priv->paint_volume;
15614 priv->paint_volume_valid = FALSE;
15620 * clutter_actor_get_paint_volume:
15621 * @self: a #ClutterActor
15623 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15624 * when a paint volume can't be determined.
15626 * The paint volume is defined as the 3D space occupied by an actor
15627 * when being painted.
15629 * This function will call the <function>get_paint_volume()</function>
15630 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15631 * should not usually care about overriding the default implementation,
15632 * unless they are, for instance: painting outside their allocation, or
15633 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15636 * <note>2D actors overriding <function>get_paint_volume()</function>
15637 * ensure their volume has a depth of 0. (This will be true so long as
15638 * you don't call clutter_paint_volume_set_depth().)</note>
15640 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15641 * or %NULL if no volume could be determined. The returned pointer
15642 * is not guaranteed to be valid across multiple frames; if you want
15643 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15647 const ClutterPaintVolume *
15648 clutter_actor_get_paint_volume (ClutterActor *self)
15650 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15652 return _clutter_actor_get_paint_volume_mutable (self);
15656 * clutter_actor_get_transformed_paint_volume:
15657 * @self: a #ClutterActor
15658 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15659 * (or %NULL for the stage)
15661 * Retrieves the 3D paint volume of an actor like
15662 * clutter_actor_get_paint_volume() does (Please refer to the
15663 * documentation of clutter_actor_get_paint_volume() for more
15664 * details.) and it additionally transforms the paint volume into the
15665 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15666 * is passed for @relative_to_ancestor)
15668 * This can be used by containers that base their paint volume on
15669 * the volume of their children. Such containers can query the
15670 * transformed paint volume of all of its children and union them
15671 * together using clutter_paint_volume_union().
15673 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15674 * or %NULL if no volume could be determined. The returned pointer is
15675 * not guaranteed to be valid across multiple frames; if you wish to
15676 * keep it, you will have to copy it using clutter_paint_volume_copy().
15680 const ClutterPaintVolume *
15681 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15682 ClutterActor *relative_to_ancestor)
15684 const ClutterPaintVolume *volume;
15685 ClutterActor *stage;
15686 ClutterPaintVolume *transformed_volume;
15688 stage = _clutter_actor_get_stage_internal (self);
15689 if (G_UNLIKELY (stage == NULL))
15692 if (relative_to_ancestor == NULL)
15693 relative_to_ancestor = stage;
15695 volume = clutter_actor_get_paint_volume (self);
15696 if (volume == NULL)
15699 transformed_volume =
15700 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15702 _clutter_paint_volume_copy_static (volume, transformed_volume);
15704 _clutter_paint_volume_transform_relative (transformed_volume,
15705 relative_to_ancestor);
15707 return transformed_volume;
15711 * clutter_actor_get_paint_box:
15712 * @self: a #ClutterActor
15713 * @box: (out): return location for a #ClutterActorBox
15715 * Retrieves the paint volume of the passed #ClutterActor, and
15716 * transforms it into a 2D bounding box in stage coordinates.
15718 * This function is useful to determine the on screen area occupied by
15719 * the actor. The box is only an approximation and may often be
15720 * considerably larger due to the optimizations used to calculate the
15721 * box. The box is never smaller though, so it can reliably be used
15724 * There are times when a 2D paint box can't be determined, e.g.
15725 * because the actor isn't yet parented under a stage or because
15726 * the actor is unable to determine a paint volume.
15728 * Return value: %TRUE if a 2D paint box could be determined, else
15734 clutter_actor_get_paint_box (ClutterActor *self,
15735 ClutterActorBox *box)
15737 ClutterActor *stage;
15738 ClutterPaintVolume *pv;
15740 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15741 g_return_val_if_fail (box != NULL, FALSE);
15743 stage = _clutter_actor_get_stage_internal (self);
15744 if (G_UNLIKELY (!stage))
15747 pv = _clutter_actor_get_paint_volume_mutable (self);
15748 if (G_UNLIKELY (!pv))
15751 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15757 * clutter_actor_has_overlaps:
15758 * @self: A #ClutterActor
15760 * Asks the actor's implementation whether it may contain overlapping
15763 * For example; Clutter may use this to determine whether the painting
15764 * should be redirected to an offscreen buffer to correctly implement
15765 * the opacity property.
15767 * Custom actors can override the default response by implementing the
15768 * #ClutterActor <function>has_overlaps</function> virtual function. See
15769 * clutter_actor_set_offscreen_redirect() for more information.
15771 * Return value: %TRUE if the actor may have overlapping primitives, and
15777 clutter_actor_has_overlaps (ClutterActor *self)
15779 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15781 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15785 * clutter_actor_has_effects:
15786 * @self: A #ClutterActor
15788 * Returns whether the actor has any effects applied.
15790 * Return value: %TRUE if the actor has any effects,
15796 clutter_actor_has_effects (ClutterActor *self)
15798 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15800 if (self->priv->effects == NULL)
15803 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15807 * clutter_actor_has_constraints:
15808 * @self: A #ClutterActor
15810 * Returns whether the actor has any constraints applied.
15812 * Return value: %TRUE if the actor has any constraints,
15818 clutter_actor_has_constraints (ClutterActor *self)
15820 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15822 return self->priv->constraints != NULL;
15826 * clutter_actor_has_actions:
15827 * @self: A #ClutterActor
15829 * Returns whether the actor has any actions applied.
15831 * Return value: %TRUE if the actor has any actions,
15837 clutter_actor_has_actions (ClutterActor *self)
15839 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15841 return self->priv->actions != NULL;
15845 * clutter_actor_get_n_children:
15846 * @self: a #ClutterActor
15848 * Retrieves the number of children of @self.
15850 * Return value: the number of children of an actor
15855 clutter_actor_get_n_children (ClutterActor *self)
15857 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15859 return self->priv->n_children;
15863 * clutter_actor_get_child_at_index:
15864 * @self: a #ClutterActor
15865 * @index_: the position in the list of children
15867 * Retrieves the actor at the given @index_ inside the list of
15868 * children of @self.
15870 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15875 clutter_actor_get_child_at_index (ClutterActor *self,
15878 ClutterActor *iter;
15881 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15882 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15884 for (iter = self->priv->first_child, i = 0;
15885 iter != NULL && i < index_;
15886 iter = iter->priv->next_sibling, i += 1)
15893 * _clutter_actor_foreach_child:
15894 * @actor: The actor whos children you want to iterate
15895 * @callback: The function to call for each child
15896 * @user_data: Private data to pass to @callback
15898 * Calls a given @callback once for each child of the specified @actor and
15899 * passing the @user_data pointer each time.
15901 * Return value: returns %TRUE if all children were iterated, else
15902 * %FALSE if a callback broke out of iteration early.
15905 _clutter_actor_foreach_child (ClutterActor *self,
15906 ClutterForeachCallback callback,
15907 gpointer user_data)
15909 ClutterActor *iter;
15912 if (self->priv->first_child == NULL)
15916 iter = self->priv->first_child;
15918 /* we use this form so that it's safe to change the children
15919 * list while iterating it
15921 while (cont && iter != NULL)
15923 ClutterActor *next = iter->priv->next_sibling;
15925 cont = callback (iter, user_data);
15934 /* For debugging purposes this gives us a simple way to print out
15935 * the scenegraph e.g in gdb using:
15937 * _clutter_actor_traverse (stage,
15939 * clutter_debug_print_actor_cb,
15944 static ClutterActorTraverseVisitFlags
15945 clutter_debug_print_actor_cb (ClutterActor *actor,
15949 g_print ("%*s%s:%p\n",
15951 _clutter_actor_get_debug_name (actor),
15954 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15959 _clutter_actor_traverse_breadth (ClutterActor *actor,
15960 ClutterTraverseCallback callback,
15961 gpointer user_data)
15963 GQueue *queue = g_queue_new ();
15964 ClutterActor dummy;
15965 int current_depth = 0;
15967 g_queue_push_tail (queue, actor);
15968 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15970 while ((actor = g_queue_pop_head (queue)))
15972 ClutterActorTraverseVisitFlags flags;
15974 if (actor == &dummy)
15977 g_queue_push_tail (queue, &dummy);
15981 flags = callback (actor, current_depth, user_data);
15982 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15984 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15986 ClutterActor *iter;
15988 for (iter = actor->priv->first_child;
15990 iter = iter->priv->next_sibling)
15992 g_queue_push_tail (queue, iter);
15997 g_queue_free (queue);
16000 static ClutterActorTraverseVisitFlags
16001 _clutter_actor_traverse_depth (ClutterActor *actor,
16002 ClutterTraverseCallback before_children_callback,
16003 ClutterTraverseCallback after_children_callback,
16005 gpointer user_data)
16007 ClutterActorTraverseVisitFlags flags;
16009 flags = before_children_callback (actor, current_depth, user_data);
16010 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16011 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16013 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16015 ClutterActor *iter;
16017 for (iter = actor->priv->first_child;
16019 iter = iter->priv->next_sibling)
16021 flags = _clutter_actor_traverse_depth (iter,
16022 before_children_callback,
16023 after_children_callback,
16027 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16028 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16032 if (after_children_callback)
16033 return after_children_callback (actor, current_depth, user_data);
16035 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16038 /* _clutter_actor_traverse:
16039 * @actor: The actor to start traversing the graph from
16040 * @flags: These flags may affect how the traversal is done
16041 * @before_children_callback: A function to call before visiting the
16042 * children of the current actor.
16043 * @after_children_callback: A function to call after visiting the
16044 * children of the current actor. (Ignored if
16045 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16046 * @user_data: The private data to pass to the callbacks
16048 * Traverses the scenegraph starting at the specified @actor and
16049 * descending through all its children and its children's children.
16050 * For each actor traversed @before_children_callback and
16051 * @after_children_callback are called with the specified
16052 * @user_data, before and after visiting that actor's children.
16054 * The callbacks can return flags that affect the ongoing traversal
16055 * such as by skipping over an actors children or bailing out of
16056 * any further traversing.
16059 _clutter_actor_traverse (ClutterActor *actor,
16060 ClutterActorTraverseFlags flags,
16061 ClutterTraverseCallback before_children_callback,
16062 ClutterTraverseCallback after_children_callback,
16063 gpointer user_data)
16065 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16066 _clutter_actor_traverse_breadth (actor,
16067 before_children_callback,
16069 else /* DEPTH_FIRST */
16070 _clutter_actor_traverse_depth (actor,
16071 before_children_callback,
16072 after_children_callback,
16073 0, /* start depth */
16078 on_layout_manager_changed (ClutterLayoutManager *manager,
16079 ClutterActor *self)
16081 clutter_actor_queue_relayout (self);
16085 * clutter_actor_set_layout_manager:
16086 * @self: a #ClutterActor
16087 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16089 * Sets the #ClutterLayoutManager delegate object that will be used to
16090 * lay out the children of @self.
16092 * The #ClutterActor will take a reference on the passed @manager which
16093 * will be released either when the layout manager is removed, or when
16094 * the actor is destroyed.
16099 clutter_actor_set_layout_manager (ClutterActor *self,
16100 ClutterLayoutManager *manager)
16102 ClutterActorPrivate *priv;
16104 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16105 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16109 if (priv->layout_manager != NULL)
16111 g_signal_handlers_disconnect_by_func (priv->layout_manager,
16112 G_CALLBACK (on_layout_manager_changed),
16114 clutter_layout_manager_set_container (priv->layout_manager, NULL);
16115 g_clear_object (&priv->layout_manager);
16118 priv->layout_manager = manager;
16120 if (priv->layout_manager != NULL)
16122 g_object_ref_sink (priv->layout_manager);
16123 clutter_layout_manager_set_container (priv->layout_manager,
16124 CLUTTER_CONTAINER (self));
16125 g_signal_connect (priv->layout_manager, "layout-changed",
16126 G_CALLBACK (on_layout_manager_changed),
16130 clutter_actor_queue_relayout (self);
16132 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16136 * clutter_actor_get_layout_manager:
16137 * @self: a #ClutterActor
16139 * Retrieves the #ClutterLayoutManager used by @self.
16141 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16146 ClutterLayoutManager *
16147 clutter_actor_get_layout_manager (ClutterActor *self)
16149 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16151 return self->priv->layout_manager;
16154 static const ClutterLayoutInfo default_layout_info = {
16155 CLUTTER_POINT_INIT_ZERO, /* fixed-pos */
16156 { 0, 0, 0, 0 }, /* margin */
16157 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16158 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16159 FALSE, FALSE, /* expand */
16160 CLUTTER_SIZE_INIT_ZERO, /* minimum */
16161 CLUTTER_SIZE_INIT_ZERO, /* natural */
16165 layout_info_free (gpointer data)
16167 if (G_LIKELY (data != NULL))
16168 g_slice_free (ClutterLayoutInfo, data);
16172 * _clutter_actor_get_layout_info:
16173 * @self: a #ClutterActor
16175 * Retrieves a pointer to the ClutterLayoutInfo structure.
16177 * If the actor does not have a ClutterLayoutInfo associated to it, one
16178 * will be created and initialized to the default values.
16180 * This function should be used for setters.
16182 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16185 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16187 ClutterLayoutInfo *
16188 _clutter_actor_get_layout_info (ClutterActor *self)
16190 ClutterLayoutInfo *retval;
16192 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16193 if (retval == NULL)
16195 retval = g_slice_new (ClutterLayoutInfo);
16197 *retval = default_layout_info;
16199 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16208 * _clutter_actor_get_layout_info_or_defaults:
16209 * @self: a #ClutterActor
16211 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16213 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16214 * then the default structure will be returned.
16216 * This function should only be used for getters.
16218 * Return value: a const pointer to the ClutterLayoutInfo structure
16220 const ClutterLayoutInfo *
16221 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16223 const ClutterLayoutInfo *info;
16225 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16227 return &default_layout_info;
16233 * clutter_actor_set_x_align:
16234 * @self: a #ClutterActor
16235 * @x_align: the horizontal alignment policy
16237 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16238 * actor received extra horizontal space.
16240 * See also the #ClutterActor:x-align property.
16245 clutter_actor_set_x_align (ClutterActor *self,
16246 ClutterActorAlign x_align)
16248 ClutterLayoutInfo *info;
16250 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16252 info = _clutter_actor_get_layout_info (self);
16254 if (info->x_align != x_align)
16256 info->x_align = x_align;
16258 clutter_actor_queue_relayout (self);
16260 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16265 * clutter_actor_get_x_align:
16266 * @self: a #ClutterActor
16268 * Retrieves the horizontal alignment policy set using
16269 * clutter_actor_set_x_align().
16271 * Return value: the horizontal alignment policy.
16276 clutter_actor_get_x_align (ClutterActor *self)
16278 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16280 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16284 * clutter_actor_set_y_align:
16285 * @self: a #ClutterActor
16286 * @y_align: the vertical alignment policy
16288 * Sets the vertical alignment policy of a #ClutterActor, in case the
16289 * actor received extra vertical space.
16291 * See also the #ClutterActor:y-align property.
16296 clutter_actor_set_y_align (ClutterActor *self,
16297 ClutterActorAlign y_align)
16299 ClutterLayoutInfo *info;
16301 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16303 info = _clutter_actor_get_layout_info (self);
16305 if (info->y_align != y_align)
16307 info->y_align = y_align;
16309 clutter_actor_queue_relayout (self);
16311 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16316 * clutter_actor_get_y_align:
16317 * @self: a #ClutterActor
16319 * Retrieves the vertical alignment policy set using
16320 * clutter_actor_set_y_align().
16322 * Return value: the vertical alignment policy.
16327 clutter_actor_get_y_align (ClutterActor *self)
16329 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16331 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16335 * clutter_actor_set_margin:
16336 * @self: a #ClutterActor
16337 * @margin: a #ClutterMargin
16339 * Sets all the components of the margin of a #ClutterActor.
16344 clutter_actor_set_margin (ClutterActor *self,
16345 const ClutterMargin *margin)
16347 ClutterLayoutInfo *info;
16351 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16352 g_return_if_fail (margin != NULL);
16354 obj = G_OBJECT (self);
16357 g_object_freeze_notify (obj);
16359 info = _clutter_actor_get_layout_info (self);
16361 if (info->margin.top != margin->top)
16363 info->margin.top = margin->top;
16364 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16368 if (info->margin.right != margin->right)
16370 info->margin.right = margin->right;
16371 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16375 if (info->margin.bottom != margin->bottom)
16377 info->margin.bottom = margin->bottom;
16378 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16382 if (info->margin.left != margin->left)
16384 info->margin.left = margin->left;
16385 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16390 clutter_actor_queue_relayout (self);
16392 g_object_thaw_notify (obj);
16396 * clutter_actor_get_margin:
16397 * @self: a #ClutterActor
16398 * @margin: (out caller-allocates): return location for a #ClutterMargin
16400 * Retrieves all the components of the margin of a #ClutterActor.
16405 clutter_actor_get_margin (ClutterActor *self,
16406 ClutterMargin *margin)
16408 const ClutterLayoutInfo *info;
16410 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16411 g_return_if_fail (margin != NULL);
16413 info = _clutter_actor_get_layout_info_or_defaults (self);
16415 *margin = info->margin;
16419 * clutter_actor_set_margin_top:
16420 * @self: a #ClutterActor
16421 * @margin: the top margin
16423 * Sets the margin from the top of a #ClutterActor.
16428 clutter_actor_set_margin_top (ClutterActor *self,
16431 ClutterLayoutInfo *info;
16433 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16434 g_return_if_fail (margin >= 0.f);
16436 info = _clutter_actor_get_layout_info (self);
16438 if (info->margin.top == margin)
16441 info->margin.top = margin;
16443 clutter_actor_queue_relayout (self);
16445 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16449 * clutter_actor_get_margin_top:
16450 * @self: a #ClutterActor
16452 * Retrieves the top margin of a #ClutterActor.
16454 * Return value: the top margin
16459 clutter_actor_get_margin_top (ClutterActor *self)
16461 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16463 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16467 * clutter_actor_set_margin_bottom:
16468 * @self: a #ClutterActor
16469 * @margin: the bottom margin
16471 * Sets the margin from the bottom of a #ClutterActor.
16476 clutter_actor_set_margin_bottom (ClutterActor *self,
16479 ClutterLayoutInfo *info;
16481 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16482 g_return_if_fail (margin >= 0.f);
16484 info = _clutter_actor_get_layout_info (self);
16486 if (info->margin.bottom == margin)
16489 info->margin.bottom = margin;
16491 clutter_actor_queue_relayout (self);
16493 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16497 * clutter_actor_get_margin_bottom:
16498 * @self: a #ClutterActor
16500 * Retrieves the bottom margin of a #ClutterActor.
16502 * Return value: the bottom margin
16507 clutter_actor_get_margin_bottom (ClutterActor *self)
16509 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16511 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16515 * clutter_actor_set_margin_left:
16516 * @self: a #ClutterActor
16517 * @margin: the left margin
16519 * Sets the margin from the left of a #ClutterActor.
16524 clutter_actor_set_margin_left (ClutterActor *self,
16527 ClutterLayoutInfo *info;
16529 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16530 g_return_if_fail (margin >= 0.f);
16532 info = _clutter_actor_get_layout_info (self);
16534 if (info->margin.left == margin)
16537 info->margin.left = margin;
16539 clutter_actor_queue_relayout (self);
16541 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16545 * clutter_actor_get_margin_left:
16546 * @self: a #ClutterActor
16548 * Retrieves the left margin of a #ClutterActor.
16550 * Return value: the left margin
16555 clutter_actor_get_margin_left (ClutterActor *self)
16557 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16559 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16563 * clutter_actor_set_margin_right:
16564 * @self: a #ClutterActor
16565 * @margin: the right margin
16567 * Sets the margin from the right of a #ClutterActor.
16572 clutter_actor_set_margin_right (ClutterActor *self,
16575 ClutterLayoutInfo *info;
16577 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16578 g_return_if_fail (margin >= 0.f);
16580 info = _clutter_actor_get_layout_info (self);
16582 if (info->margin.right == margin)
16585 info->margin.right = margin;
16587 clutter_actor_queue_relayout (self);
16589 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16593 * clutter_actor_get_margin_right:
16594 * @self: a #ClutterActor
16596 * Retrieves the right margin of a #ClutterActor.
16598 * Return value: the right margin
16603 clutter_actor_get_margin_right (ClutterActor *self)
16605 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16607 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16611 clutter_actor_set_background_color_internal (ClutterActor *self,
16612 const ClutterColor *color)
16614 ClutterActorPrivate *priv = self->priv;
16617 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16620 obj = G_OBJECT (self);
16622 priv->bg_color = *color;
16623 priv->bg_color_set = TRUE;
16625 clutter_actor_queue_redraw (self);
16627 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16628 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16632 * clutter_actor_set_background_color:
16633 * @self: a #ClutterActor
16634 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16637 * Sets the background color of a #ClutterActor.
16639 * The background color will be used to cover the whole allocation of the
16640 * actor. The default background color of an actor is transparent.
16642 * To check whether an actor has a background color, you can use the
16643 * #ClutterActor:background-color-set actor property.
16645 * The #ClutterActor:background-color property is animatable.
16650 clutter_actor_set_background_color (ClutterActor *self,
16651 const ClutterColor *color)
16653 ClutterActorPrivate *priv;
16655 GParamSpec *bg_color_pspec;
16657 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16659 obj = G_OBJECT (self);
16665 priv->bg_color_set = FALSE;
16666 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16667 clutter_actor_queue_redraw (self);
16671 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16672 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16674 _clutter_actor_create_transition (self, bg_color_pspec,
16679 _clutter_actor_update_transition (self, bg_color_pspec, color);
16681 clutter_actor_queue_redraw (self);
16685 * clutter_actor_get_background_color:
16686 * @self: a #ClutterActor
16687 * @color: (out caller-allocates): return location for a #ClutterColor
16689 * Retrieves the color set using clutter_actor_set_background_color().
16694 clutter_actor_get_background_color (ClutterActor *self,
16695 ClutterColor *color)
16697 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16698 g_return_if_fail (color != NULL);
16700 *color = self->priv->bg_color;
16704 * clutter_actor_get_previous_sibling:
16705 * @self: a #ClutterActor
16707 * Retrieves the sibling of @self that comes before it in the list
16708 * of children of @self's parent.
16710 * The returned pointer is only valid until the scene graph changes; it
16711 * is not safe to modify the list of children of @self while iterating
16714 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16719 clutter_actor_get_previous_sibling (ClutterActor *self)
16721 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16723 return self->priv->prev_sibling;
16727 * clutter_actor_get_next_sibling:
16728 * @self: a #ClutterActor
16730 * Retrieves the sibling of @self that comes after it in the list
16731 * of children of @self's parent.
16733 * The returned pointer is only valid until the scene graph changes; it
16734 * is not safe to modify the list of children of @self while iterating
16737 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16742 clutter_actor_get_next_sibling (ClutterActor *self)
16744 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16746 return self->priv->next_sibling;
16750 * clutter_actor_get_first_child:
16751 * @self: a #ClutterActor
16753 * Retrieves the first child of @self.
16755 * The returned pointer is only valid until the scene graph changes; it
16756 * is not safe to modify the list of children of @self while iterating
16759 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16764 clutter_actor_get_first_child (ClutterActor *self)
16766 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16768 return self->priv->first_child;
16772 * clutter_actor_get_last_child:
16773 * @self: a #ClutterActor
16775 * Retrieves the last child of @self.
16777 * The returned pointer is only valid until the scene graph changes; it
16778 * is not safe to modify the list of children of @self while iterating
16781 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16786 clutter_actor_get_last_child (ClutterActor *self)
16788 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16790 return self->priv->last_child;
16793 /* easy way to have properly named fields instead of the dummy ones
16794 * we use in the public structure
16796 typedef struct _RealActorIter
16798 ClutterActor *root; /* dummy1 */
16799 ClutterActor *current; /* dummy2 */
16800 gpointer padding_1; /* dummy3 */
16801 gint age; /* dummy4 */
16802 gpointer padding_2; /* dummy5 */
16806 * clutter_actor_iter_init:
16807 * @iter: a #ClutterActorIter
16808 * @root: a #ClutterActor
16810 * Initializes a #ClutterActorIter, which can then be used to iterate
16811 * efficiently over a section of the scene graph, and associates it
16814 * Modifying the scene graph section that contains @root will invalidate
16818 * ClutterActorIter iter;
16819 * ClutterActor *child;
16821 * clutter_actor_iter_init (&iter, container);
16822 * while (clutter_actor_iter_next (&iter, &child))
16824 * /* do something with child */
16831 clutter_actor_iter_init (ClutterActorIter *iter,
16832 ClutterActor *root)
16834 RealActorIter *ri = (RealActorIter *) iter;
16836 g_return_if_fail (iter != NULL);
16837 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16840 ri->current = NULL;
16841 ri->age = root->priv->age;
16845 * clutter_actor_iter_next:
16846 * @iter: a #ClutterActorIter
16847 * @child: (out): return location for a #ClutterActor
16849 * Advances the @iter and retrieves the next child of the root #ClutterActor
16850 * that was used to initialize the #ClutterActorIterator.
16852 * If the iterator can advance, this function returns %TRUE and sets the
16855 * If the iterator cannot advance, this function returns %FALSE, and
16856 * the contents of @child are undefined.
16858 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16863 clutter_actor_iter_next (ClutterActorIter *iter,
16864 ClutterActor **child)
16866 RealActorIter *ri = (RealActorIter *) iter;
16868 g_return_val_if_fail (iter != NULL, FALSE);
16869 g_return_val_if_fail (ri->root != NULL, FALSE);
16870 #ifndef G_DISABLE_ASSERT
16871 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16874 if (ri->current == NULL)
16875 ri->current = ri->root->priv->first_child;
16877 ri->current = ri->current->priv->next_sibling;
16880 *child = ri->current;
16882 return ri->current != NULL;
16886 * clutter_actor_iter_prev:
16887 * @iter: a #ClutterActorIter
16888 * @child: (out): return location for a #ClutterActor
16890 * Advances the @iter and retrieves the previous child of the root
16891 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16893 * If the iterator can advance, this function returns %TRUE and sets the
16896 * If the iterator cannot advance, this function returns %FALSE, and
16897 * the contents of @child are undefined.
16899 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16904 clutter_actor_iter_prev (ClutterActorIter *iter,
16905 ClutterActor **child)
16907 RealActorIter *ri = (RealActorIter *) iter;
16909 g_return_val_if_fail (iter != NULL, FALSE);
16910 g_return_val_if_fail (ri->root != NULL, FALSE);
16911 #ifndef G_DISABLE_ASSERT
16912 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16915 if (ri->current == NULL)
16916 ri->current = ri->root->priv->last_child;
16918 ri->current = ri->current->priv->prev_sibling;
16921 *child = ri->current;
16923 return ri->current != NULL;
16927 * clutter_actor_iter_remove:
16928 * @iter: a #ClutterActorIter
16930 * Safely removes the #ClutterActor currently pointer to by the iterator
16933 * This function can only be called after clutter_actor_iter_next() or
16934 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16935 * than once for the same actor.
16937 * This function will call clutter_actor_remove_child() internally.
16942 clutter_actor_iter_remove (ClutterActorIter *iter)
16944 RealActorIter *ri = (RealActorIter *) iter;
16947 g_return_if_fail (iter != NULL);
16948 g_return_if_fail (ri->root != NULL);
16949 #ifndef G_DISABLE_ASSERT
16950 g_return_if_fail (ri->age == ri->root->priv->age);
16952 g_return_if_fail (ri->current != NULL);
16958 ri->current = cur->priv->prev_sibling;
16960 clutter_actor_remove_child_internal (ri->root, cur,
16961 REMOVE_CHILD_DEFAULT_FLAGS);
16968 * clutter_actor_iter_destroy:
16969 * @iter: a #ClutterActorIter
16971 * Safely destroys the #ClutterActor currently pointer to by the iterator
16974 * This function can only be called after clutter_actor_iter_next() or
16975 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16976 * than once for the same actor.
16978 * This function will call clutter_actor_destroy() internally.
16983 clutter_actor_iter_destroy (ClutterActorIter *iter)
16985 RealActorIter *ri = (RealActorIter *) iter;
16988 g_return_if_fail (iter != NULL);
16989 g_return_if_fail (ri->root != NULL);
16990 #ifndef G_DISABLE_ASSERT
16991 g_return_if_fail (ri->age == ri->root->priv->age);
16993 g_return_if_fail (ri->current != NULL);
16999 ri->current = cur->priv->prev_sibling;
17001 clutter_actor_destroy (cur);
17007 static const ClutterAnimationInfo default_animation_info = {
17008 NULL, /* transitions */
17010 NULL, /* cur_state */
17014 clutter_animation_info_free (gpointer data)
17018 ClutterAnimationInfo *info = data;
17020 if (info->transitions != NULL)
17021 g_hash_table_unref (info->transitions);
17023 if (info->states != NULL)
17024 g_array_unref (info->states);
17026 g_slice_free (ClutterAnimationInfo, info);
17030 const ClutterAnimationInfo *
17031 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17033 const ClutterAnimationInfo *res;
17034 GObject *obj = G_OBJECT (self);
17036 res = g_object_get_qdata (obj, quark_actor_animation_info);
17040 return &default_animation_info;
17043 ClutterAnimationInfo *
17044 _clutter_actor_get_animation_info (ClutterActor *self)
17046 GObject *obj = G_OBJECT (self);
17047 ClutterAnimationInfo *res;
17049 res = g_object_get_qdata (obj, quark_actor_animation_info);
17052 res = g_slice_new (ClutterAnimationInfo);
17054 *res = default_animation_info;
17056 g_object_set_qdata_full (obj, quark_actor_animation_info,
17058 clutter_animation_info_free);
17064 ClutterTransition *
17065 _clutter_actor_get_transition (ClutterActor *actor,
17068 const ClutterAnimationInfo *info;
17070 info = _clutter_actor_get_animation_info_or_defaults (actor);
17072 if (info->transitions == NULL)
17075 return g_hash_table_lookup (info->transitions, pspec->name);
17078 typedef struct _TransitionClosure
17080 ClutterActor *actor;
17081 ClutterTransition *transition;
17083 gulong completed_id;
17084 } TransitionClosure;
17087 transition_closure_free (gpointer data)
17089 if (G_LIKELY (data != NULL))
17091 TransitionClosure *clos = data;
17092 ClutterTimeline *timeline;
17094 timeline = CLUTTER_TIMELINE (clos->transition);
17096 if (clutter_timeline_is_playing (timeline))
17097 clutter_timeline_stop (timeline);
17099 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17101 g_object_unref (clos->transition);
17102 g_free (clos->name);
17104 g_slice_free (TransitionClosure, clos);
17109 on_transition_completed (ClutterTransition *transition,
17110 TransitionClosure *clos)
17112 ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17113 ClutterActor *actor = clos->actor;
17114 ClutterAnimationInfo *info;
17115 gint n_repeats, cur_repeat;
17117 info = _clutter_actor_get_animation_info (actor);
17119 /* reset the caches used by animations */
17120 clutter_actor_store_content_box (actor, NULL);
17122 /* ensure that we remove the transition only at the end
17123 * of its run; we emit ::completed for every repeat
17125 n_repeats = clutter_timeline_get_repeat_count (timeline);
17126 cur_repeat = clutter_timeline_get_current_repeat (timeline);
17128 if (cur_repeat == n_repeats)
17130 if (clutter_transition_get_remove_on_complete (transition))
17132 /* we take a reference here because removing the closure
17133 * will release the reference on the transition, and we
17134 * want the transition to survive the signal emission;
17135 * the master clock will release the last reference at
17136 * the end of the frame processing.
17138 g_object_ref (transition);
17139 g_hash_table_remove (info->transitions, clos->name);
17143 /* if it's the last transition then we clean up */
17144 if (g_hash_table_size (info->transitions) == 0)
17146 g_hash_table_unref (info->transitions);
17147 info->transitions = NULL;
17149 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17150 _clutter_actor_get_debug_name (actor));
17152 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17157 _clutter_actor_update_transition (ClutterActor *actor,
17161 TransitionClosure *clos;
17162 ClutterTimeline *timeline;
17163 ClutterInterval *interval;
17164 const ClutterAnimationInfo *info;
17167 GValue initial = G_VALUE_INIT;
17168 GValue final = G_VALUE_INIT;
17169 char *error = NULL;
17171 info = _clutter_actor_get_animation_info_or_defaults (actor);
17173 if (info->transitions == NULL)
17176 clos = g_hash_table_lookup (info->transitions, pspec->name);
17180 timeline = CLUTTER_TIMELINE (clos->transition);
17182 va_start (var_args, pspec);
17184 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17186 g_value_init (&initial, ptype);
17187 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17191 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17194 g_critical ("%s: %s", G_STRLOC, error);
17199 interval = clutter_transition_get_interval (clos->transition);
17200 clutter_interval_set_initial_value (interval, &initial);
17201 clutter_interval_set_final_value (interval, &final);
17203 /* if we're updating with an easing duration of zero milliseconds,
17204 * we just jump the timeline to the end and let it run its course
17206 if (info->cur_state != NULL &&
17207 info->cur_state->easing_duration != 0)
17209 guint cur_duration = clutter_timeline_get_duration (timeline);
17210 ClutterAnimationMode cur_mode =
17211 clutter_timeline_get_progress_mode (timeline);
17213 if (cur_duration != info->cur_state->easing_duration)
17214 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17216 if (cur_mode != info->cur_state->easing_mode)
17217 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17219 clutter_timeline_rewind (timeline);
17223 guint duration = clutter_timeline_get_duration (timeline);
17225 clutter_timeline_advance (timeline, duration);
17229 g_value_unset (&initial);
17230 g_value_unset (&final);
17236 * _clutter_actor_create_transition:
17237 * @actor: a #ClutterActor
17238 * @pspec: the property used for the transition
17239 * @...: initial and final state
17241 * Creates a #ClutterTransition for the property represented by @pspec.
17243 * Return value: a #ClutterTransition
17245 ClutterTransition *
17246 _clutter_actor_create_transition (ClutterActor *actor,
17250 ClutterAnimationInfo *info;
17251 ClutterTransition *res = NULL;
17252 gboolean call_restore = FALSE;
17253 TransitionClosure *clos;
17256 info = _clutter_actor_get_animation_info (actor);
17258 /* XXX - this will go away in 2.0
17260 * if no state has been pushed, we assume that the easing state is
17261 * in "compatibility mode": all transitions have a duration of 0
17262 * msecs, which means that they happen immediately. in Clutter 2.0
17263 * this will turn into a g_assert(info->states != NULL), as every
17264 * actor will start with a predefined easing state
17266 if (info->states == NULL)
17268 clutter_actor_save_easing_state (actor);
17269 clutter_actor_set_easing_duration (actor, 0);
17270 call_restore = TRUE;
17273 if (info->transitions == NULL)
17274 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17276 transition_closure_free);
17278 va_start (var_args, pspec);
17280 clos = g_hash_table_lookup (info->transitions, pspec->name);
17283 ClutterTimeline *timeline;
17284 ClutterInterval *interval;
17285 GValue initial = G_VALUE_INIT;
17286 GValue final = G_VALUE_INIT;
17290 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17292 G_VALUE_COLLECT_INIT (&initial, ptype,
17297 g_critical ("%s: %s", G_STRLOC, error);
17302 G_VALUE_COLLECT_INIT (&final, ptype,
17308 g_critical ("%s: %s", G_STRLOC, error);
17309 g_value_unset (&initial);
17314 /* if the current easing state has a duration of 0, then we don't
17315 * bother to create the transition, and we just set the final value
17316 * directly on the actor; we don't go through the Animatable
17317 * interface because we know we got here through an animatable
17320 if (info->cur_state->easing_duration == 0)
17322 clutter_actor_set_animatable_property (actor,
17326 g_value_unset (&initial);
17327 g_value_unset (&final);
17332 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17334 g_value_unset (&initial);
17335 g_value_unset (&final);
17337 res = clutter_property_transition_new (pspec->name);
17339 clutter_transition_set_interval (res, interval);
17340 clutter_transition_set_remove_on_complete (res, TRUE);
17342 timeline = CLUTTER_TIMELINE (res);
17343 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17344 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17345 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17347 /* this will start the transition as well */
17348 clutter_actor_add_transition (actor, pspec->name, res);
17350 /* the actor now owns the transition */
17351 g_object_unref (res);
17354 res = clos->transition;
17358 clutter_actor_restore_easing_state (actor);
17366 * clutter_actor_add_transition:
17367 * @self: a #ClutterActor
17368 * @name: the name of the transition to add
17369 * @transition: the #ClutterTransition to add
17371 * Adds a @transition to the #ClutterActor's list of animations.
17373 * The @name string is a per-actor unique identifier of the @transition: only
17374 * one #ClutterTransition can be associated to the specified @name.
17376 * The @transition will be started once added.
17378 * This function will take a reference on the @transition.
17380 * This function is usually called implicitly when modifying an animatable
17386 clutter_actor_add_transition (ClutterActor *self,
17388 ClutterTransition *transition)
17390 ClutterTimeline *timeline;
17391 TransitionClosure *clos;
17392 ClutterAnimationInfo *info;
17394 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17395 g_return_if_fail (name != NULL);
17396 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17398 info = _clutter_actor_get_animation_info (self);
17400 if (info->transitions == NULL)
17401 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17403 transition_closure_free);
17405 if (g_hash_table_lookup (info->transitions, name) != NULL)
17407 g_warning ("A transition with name '%s' already exists for "
17410 _clutter_actor_get_debug_name (self));
17414 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17416 timeline = CLUTTER_TIMELINE (transition);
17418 clos = g_slice_new (TransitionClosure);
17419 clos->actor = self;
17420 clos->transition = g_object_ref (transition);
17421 clos->name = g_strdup (name);
17422 clos->completed_id = g_signal_connect (timeline, "completed",
17423 G_CALLBACK (on_transition_completed),
17426 CLUTTER_NOTE (ANIMATION,
17427 "Adding transition '%s' [%p] to actor '%s'",
17430 _clutter_actor_get_debug_name (self));
17432 g_hash_table_insert (info->transitions, clos->name, clos);
17433 clutter_timeline_start (timeline);
17437 * clutter_actor_remove_transition:
17438 * @self: a #ClutterActor
17439 * @name: the name of the transition to remove
17441 * Removes the transition stored inside a #ClutterActor using @name
17444 * If the transition is currently in progress, it will be stopped.
17446 * This function releases the reference acquired when the transition
17447 * was added to the #ClutterActor.
17452 clutter_actor_remove_transition (ClutterActor *self,
17455 const ClutterAnimationInfo *info;
17457 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17458 g_return_if_fail (name != NULL);
17460 info = _clutter_actor_get_animation_info_or_defaults (self);
17462 if (info->transitions == NULL)
17465 g_hash_table_remove (info->transitions, name);
17469 * clutter_actor_remove_all_transitions:
17470 * @self: a #ClutterActor
17472 * Removes all transitions associated to @self.
17477 clutter_actor_remove_all_transitions (ClutterActor *self)
17479 const ClutterAnimationInfo *info;
17481 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17483 info = _clutter_actor_get_animation_info_or_defaults (self);
17484 if (info->transitions == NULL)
17487 g_hash_table_remove_all (info->transitions);
17491 * clutter_actor_set_easing_duration:
17492 * @self: a #ClutterActor
17493 * @msecs: the duration of the easing, or %NULL
17495 * Sets the duration of the tweening for animatable properties
17496 * of @self for the current easing state.
17501 clutter_actor_set_easing_duration (ClutterActor *self,
17504 ClutterAnimationInfo *info;
17506 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17508 info = _clutter_actor_get_animation_info (self);
17510 if (info->cur_state == NULL)
17512 g_warning ("You must call clutter_actor_save_easing_state() prior "
17513 "to calling clutter_actor_set_easing_duration().");
17517 if (info->cur_state->easing_duration != msecs)
17518 info->cur_state->easing_duration = msecs;
17522 * clutter_actor_get_easing_duration:
17523 * @self: a #ClutterActor
17525 * Retrieves the duration of the tweening for animatable
17526 * properties of @self for the current easing state.
17528 * Return value: the duration of the tweening, in milliseconds
17533 clutter_actor_get_easing_duration (ClutterActor *self)
17535 const ClutterAnimationInfo *info;
17537 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17539 info = _clutter_actor_get_animation_info_or_defaults (self);
17541 if (info->cur_state != NULL)
17542 return info->cur_state->easing_duration;
17548 * clutter_actor_set_easing_mode:
17549 * @self: a #ClutterActor
17550 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17552 * Sets the easing mode for the tweening of animatable properties
17558 clutter_actor_set_easing_mode (ClutterActor *self,
17559 ClutterAnimationMode mode)
17561 ClutterAnimationInfo *info;
17563 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17564 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17565 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17567 info = _clutter_actor_get_animation_info (self);
17569 if (info->cur_state == NULL)
17571 g_warning ("You must call clutter_actor_save_easing_state() prior "
17572 "to calling clutter_actor_set_easing_mode().");
17576 if (info->cur_state->easing_mode != mode)
17577 info->cur_state->easing_mode = mode;
17581 * clutter_actor_get_easing_mode:
17582 * @self: a #ClutterActor
17584 * Retrieves the easing mode for the tweening of animatable properties
17585 * of @self for the current easing state.
17587 * Return value: an easing mode
17591 ClutterAnimationMode
17592 clutter_actor_get_easing_mode (ClutterActor *self)
17594 const ClutterAnimationInfo *info;
17596 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17598 info = _clutter_actor_get_animation_info_or_defaults (self);
17600 if (info->cur_state != NULL)
17601 return info->cur_state->easing_mode;
17603 return CLUTTER_EASE_OUT_CUBIC;
17607 * clutter_actor_set_easing_delay:
17608 * @self: a #ClutterActor
17609 * @msecs: the delay before the start of the tweening, in milliseconds
17611 * Sets the delay that should be applied before tweening animatable
17617 clutter_actor_set_easing_delay (ClutterActor *self,
17620 ClutterAnimationInfo *info;
17622 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17624 info = _clutter_actor_get_animation_info (self);
17626 if (info->cur_state == NULL)
17628 g_warning ("You must call clutter_actor_save_easing_state() prior "
17629 "to calling clutter_actor_set_easing_delay().");
17633 if (info->cur_state->easing_delay != msecs)
17634 info->cur_state->easing_delay = msecs;
17638 * clutter_actor_get_easing_delay:
17639 * @self: a #ClutterActor
17641 * Retrieves the delay that should be applied when tweening animatable
17644 * Return value: a delay, in milliseconds
17649 clutter_actor_get_easing_delay (ClutterActor *self)
17651 const ClutterAnimationInfo *info;
17653 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17655 info = _clutter_actor_get_animation_info_or_defaults (self);
17657 if (info->cur_state != NULL)
17658 return info->cur_state->easing_delay;
17664 * clutter_actor_get_transition:
17665 * @self: a #ClutterActor
17666 * @name: the name of the transition
17668 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17669 * transition @name.
17671 * Transitions created for animatable properties use the name of the
17672 * property itself, for instance the code below:
17675 * clutter_actor_set_easing_duration (actor, 1000);
17676 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17678 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17679 * g_signal_connect (transition, "completed",
17680 * G_CALLBACK (on_transition_complete),
17684 * will call the <function>on_transition_complete</function> callback when
17685 * the transition is complete.
17687 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17688 * was found to match the passed name; the returned instance is owned
17689 * by Clutter and it should not be freed
17693 ClutterTransition *
17694 clutter_actor_get_transition (ClutterActor *self,
17697 TransitionClosure *clos;
17698 const ClutterAnimationInfo *info;
17700 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17701 g_return_val_if_fail (name != NULL, NULL);
17703 info = _clutter_actor_get_animation_info_or_defaults (self);
17704 if (info->transitions == NULL)
17707 clos = g_hash_table_lookup (info->transitions, name);
17711 return clos->transition;
17715 * clutter_actor_save_easing_state:
17716 * @self: a #ClutterActor
17718 * Saves the current easing state for animatable properties, and creates
17719 * a new state with the default values for easing mode and duration.
17724 clutter_actor_save_easing_state (ClutterActor *self)
17726 ClutterAnimationInfo *info;
17729 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17731 info = _clutter_actor_get_animation_info (self);
17733 if (info->states == NULL)
17734 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17736 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17737 new_state.easing_duration = 250;
17738 new_state.easing_delay = 0;
17740 g_array_append_val (info->states, new_state);
17742 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17746 * clutter_actor_restore_easing_state:
17747 * @self: a #ClutterActor
17749 * Restores the easing state as it was prior to a call to
17750 * clutter_actor_save_easing_state().
17755 clutter_actor_restore_easing_state (ClutterActor *self)
17757 ClutterAnimationInfo *info;
17759 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17761 info = _clutter_actor_get_animation_info (self);
17763 if (info->states == NULL)
17765 g_critical ("The function clutter_actor_restore_easing_state() has "
17766 "called without a previous call to "
17767 "clutter_actor_save_easing_state().");
17771 g_array_remove_index (info->states, info->states->len - 1);
17773 if (info->states->len > 0)
17774 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17777 g_array_unref (info->states);
17778 info->states = NULL;
17779 info->cur_state = NULL;
17784 * clutter_actor_set_content:
17785 * @self: a #ClutterActor
17786 * @content: (allow-none): a #ClutterContent, or %NULL
17788 * Sets the contents of a #ClutterActor.
17793 clutter_actor_set_content (ClutterActor *self,
17794 ClutterContent *content)
17796 ClutterActorPrivate *priv;
17798 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17799 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17803 if (priv->content != NULL)
17805 _clutter_content_detached (priv->content, self);
17806 g_clear_object (&priv->content);
17809 priv->content = content;
17811 if (priv->content != NULL)
17813 g_object_ref (priv->content);
17814 _clutter_content_attached (priv->content, self);
17817 /* given that the content is always painted within the allocation,
17818 * we only need to queue a redraw here
17820 clutter_actor_queue_redraw (self);
17822 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17824 /* if the content gravity is not resize-fill, and the new content has a
17825 * different preferred size than the previous one, then the content box
17826 * may have been changed. since we compute that lazily, we just notify
17827 * here, and let whomever watches :content-box do whatever they need to
17830 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17831 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17835 * clutter_actor_get_content:
17836 * @self: a #ClutterActor
17838 * Retrieves the contents of @self.
17840 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17841 * or %NULL if none was set
17846 clutter_actor_get_content (ClutterActor *self)
17848 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17850 return self->priv->content;
17854 * clutter_actor_set_content_gravity:
17855 * @self: a #ClutterActor
17856 * @gravity: the #ClutterContentGravity
17858 * Sets the gravity of the #ClutterContent used by @self.
17860 * See the description of the #ClutterActor:content-gravity property for
17861 * more information.
17863 * The #ClutterActor:content-gravity property is animatable.
17868 clutter_actor_set_content_gravity (ClutterActor *self,
17869 ClutterContentGravity gravity)
17871 ClutterActorPrivate *priv;
17873 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17877 if (priv->content_gravity == gravity)
17880 priv->content_box_valid = FALSE;
17882 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17884 ClutterActorBox from_box, to_box;
17886 clutter_actor_get_content_box (self, &from_box);
17888 priv->content_gravity = gravity;
17890 clutter_actor_get_content_box (self, &to_box);
17892 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17898 ClutterActorBox to_box;
17900 priv->content_gravity = gravity;
17902 clutter_actor_get_content_box (self, &to_box);
17904 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17908 clutter_actor_queue_redraw (self);
17910 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17914 * clutter_actor_get_content_gravity:
17915 * @self: a #ClutterActor
17917 * Retrieves the content gravity as set using
17918 * clutter_actor_get_content_gravity().
17920 * Return value: the content gravity
17924 ClutterContentGravity
17925 clutter_actor_get_content_gravity (ClutterActor *self)
17927 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17928 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17930 return self->priv->content_gravity;
17934 * clutter_actor_get_content_box:
17935 * @self: a #ClutterActor
17936 * @box: (out caller-allocates): the return location for the bounding
17937 * box for the #ClutterContent
17939 * Retrieves the bounding box for the #ClutterContent of @self.
17941 * The bounding box is relative to the actor's allocation.
17943 * If no #ClutterContent is set for @self, or if @self has not been
17944 * allocated yet, then the result is undefined.
17946 * The content box is guaranteed to be, at most, as big as the allocation
17947 * of the #ClutterActor.
17949 * If the #ClutterContent used by the actor has a preferred size, then
17950 * it is possible to modify the content box by using the
17951 * #ClutterActor:content-gravity property.
17956 clutter_actor_get_content_box (ClutterActor *self,
17957 ClutterActorBox *box)
17959 ClutterActorPrivate *priv;
17960 gfloat content_w, content_h;
17961 gfloat alloc_w, alloc_h;
17963 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17964 g_return_if_fail (box != NULL);
17970 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17971 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17973 if (priv->content_box_valid)
17975 *box = priv->content_box;
17979 /* no need to do any more work */
17980 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17983 if (priv->content == NULL)
17986 /* if the content does not have a preferred size then there is
17987 * no point in computing the content box
17989 if (!clutter_content_get_preferred_size (priv->content,
17997 switch (priv->content_gravity)
17999 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18000 box->x2 = box->x1 + MIN (content_w, alloc_w);
18001 box->y2 = box->y1 + MIN (content_h, alloc_h);
18004 case CLUTTER_CONTENT_GRAVITY_TOP:
18005 if (alloc_w > content_w)
18007 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18008 box->x2 = box->x1 + content_w;
18010 box->y2 = box->y1 + MIN (content_h, alloc_h);
18013 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18014 if (alloc_w > content_w)
18016 box->x1 += (alloc_w - content_w);
18017 box->x2 = box->x1 + content_w;
18019 box->y2 = box->y1 + MIN (content_h, alloc_h);
18022 case CLUTTER_CONTENT_GRAVITY_LEFT:
18023 box->x2 = box->x1 + MIN (content_w, alloc_w);
18024 if (alloc_h > content_h)
18026 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18027 box->y2 = box->y1 + content_h;
18031 case CLUTTER_CONTENT_GRAVITY_CENTER:
18032 if (alloc_w > content_w)
18034 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18035 box->x2 = box->x1 + content_w;
18037 if (alloc_h > content_h)
18039 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18040 box->y2 = box->y1 + content_h;
18044 case CLUTTER_CONTENT_GRAVITY_RIGHT:
18045 if (alloc_w > content_w)
18047 box->x1 += (alloc_w - content_w);
18048 box->x2 = box->x1 + content_w;
18050 if (alloc_h > content_h)
18052 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18053 box->y2 = box->y1 + content_h;
18057 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18058 box->x2 = box->x1 + MIN (content_w, alloc_w);
18059 if (alloc_h > content_h)
18061 box->y1 += (alloc_h - content_h);
18062 box->y2 = box->y1 + content_h;
18066 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18067 if (alloc_w > content_w)
18069 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18070 box->x2 = box->x1 + content_w;
18072 if (alloc_h > content_h)
18074 box->y1 += (alloc_h - content_h);
18075 box->y2 = box->y1 + content_h;
18079 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18080 if (alloc_w > content_w)
18082 box->x1 += (alloc_w - content_w);
18083 box->x2 = box->x1 + content_w;
18085 if (alloc_h > content_h)
18087 box->y1 += (alloc_h - content_h);
18088 box->y2 = box->y1 + content_h;
18092 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18093 g_assert_not_reached ();
18096 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18098 double r_c = content_w / content_h;
18099 double r_a = alloc_w / alloc_h;
18108 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18109 box->y2 = box->y1 + (alloc_w * r_c);
18116 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18117 box->x2 = box->x1 + (alloc_h * r_c);
18127 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18128 box->x2 = box->x1 + (alloc_h * r_c);
18135 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18136 box->y2 = box->y1 + (alloc_w * r_c);
18145 * clutter_actor_set_content_scaling_filters:
18146 * @self: a #ClutterActor
18147 * @min_filter: the minification filter for the content
18148 * @mag_filter: the magnification filter for the content
18150 * Sets the minification and magnification filter to be applied when
18151 * scaling the #ClutterActor:content of a #ClutterActor.
18153 * The #ClutterActor:minification-filter will be used when reducing
18154 * the size of the content; the #ClutterActor:magnification-filter
18155 * will be used when increasing the size of the content.
18160 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18161 ClutterScalingFilter min_filter,
18162 ClutterScalingFilter mag_filter)
18164 ClutterActorPrivate *priv;
18168 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18171 obj = G_OBJECT (self);
18173 g_object_freeze_notify (obj);
18177 if (priv->min_filter != min_filter)
18179 priv->min_filter = min_filter;
18182 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18185 if (priv->mag_filter != mag_filter)
18187 priv->mag_filter = mag_filter;
18190 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18194 clutter_actor_queue_redraw (self);
18196 g_object_thaw_notify (obj);
18200 * clutter_actor_get_content_scaling_filters:
18201 * @self: a #ClutterActor
18202 * @min_filter: (out) (allow-none): return location for the minification
18204 * @mag_filter: (out) (allow-none): return location for the magnification
18207 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18212 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18213 ClutterScalingFilter *min_filter,
18214 ClutterScalingFilter *mag_filter)
18216 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18218 if (min_filter != NULL)
18219 *min_filter = self->priv->min_filter;
18221 if (mag_filter != NULL)
18222 *mag_filter = self->priv->mag_filter;
18226 * clutter_actor_queue_compute_expand:
18227 * @self: a #ClutterActor
18229 * Invalidates the needs_x_expand and needs_y_expand flags on @self
18230 * and its parents up to the top-level actor.
18232 * This function also queues a relayout if anything changed.
18235 clutter_actor_queue_compute_expand (ClutterActor *self)
18237 ClutterActor *parent;
18240 if (self->priv->needs_compute_expand)
18245 while (parent != NULL)
18247 if (!parent->priv->needs_compute_expand)
18249 parent->priv->needs_compute_expand = TRUE;
18253 parent = parent->priv->parent;
18257 clutter_actor_queue_relayout (self);
18261 * clutter_actor_set_x_expand:
18262 * @self: a #ClutterActor
18263 * @expand: whether the actor should expand horizontally
18265 * Sets whether a #ClutterActor should expand horizontally; this means
18266 * that layout manager should allocate extra space for the actor, if
18269 * Setting an actor to expand will also make all its parent expand, so
18270 * that it's possible to build an actor tree and only set this flag on
18271 * its leaves and not on every single actor.
18276 clutter_actor_set_x_expand (ClutterActor *self,
18279 ClutterLayoutInfo *info;
18281 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18285 info = _clutter_actor_get_layout_info (self);
18286 if (info->x_expand != expand)
18288 info->x_expand = expand;
18290 self->priv->x_expand_set = TRUE;
18292 clutter_actor_queue_compute_expand (self);
18294 g_object_notify_by_pspec (G_OBJECT (self),
18295 obj_props[PROP_X_EXPAND]);
18300 * clutter_actor_get_x_expand:
18301 * @self: a #ClutterActor
18303 * Retrieves the value set with clutter_actor_set_x_expand().
18305 * See also: clutter_actor_needs_x_expand()
18307 * Return value: %TRUE if the actor has been set to expand
18312 clutter_actor_get_x_expand (ClutterActor *self)
18314 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18316 return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18320 * clutter_actor_set_y_expand:
18321 * @self: a #ClutterActor
18322 * @expand: whether the actor should expand vertically
18324 * Sets whether a #ClutterActor should expand horizontally; this means
18325 * that layout manager should allocate extra space for the actor, if
18328 * Setting an actor to expand will also make all its parent expand, so
18329 * that it's possible to build an actor tree and only set this flag on
18330 * its leaves and not on every single actor.
18335 clutter_actor_set_y_expand (ClutterActor *self,
18338 ClutterLayoutInfo *info;
18340 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18344 info = _clutter_actor_get_layout_info (self);
18345 if (info->y_expand != expand)
18347 info->y_expand = expand;
18349 self->priv->y_expand_set = TRUE;
18351 clutter_actor_queue_compute_expand (self);
18353 g_object_notify_by_pspec (G_OBJECT (self),
18354 obj_props[PROP_Y_EXPAND]);
18359 * clutter_actor_get_y_expand:
18360 * @self: a #ClutterActor
18362 * Retrieves the value set with clutter_actor_set_y_expand().
18364 * See also: clutter_actor_needs_y_expand()
18366 * Return value: %TRUE if the actor has been set to expand
18371 clutter_actor_get_y_expand (ClutterActor *self)
18373 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18375 return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18379 clutter_actor_compute_expand_recursive (ClutterActor *self,
18380 gboolean *x_expand_p,
18381 gboolean *y_expand_p)
18383 ClutterActorIter iter;
18384 ClutterActor *child;
18385 gboolean x_expand, y_expand;
18387 x_expand = y_expand = FALSE;
18389 clutter_actor_iter_init (&iter, self);
18390 while (clutter_actor_iter_next (&iter, &child))
18392 x_expand = x_expand || clutter_actor_needs_x_expand (child);
18393 y_expand = y_expand || clutter_actor_needs_y_expand (child);
18396 *x_expand_p = x_expand;
18397 *y_expand_p = y_expand;
18401 clutter_actor_compute_expand (ClutterActor *self)
18403 if (self->priv->needs_compute_expand)
18405 const ClutterLayoutInfo *info;
18406 gboolean x_expand, y_expand;
18408 info = _clutter_actor_get_layout_info_or_defaults (self);
18410 if (self->priv->x_expand_set)
18411 x_expand = info->x_expand;
18415 if (self->priv->y_expand_set)
18416 y_expand = info->y_expand;
18420 /* we don't need to recurse down to the children if the
18421 * actor has been forcibly set to expand
18423 if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18425 if (self->priv->n_children != 0)
18427 gboolean *x_expand_p, *y_expand_p;
18428 gboolean ignored = FALSE;
18430 x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18431 y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18433 clutter_actor_compute_expand_recursive (self,
18439 self->priv->needs_compute_expand = FALSE;
18440 self->priv->needs_x_expand = (x_expand != FALSE);
18441 self->priv->needs_y_expand = (y_expand != FALSE);
18446 * clutter_actor_needs_x_expand:
18447 * @self: a #ClutterActor
18449 * Checks whether an actor, or any of its children, is set to expand
18452 * This function should only be called by layout managers that can
18453 * assign extra space to their children.
18455 * If you want to know whether the actor was explicitly set to expand,
18456 * use clutter_actor_get_y_expand().
18458 * Return value: %TRUE if the actor should expand
18463 clutter_actor_needs_x_expand (ClutterActor *self)
18465 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18467 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18470 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18473 clutter_actor_compute_expand (self);
18475 return self->priv->needs_x_expand;
18479 * clutter_actor_needs_y_expand:
18480 * @self: a #ClutterActor
18482 * Checks whether an actor, or any of its children, is set to expand
18485 * This function should only be called by layout managers that can
18486 * assign extra space to their children.
18488 * If you want to know whether the actor was explicitly set to expand,
18489 * use clutter_actor_get_y_expand().
18491 * Return value: %TRUE if the actor should expand
18496 clutter_actor_needs_y_expand (ClutterActor *self)
18498 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18500 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18503 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18506 clutter_actor_compute_expand (self);
18508 return self->priv->needs_x_expand;