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;
782 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
783 * when set they force a size request, when gotten they
784 * get the allocation if the allocation is valid, and the
795 /* Then the rest of these size-related properties are the "actual"
796 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
801 PROP_FIXED_POSITION_SET,
810 PROP_NATURAL_WIDTH_SET,
813 PROP_NATURAL_HEIGHT_SET,
817 /* Allocation properties are read-only */
824 PROP_CLIP_TO_ALLOCATION,
828 PROP_OFFSCREEN_REDIRECT,
841 PROP_ROTATION_ANGLE_X,
842 PROP_ROTATION_ANGLE_Y,
843 PROP_ROTATION_ANGLE_Z,
844 PROP_ROTATION_CENTER_X,
845 PROP_ROTATION_CENTER_Y,
846 PROP_ROTATION_CENTER_Z,
847 /* This property only makes sense for the z rotation because the
848 others would depend on the actor having a size along the
850 PROP_ROTATION_CENTER_Z_GRAVITY,
856 PROP_SHOW_ON_SET_PARENT,
874 PROP_BACKGROUND_COLOR,
875 PROP_BACKGROUND_COLOR_SET,
881 PROP_CONTENT_GRAVITY,
883 PROP_MINIFICATION_FILTER,
884 PROP_MAGNIFICATION_FILTER,
889 static GParamSpec *obj_props[PROP_LAST];
908 BUTTON_RELEASE_EVENT,
916 TRANSITIONS_COMPLETED,
921 static guint actor_signals[LAST_SIGNAL] = { 0, };
923 static void clutter_container_iface_init (ClutterContainerIface *iface);
924 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
925 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
926 static void atk_implementor_iface_init (AtkImplementorIface *iface);
928 /* These setters are all static for now, maybe they should be in the
929 * public API, but they are perhaps obscure enough to leave only as
932 static void clutter_actor_set_min_width (ClutterActor *self,
934 static void clutter_actor_set_min_height (ClutterActor *self,
936 static void clutter_actor_set_natural_width (ClutterActor *self,
937 gfloat natural_width);
938 static void clutter_actor_set_natural_height (ClutterActor *self,
939 gfloat natural_height);
940 static void clutter_actor_set_min_width_set (ClutterActor *self,
941 gboolean use_min_width);
942 static void clutter_actor_set_min_height_set (ClutterActor *self,
943 gboolean use_min_height);
944 static void clutter_actor_set_natural_width_set (ClutterActor *self,
945 gboolean use_natural_width);
946 static void clutter_actor_set_natural_height_set (ClutterActor *self,
947 gboolean use_natural_height);
948 static void clutter_actor_update_map_state (ClutterActor *self,
949 MapStateChange change);
950 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
952 /* Helper routines for managing anchor coords */
953 static void clutter_anchor_coord_get_units (ClutterActor *self,
954 const AnchorCoord *coord,
958 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
963 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
964 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
965 ClutterGravity gravity);
967 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
969 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
971 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
972 ClutterActor *ancestor,
975 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
977 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
979 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
980 const ClutterColor *color);
982 static void on_layout_manager_changed (ClutterLayoutManager *manager,
985 /* Helper macro which translates by the anchor coord, applies the
986 given transformation and then translates back */
987 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
988 gfloat _tx, _ty, _tz; \
989 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
990 cogl_matrix_translate ((m), _tx, _ty, _tz); \
992 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
994 static GQuark quark_shader_data = 0;
995 static GQuark quark_actor_layout_info = 0;
996 static GQuark quark_actor_transform_info = 0;
997 static GQuark quark_actor_animation_info = 0;
999 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1001 G_TYPE_INITIALLY_UNOWNED,
1002 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1003 clutter_container_iface_init)
1004 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1005 clutter_scriptable_iface_init)
1006 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1007 clutter_animatable_iface_init)
1008 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1009 atk_implementor_iface_init));
1012 * clutter_actor_get_debug_name:
1013 * @actor: a #ClutterActor
1015 * Retrieves a printable name of @actor for debugging messages
1017 * Return value: a string with a printable name
1020 _clutter_actor_get_debug_name (ClutterActor *actor)
1022 return actor->priv->name != NULL ? actor->priv->name
1023 : G_OBJECT_TYPE_NAME (actor);
1026 #ifdef CLUTTER_ENABLE_DEBUG
1027 /* XXX - this is for debugging only, remove once working (or leave
1028 * in only in some debug mode). Should leave it for a little while
1029 * until we're confident in the new map/realize/visible handling.
1032 clutter_actor_verify_map_state (ClutterActor *self)
1034 ClutterActorPrivate *priv = self->priv;
1036 if (CLUTTER_ACTOR_IS_REALIZED (self))
1038 /* all bets are off during reparent when we're potentially realized,
1039 * but should not be according to invariants
1041 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1043 if (priv->parent == NULL)
1045 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1049 g_warning ("Realized non-toplevel actor '%s' should "
1051 _clutter_actor_get_debug_name (self));
1053 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1055 g_warning ("Realized actor %s has an unrealized parent %s",
1056 _clutter_actor_get_debug_name (self),
1057 _clutter_actor_get_debug_name (priv->parent));
1062 if (CLUTTER_ACTOR_IS_MAPPED (self))
1064 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1065 g_warning ("Actor '%s' is mapped but not realized",
1066 _clutter_actor_get_debug_name (self));
1068 /* remaining bets are off during reparent when we're potentially
1069 * mapped, but should not be according to invariants
1071 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1073 if (priv->parent == NULL)
1075 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1077 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1078 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1080 g_warning ("Toplevel actor '%s' is mapped "
1082 _clutter_actor_get_debug_name (self));
1087 g_warning ("Mapped actor '%s' should have a parent",
1088 _clutter_actor_get_debug_name (self));
1093 ClutterActor *iter = self;
1095 /* check for the enable_paint_unmapped flag on the actor
1096 * and parents; if the flag is enabled at any point of this
1097 * branch of the scene graph then all the later checks
1100 while (iter != NULL)
1102 if (iter->priv->enable_paint_unmapped)
1105 iter = iter->priv->parent;
1108 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1110 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1112 _clutter_actor_get_debug_name (self),
1113 _clutter_actor_get_debug_name (priv->parent));
1116 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1118 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1120 _clutter_actor_get_debug_name (self),
1121 _clutter_actor_get_debug_name (priv->parent));
1124 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1126 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1127 g_warning ("Actor '%s' is mapped but its non-toplevel "
1128 "parent '%s' is not mapped",
1129 _clutter_actor_get_debug_name (self),
1130 _clutter_actor_get_debug_name (priv->parent));
1137 #endif /* CLUTTER_ENABLE_DEBUG */
1140 clutter_actor_set_mapped (ClutterActor *self,
1143 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1148 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1149 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1153 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1154 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1158 /* this function updates the mapped and realized states according to
1159 * invariants, in the appropriate order.
1162 clutter_actor_update_map_state (ClutterActor *self,
1163 MapStateChange change)
1165 gboolean was_mapped;
1167 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1169 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1171 /* the mapped flag on top-level actors must be set by the
1172 * per-backend implementation because it might be asynchronous.
1174 * That is, the MAPPED flag on toplevels currently tracks the X
1175 * server mapped-ness of the window, while the expected behavior
1176 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1177 * This creates some weird complexity by breaking the invariant
1178 * that if we're visible and all ancestors shown then we are
1179 * also mapped - instead, we are mapped if all ancestors
1180 * _possibly excepting_ the stage are mapped. The stage
1181 * will map/unmap for example when it is minimized or
1182 * moved to another workspace.
1184 * So, the only invariant on the stage is that if visible it
1185 * should be realized, and that it has to be visible to be
1188 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1189 clutter_actor_realize (self);
1193 case MAP_STATE_CHECK:
1196 case MAP_STATE_MAKE_MAPPED:
1197 g_assert (!was_mapped);
1198 clutter_actor_set_mapped (self, TRUE);
1201 case MAP_STATE_MAKE_UNMAPPED:
1202 g_assert (was_mapped);
1203 clutter_actor_set_mapped (self, FALSE);
1206 case MAP_STATE_MAKE_UNREALIZED:
1207 /* we only use MAKE_UNREALIZED in unparent,
1208 * and unparenting a stage isn't possible.
1209 * If someone wants to just unrealize a stage
1210 * then clutter_actor_unrealize() doesn't
1211 * go through this codepath.
1213 g_warning ("Trying to force unrealize stage is not allowed");
1217 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1218 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1219 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1221 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1222 "it is somehow still mapped",
1223 _clutter_actor_get_debug_name (self));
1228 ClutterActorPrivate *priv = self->priv;
1229 ClutterActor *parent = priv->parent;
1230 gboolean should_be_mapped;
1231 gboolean may_be_realized;
1232 gboolean must_be_realized;
1234 should_be_mapped = FALSE;
1235 may_be_realized = TRUE;
1236 must_be_realized = FALSE;
1238 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1240 may_be_realized = FALSE;
1244 /* Maintain invariant that if parent is mapped, and we are
1245 * visible, then we are mapped ... unless parent is a
1246 * stage, in which case we map regardless of parent's map
1247 * state but do require stage to be visible and realized.
1249 * If parent is realized, that does not force us to be
1250 * realized; but if parent is unrealized, that does force
1251 * us to be unrealized.
1253 * The reason we don't force children to realize with
1254 * parents is _clutter_actor_rerealize(); if we require that
1255 * a realized parent means children are realized, then to
1256 * unrealize an actor we would have to unrealize its
1257 * parents, which would end up meaning unrealizing and
1258 * hiding the entire stage. So we allow unrealizing a
1259 * child (as long as that child is not mapped) while that
1260 * child still has a realized parent.
1262 * Also, if we unrealize from leaf nodes to root, and
1263 * realize from root to leaf, the invariants are never
1264 * violated if we allow children to be unrealized
1265 * while parents are realized.
1267 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1268 * to force us to unmap, even though parent is still
1269 * mapped. This is because we're unmapping from leaf nodes
1272 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1273 change != MAP_STATE_MAKE_UNMAPPED)
1275 gboolean parent_is_visible_realized_toplevel;
1277 parent_is_visible_realized_toplevel =
1278 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1279 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1280 CLUTTER_ACTOR_IS_REALIZED (parent));
1282 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1283 parent_is_visible_realized_toplevel)
1285 must_be_realized = TRUE;
1286 should_be_mapped = TRUE;
1290 /* if the actor has been set to be painted even if unmapped
1291 * then we should map it and check for realization as well;
1292 * this is an override for the branch of the scene graph
1293 * which begins with this node
1295 if (priv->enable_paint_unmapped)
1297 if (priv->parent == NULL)
1298 g_warning ("Attempting to map an unparented actor '%s'",
1299 _clutter_actor_get_debug_name (self));
1301 should_be_mapped = TRUE;
1302 must_be_realized = TRUE;
1305 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1306 may_be_realized = FALSE;
1309 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1312 g_warning ("Attempting to map a child that does not "
1313 "meet the necessary invariants: the actor '%s' "
1315 _clutter_actor_get_debug_name (self));
1317 g_warning ("Attempting to map a child that does not "
1318 "meet the necessary invariants: the actor '%s' "
1319 "is parented to an unmapped actor '%s'",
1320 _clutter_actor_get_debug_name (self),
1321 _clutter_actor_get_debug_name (priv->parent));
1324 /* If in reparent, we temporarily suspend unmap and unrealize.
1326 * We want to go in the order "realize, map" and "unmap, unrealize"
1330 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1331 clutter_actor_set_mapped (self, FALSE);
1334 if (must_be_realized)
1335 clutter_actor_realize (self);
1337 /* if we must be realized then we may be, presumably */
1338 g_assert (!(must_be_realized && !may_be_realized));
1341 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1342 clutter_actor_unrealize_not_hiding (self);
1345 if (should_be_mapped)
1347 if (!must_be_realized)
1348 g_warning ("Somehow we think actor '%s' should be mapped but "
1349 "not realized, which isn't allowed",
1350 _clutter_actor_get_debug_name (self));
1352 /* realization is allowed to fail (though I don't know what
1353 * an app is supposed to do about that - shouldn't it just
1354 * be a g_error? anyway, we have to avoid mapping if this
1357 if (CLUTTER_ACTOR_IS_REALIZED (self))
1358 clutter_actor_set_mapped (self, TRUE);
1362 #ifdef CLUTTER_ENABLE_DEBUG
1363 /* check all invariants were kept */
1364 clutter_actor_verify_map_state (self);
1369 clutter_actor_real_map (ClutterActor *self)
1371 ClutterActorPrivate *priv = self->priv;
1372 ClutterActor *stage, *iter;
1374 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1376 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1377 _clutter_actor_get_debug_name (self));
1379 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1381 stage = _clutter_actor_get_stage_internal (self);
1382 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1384 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1386 _clutter_actor_get_debug_name (self));
1388 /* notify on parent mapped before potentially mapping
1389 * children, so apps see a top-down notification.
1391 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1393 for (iter = self->priv->first_child;
1395 iter = iter->priv->next_sibling)
1397 clutter_actor_map (iter);
1402 * clutter_actor_map:
1403 * @self: A #ClutterActor
1405 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1406 * and realizes its children if they are visible. Does nothing if the
1407 * actor is not visible.
1409 * Calling this function is strongly disencouraged: the default
1410 * implementation of #ClutterActorClass.map() will map all the children
1411 * of an actor when mapping its parent.
1413 * When overriding map, it is mandatory to chain up to the parent
1419 clutter_actor_map (ClutterActor *self)
1421 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1423 if (CLUTTER_ACTOR_IS_MAPPED (self))
1426 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1429 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1433 clutter_actor_real_unmap (ClutterActor *self)
1435 ClutterActorPrivate *priv = self->priv;
1438 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1440 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1441 _clutter_actor_get_debug_name (self));
1443 for (iter = self->priv->first_child;
1445 iter = iter->priv->next_sibling)
1447 clutter_actor_unmap (iter);
1450 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1452 /* clear the contents of the last paint volume, so that hiding + moving +
1453 * showing will not result in the wrong area being repainted
1455 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1456 priv->last_paint_volume_valid = TRUE;
1458 /* notify on parent mapped after potentially unmapping
1459 * children, so apps see a bottom-up notification.
1461 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1463 /* relinquish keyboard focus if we were unmapped while owning it */
1464 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1466 ClutterStage *stage;
1468 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1471 _clutter_stage_release_pick_id (stage, priv->pick_id);
1475 if (stage != NULL &&
1476 clutter_stage_get_key_focus (stage) == self)
1478 clutter_stage_set_key_focus (stage, NULL);
1484 * clutter_actor_unmap:
1485 * @self: A #ClutterActor
1487 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1488 * unmaps its children if they were mapped.
1490 * Calling this function is not encouraged: the default #ClutterActor
1491 * implementation of #ClutterActorClass.unmap() will also unmap any
1492 * eventual children by default when their parent is unmapped.
1494 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1495 * chain up to the parent implementation.
1497 * <note>It is important to note that the implementation of the
1498 * #ClutterActorClass.unmap() virtual function may be called after
1499 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1500 * implementation, but it is guaranteed to be called before the
1501 * #GObjectClass.finalize() implementation.</note>
1506 clutter_actor_unmap (ClutterActor *self)
1508 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1510 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1513 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1517 clutter_actor_real_show (ClutterActor *self)
1519 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1521 ClutterActorPrivate *priv = self->priv;
1523 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1525 /* we notify on the "visible" flag in the clutter_actor_show()
1526 * wrapper so the entire show signal emission completes first
1529 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1531 /* we queue a relayout unless the actor is inside a
1532 * container that explicitly told us not to
1534 if (priv->parent != NULL &&
1535 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1537 /* While an actor is hidden the parent may not have
1538 * allocated/requested so we need to start from scratch
1539 * and avoid the short-circuiting in
1540 * clutter_actor_queue_relayout().
1542 priv->needs_width_request = FALSE;
1543 priv->needs_height_request = FALSE;
1544 priv->needs_allocation = FALSE;
1545 clutter_actor_queue_relayout (self);
1551 set_show_on_set_parent (ClutterActor *self,
1554 ClutterActorPrivate *priv = self->priv;
1556 set_show = !!set_show;
1558 if (priv->show_on_set_parent == set_show)
1561 if (priv->parent == NULL)
1563 priv->show_on_set_parent = set_show;
1564 g_object_notify_by_pspec (G_OBJECT (self),
1565 obj_props[PROP_SHOW_ON_SET_PARENT]);
1570 * clutter_actor_show:
1571 * @self: A #ClutterActor
1573 * Flags an actor to be displayed. An actor that isn't shown will not
1574 * be rendered on the stage.
1576 * Actors are visible by default.
1578 * If this function is called on an actor without a parent, the
1579 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1583 clutter_actor_show (ClutterActor *self)
1585 ClutterActorPrivate *priv;
1587 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1589 /* simple optimization */
1590 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1592 /* we still need to set the :show-on-set-parent property, in
1593 * case show() is called on an unparented actor
1595 set_show_on_set_parent (self, TRUE);
1599 #ifdef CLUTTER_ENABLE_DEBUG
1600 clutter_actor_verify_map_state (self);
1605 g_object_freeze_notify (G_OBJECT (self));
1607 set_show_on_set_parent (self, TRUE);
1609 g_signal_emit (self, actor_signals[SHOW], 0);
1610 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1612 if (priv->parent != NULL)
1613 clutter_actor_queue_redraw (priv->parent);
1615 g_object_thaw_notify (G_OBJECT (self));
1619 * clutter_actor_show_all:
1620 * @self: a #ClutterActor
1622 * Calls clutter_actor_show() on all children of an actor (if any).
1626 * Deprecated: 1.10: Actors are visible by default
1629 clutter_actor_show_all (ClutterActor *self)
1631 ClutterActorClass *klass;
1633 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1635 klass = CLUTTER_ACTOR_GET_CLASS (self);
1636 if (klass->show_all)
1637 klass->show_all (self);
1641 clutter_actor_real_hide (ClutterActor *self)
1643 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1645 ClutterActorPrivate *priv = self->priv;
1647 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1649 /* we notify on the "visible" flag in the clutter_actor_hide()
1650 * wrapper so the entire hide signal emission completes first
1653 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1655 /* we queue a relayout unless the actor is inside a
1656 * container that explicitly told us not to
1658 if (priv->parent != NULL &&
1659 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1660 clutter_actor_queue_relayout (priv->parent);
1665 * clutter_actor_hide:
1666 * @self: A #ClutterActor
1668 * Flags an actor to be hidden. A hidden actor will not be
1669 * rendered on the stage.
1671 * Actors are visible by default.
1673 * If this function is called on an actor without a parent, the
1674 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1678 clutter_actor_hide (ClutterActor *self)
1680 ClutterActorPrivate *priv;
1682 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1684 /* simple optimization */
1685 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1687 /* we still need to set the :show-on-set-parent property, in
1688 * case hide() is called on an unparented actor
1690 set_show_on_set_parent (self, FALSE);
1694 #ifdef CLUTTER_ENABLE_DEBUG
1695 clutter_actor_verify_map_state (self);
1700 g_object_freeze_notify (G_OBJECT (self));
1702 set_show_on_set_parent (self, FALSE);
1704 g_signal_emit (self, actor_signals[HIDE], 0);
1705 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1707 if (priv->parent != NULL)
1708 clutter_actor_queue_redraw (priv->parent);
1710 g_object_thaw_notify (G_OBJECT (self));
1714 * clutter_actor_hide_all:
1715 * @self: a #ClutterActor
1717 * Calls clutter_actor_hide() on all child actors (if any).
1721 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1722 * prevent its children from being painted as well.
1725 clutter_actor_hide_all (ClutterActor *self)
1727 ClutterActorClass *klass;
1729 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1731 klass = CLUTTER_ACTOR_GET_CLASS (self);
1732 if (klass->hide_all)
1733 klass->hide_all (self);
1737 * clutter_actor_realize:
1738 * @self: A #ClutterActor
1740 * Realization informs the actor that it is attached to a stage. It
1741 * can use this to allocate resources if it wanted to delay allocation
1742 * until it would be rendered. However it is perfectly acceptable for
1743 * an actor to create resources before being realized because Clutter
1744 * only ever has a single rendering context so that actor is free to
1745 * be moved from one stage to another.
1747 * This function does nothing if the actor is already realized.
1749 * Because a realized actor must have realized parent actors, calling
1750 * clutter_actor_realize() will also realize all parents of the actor.
1752 * This function does not realize child actors, except in the special
1753 * case that realizing the stage, when the stage is visible, will
1754 * suddenly map (and thus realize) the children of the stage.
1757 clutter_actor_realize (ClutterActor *self)
1759 ClutterActorPrivate *priv;
1761 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1765 #ifdef CLUTTER_ENABLE_DEBUG
1766 clutter_actor_verify_map_state (self);
1769 if (CLUTTER_ACTOR_IS_REALIZED (self))
1772 /* To be realized, our parent actors must be realized first.
1773 * This will only succeed if we're inside a toplevel.
1775 if (priv->parent != NULL)
1776 clutter_actor_realize (priv->parent);
1778 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1780 /* toplevels can be realized at any time */
1784 /* "Fail" the realization if parent is missing or unrealized;
1785 * this should really be a g_warning() not some kind of runtime
1786 * failure; how can an app possibly recover? Instead it's a bug
1787 * in the app and the app should get an explanatory warning so
1788 * someone can fix it. But for now it's too hard to fix this
1789 * because e.g. ClutterTexture needs reworking.
1791 if (priv->parent == NULL ||
1792 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1796 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1798 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1799 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1801 g_signal_emit (self, actor_signals[REALIZE], 0);
1803 /* Stage actor is allowed to unset the realized flag again in its
1804 * default signal handler, though that is a pathological situation.
1807 /* If realization "failed" we'll have to update child state. */
1808 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1812 clutter_actor_real_unrealize (ClutterActor *self)
1814 /* we must be unmapped (implying our children are also unmapped) */
1815 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1819 * clutter_actor_unrealize:
1820 * @self: A #ClutterActor
1822 * Unrealization informs the actor that it may be being destroyed or
1823 * moved to another stage. The actor may want to destroy any
1824 * underlying graphics resources at this point. However it is
1825 * perfectly acceptable for it to retain the resources until the actor
1826 * is destroyed because Clutter only ever uses a single rendering
1827 * context and all of the graphics resources are valid on any stage.
1829 * Because mapped actors must be realized, actors may not be
1830 * unrealized if they are mapped. This function hides the actor to be
1831 * sure it isn't mapped, an application-visible side effect that you
1832 * may not be expecting.
1834 * This function should not be called by application code.
1837 clutter_actor_unrealize (ClutterActor *self)
1839 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1840 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1842 /* This function should not really be in the public API, because
1843 * there isn't a good reason to call it. ClutterActor will already
1844 * unrealize things for you when it's important to do so.
1846 * If you were using clutter_actor_unrealize() in a dispose
1847 * implementation, then don't, just chain up to ClutterActor's
1850 * If you were using clutter_actor_unrealize() to implement
1851 * unrealizing children of your container, then don't, ClutterActor
1852 * will already take care of that.
1854 * If you were using clutter_actor_unrealize() to re-realize to
1855 * create your resources in a different way, then use
1856 * _clutter_actor_rerealize() (inside Clutter) or just call your
1857 * code that recreates your resources directly (outside Clutter).
1860 #ifdef CLUTTER_ENABLE_DEBUG
1861 clutter_actor_verify_map_state (self);
1864 clutter_actor_hide (self);
1866 clutter_actor_unrealize_not_hiding (self);
1869 static ClutterActorTraverseVisitFlags
1870 unrealize_actor_before_children_cb (ClutterActor *self,
1874 /* If an actor is already unrealized we know its children have also
1875 * already been unrealized... */
1876 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1877 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1879 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1881 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1884 static ClutterActorTraverseVisitFlags
1885 unrealize_actor_after_children_cb (ClutterActor *self,
1889 /* We want to unset the realized flag only _after_
1890 * child actors are unrealized, to maintain invariants.
1892 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1893 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1894 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1898 * clutter_actor_unrealize_not_hiding:
1899 * @self: A #ClutterActor
1901 * Unrealization informs the actor that it may be being destroyed or
1902 * moved to another stage. The actor may want to destroy any
1903 * underlying graphics resources at this point. However it is
1904 * perfectly acceptable for it to retain the resources until the actor
1905 * is destroyed because Clutter only ever uses a single rendering
1906 * context and all of the graphics resources are valid on any stage.
1908 * Because mapped actors must be realized, actors may not be
1909 * unrealized if they are mapped. You must hide the actor or one of
1910 * its parents before attempting to unrealize.
1912 * This function is separate from clutter_actor_unrealize() because it
1913 * does not automatically hide the actor.
1914 * Actors need not be hidden to be unrealized, they just need to
1915 * be unmapped. In fact we don't want to mess up the application's
1916 * setting of the "visible" flag, so hiding is very undesirable.
1918 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1919 * backward compatibility.
1922 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1924 _clutter_actor_traverse (self,
1925 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1926 unrealize_actor_before_children_cb,
1927 unrealize_actor_after_children_cb,
1932 * _clutter_actor_rerealize:
1933 * @self: A #ClutterActor
1934 * @callback: Function to call while unrealized
1935 * @data: data for callback
1937 * If an actor is already unrealized, this just calls the callback.
1939 * If it is realized, it unrealizes temporarily, calls the callback,
1940 * and then re-realizes the actor.
1942 * As a side effect, leaves all children of the actor unrealized if
1943 * the actor was realized but not showing. This is because when we
1944 * unrealize the actor temporarily we must unrealize its children
1945 * (e.g. children of a stage can't be realized if stage window is
1946 * gone). And we aren't clever enough to save the realization state of
1947 * all children. In most cases this should not matter, because
1948 * the children will automatically realize when they next become mapped.
1951 _clutter_actor_rerealize (ClutterActor *self,
1952 ClutterCallback callback,
1955 gboolean was_mapped;
1956 gboolean was_showing;
1957 gboolean was_realized;
1959 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1961 #ifdef CLUTTER_ENABLE_DEBUG
1962 clutter_actor_verify_map_state (self);
1965 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1966 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1967 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1969 /* Must be unmapped to unrealize. Note we only have to hide this
1970 * actor if it was mapped (if all parents were showing). If actor
1971 * is merely visible (but not mapped), then that's fine, we can
1975 clutter_actor_hide (self);
1977 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1979 /* unrealize self and all children */
1980 clutter_actor_unrealize_not_hiding (self);
1982 if (callback != NULL)
1984 (* callback) (self, data);
1988 clutter_actor_show (self); /* will realize only if mapping implies it */
1989 else if (was_realized)
1990 clutter_actor_realize (self); /* realize self and all parents */
1994 clutter_actor_real_pick (ClutterActor *self,
1995 const ClutterColor *color)
1997 /* the default implementation is just to paint a rectangle
1998 * with the same size of the actor using the passed color
2000 if (clutter_actor_should_pick_paint (self))
2002 ClutterActorBox box = { 0, };
2003 float width, height;
2005 clutter_actor_get_allocation_box (self, &box);
2007 width = box.x2 - box.x1;
2008 height = box.y2 - box.y1;
2010 cogl_set_source_color4ub (color->red,
2015 cogl_rectangle (0, 0, width, height);
2018 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2019 * with existing container classes that override the pick() virtual
2020 * and chain up to the default implementation - otherwise we'll end up
2021 * painting our children twice.
2023 * this has to go away for 2.0; hopefully along the pick() itself.
2025 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2029 for (iter = self->priv->first_child;
2031 iter = iter->priv->next_sibling)
2032 clutter_actor_paint (iter);
2037 * clutter_actor_should_pick_paint:
2038 * @self: A #ClutterActor
2040 * Should be called inside the implementation of the
2041 * #ClutterActor::pick virtual function in order to check whether
2042 * the actor should paint itself in pick mode or not.
2044 * This function should never be called directly by applications.
2046 * Return value: %TRUE if the actor should paint its silhouette,
2050 clutter_actor_should_pick_paint (ClutterActor *self)
2052 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2054 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2055 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2056 CLUTTER_ACTOR_IS_REACTIVE (self)))
2063 clutter_actor_real_get_preferred_width (ClutterActor *self,
2065 gfloat *min_width_p,
2066 gfloat *natural_width_p)
2068 ClutterActorPrivate *priv = self->priv;
2070 if (priv->n_children != 0 &&
2071 priv->layout_manager != NULL)
2073 ClutterContainer *container = CLUTTER_CONTAINER (self);
2075 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2076 "for the preferred width",
2077 G_OBJECT_TYPE_NAME (priv->layout_manager),
2078 priv->layout_manager);
2080 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2089 /* Default implementation is always 0x0, usually an actor
2090 * using this default is relying on someone to set the
2093 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2098 if (natural_width_p)
2099 *natural_width_p = 0;
2103 clutter_actor_real_get_preferred_height (ClutterActor *self,
2105 gfloat *min_height_p,
2106 gfloat *natural_height_p)
2108 ClutterActorPrivate *priv = self->priv;
2110 if (priv->n_children != 0 &&
2111 priv->layout_manager != NULL)
2113 ClutterContainer *container = CLUTTER_CONTAINER (self);
2115 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2116 "for the preferred height",
2117 G_OBJECT_TYPE_NAME (priv->layout_manager),
2118 priv->layout_manager);
2120 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2128 /* Default implementation is always 0x0, usually an actor
2129 * using this default is relying on someone to set the
2132 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2137 if (natural_height_p)
2138 *natural_height_p = 0;
2142 clutter_actor_store_old_geometry (ClutterActor *self,
2143 ClutterActorBox *box)
2145 *box = self->priv->allocation;
2149 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2150 const ClutterActorBox *old)
2152 ClutterActorPrivate *priv = self->priv;
2153 GObject *obj = G_OBJECT (self);
2155 g_object_freeze_notify (obj);
2157 /* to avoid excessive requisition or allocation cycles we
2158 * use the cached values.
2160 * - if we don't have an allocation we assume that we need
2162 * - if we don't have a width or a height request we notify
2164 * - if we have a valid allocation then we check the old
2165 * bounding box with the current allocation and we notify
2168 if (priv->needs_allocation)
2170 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2171 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2172 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2173 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2174 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2175 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2177 else if (priv->needs_width_request || priv->needs_height_request)
2179 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2180 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2181 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2186 gfloat width, height;
2188 x = priv->allocation.x1;
2189 y = priv->allocation.y1;
2190 width = priv->allocation.x2 - priv->allocation.x1;
2191 height = priv->allocation.y2 - priv->allocation.y1;
2195 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2196 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2201 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2202 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2205 if (width != (old->x2 - old->x1))
2207 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2208 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2211 if (height != (old->y2 - old->y1))
2213 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2214 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2218 g_object_thaw_notify (obj);
2222 * clutter_actor_set_allocation_internal:
2223 * @self: a #ClutterActor
2224 * @box: a #ClutterActorBox
2225 * @flags: allocation flags
2227 * Stores the allocation of @self.
2229 * This function only performs basic storage and property notification.
2231 * This function should be called by clutter_actor_set_allocation()
2232 * and by the default implementation of #ClutterActorClass.allocate().
2234 * Return value: %TRUE if the allocation of the #ClutterActor has been
2235 * changed, and %FALSE otherwise
2237 static inline gboolean
2238 clutter_actor_set_allocation_internal (ClutterActor *self,
2239 const ClutterActorBox *box,
2240 ClutterAllocationFlags flags)
2242 ClutterActorPrivate *priv = self->priv;
2244 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2245 gboolean flags_changed;
2247 ClutterActorBox old_alloc = { 0, };
2249 obj = G_OBJECT (self);
2251 g_object_freeze_notify (obj);
2253 clutter_actor_store_old_geometry (self, &old_alloc);
2255 x1_changed = priv->allocation.x1 != box->x1;
2256 y1_changed = priv->allocation.y1 != box->y1;
2257 x2_changed = priv->allocation.x2 != box->x2;
2258 y2_changed = priv->allocation.y2 != box->y2;
2260 flags_changed = priv->allocation_flags != flags;
2262 priv->allocation = *box;
2263 priv->allocation_flags = flags;
2265 /* allocation is authoritative */
2266 priv->needs_width_request = FALSE;
2267 priv->needs_height_request = FALSE;
2268 priv->needs_allocation = FALSE;
2270 if (x1_changed || y1_changed ||
2271 x2_changed || y2_changed ||
2274 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2275 _clutter_actor_get_debug_name (self));
2277 priv->transform_valid = FALSE;
2279 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2281 /* if the allocation changes, so does the content box */
2282 if (priv->content != NULL)
2284 priv->content_box_valid = FALSE;
2285 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2293 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2295 g_object_thaw_notify (obj);
2300 static void clutter_actor_real_allocate (ClutterActor *self,
2301 const ClutterActorBox *box,
2302 ClutterAllocationFlags flags);
2305 clutter_actor_maybe_layout_children (ClutterActor *self,
2306 const ClutterActorBox *allocation,
2307 ClutterAllocationFlags flags)
2309 ClutterActorPrivate *priv = self->priv;
2311 /* this is going to be a bit hard to follow, so let's put an explanation
2314 * we want ClutterActor to have a default layout manager if the actor was
2315 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2317 * we also want any subclass of ClutterActor that does not override the
2318 * ::allocate() virtual function to delegate to a layout manager.
2320 * finally, we want to allow people subclassing ClutterActor and overriding
2321 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2323 * on the other hand, we want existing actor subclasses overriding the
2324 * ::allocate() virtual function and chaining up to the parent's
2325 * implementation to continue working without allocating their children
2326 * twice, or without entering an allocation loop.
2328 * for the first two points, we check if the class of the actor is
2329 * overridding the ::allocate() virtual function; if it isn't, then we
2330 * follow through with checking whether we have children and a layout
2331 * manager, and eventually calling clutter_layout_manager_allocate().
2333 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2334 * allocation flags that we got passed, and if it is present, we continue
2335 * with the check above.
2337 * if neither of these two checks yields a positive result, we just
2338 * assume that the ::allocate() virtual function that resulted in this
2339 * function being called will also allocate the children of the actor.
2342 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2345 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2351 if (priv->n_children != 0 &&
2352 priv->layout_manager != NULL)
2354 ClutterContainer *container = CLUTTER_CONTAINER (self);
2355 ClutterAllocationFlags children_flags;
2356 ClutterActorBox children_box;
2358 /* normalize the box passed to the layout manager */
2359 children_box.x1 = children_box.y1 = 0.f;
2360 children_box.x2 = (allocation->x2 - allocation->x1);
2361 children_box.y2 = (allocation->y2 - allocation->y1);
2363 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2364 * the actor's children, since it refers only to the current
2365 * actor's allocation.
2367 children_flags = flags;
2368 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2370 CLUTTER_NOTE (LAYOUT,
2371 "Allocating %d children of %s "
2372 "at { %.2f, %.2f - %.2f x %.2f } "
2375 _clutter_actor_get_debug_name (self),
2378 (allocation->x2 - allocation->x1),
2379 (allocation->y2 - allocation->y1),
2380 G_OBJECT_TYPE_NAME (priv->layout_manager));
2382 clutter_layout_manager_allocate (priv->layout_manager,
2390 clutter_actor_real_allocate (ClutterActor *self,
2391 const ClutterActorBox *box,
2392 ClutterAllocationFlags flags)
2394 ClutterActorPrivate *priv = self->priv;
2397 g_object_freeze_notify (G_OBJECT (self));
2399 changed = clutter_actor_set_allocation_internal (self, box, flags);
2401 /* we allocate our children before we notify changes in our geometry,
2402 * so that people connecting to properties will be able to get valid
2403 * data out of the sub-tree of the scene graph that has this actor at
2406 clutter_actor_maybe_layout_children (self, box, flags);
2410 ClutterActorBox signal_box = priv->allocation;
2411 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2413 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2418 g_object_thaw_notify (G_OBJECT (self));
2422 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2423 ClutterActor *origin)
2425 /* no point in queuing a redraw on a destroyed actor */
2426 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2429 /* NB: We can't bail out early here if the actor is hidden in case
2430 * the actor bas been cloned. In this case the clone will need to
2431 * receive the signal so it can queue its own redraw.
2434 /* calls klass->queue_redraw in default handler */
2435 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2439 clutter_actor_real_queue_redraw (ClutterActor *self,
2440 ClutterActor *origin)
2442 ClutterActor *parent;
2444 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2445 _clutter_actor_get_debug_name (self),
2446 origin != NULL ? _clutter_actor_get_debug_name (origin)
2449 /* no point in queuing a redraw on a destroyed actor */
2450 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2453 /* If the queue redraw is coming from a child then the actor has
2454 become dirty and any queued effect is no longer valid */
2457 self->priv->is_dirty = TRUE;
2458 self->priv->effect_to_redraw = NULL;
2461 /* If the actor isn't visible, we still had to emit the signal
2462 * to allow for a ClutterClone, but the appearance of the parent
2463 * won't change so we don't have to propagate up the hierarchy.
2465 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2468 /* Although we could determine here that a full stage redraw
2469 * has already been queued and immediately bail out, we actually
2470 * guarantee that we will propagate a queue-redraw signal to our
2471 * parent at least once so that it's possible to implement a
2472 * container that tracks which of its children have queued a
2475 if (self->priv->propagated_one_redraw)
2477 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2478 if (stage != NULL &&
2479 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2483 self->priv->propagated_one_redraw = TRUE;
2485 /* notify parents, if they are all visible eventually we'll
2486 * queue redraw on the stage, which queues the redraw idle.
2488 parent = clutter_actor_get_parent (self);
2491 /* this will go up recursively */
2492 _clutter_actor_signal_queue_redraw (parent, origin);
2497 clutter_actor_real_queue_relayout (ClutterActor *self)
2499 ClutterActorPrivate *priv = self->priv;
2501 /* no point in queueing a redraw on a destroyed actor */
2502 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2505 priv->needs_width_request = TRUE;
2506 priv->needs_height_request = TRUE;
2507 priv->needs_allocation = TRUE;
2509 /* reset the cached size requests */
2510 memset (priv->width_requests, 0,
2511 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2512 memset (priv->height_requests, 0,
2513 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2515 /* We need to go all the way up the hierarchy */
2516 if (priv->parent != NULL)
2517 _clutter_actor_queue_only_relayout (priv->parent);
2521 * clutter_actor_apply_relative_transform_to_point:
2522 * @self: A #ClutterActor
2523 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2524 * default #ClutterStage
2525 * @point: A point as #ClutterVertex
2526 * @vertex: (out caller-allocates): The translated #ClutterVertex
2528 * Transforms @point in coordinates relative to the actor into
2529 * ancestor-relative coordinates using the relevant transform
2530 * stack (i.e. scale, rotation, etc).
2532 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2533 * this case, the coordinates returned will be the coordinates on
2534 * the stage before the projection is applied. This is different from
2535 * the behaviour of clutter_actor_apply_transform_to_point().
2540 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2541 ClutterActor *ancestor,
2542 const ClutterVertex *point,
2543 ClutterVertex *vertex)
2548 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2549 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2550 g_return_if_fail (point != NULL);
2551 g_return_if_fail (vertex != NULL);
2556 if (ancestor == NULL)
2557 ancestor = _clutter_actor_get_stage_internal (self);
2559 if (ancestor == NULL)
2565 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2566 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2570 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2571 const ClutterVertex *vertices_in,
2572 ClutterVertex *vertices_out,
2575 ClutterActor *stage;
2576 CoglMatrix modelview;
2577 CoglMatrix projection;
2580 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2582 stage = _clutter_actor_get_stage_internal (self);
2584 /* We really can't do anything meaningful in this case so don't try
2585 * to do any transform */
2589 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2590 * that gets us to stage coordinates, we want to go all the way to eye
2592 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2594 /* Fetch the projection and viewport */
2595 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2596 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2602 _clutter_util_fully_transform_vertices (&modelview,
2613 * clutter_actor_apply_transform_to_point:
2614 * @self: A #ClutterActor
2615 * @point: A point as #ClutterVertex
2616 * @vertex: (out caller-allocates): The translated #ClutterVertex
2618 * Transforms @point in coordinates relative to the actor
2619 * into screen-relative coordinates with the current actor
2620 * transformation (i.e. scale, rotation, etc)
2625 clutter_actor_apply_transform_to_point (ClutterActor *self,
2626 const ClutterVertex *point,
2627 ClutterVertex *vertex)
2629 g_return_if_fail (point != NULL);
2630 g_return_if_fail (vertex != NULL);
2631 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2635 * _clutter_actor_get_relative_transformation_matrix:
2636 * @self: The actor whose coordinate space you want to transform from.
2637 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2638 * or %NULL if you want to transform all the way to eye coordinates.
2639 * @matrix: A #CoglMatrix to store the transformation
2641 * This gets a transformation @matrix that will transform coordinates from the
2642 * coordinate space of @self into the coordinate space of @ancestor.
2644 * For example if you need a matrix that can transform the local actor
2645 * coordinates of @self into stage coordinates you would pass the actor's stage
2646 * pointer as the @ancestor.
2648 * If you pass %NULL then the transformation will take you all the way through
2649 * to eye coordinates. This can be useful if you want to extract the entire
2650 * modelview transform that Clutter applies before applying the projection
2651 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2652 * using cogl_set_modelview_matrix() for example then you would want a matrix
2653 * that transforms into eye coordinates.
2655 * <note><para>This function explicitly initializes the given @matrix. If you just
2656 * want clutter to multiply a relative transformation with an existing matrix
2657 * you can use clutter_actor_apply_relative_transformation_matrix()
2658 * instead.</para></note>
2661 /* XXX: We should consider caching the stage relative modelview along with
2662 * the actor itself */
2664 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2665 ClutterActor *ancestor,
2668 cogl_matrix_init_identity (matrix);
2670 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2673 /* Project the given @box into stage window coordinates, writing the
2674 * transformed vertices to @verts[]. */
2676 _clutter_actor_transform_and_project_box (ClutterActor *self,
2677 const ClutterActorBox *box,
2678 ClutterVertex verts[])
2680 ClutterVertex box_vertices[4];
2682 box_vertices[0].x = box->x1;
2683 box_vertices[0].y = box->y1;
2684 box_vertices[0].z = 0;
2685 box_vertices[1].x = box->x2;
2686 box_vertices[1].y = box->y1;
2687 box_vertices[1].z = 0;
2688 box_vertices[2].x = box->x1;
2689 box_vertices[2].y = box->y2;
2690 box_vertices[2].z = 0;
2691 box_vertices[3].x = box->x2;
2692 box_vertices[3].y = box->y2;
2693 box_vertices[3].z = 0;
2696 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2700 * clutter_actor_get_allocation_vertices:
2701 * @self: A #ClutterActor
2702 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2703 * against, or %NULL to use the #ClutterStage
2704 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2705 * location for an array of 4 #ClutterVertex in which to store the result
2707 * Calculates the transformed coordinates of the four corners of the
2708 * actor in the plane of @ancestor. The returned vertices relate to
2709 * the #ClutterActorBox coordinates as follows:
2711 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2712 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2713 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2714 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2717 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2718 * this case, the coordinates returned will be the coordinates on
2719 * the stage before the projection is applied. This is different from
2720 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2725 clutter_actor_get_allocation_vertices (ClutterActor *self,
2726 ClutterActor *ancestor,
2727 ClutterVertex verts[])
2729 ClutterActorPrivate *priv;
2730 ClutterActorBox box;
2731 ClutterVertex vertices[4];
2732 CoglMatrix modelview;
2734 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2735 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2737 if (ancestor == NULL)
2738 ancestor = _clutter_actor_get_stage_internal (self);
2740 /* Fallback to a NOP transform if the actor isn't parented under a
2742 if (ancestor == NULL)
2747 /* if the actor needs to be allocated we force a relayout, so that
2748 * we will have valid values to use in the transformations */
2749 if (priv->needs_allocation)
2751 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2753 _clutter_stage_maybe_relayout (stage);
2756 box.x1 = box.y1 = 0;
2757 /* The result isn't really meaningful in this case but at
2758 * least try to do something *vaguely* reasonable... */
2759 clutter_actor_get_size (self, &box.x2, &box.y2);
2763 clutter_actor_get_allocation_box (self, &box);
2765 vertices[0].x = box.x1;
2766 vertices[0].y = box.y1;
2768 vertices[1].x = box.x2;
2769 vertices[1].y = box.y1;
2771 vertices[2].x = box.x1;
2772 vertices[2].y = box.y2;
2774 vertices[3].x = box.x2;
2775 vertices[3].y = box.y2;
2778 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2781 cogl_matrix_transform_points (&modelview,
2783 sizeof (ClutterVertex),
2785 sizeof (ClutterVertex),
2791 * clutter_actor_get_abs_allocation_vertices:
2792 * @self: A #ClutterActor
2793 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2794 * of 4 #ClutterVertex where to store the result.
2796 * Calculates the transformed screen coordinates of the four corners of
2797 * the actor; the returned vertices relate to the #ClutterActorBox
2798 * coordinates as follows:
2800 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2801 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2802 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2803 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2809 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2810 ClutterVertex verts[])
2812 ClutterActorPrivate *priv;
2813 ClutterActorBox actor_space_allocation;
2815 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2819 /* if the actor needs to be allocated we force a relayout, so that
2820 * the actor allocation box will be valid for
2821 * _clutter_actor_transform_and_project_box()
2823 if (priv->needs_allocation)
2825 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2826 /* There's nothing meaningful we can do now */
2830 _clutter_stage_maybe_relayout (stage);
2833 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2834 * own coordinate space... */
2835 actor_space_allocation.x1 = 0;
2836 actor_space_allocation.y1 = 0;
2837 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2838 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2839 _clutter_actor_transform_and_project_box (self,
2840 &actor_space_allocation,
2845 clutter_actor_real_apply_transform (ClutterActor *self,
2848 ClutterActorPrivate *priv = self->priv;
2850 if (!priv->transform_valid)
2852 CoglMatrix *transform = &priv->transform;
2853 const ClutterTransformInfo *info;
2855 info = _clutter_actor_get_transform_info_or_defaults (self);
2857 cogl_matrix_init_identity (transform);
2859 cogl_matrix_translate (transform,
2860 priv->allocation.x1,
2861 priv->allocation.y1,
2865 cogl_matrix_translate (transform, 0, 0, info->depth);
2868 * because the rotation involves translations, we must scale
2869 * before applying the rotations (if we apply the scale after
2870 * the rotations, the translations included in the rotation are
2871 * not scaled and so the entire object will move on the screen
2872 * as a result of rotating it).
2874 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2876 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2877 &info->scale_center,
2878 cogl_matrix_scale (transform,
2885 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2887 cogl_matrix_rotate (transform,
2892 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2894 cogl_matrix_rotate (transform,
2899 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2901 cogl_matrix_rotate (transform,
2905 if (!clutter_anchor_coord_is_zero (&info->anchor))
2909 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2910 cogl_matrix_translate (transform, -x, -y, -z);
2913 priv->transform_valid = TRUE;
2916 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2919 /* Applies the transforms associated with this actor to the given
2922 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2925 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2929 * clutter_actor_apply_relative_transformation_matrix:
2930 * @self: The actor whose coordinate space you want to transform from.
2931 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2932 * or %NULL if you want to transform all the way to eye coordinates.
2933 * @matrix: A #CoglMatrix to apply the transformation too.
2935 * This multiplies a transform with @matrix that will transform coordinates
2936 * from the coordinate space of @self into the coordinate space of @ancestor.
2938 * For example if you need a matrix that can transform the local actor
2939 * coordinates of @self into stage coordinates you would pass the actor's stage
2940 * pointer as the @ancestor.
2942 * If you pass %NULL then the transformation will take you all the way through
2943 * to eye coordinates. This can be useful if you want to extract the entire
2944 * modelview transform that Clutter applies before applying the projection
2945 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2946 * using cogl_set_modelview_matrix() for example then you would want a matrix
2947 * that transforms into eye coordinates.
2949 * <note>This function doesn't initialize the given @matrix, it simply
2950 * multiplies the requested transformation matrix with the existing contents of
2951 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2952 * before calling this function, or you can use
2953 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2956 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2957 ClutterActor *ancestor,
2960 ClutterActor *parent;
2962 /* Note we terminate before ever calling stage->apply_transform()
2963 * since that would conceptually be relative to the underlying
2964 * window OpenGL coordinates so we'd need a special @ancestor
2965 * value to represent the fake parent of the stage. */
2966 if (self == ancestor)
2969 parent = clutter_actor_get_parent (self);
2972 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2975 _clutter_actor_apply_modelview_transform (self, matrix);
2979 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2980 ClutterPaintVolume *pv,
2982 const CoglColor *color)
2984 static CoglPipeline *outline = NULL;
2985 CoglPrimitive *prim;
2986 ClutterVertex line_ends[12 * 2];
2989 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2990 /* XXX: at some point we'll query this from the stage but we can't
2991 * do that until the osx backend uses Cogl natively. */
2992 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2994 if (outline == NULL)
2995 outline = cogl_pipeline_new (ctx);
2997 _clutter_paint_volume_complete (pv);
2999 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3002 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3003 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3004 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3005 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3010 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3011 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3012 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3013 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3015 /* Lines connecting front face to back face */
3016 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3017 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3018 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3019 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3022 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3024 (CoglVertexP3 *)line_ends);
3026 cogl_pipeline_set_color (outline, color);
3027 cogl_framebuffer_draw_primitive (fb, outline, prim);
3028 cogl_object_unref (prim);
3032 PangoLayout *layout;
3033 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3034 pango_layout_set_text (layout, label, -1);
3035 cogl_pango_render_layout (layout,
3040 g_object_unref (layout);
3045 _clutter_actor_draw_paint_volume (ClutterActor *self)
3047 ClutterPaintVolume *pv;
3050 pv = _clutter_actor_get_paint_volume_mutable (self);
3053 gfloat width, height;
3054 ClutterPaintVolume fake_pv;
3056 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3057 _clutter_paint_volume_init_static (&fake_pv, stage);
3059 clutter_actor_get_size (self, &width, &height);
3060 clutter_paint_volume_set_width (&fake_pv, width);
3061 clutter_paint_volume_set_height (&fake_pv, height);
3063 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3064 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3065 _clutter_actor_get_debug_name (self),
3068 clutter_paint_volume_free (&fake_pv);
3072 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3073 _clutter_actor_draw_paint_volume_full (self, pv,
3074 _clutter_actor_get_debug_name (self),
3080 _clutter_actor_paint_cull_result (ClutterActor *self,
3082 ClutterCullResult result)
3084 ClutterPaintVolume *pv;
3089 if (result == CLUTTER_CULL_RESULT_IN)
3090 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3091 else if (result == CLUTTER_CULL_RESULT_OUT)
3092 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3094 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3097 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3099 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3100 _clutter_actor_draw_paint_volume_full (self, pv,
3101 _clutter_actor_get_debug_name (self),
3105 PangoLayout *layout;
3107 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3108 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3109 cogl_set_source_color (&color);
3111 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3112 pango_layout_set_text (layout, label, -1);
3113 cogl_pango_render_layout (layout,
3119 g_object_unref (layout);
3123 static int clone_paint_level = 0;
3126 _clutter_actor_push_clone_paint (void)
3128 clone_paint_level++;
3132 _clutter_actor_pop_clone_paint (void)
3134 clone_paint_level--;
3138 in_clone_paint (void)
3140 return clone_paint_level > 0;
3143 /* Returns TRUE if the actor can be ignored */
3144 /* FIXME: we should return a ClutterCullResult, and
3145 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3146 * means there's no point in trying to cull descendants of the current
3149 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3151 ClutterActorPrivate *priv = self->priv;
3152 ClutterActor *stage;
3153 const ClutterPlane *stage_clip;
3155 if (!priv->last_paint_volume_valid)
3157 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3158 "->last_paint_volume_valid == FALSE",
3159 _clutter_actor_get_debug_name (self));
3163 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3166 stage = _clutter_actor_get_stage_internal (self);
3167 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3168 if (G_UNLIKELY (!stage_clip))
3170 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3171 "No stage clip set",
3172 _clutter_actor_get_debug_name (self));
3176 if (cogl_get_draw_framebuffer () !=
3177 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3179 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3180 "Current framebuffer doesn't correspond to stage",
3181 _clutter_actor_get_debug_name (self));
3186 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3191 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3193 ClutterActorPrivate *priv = self->priv;
3194 const ClutterPaintVolume *pv;
3196 if (priv->last_paint_volume_valid)
3198 clutter_paint_volume_free (&priv->last_paint_volume);
3199 priv->last_paint_volume_valid = FALSE;
3202 pv = clutter_actor_get_paint_volume (self);
3205 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3206 "Actor failed to report a paint volume",
3207 _clutter_actor_get_debug_name (self));
3211 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3213 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3214 NULL); /* eye coordinates */
3216 priv->last_paint_volume_valid = TRUE;
3219 static inline gboolean
3220 actor_has_shader_data (ClutterActor *self)
3222 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3226 _clutter_actor_get_pick_id (ClutterActor *self)
3228 if (self->priv->pick_id < 0)
3231 return self->priv->pick_id;
3234 /* This is the same as clutter_actor_add_effect except that it doesn't
3235 queue a redraw and it doesn't notify on the effect property */
3237 _clutter_actor_add_effect_internal (ClutterActor *self,
3238 ClutterEffect *effect)
3240 ClutterActorPrivate *priv = self->priv;
3242 if (priv->effects == NULL)
3244 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3245 priv->effects->actor = self;
3248 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3251 /* This is the same as clutter_actor_remove_effect except that it doesn't
3252 queue a redraw and it doesn't notify on the effect property */
3254 _clutter_actor_remove_effect_internal (ClutterActor *self,
3255 ClutterEffect *effect)
3257 ClutterActorPrivate *priv = self->priv;
3259 if (priv->effects == NULL)
3262 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3264 if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3265 g_clear_object (&priv->effects);
3269 needs_flatten_effect (ClutterActor *self)
3271 ClutterActorPrivate *priv = self->priv;
3273 if (G_UNLIKELY (clutter_paint_debug_flags &
3274 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3277 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3279 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3281 if (clutter_actor_get_paint_opacity (self) < 255 &&
3282 clutter_actor_has_overlaps (self))
3290 add_or_remove_flatten_effect (ClutterActor *self)
3292 ClutterActorPrivate *priv = self->priv;
3294 /* Add or remove the flatten effect depending on the
3295 offscreen-redirect property. */
3296 if (needs_flatten_effect (self))
3298 if (priv->flatten_effect == NULL)
3300 ClutterActorMeta *actor_meta;
3303 priv->flatten_effect = _clutter_flatten_effect_new ();
3304 /* Keep a reference to the effect so that we can queue
3306 g_object_ref_sink (priv->flatten_effect);
3308 /* Set the priority of the effect to high so that it will
3309 always be applied to the actor first. It uses an internal
3310 priority so that it won't be visible to applications */
3311 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3312 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3313 _clutter_actor_meta_set_priority (actor_meta, priority);
3315 /* This will add the effect without queueing a redraw */
3316 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3321 if (priv->flatten_effect != NULL)
3323 /* Destroy the effect so that it will lose its fbo cache of
3325 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3326 g_clear_object (&priv->flatten_effect);
3332 clutter_actor_real_paint (ClutterActor *actor)
3334 ClutterActorPrivate *priv = actor->priv;
3337 for (iter = priv->first_child;
3339 iter = iter->priv->next_sibling)
3341 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3342 _clutter_actor_get_debug_name (iter),
3343 _clutter_actor_get_debug_name (actor),
3344 iter->priv->allocation.x1,
3345 iter->priv->allocation.y1,
3346 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3347 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3349 clutter_actor_paint (iter);
3354 clutter_actor_paint_node (ClutterActor *actor,
3355 ClutterPaintNode *root)
3357 ClutterActorPrivate *priv = actor->priv;
3362 if (priv->bg_color_set &&
3363 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3365 ClutterPaintNode *node;
3366 ClutterColor bg_color;
3367 ClutterActorBox box;
3371 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3372 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3374 bg_color = priv->bg_color;
3375 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3376 * priv->bg_color.alpha
3379 node = clutter_color_node_new (&bg_color);
3380 clutter_paint_node_set_name (node, "backgroundColor");
3381 clutter_paint_node_add_rectangle (node, &box);
3382 clutter_paint_node_add_child (root, node);
3383 clutter_paint_node_unref (node);
3386 if (priv->content != NULL)
3387 _clutter_content_paint_content (priv->content, actor, root);
3389 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3390 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3392 if (clutter_paint_node_get_n_children (root) == 0)
3395 #ifdef CLUTTER_ENABLE_DEBUG
3396 if (CLUTTER_HAS_DEBUG (PAINT))
3398 /* dump the tree only if we have one */
3399 _clutter_paint_node_dump_tree (root);
3401 #endif /* CLUTTER_ENABLE_DEBUG */
3403 _clutter_paint_node_paint (root);
3406 /* XXX: Uncomment this when we disable emitting the paint signal */
3407 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3414 * clutter_actor_paint:
3415 * @self: A #ClutterActor
3417 * Renders the actor to display.
3419 * This function should not be called directly by applications.
3420 * Call clutter_actor_queue_redraw() to queue paints, instead.
3422 * This function is context-aware, and will either cause a
3423 * regular paint or a pick paint.
3425 * This function will emit the #ClutterActor::paint signal or
3426 * the #ClutterActor::pick signal, depending on the context.
3428 * This function does not paint the actor if the actor is set to 0,
3429 * unless it is performing a pick paint.
3432 clutter_actor_paint (ClutterActor *self)
3434 ClutterActorPrivate *priv;
3435 ClutterPickMode pick_mode;
3436 gboolean clip_set = FALSE;
3437 gboolean shader_applied = FALSE;
3439 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3440 "Actor real-paint counter",
3441 "Increments each time any actor is painted",
3442 0 /* no application private data */);
3443 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3444 "Actor pick-paint counter",
3445 "Increments each time any actor is painted "
3447 0 /* no application private data */);
3449 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3451 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3456 pick_mode = _clutter_context_get_pick_mode ();
3458 if (pick_mode == CLUTTER_PICK_NONE)
3459 priv->propagated_one_redraw = FALSE;
3461 /* It's an important optimization that we consider painting of
3462 * actors with 0 opacity to be a NOP... */
3463 if (pick_mode == CLUTTER_PICK_NONE &&
3464 /* ignore top-levels, since they might be transparent */
3465 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3466 /* Use the override opacity if its been set */
3467 ((priv->opacity_override >= 0) ?
3468 priv->opacity_override : priv->opacity) == 0)
3471 /* if we aren't paintable (not in a toplevel with all
3472 * parents paintable) then do nothing.
3474 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3477 /* mark that we are in the paint process */
3478 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3482 if (priv->enable_model_view_transform)
3486 /* XXX: It could be better to cache the modelview with the actor
3487 * instead of progressively building up the transformations on
3488 * the matrix stack every time we paint. */
3489 cogl_get_modelview_matrix (&matrix);
3490 _clutter_actor_apply_modelview_transform (self, &matrix);
3492 #ifdef CLUTTER_ENABLE_DEBUG
3493 /* Catch when out-of-band transforms have been made by actors not as part
3494 * of an apply_transform vfunc... */
3495 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3497 CoglMatrix expected_matrix;
3499 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3502 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3504 GString *buf = g_string_sized_new (1024);
3505 ClutterActor *parent;
3508 while (parent != NULL)
3510 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3512 if (parent->priv->parent != NULL)
3513 g_string_append (buf, "->");
3515 parent = parent->priv->parent;
3518 g_warning ("Unexpected transform found when painting actor "
3519 "\"%s\". This will be caused by one of the actor's "
3520 "ancestors (%s) using the Cogl API directly to transform "
3521 "children instead of using ::apply_transform().",
3522 _clutter_actor_get_debug_name (self),
3525 g_string_free (buf, TRUE);
3528 #endif /* CLUTTER_ENABLE_DEBUG */
3530 cogl_set_modelview_matrix (&matrix);
3535 cogl_clip_push_rectangle (priv->clip.x,
3537 priv->clip.x + priv->clip.width,
3538 priv->clip.y + priv->clip.height);
3541 else if (priv->clip_to_allocation)
3543 gfloat width, height;
3545 width = priv->allocation.x2 - priv->allocation.x1;
3546 height = priv->allocation.y2 - priv->allocation.y1;
3548 cogl_clip_push_rectangle (0, 0, width, height);
3552 if (pick_mode == CLUTTER_PICK_NONE)
3554 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3556 /* We check whether we need to add the flatten effect before
3557 each paint so that we can avoid having a mechanism for
3558 applications to notify when the value of the
3559 has_overlaps virtual changes. */
3560 add_or_remove_flatten_effect (self);
3563 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3565 /* We save the current paint volume so that the next time the
3566 * actor queues a redraw we can constrain the redraw to just
3567 * cover the union of the new bounding box and the old.
3569 * We also fetch the current paint volume to perform culling so
3570 * we can avoid painting actors outside the current clip region.
3572 * If we are painting inside a clone, we should neither update
3573 * the paint volume or use it to cull painting, since the paint
3574 * box represents the location of the source actor on the
3577 * XXX: We are starting to do a lot of vertex transforms on
3578 * the CPU in a typical paint, so at some point we should
3579 * audit these and consider caching some things.
3581 * NB: We don't perform culling while picking at this point because
3582 * clutter-stage.c doesn't setup the clipping planes appropriately.
3584 * NB: We don't want to update the last-paint-volume during picking
3585 * because the last-paint-volume is used to determine the old screen
3586 * space location of an actor that has moved so we can know the
3587 * minimal region to redraw to clear an old view of the actor. If we
3588 * update this during picking then by the time we come around to
3589 * paint then the last-paint-volume would likely represent the new
3590 * actor position not the old.
3592 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3595 /* annoyingly gcc warns if uninitialized even though
3596 * the initialization is redundant :-( */
3597 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3599 if (G_LIKELY ((clutter_paint_debug_flags &
3600 (CLUTTER_DEBUG_DISABLE_CULLING |
3601 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3602 (CLUTTER_DEBUG_DISABLE_CULLING |
3603 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3604 _clutter_actor_update_last_paint_volume (self);
3606 success = cull_actor (self, &result);
3608 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3609 _clutter_actor_paint_cull_result (self, success, result);
3610 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3614 if (priv->effects == NULL)
3616 if (pick_mode == CLUTTER_PICK_NONE &&
3617 actor_has_shader_data (self))
3619 _clutter_actor_shader_pre_paint (self, FALSE);
3620 shader_applied = TRUE;
3623 priv->next_effect_to_paint = NULL;
3626 priv->next_effect_to_paint =
3627 _clutter_meta_group_peek_metas (priv->effects);
3629 clutter_actor_continue_paint (self);
3632 _clutter_actor_shader_post_paint (self);
3634 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3635 pick_mode == CLUTTER_PICK_NONE))
3636 _clutter_actor_draw_paint_volume (self);
3639 /* If we make it here then the actor has run through a complete
3640 paint run including all the effects so it's no longer dirty */
3641 if (pick_mode == CLUTTER_PICK_NONE)
3642 priv->is_dirty = FALSE;
3649 /* paint sequence complete */
3650 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3654 * clutter_actor_continue_paint:
3655 * @self: A #ClutterActor
3657 * Run the next stage of the paint sequence. This function should only
3658 * be called within the implementation of the ‘run’ virtual of a
3659 * #ClutterEffect. It will cause the run method of the next effect to
3660 * be applied, or it will paint the actual actor if the current effect
3661 * is the last effect in the chain.
3666 clutter_actor_continue_paint (ClutterActor *self)
3668 ClutterActorPrivate *priv;
3670 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3671 /* This should only be called from with in the ‘run’ implementation
3672 of a ClutterEffect */
3673 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3677 /* Skip any effects that are disabled */
3678 while (priv->next_effect_to_paint &&
3679 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3680 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3682 /* If this has come from the last effect then we'll just paint the
3684 if (priv->next_effect_to_paint == NULL)
3686 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3688 ClutterPaintNode *dummy;
3690 /* XXX - this will go away in 2.0, when we can get rid of this
3691 * stuff and switch to a pure retained render tree of PaintNodes
3692 * for the entire frame, starting from the Stage; the paint()
3693 * virtual function can then be called directly.
3695 dummy = _clutter_dummy_node_new (self);
3696 clutter_paint_node_set_name (dummy, "Root");
3698 /* XXX - for 1.12, we use the return value of paint_node() to
3699 * decide whether we should emit the ::paint signal.
3701 clutter_actor_paint_node (self, dummy);
3702 clutter_paint_node_unref (dummy);
3704 g_signal_emit (self, actor_signals[PAINT], 0);
3708 ClutterColor col = { 0, };
3710 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3712 /* Actor will then paint silhouette of itself in supplied
3713 * color. See clutter_stage_get_actor_at_pos() for where
3714 * picking is enabled.
3716 g_signal_emit (self, actor_signals[PICK], 0, &col);
3721 ClutterEffect *old_current_effect;
3722 ClutterEffectPaintFlags run_flags = 0;
3724 /* Cache the current effect so that we can put it back before
3726 old_current_effect = priv->current_effect;
3728 priv->current_effect = priv->next_effect_to_paint->data;
3729 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3731 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3735 /* If there's an effect queued with this redraw then all
3736 effects up to that one will be considered dirty. It
3737 is expected the queued effect will paint the cached
3738 image and not call clutter_actor_continue_paint again
3739 (although it should work ok if it does) */
3740 if (priv->effect_to_redraw == NULL ||
3741 priv->current_effect != priv->effect_to_redraw)
3742 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3745 _clutter_effect_paint (priv->current_effect, run_flags);
3749 /* We can't determine when an actor has been modified since
3750 its last pick so lets just assume it has always been
3752 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3754 _clutter_effect_pick (priv->current_effect, run_flags);
3757 priv->current_effect = old_current_effect;
3761 static ClutterActorTraverseVisitFlags
3762 invalidate_queue_redraw_entry (ClutterActor *self,
3766 ClutterActorPrivate *priv = self->priv;
3768 if (priv->queue_redraw_entry != NULL)
3770 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3771 priv->queue_redraw_entry = NULL;
3774 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3778 remove_child (ClutterActor *self,
3779 ClutterActor *child)
3781 ClutterActor *prev_sibling, *next_sibling;
3783 prev_sibling = child->priv->prev_sibling;
3784 next_sibling = child->priv->next_sibling;
3786 if (prev_sibling != NULL)
3787 prev_sibling->priv->next_sibling = next_sibling;
3789 if (next_sibling != NULL)
3790 next_sibling->priv->prev_sibling = prev_sibling;
3792 if (self->priv->first_child == child)
3793 self->priv->first_child = next_sibling;
3795 if (self->priv->last_child == child)
3796 self->priv->last_child = prev_sibling;
3798 child->priv->parent = NULL;
3799 child->priv->prev_sibling = NULL;
3800 child->priv->next_sibling = NULL;
3804 REMOVE_CHILD_DESTROY_META = 1 << 0,
3805 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3806 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3807 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3808 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3809 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3811 /* default flags for public API */
3812 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3813 REMOVE_CHILD_EMIT_PARENT_SET |
3814 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3815 REMOVE_CHILD_CHECK_STATE |
3816 REMOVE_CHILD_FLUSH_QUEUE |
3817 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3819 /* flags for legacy/deprecated API */
3820 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3821 REMOVE_CHILD_FLUSH_QUEUE |
3822 REMOVE_CHILD_EMIT_PARENT_SET |
3823 REMOVE_CHILD_NOTIFY_FIRST_LAST
3824 } ClutterActorRemoveChildFlags;
3827 * clutter_actor_remove_child_internal:
3828 * @self: a #ClutterActor
3829 * @child: the child of @self that has to be removed
3830 * @flags: control the removal operations
3832 * Removes @child from the list of children of @self.
3835 clutter_actor_remove_child_internal (ClutterActor *self,
3836 ClutterActor *child,
3837 ClutterActorRemoveChildFlags flags)
3839 ClutterActor *old_first, *old_last;
3840 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3841 gboolean flush_queue;
3842 gboolean notify_first_last;
3843 gboolean was_mapped;
3845 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3846 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3847 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3848 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3849 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3850 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3852 g_object_freeze_notify (G_OBJECT (self));
3855 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3859 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3861 /* we need to unrealize *before* we set parent_actor to NULL,
3862 * because in an unrealize method actors are dissociating from the
3863 * stage, which means they need to be able to
3864 * clutter_actor_get_stage().
3866 * yhis should unmap and unrealize, unless we're reparenting.
3868 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3875 /* We take this opportunity to invalidate any queue redraw entry
3876 * associated with the actor and descendants since we won't be able to
3877 * determine the appropriate stage after this.
3879 * we do this after we updated the mapped state because actors might
3880 * end up queueing redraws inside their mapped/unmapped virtual
3881 * functions, and if we invalidate the redraw entry we could end up
3882 * with an inconsistent state and weird memory corruption. see
3885 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3886 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3888 _clutter_actor_traverse (child,
3890 invalidate_queue_redraw_entry,
3895 old_first = self->priv->first_child;
3896 old_last = self->priv->last_child;
3898 remove_child (self, child);
3900 self->priv->n_children -= 1;
3902 self->priv->age += 1;
3904 /* clutter_actor_reparent() will emit ::parent-set for us */
3905 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3906 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3908 /* if the child was mapped then we need to relayout ourselves to account
3909 * for the removed child
3912 clutter_actor_queue_relayout (self);
3914 /* we need to emit the signal before dropping the reference */
3915 if (emit_actor_removed)
3916 g_signal_emit_by_name (self, "actor-removed", child);
3918 if (notify_first_last)
3920 if (old_first != self->priv->first_child)
3921 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3923 if (old_last != self->priv->last_child)
3924 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3927 g_object_thaw_notify (G_OBJECT (self));
3929 /* remove the reference we acquired in clutter_actor_add_child() */
3930 g_object_unref (child);
3933 static const ClutterTransformInfo default_transform_info = {
3934 0.0, { 0, }, /* rotation-x */
3935 0.0, { 0, }, /* rotation-y */
3936 0.0, { 0, }, /* rotation-z */
3938 1.0, 1.0, { 0, }, /* scale */
3940 { 0, }, /* anchor */
3946 * _clutter_actor_get_transform_info_or_defaults:
3947 * @self: a #ClutterActor
3949 * Retrieves the ClutterTransformInfo structure associated to an actor.
3951 * If the actor does not have a ClutterTransformInfo structure associated
3952 * to it, then the default structure will be returned.
3954 * This function should only be used for getters.
3956 * Return value: a const pointer to the ClutterTransformInfo structure
3958 const ClutterTransformInfo *
3959 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3961 ClutterTransformInfo *info;
3963 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3967 return &default_transform_info;
3971 clutter_transform_info_free (gpointer data)
3974 g_slice_free (ClutterTransformInfo, data);
3978 * _clutter_actor_get_transform_info:
3979 * @self: a #ClutterActor
3981 * Retrieves a pointer to the ClutterTransformInfo structure.
3983 * If the actor does not have a ClutterTransformInfo associated to it, one
3984 * will be created and initialized to the default values.
3986 * This function should be used for setters.
3988 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3991 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3994 ClutterTransformInfo *
3995 _clutter_actor_get_transform_info (ClutterActor *self)
3997 ClutterTransformInfo *info;
3999 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4002 info = g_slice_new (ClutterTransformInfo);
4004 *info = default_transform_info;
4006 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4008 clutter_transform_info_free);
4015 * clutter_actor_set_rotation_angle_internal:
4016 * @self: a #ClutterActor
4017 * @axis: the axis of the angle to change
4018 * @angle: the angle of rotation
4020 * Sets the rotation angle on the given axis without affecting the
4021 * rotation center point.
4024 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4025 ClutterRotateAxis axis,
4028 GObject *obj = G_OBJECT (self);
4029 ClutterTransformInfo *info;
4031 info = _clutter_actor_get_transform_info (self);
4033 g_object_freeze_notify (obj);
4037 case CLUTTER_X_AXIS:
4038 info->rx_angle = angle;
4039 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4042 case CLUTTER_Y_AXIS:
4043 info->ry_angle = angle;
4044 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4047 case CLUTTER_Z_AXIS:
4048 info->rz_angle = angle;
4049 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4053 self->priv->transform_valid = FALSE;
4055 g_object_thaw_notify (obj);
4057 clutter_actor_queue_redraw (self);
4061 clutter_actor_set_rotation_angle (ClutterActor *self,
4062 ClutterRotateAxis axis,
4065 const ClutterTransformInfo *info;
4066 const double *cur_angle_p = NULL;
4067 GParamSpec *pspec = NULL;
4069 info = _clutter_actor_get_transform_info_or_defaults (self);
4073 case CLUTTER_X_AXIS:
4074 cur_angle_p = &info->rx_angle;
4075 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4078 case CLUTTER_Y_AXIS:
4079 cur_angle_p = &info->ry_angle;
4080 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4083 case CLUTTER_Z_AXIS:
4084 cur_angle_p = &info->rz_angle;
4085 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4089 g_assert (pspec != NULL);
4090 g_assert (cur_angle_p != NULL);
4092 if (_clutter_actor_get_transition (self, pspec) == NULL)
4093 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4095 _clutter_actor_update_transition (self, pspec, angle);
4097 clutter_actor_queue_redraw (self);
4101 * clutter_actor_set_rotation_center_internal:
4102 * @self: a #ClutterActor
4103 * @axis: the axis of the center to change
4104 * @center: the coordinates of the rotation center
4106 * Sets the rotation center on the given axis without affecting the
4110 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4111 ClutterRotateAxis axis,
4112 const ClutterVertex *center)
4114 GObject *obj = G_OBJECT (self);
4115 ClutterTransformInfo *info;
4116 ClutterVertex v = { 0, 0, 0 };
4118 info = _clutter_actor_get_transform_info (self);
4123 g_object_freeze_notify (obj);
4127 case CLUTTER_X_AXIS:
4128 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4129 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4132 case CLUTTER_Y_AXIS:
4133 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4134 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4137 case CLUTTER_Z_AXIS:
4138 /* if the previously set rotation center was fractional, then
4139 * setting explicit coordinates will have to notify the
4140 * :rotation-center-z-gravity property as well
4142 if (info->rz_center.is_fractional)
4143 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4145 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4146 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4150 self->priv->transform_valid = FALSE;
4152 g_object_thaw_notify (obj);
4154 clutter_actor_queue_redraw (self);
4158 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4162 GObject *obj = G_OBJECT (self);
4163 ClutterTransformInfo *info;
4165 info = _clutter_actor_get_transform_info (self);
4167 if (pspec == obj_props[PROP_SCALE_X])
4168 info->scale_x = factor;
4170 info->scale_y = factor;
4172 self->priv->transform_valid = FALSE;
4173 clutter_actor_queue_redraw (self);
4174 g_object_notify_by_pspec (obj, pspec);
4178 clutter_actor_set_scale_factor (ClutterActor *self,
4179 ClutterRotateAxis axis,
4182 const ClutterTransformInfo *info;
4183 const double *scale_p = NULL;
4184 GParamSpec *pspec = NULL;
4186 info = _clutter_actor_get_transform_info_or_defaults (self);
4190 case CLUTTER_X_AXIS:
4191 pspec = obj_props[PROP_SCALE_X];
4192 scale_p = &info->scale_x;
4195 case CLUTTER_Y_AXIS:
4196 pspec = obj_props[PROP_SCALE_Y];
4197 scale_p = &info->scale_y;
4200 case CLUTTER_Z_AXIS:
4204 g_assert (pspec != NULL);
4205 g_assert (scale_p != NULL);
4207 if (_clutter_actor_get_transition (self, pspec) == NULL)
4208 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4210 _clutter_actor_update_transition (self, pspec, factor);
4212 clutter_actor_queue_redraw (self);
4216 clutter_actor_set_scale_center (ClutterActor *self,
4217 ClutterRotateAxis axis,
4220 GObject *obj = G_OBJECT (self);
4221 ClutterTransformInfo *info;
4222 gfloat center_x, center_y;
4224 info = _clutter_actor_get_transform_info (self);
4226 g_object_freeze_notify (obj);
4228 /* get the current scale center coordinates */
4229 clutter_anchor_coord_get_units (self, &info->scale_center,
4234 /* we need to notify this too, because setting explicit coordinates will
4235 * change the gravity as a side effect
4237 if (info->scale_center.is_fractional)
4238 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4242 case CLUTTER_X_AXIS:
4243 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4244 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4247 case CLUTTER_Y_AXIS:
4248 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4249 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4253 g_assert_not_reached ();
4256 self->priv->transform_valid = FALSE;
4258 clutter_actor_queue_redraw (self);
4260 g_object_thaw_notify (obj);
4264 clutter_actor_set_scale_gravity (ClutterActor *self,
4265 ClutterGravity gravity)
4267 ClutterTransformInfo *info;
4270 info = _clutter_actor_get_transform_info (self);
4271 obj = G_OBJECT (self);
4273 if (gravity == CLUTTER_GRAVITY_NONE)
4274 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4276 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4278 self->priv->transform_valid = FALSE;
4280 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4281 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4282 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4284 clutter_actor_queue_redraw (self);
4288 clutter_actor_set_anchor_coord (ClutterActor *self,
4289 ClutterRotateAxis axis,
4292 GObject *obj = G_OBJECT (self);
4293 ClutterTransformInfo *info;
4294 gfloat anchor_x, anchor_y;
4296 info = _clutter_actor_get_transform_info (self);
4298 g_object_freeze_notify (obj);
4300 clutter_anchor_coord_get_units (self, &info->anchor,
4305 if (info->anchor.is_fractional)
4306 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4310 case CLUTTER_X_AXIS:
4311 clutter_anchor_coord_set_units (&info->anchor,
4315 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4318 case CLUTTER_Y_AXIS:
4319 clutter_anchor_coord_set_units (&info->anchor,
4323 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4327 g_assert_not_reached ();
4330 self->priv->transform_valid = FALSE;
4332 clutter_actor_queue_redraw (self);
4334 g_object_thaw_notify (obj);
4338 clutter_actor_set_property (GObject *object,
4340 const GValue *value,
4343 ClutterActor *actor = CLUTTER_ACTOR (object);
4344 ClutterActorPrivate *priv = actor->priv;
4349 clutter_actor_set_x (actor, g_value_get_float (value));
4353 clutter_actor_set_y (actor, g_value_get_float (value));
4358 const ClutterPoint *pos = g_value_get_boxed (value);
4361 clutter_actor_set_position (actor, pos->x, pos->y);
4363 clutter_actor_set_fixed_position_set (actor, FALSE);
4368 clutter_actor_set_width (actor, g_value_get_float (value));
4372 clutter_actor_set_height (actor, g_value_get_float (value));
4377 const ClutterSize *size = g_value_get_boxed (value);
4380 clutter_actor_set_size (actor, size->width, size->height);
4382 clutter_actor_set_size (actor, -1, -1);
4387 clutter_actor_set_x (actor, g_value_get_float (value));
4391 clutter_actor_set_y (actor, g_value_get_float (value));
4394 case PROP_FIXED_POSITION_SET:
4395 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4398 case PROP_MIN_WIDTH:
4399 clutter_actor_set_min_width (actor, g_value_get_float (value));
4402 case PROP_MIN_HEIGHT:
4403 clutter_actor_set_min_height (actor, g_value_get_float (value));
4406 case PROP_NATURAL_WIDTH:
4407 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4410 case PROP_NATURAL_HEIGHT:
4411 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4414 case PROP_MIN_WIDTH_SET:
4415 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4418 case PROP_MIN_HEIGHT_SET:
4419 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4422 case PROP_NATURAL_WIDTH_SET:
4423 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4426 case PROP_NATURAL_HEIGHT_SET:
4427 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4430 case PROP_REQUEST_MODE:
4431 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4435 clutter_actor_set_depth (actor, g_value_get_float (value));
4439 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4442 case PROP_OFFSCREEN_REDIRECT:
4443 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4447 clutter_actor_set_name (actor, g_value_get_string (value));
4451 if (g_value_get_boolean (value) == TRUE)
4452 clutter_actor_show (actor);
4454 clutter_actor_hide (actor);
4458 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4459 g_value_get_double (value));
4463 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4464 g_value_get_double (value));
4467 case PROP_SCALE_CENTER_X:
4468 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4469 g_value_get_float (value));
4472 case PROP_SCALE_CENTER_Y:
4473 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4474 g_value_get_float (value));
4477 case PROP_SCALE_GRAVITY:
4478 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4483 const ClutterGeometry *geom = g_value_get_boxed (value);
4485 clutter_actor_set_clip (actor,
4487 geom->width, geom->height);
4491 case PROP_CLIP_TO_ALLOCATION:
4492 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4496 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4499 case PROP_ROTATION_ANGLE_X:
4500 clutter_actor_set_rotation_angle (actor,
4502 g_value_get_double (value));
4505 case PROP_ROTATION_ANGLE_Y:
4506 clutter_actor_set_rotation_angle (actor,
4508 g_value_get_double (value));
4511 case PROP_ROTATION_ANGLE_Z:
4512 clutter_actor_set_rotation_angle (actor,
4514 g_value_get_double (value));
4517 case PROP_ROTATION_CENTER_X:
4518 clutter_actor_set_rotation_center_internal (actor,
4520 g_value_get_boxed (value));
4523 case PROP_ROTATION_CENTER_Y:
4524 clutter_actor_set_rotation_center_internal (actor,
4526 g_value_get_boxed (value));
4529 case PROP_ROTATION_CENTER_Z:
4530 clutter_actor_set_rotation_center_internal (actor,
4532 g_value_get_boxed (value));
4535 case PROP_ROTATION_CENTER_Z_GRAVITY:
4537 const ClutterTransformInfo *info;
4539 info = _clutter_actor_get_transform_info_or_defaults (actor);
4540 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4541 g_value_get_enum (value));
4546 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4547 g_value_get_float (value));
4551 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4552 g_value_get_float (value));
4555 case PROP_ANCHOR_GRAVITY:
4556 clutter_actor_set_anchor_point_from_gravity (actor,
4557 g_value_get_enum (value));
4560 case PROP_SHOW_ON_SET_PARENT:
4561 priv->show_on_set_parent = g_value_get_boolean (value);
4564 case PROP_TEXT_DIRECTION:
4565 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4569 clutter_actor_add_action (actor, g_value_get_object (value));
4572 case PROP_CONSTRAINTS:
4573 clutter_actor_add_constraint (actor, g_value_get_object (value));
4577 clutter_actor_add_effect (actor, g_value_get_object (value));
4580 case PROP_LAYOUT_MANAGER:
4581 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4585 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4589 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4592 case PROP_MARGIN_TOP:
4593 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4596 case PROP_MARGIN_BOTTOM:
4597 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4600 case PROP_MARGIN_LEFT:
4601 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4604 case PROP_MARGIN_RIGHT:
4605 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4608 case PROP_BACKGROUND_COLOR:
4609 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4613 clutter_actor_set_content (actor, g_value_get_object (value));
4616 case PROP_CONTENT_GRAVITY:
4617 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4620 case PROP_MINIFICATION_FILTER:
4621 clutter_actor_set_content_scaling_filters (actor,
4622 g_value_get_enum (value),
4623 actor->priv->mag_filter);
4626 case PROP_MAGNIFICATION_FILTER:
4627 clutter_actor_set_content_scaling_filters (actor,
4628 actor->priv->min_filter,
4629 g_value_get_enum (value));
4633 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4639 clutter_actor_get_property (GObject *object,
4644 ClutterActor *actor = CLUTTER_ACTOR (object);
4645 ClutterActorPrivate *priv = actor->priv;
4650 g_value_set_float (value, clutter_actor_get_x (actor));
4654 g_value_set_float (value, clutter_actor_get_y (actor));
4659 ClutterPoint position;
4661 clutter_point_init (&position,
4662 clutter_actor_get_x (actor),
4663 clutter_actor_get_y (actor));
4664 g_value_set_boxed (value, &position);
4669 g_value_set_float (value, clutter_actor_get_width (actor));
4673 g_value_set_float (value, clutter_actor_get_height (actor));
4680 clutter_size_init (&size,
4681 clutter_actor_get_width (actor),
4682 clutter_actor_get_height (actor));
4683 g_value_set_boxed (value, &size);
4689 const ClutterLayoutInfo *info;
4691 info = _clutter_actor_get_layout_info_or_defaults (actor);
4692 g_value_set_float (value, info->fixed_pos.x);
4698 const ClutterLayoutInfo *info;
4700 info = _clutter_actor_get_layout_info_or_defaults (actor);
4701 g_value_set_float (value, info->fixed_pos.y);
4705 case PROP_FIXED_POSITION_SET:
4706 g_value_set_boolean (value, priv->position_set);
4709 case PROP_MIN_WIDTH:
4711 const ClutterLayoutInfo *info;
4713 info = _clutter_actor_get_layout_info_or_defaults (actor);
4714 g_value_set_float (value, info->minimum.width);
4718 case PROP_MIN_HEIGHT:
4720 const ClutterLayoutInfo *info;
4722 info = _clutter_actor_get_layout_info_or_defaults (actor);
4723 g_value_set_float (value, info->minimum.height);
4727 case PROP_NATURAL_WIDTH:
4729 const ClutterLayoutInfo *info;
4731 info = _clutter_actor_get_layout_info_or_defaults (actor);
4732 g_value_set_float (value, info->natural.width);
4736 case PROP_NATURAL_HEIGHT:
4738 const ClutterLayoutInfo *info;
4740 info = _clutter_actor_get_layout_info_or_defaults (actor);
4741 g_value_set_float (value, info->natural.height);
4745 case PROP_MIN_WIDTH_SET:
4746 g_value_set_boolean (value, priv->min_width_set);
4749 case PROP_MIN_HEIGHT_SET:
4750 g_value_set_boolean (value, priv->min_height_set);
4753 case PROP_NATURAL_WIDTH_SET:
4754 g_value_set_boolean (value, priv->natural_width_set);
4757 case PROP_NATURAL_HEIGHT_SET:
4758 g_value_set_boolean (value, priv->natural_height_set);
4761 case PROP_REQUEST_MODE:
4762 g_value_set_enum (value, priv->request_mode);
4765 case PROP_ALLOCATION:
4766 g_value_set_boxed (value, &priv->allocation);
4770 g_value_set_float (value, clutter_actor_get_depth (actor));
4774 g_value_set_uint (value, priv->opacity);
4777 case PROP_OFFSCREEN_REDIRECT:
4778 g_value_set_enum (value, priv->offscreen_redirect);
4782 g_value_set_string (value, priv->name);
4786 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4790 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4794 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4798 g_value_set_boolean (value, priv->has_clip);
4803 ClutterGeometry clip;
4805 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4806 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4807 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4808 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4810 g_value_set_boxed (value, &clip);
4814 case PROP_CLIP_TO_ALLOCATION:
4815 g_value_set_boolean (value, priv->clip_to_allocation);
4820 const ClutterTransformInfo *info;
4822 info = _clutter_actor_get_transform_info_or_defaults (actor);
4823 g_value_set_double (value, info->scale_x);
4829 const ClutterTransformInfo *info;
4831 info = _clutter_actor_get_transform_info_or_defaults (actor);
4832 g_value_set_double (value, info->scale_y);
4836 case PROP_SCALE_CENTER_X:
4840 clutter_actor_get_scale_center (actor, ¢er, NULL);
4842 g_value_set_float (value, center);
4846 case PROP_SCALE_CENTER_Y:
4850 clutter_actor_get_scale_center (actor, NULL, ¢er);
4852 g_value_set_float (value, center);
4856 case PROP_SCALE_GRAVITY:
4857 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4861 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4864 case PROP_ROTATION_ANGLE_X:
4866 const ClutterTransformInfo *info;
4868 info = _clutter_actor_get_transform_info_or_defaults (actor);
4869 g_value_set_double (value, info->rx_angle);
4873 case PROP_ROTATION_ANGLE_Y:
4875 const ClutterTransformInfo *info;
4877 info = _clutter_actor_get_transform_info_or_defaults (actor);
4878 g_value_set_double (value, info->ry_angle);
4882 case PROP_ROTATION_ANGLE_Z:
4884 const ClutterTransformInfo *info;
4886 info = _clutter_actor_get_transform_info_or_defaults (actor);
4887 g_value_set_double (value, info->rz_angle);
4891 case PROP_ROTATION_CENTER_X:
4893 ClutterVertex center;
4895 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4900 g_value_set_boxed (value, ¢er);
4904 case PROP_ROTATION_CENTER_Y:
4906 ClutterVertex center;
4908 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4913 g_value_set_boxed (value, ¢er);
4917 case PROP_ROTATION_CENTER_Z:
4919 ClutterVertex center;
4921 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4926 g_value_set_boxed (value, ¢er);
4930 case PROP_ROTATION_CENTER_Z_GRAVITY:
4931 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4936 const ClutterTransformInfo *info;
4939 info = _clutter_actor_get_transform_info_or_defaults (actor);
4940 clutter_anchor_coord_get_units (actor, &info->anchor,
4944 g_value_set_float (value, anchor_x);
4950 const ClutterTransformInfo *info;
4953 info = _clutter_actor_get_transform_info_or_defaults (actor);
4954 clutter_anchor_coord_get_units (actor, &info->anchor,
4958 g_value_set_float (value, anchor_y);
4962 case PROP_ANCHOR_GRAVITY:
4963 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4966 case PROP_SHOW_ON_SET_PARENT:
4967 g_value_set_boolean (value, priv->show_on_set_parent);
4970 case PROP_TEXT_DIRECTION:
4971 g_value_set_enum (value, priv->text_direction);
4974 case PROP_HAS_POINTER:
4975 g_value_set_boolean (value, priv->has_pointer);
4978 case PROP_LAYOUT_MANAGER:
4979 g_value_set_object (value, priv->layout_manager);
4984 const ClutterLayoutInfo *info;
4986 info = _clutter_actor_get_layout_info_or_defaults (actor);
4987 g_value_set_enum (value, info->x_align);
4993 const ClutterLayoutInfo *info;
4995 info = _clutter_actor_get_layout_info_or_defaults (actor);
4996 g_value_set_enum (value, info->y_align);
5000 case PROP_MARGIN_TOP:
5002 const ClutterLayoutInfo *info;
5004 info = _clutter_actor_get_layout_info_or_defaults (actor);
5005 g_value_set_float (value, info->margin.top);
5009 case PROP_MARGIN_BOTTOM:
5011 const ClutterLayoutInfo *info;
5013 info = _clutter_actor_get_layout_info_or_defaults (actor);
5014 g_value_set_float (value, info->margin.bottom);
5018 case PROP_MARGIN_LEFT:
5020 const ClutterLayoutInfo *info;
5022 info = _clutter_actor_get_layout_info_or_defaults (actor);
5023 g_value_set_float (value, info->margin.left);
5027 case PROP_MARGIN_RIGHT:
5029 const ClutterLayoutInfo *info;
5031 info = _clutter_actor_get_layout_info_or_defaults (actor);
5032 g_value_set_float (value, info->margin.right);
5036 case PROP_BACKGROUND_COLOR_SET:
5037 g_value_set_boolean (value, priv->bg_color_set);
5040 case PROP_BACKGROUND_COLOR:
5041 g_value_set_boxed (value, &priv->bg_color);
5044 case PROP_FIRST_CHILD:
5045 g_value_set_object (value, priv->first_child);
5048 case PROP_LAST_CHILD:
5049 g_value_set_object (value, priv->last_child);
5053 g_value_set_object (value, priv->content);
5056 case PROP_CONTENT_GRAVITY:
5057 g_value_set_enum (value, priv->content_gravity);
5060 case PROP_CONTENT_BOX:
5062 ClutterActorBox box = { 0, };
5064 clutter_actor_get_content_box (actor, &box);
5065 g_value_set_boxed (value, &box);
5069 case PROP_MINIFICATION_FILTER:
5070 g_value_set_enum (value, priv->min_filter);
5073 case PROP_MAGNIFICATION_FILTER:
5074 g_value_set_enum (value, priv->mag_filter);
5078 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5084 clutter_actor_dispose (GObject *object)
5086 ClutterActor *self = CLUTTER_ACTOR (object);
5087 ClutterActorPrivate *priv = self->priv;
5089 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5091 g_type_name (G_OBJECT_TYPE (self)),
5094 g_signal_emit (self, actor_signals[DESTROY], 0);
5096 /* avoid recursing when called from clutter_actor_destroy() */
5097 if (priv->parent != NULL)
5099 ClutterActor *parent = priv->parent;
5101 /* go through the Container implementation unless this
5102 * is an internal child and has been marked as such.
5104 * removing the actor from its parent will reset the
5105 * realized and mapped states.
5107 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5108 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5110 clutter_actor_remove_child_internal (parent, self,
5111 REMOVE_CHILD_LEGACY_FLAGS);
5114 /* parent must be gone at this point */
5115 g_assert (priv->parent == NULL);
5117 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5119 /* can't be mapped or realized with no parent */
5120 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5121 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5124 g_clear_object (&priv->pango_context);
5125 g_clear_object (&priv->actions);
5126 g_clear_object (&priv->constraints);
5127 g_clear_object (&priv->effects);
5128 g_clear_object (&priv->flatten_effect);
5130 if (priv->layout_manager != NULL)
5132 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5133 g_clear_object (&priv->layout_manager);
5136 if (priv->content != NULL)
5138 _clutter_content_detached (priv->content, self);
5139 g_clear_object (&priv->content);
5142 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5146 clutter_actor_finalize (GObject *object)
5148 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5150 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5151 priv->name != NULL ? priv->name : "<none>",
5153 g_type_name (G_OBJECT_TYPE (object)));
5155 _clutter_context_release_id (priv->id);
5157 g_free (priv->name);
5159 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5164 * clutter_actor_get_accessible:
5165 * @self: a #ClutterActor
5167 * Returns the accessible object that describes the actor to an
5168 * assistive technology.
5170 * If no class-specific #AtkObject implementation is available for the
5171 * actor instance in question, it will inherit an #AtkObject
5172 * implementation from the first ancestor class for which such an
5173 * implementation is defined.
5175 * The documentation of the <ulink
5176 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5177 * library contains more information about accessible objects and
5180 * Returns: (transfer none): the #AtkObject associated with @actor
5183 clutter_actor_get_accessible (ClutterActor *self)
5185 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5187 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5191 clutter_actor_real_get_accessible (ClutterActor *actor)
5193 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5197 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5199 AtkObject *accessible;
5201 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5202 if (accessible != NULL)
5203 g_object_ref (accessible);
5209 atk_implementor_iface_init (AtkImplementorIface *iface)
5211 iface->ref_accessible = _clutter_actor_ref_accessible;
5215 clutter_actor_update_default_paint_volume (ClutterActor *self,
5216 ClutterPaintVolume *volume)
5218 ClutterActorPrivate *priv = self->priv;
5219 gboolean res = TRUE;
5221 /* we start from the allocation */
5222 clutter_paint_volume_set_width (volume,
5223 priv->allocation.x2 - priv->allocation.x1);
5224 clutter_paint_volume_set_height (volume,
5225 priv->allocation.y2 - priv->allocation.y1);
5227 /* if the actor has a clip set then we have a pretty definite
5228 * size for the paint volume: the actor cannot possibly paint
5229 * outside the clip region.
5231 if (priv->clip_to_allocation)
5233 /* the allocation has already been set, so we just flip the
5240 ClutterActor *child;
5242 if (priv->has_clip &&
5243 priv->clip.width >= 0 &&
5244 priv->clip.height >= 0)
5246 ClutterVertex origin;
5248 origin.x = priv->clip.x;
5249 origin.y = priv->clip.y;
5252 clutter_paint_volume_set_origin (volume, &origin);
5253 clutter_paint_volume_set_width (volume, priv->clip.width);
5254 clutter_paint_volume_set_height (volume, priv->clip.height);
5259 /* if we don't have children we just bail out here... */
5260 if (priv->n_children == 0)
5263 /* ...but if we have children then we ask for their paint volume in
5264 * our coordinates. if any of our children replies that it doesn't
5265 * have a paint volume, we bail out
5267 for (child = priv->first_child;
5269 child = child->priv->next_sibling)
5271 const ClutterPaintVolume *child_volume;
5273 if (!CLUTTER_ACTOR_IS_MAPPED (child))
5276 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5277 if (child_volume == NULL)
5283 clutter_paint_volume_union (volume, child_volume);
5293 clutter_actor_real_get_paint_volume (ClutterActor *self,
5294 ClutterPaintVolume *volume)
5296 ClutterActorClass *klass;
5299 klass = CLUTTER_ACTOR_GET_CLASS (self);
5301 /* XXX - this thoroughly sucks, but we don't want to penalize users
5302 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5303 * redraw. This should go away in 2.0.
5305 if (klass->paint == clutter_actor_real_paint &&
5306 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5312 /* this is the default return value: we cannot know if a class
5313 * is going to paint outside its allocation, so we take the
5314 * conservative approach.
5319 /* update_default_paint_volume() should only fail if one of the children
5320 * reported an invalid, or no, paint volume
5322 if (!clutter_actor_update_default_paint_volume (self, volume))
5329 * clutter_actor_get_default_paint_volume:
5330 * @self: a #ClutterActor
5332 * Retrieves the default paint volume for @self.
5334 * This function provides the same #ClutterPaintVolume that would be
5335 * computed by the default implementation inside #ClutterActor of the
5336 * #ClutterActorClass.get_paint_volume() virtual function.
5338 * This function should only be used by #ClutterActor subclasses that
5339 * cannot chain up to the parent implementation when computing their
5342 * Return value: (transfer none): a pointer to the default
5343 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5344 * the actor could not compute a valid paint volume. The returned value
5345 * is not guaranteed to be stable across multiple frames, so if you
5346 * want to retain it, you will need to copy it using
5347 * clutter_paint_volume_copy().
5351 const ClutterPaintVolume *
5352 clutter_actor_get_default_paint_volume (ClutterActor *self)
5354 ClutterPaintVolume volume;
5355 ClutterPaintVolume *res;
5357 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5360 _clutter_paint_volume_init_static (&volume, self);
5361 if (clutter_actor_update_default_paint_volume (self, &volume))
5363 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5367 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5368 _clutter_paint_volume_copy_static (&volume, res);
5372 clutter_paint_volume_free (&volume);
5378 clutter_actor_real_has_overlaps (ClutterActor *self)
5380 /* By default we'll assume that all actors need an offscreen redirect to get
5381 * the correct opacity. Actors such as ClutterTexture that would never need
5382 * an offscreen redirect can override this to return FALSE. */
5387 clutter_actor_real_destroy (ClutterActor *actor)
5389 ClutterActorIter iter;
5391 g_object_freeze_notify (G_OBJECT (actor));
5393 clutter_actor_iter_init (&iter, actor);
5394 while (clutter_actor_iter_next (&iter, NULL))
5395 clutter_actor_iter_destroy (&iter);
5397 g_object_thaw_notify (G_OBJECT (actor));
5401 clutter_actor_constructor (GType gtype,
5403 GObjectConstructParam *props)
5405 GObjectClass *gobject_class;
5409 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5410 retval = gobject_class->constructor (gtype, n_props, props);
5411 self = CLUTTER_ACTOR (retval);
5413 if (self->priv->layout_manager == NULL)
5415 ClutterLayoutManager *default_layout;
5417 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5419 default_layout = clutter_fixed_layout_new ();
5420 clutter_actor_set_layout_manager (self, default_layout);
5427 clutter_actor_class_init (ClutterActorClass *klass)
5429 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5431 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5432 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5433 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5434 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5436 object_class->constructor = clutter_actor_constructor;
5437 object_class->set_property = clutter_actor_set_property;
5438 object_class->get_property = clutter_actor_get_property;
5439 object_class->dispose = clutter_actor_dispose;
5440 object_class->finalize = clutter_actor_finalize;
5442 klass->show = clutter_actor_real_show;
5443 klass->show_all = clutter_actor_show;
5444 klass->hide = clutter_actor_real_hide;
5445 klass->hide_all = clutter_actor_hide;
5446 klass->map = clutter_actor_real_map;
5447 klass->unmap = clutter_actor_real_unmap;
5448 klass->unrealize = clutter_actor_real_unrealize;
5449 klass->pick = clutter_actor_real_pick;
5450 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5451 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5452 klass->allocate = clutter_actor_real_allocate;
5453 klass->queue_redraw = clutter_actor_real_queue_redraw;
5454 klass->queue_relayout = clutter_actor_real_queue_relayout;
5455 klass->apply_transform = clutter_actor_real_apply_transform;
5456 klass->get_accessible = clutter_actor_real_get_accessible;
5457 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5458 klass->has_overlaps = clutter_actor_real_has_overlaps;
5459 klass->paint = clutter_actor_real_paint;
5460 klass->destroy = clutter_actor_real_destroy;
5462 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5467 * X coordinate of the actor in pixels. If written, forces a fixed
5468 * position for the actor. If read, returns the fixed position if any,
5469 * otherwise the allocation if available, otherwise 0.
5471 * The #ClutterActor:x property is animatable.
5474 g_param_spec_float ("x",
5476 P_("X coordinate of the actor"),
5477 -G_MAXFLOAT, G_MAXFLOAT,
5480 G_PARAM_STATIC_STRINGS |
5481 CLUTTER_PARAM_ANIMATABLE);
5486 * Y coordinate of the actor in pixels. If written, forces a fixed
5487 * position for the actor. If read, returns the fixed position if
5488 * any, otherwise the allocation if available, otherwise 0.
5490 * The #ClutterActor:y property is animatable.
5493 g_param_spec_float ("y",
5495 P_("Y coordinate of the actor"),
5496 -G_MAXFLOAT, G_MAXFLOAT,
5499 G_PARAM_STATIC_STRINGS |
5500 CLUTTER_PARAM_ANIMATABLE);
5503 * ClutterActor:position:
5505 * The position of the origin of the actor.
5507 * This property is a shorthand for setting and getting the
5508 * #ClutterActor:x and #ClutterActor:y properties at the same
5511 * The #ClutterActor:position property is animatable.
5515 obj_props[PROP_POSITION] =
5516 g_param_spec_boxed ("position",
5518 P_("The position of the origin of the actor"),
5521 G_PARAM_STATIC_STRINGS |
5522 CLUTTER_PARAM_ANIMATABLE);
5525 * ClutterActor:width:
5527 * Width of the actor (in pixels). If written, forces the minimum and
5528 * natural size request of the actor to the given width. If read, returns
5529 * the allocated width if available, otherwise the width request.
5531 * The #ClutterActor:width property is animatable.
5533 obj_props[PROP_WIDTH] =
5534 g_param_spec_float ("width",
5536 P_("Width of the actor"),
5540 G_PARAM_STATIC_STRINGS |
5541 CLUTTER_PARAM_ANIMATABLE);
5544 * ClutterActor:height:
5546 * Height of the actor (in pixels). If written, forces the minimum and
5547 * natural size request of the actor to the given height. If read, returns
5548 * the allocated height if available, otherwise the height request.
5550 * The #ClutterActor:height property is animatable.
5552 obj_props[PROP_HEIGHT] =
5553 g_param_spec_float ("height",
5555 P_("Height of the actor"),
5559 G_PARAM_STATIC_STRINGS |
5560 CLUTTER_PARAM_ANIMATABLE);
5563 * ClutterActor:size:
5565 * The size of the actor.
5567 * This property is a shorthand for setting and getting the
5568 * #ClutterActor:width and #ClutterActor:height at the same time.
5570 * The #ClutterActor:size property is animatable.
5574 obj_props[PROP_SIZE] =
5575 g_param_spec_boxed ("size",
5577 P_("The size of the actor"),
5580 G_PARAM_STATIC_STRINGS |
5581 CLUTTER_PARAM_ANIMATABLE);
5584 * ClutterActor:fixed-x:
5586 * The fixed X position of the actor in pixels.
5588 * Writing this property sets #ClutterActor:fixed-position-set
5589 * property as well, as a side effect
5593 obj_props[PROP_FIXED_X] =
5594 g_param_spec_float ("fixed-x",
5596 P_("Forced X position of the actor"),
5597 -G_MAXFLOAT, G_MAXFLOAT,
5599 CLUTTER_PARAM_READWRITE);
5602 * ClutterActor:fixed-y:
5604 * The fixed Y position of the actor in pixels.
5606 * Writing this property sets the #ClutterActor:fixed-position-set
5607 * property as well, as a side effect
5611 obj_props[PROP_FIXED_Y] =
5612 g_param_spec_float ("fixed-y",
5614 P_("Forced Y position of the actor"),
5615 -G_MAXFLOAT, G_MAXFLOAT,
5617 CLUTTER_PARAM_READWRITE);
5620 * ClutterActor:fixed-position-set:
5622 * This flag controls whether the #ClutterActor:fixed-x and
5623 * #ClutterActor:fixed-y properties are used
5627 obj_props[PROP_FIXED_POSITION_SET] =
5628 g_param_spec_boolean ("fixed-position-set",
5629 P_("Fixed position set"),
5630 P_("Whether to use fixed positioning for the actor"),
5632 CLUTTER_PARAM_READWRITE);
5635 * ClutterActor:min-width:
5637 * A forced minimum width request for the actor, in pixels
5639 * Writing this property sets the #ClutterActor:min-width-set property
5640 * as well, as a side effect.
5642 *This property overrides the usual width request of the actor.
5646 obj_props[PROP_MIN_WIDTH] =
5647 g_param_spec_float ("min-width",
5649 P_("Forced minimum width request for the actor"),
5652 CLUTTER_PARAM_READWRITE);
5655 * ClutterActor:min-height:
5657 * A forced minimum height request for the actor, in pixels
5659 * Writing this property sets the #ClutterActor:min-height-set property
5660 * as well, as a side effect. This property overrides the usual height
5661 * request of the actor.
5665 obj_props[PROP_MIN_HEIGHT] =
5666 g_param_spec_float ("min-height",
5668 P_("Forced minimum height request for the actor"),
5671 CLUTTER_PARAM_READWRITE);
5674 * ClutterActor:natural-width:
5676 * A forced natural width request for the actor, in pixels
5678 * Writing this property sets the #ClutterActor:natural-width-set
5679 * property as well, as a side effect. This property overrides the
5680 * usual width request of the actor
5684 obj_props[PROP_NATURAL_WIDTH] =
5685 g_param_spec_float ("natural-width",
5686 P_("Natural Width"),
5687 P_("Forced natural width request for the actor"),
5690 CLUTTER_PARAM_READWRITE);
5693 * ClutterActor:natural-height:
5695 * A forced natural height request for the actor, in pixels
5697 * Writing this property sets the #ClutterActor:natural-height-set
5698 * property as well, as a side effect. This property overrides the
5699 * usual height request of the actor
5703 obj_props[PROP_NATURAL_HEIGHT] =
5704 g_param_spec_float ("natural-height",
5705 P_("Natural Height"),
5706 P_("Forced natural height request for the actor"),
5709 CLUTTER_PARAM_READWRITE);
5712 * ClutterActor:min-width-set:
5714 * This flag controls whether the #ClutterActor:min-width property
5719 obj_props[PROP_MIN_WIDTH_SET] =
5720 g_param_spec_boolean ("min-width-set",
5721 P_("Minimum width set"),
5722 P_("Whether to use the min-width property"),
5724 CLUTTER_PARAM_READWRITE);
5727 * ClutterActor:min-height-set:
5729 * This flag controls whether the #ClutterActor:min-height property
5734 obj_props[PROP_MIN_HEIGHT_SET] =
5735 g_param_spec_boolean ("min-height-set",
5736 P_("Minimum height set"),
5737 P_("Whether to use the min-height property"),
5739 CLUTTER_PARAM_READWRITE);
5742 * ClutterActor:natural-width-set:
5744 * This flag controls whether the #ClutterActor:natural-width property
5749 obj_props[PROP_NATURAL_WIDTH_SET] =
5750 g_param_spec_boolean ("natural-width-set",
5751 P_("Natural width set"),
5752 P_("Whether to use the natural-width property"),
5754 CLUTTER_PARAM_READWRITE);
5757 * ClutterActor:natural-height-set:
5759 * This flag controls whether the #ClutterActor:natural-height property
5764 obj_props[PROP_NATURAL_HEIGHT_SET] =
5765 g_param_spec_boolean ("natural-height-set",
5766 P_("Natural height set"),
5767 P_("Whether to use the natural-height property"),
5769 CLUTTER_PARAM_READWRITE);
5772 * ClutterActor:allocation:
5774 * The allocation for the actor, in pixels
5776 * This is property is read-only, but you might monitor it to know when an
5777 * actor moves or resizes
5781 obj_props[PROP_ALLOCATION] =
5782 g_param_spec_boxed ("allocation",
5784 P_("The actor's allocation"),
5785 CLUTTER_TYPE_ACTOR_BOX,
5786 CLUTTER_PARAM_READABLE);
5789 * ClutterActor:request-mode:
5791 * Request mode for the #ClutterActor. The request mode determines the
5792 * type of geometry management used by the actor, either height for width
5793 * (the default) or width for height.
5795 * For actors implementing height for width, the parent container should get
5796 * the preferred width first, and then the preferred height for that width.
5798 * For actors implementing width for height, the parent container should get
5799 * the preferred height first, and then the preferred width for that height.
5804 * ClutterRequestMode mode;
5805 * gfloat natural_width, min_width;
5806 * gfloat natural_height, min_height;
5808 * mode = clutter_actor_get_request_mode (child);
5809 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5811 * clutter_actor_get_preferred_width (child, -1,
5813 * &natural_width);
5814 * clutter_actor_get_preferred_height (child, natural_width,
5816 * &natural_height);
5820 * clutter_actor_get_preferred_height (child, -1,
5822 * &natural_height);
5823 * clutter_actor_get_preferred_width (child, natural_height,
5825 * &natural_width);
5829 * will retrieve the minimum and natural width and height depending on the
5830 * preferred request mode of the #ClutterActor "child".
5832 * The clutter_actor_get_preferred_size() function will implement this
5837 obj_props[PROP_REQUEST_MODE] =
5838 g_param_spec_enum ("request-mode",
5840 P_("The actor's request mode"),
5841 CLUTTER_TYPE_REQUEST_MODE,
5842 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5843 CLUTTER_PARAM_READWRITE);
5846 * ClutterActor:depth:
5848 * The position of the actor on the Z axis.
5850 * The #ClutterActor:depth property is relative to the parent's
5853 * The #ClutterActor:depth property is animatable.
5857 obj_props[PROP_DEPTH] =
5858 g_param_spec_float ("depth",
5860 P_("Position on the Z axis"),
5861 -G_MAXFLOAT, G_MAXFLOAT,
5864 G_PARAM_STATIC_STRINGS |
5865 CLUTTER_PARAM_ANIMATABLE);
5868 * ClutterActor:opacity:
5870 * Opacity of an actor, between 0 (fully transparent) and
5871 * 255 (fully opaque)
5873 * The #ClutterActor:opacity property is animatable.
5875 obj_props[PROP_OPACITY] =
5876 g_param_spec_uint ("opacity",
5878 P_("Opacity of an actor"),
5882 G_PARAM_STATIC_STRINGS |
5883 CLUTTER_PARAM_ANIMATABLE);
5886 * ClutterActor:offscreen-redirect:
5888 * Determines the conditions in which the actor will be redirected
5889 * to an offscreen framebuffer while being painted. For example this
5890 * can be used to cache an actor in a framebuffer or for improved
5891 * handling of transparent actors. See
5892 * clutter_actor_set_offscreen_redirect() for details.
5896 obj_props[PROP_OFFSCREEN_REDIRECT] =
5897 g_param_spec_flags ("offscreen-redirect",
5898 P_("Offscreen redirect"),
5899 P_("Flags controlling when to flatten the actor into a single image"),
5900 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5902 CLUTTER_PARAM_READWRITE);
5905 * ClutterActor:visible:
5907 * Whether the actor is set to be visible or not
5909 * See also #ClutterActor:mapped
5911 obj_props[PROP_VISIBLE] =
5912 g_param_spec_boolean ("visible",
5914 P_("Whether the actor is visible or not"),
5916 CLUTTER_PARAM_READWRITE);
5919 * ClutterActor:mapped:
5921 * Whether the actor is mapped (will be painted when the stage
5922 * to which it belongs is mapped)
5926 obj_props[PROP_MAPPED] =
5927 g_param_spec_boolean ("mapped",
5929 P_("Whether the actor will be painted"),
5931 CLUTTER_PARAM_READABLE);
5934 * ClutterActor:realized:
5936 * Whether the actor has been realized
5940 obj_props[PROP_REALIZED] =
5941 g_param_spec_boolean ("realized",
5943 P_("Whether the actor has been realized"),
5945 CLUTTER_PARAM_READABLE);
5948 * ClutterActor:reactive:
5950 * Whether the actor is reactive to events or not
5952 * Only reactive actors will emit event-related signals
5956 obj_props[PROP_REACTIVE] =
5957 g_param_spec_boolean ("reactive",
5959 P_("Whether the actor is reactive to events"),
5961 CLUTTER_PARAM_READWRITE);
5964 * ClutterActor:has-clip:
5966 * Whether the actor has the #ClutterActor:clip property set or not
5968 obj_props[PROP_HAS_CLIP] =
5969 g_param_spec_boolean ("has-clip",
5971 P_("Whether the actor has a clip set"),
5973 CLUTTER_PARAM_READABLE);
5976 * ClutterActor:clip:
5978 * The clip region for the actor, in actor-relative coordinates
5980 * Every part of the actor outside the clip region will not be
5983 obj_props[PROP_CLIP] =
5984 g_param_spec_boxed ("clip",
5986 P_("The clip region for the actor"),
5987 CLUTTER_TYPE_GEOMETRY,
5988 CLUTTER_PARAM_READWRITE);
5991 * ClutterActor:name:
5993 * The name of the actor
5997 obj_props[PROP_NAME] =
5998 g_param_spec_string ("name",
6000 P_("Name of the actor"),
6002 CLUTTER_PARAM_READWRITE);
6005 * ClutterActor:scale-x:
6007 * The horizontal scale of the actor.
6009 * The #ClutterActor:scale-x property is animatable.
6013 obj_props[PROP_SCALE_X] =
6014 g_param_spec_double ("scale-x",
6016 P_("Scale factor on the X axis"),
6020 G_PARAM_STATIC_STRINGS |
6021 CLUTTER_PARAM_ANIMATABLE);
6024 * ClutterActor:scale-y:
6026 * The vertical scale of the actor.
6028 * The #ClutterActor:scale-y property is animatable.
6032 obj_props[PROP_SCALE_Y] =
6033 g_param_spec_double ("scale-y",
6035 P_("Scale factor on the Y axis"),
6039 G_PARAM_STATIC_STRINGS |
6040 CLUTTER_PARAM_ANIMATABLE);
6043 * ClutterActor:scale-center-x:
6045 * The horizontal center point for scaling
6049 obj_props[PROP_SCALE_CENTER_X] =
6050 g_param_spec_float ("scale-center-x",
6051 P_("Scale Center X"),
6052 P_("Horizontal scale center"),
6053 -G_MAXFLOAT, G_MAXFLOAT,
6055 CLUTTER_PARAM_READWRITE);
6058 * ClutterActor:scale-center-y:
6060 * The vertical center point for scaling
6064 obj_props[PROP_SCALE_CENTER_Y] =
6065 g_param_spec_float ("scale-center-y",
6066 P_("Scale Center Y"),
6067 P_("Vertical scale center"),
6068 -G_MAXFLOAT, G_MAXFLOAT,
6070 CLUTTER_PARAM_READWRITE);
6073 * ClutterActor:scale-gravity:
6075 * The center point for scaling expressed as a #ClutterGravity
6079 obj_props[PROP_SCALE_GRAVITY] =
6080 g_param_spec_enum ("scale-gravity",
6081 P_("Scale Gravity"),
6082 P_("The center of scaling"),
6083 CLUTTER_TYPE_GRAVITY,
6084 CLUTTER_GRAVITY_NONE,
6085 CLUTTER_PARAM_READWRITE);
6088 * ClutterActor:rotation-angle-x:
6090 * The rotation angle on the X axis.
6092 * The #ClutterActor:rotation-angle-x property is animatable.
6096 obj_props[PROP_ROTATION_ANGLE_X] =
6097 g_param_spec_double ("rotation-angle-x",
6098 P_("Rotation Angle X"),
6099 P_("The rotation angle on the X axis"),
6100 -G_MAXDOUBLE, G_MAXDOUBLE,
6103 G_PARAM_STATIC_STRINGS |
6104 CLUTTER_PARAM_ANIMATABLE);
6107 * ClutterActor:rotation-angle-y:
6109 * The rotation angle on the Y axis
6111 * The #ClutterActor:rotation-angle-y property is animatable.
6115 obj_props[PROP_ROTATION_ANGLE_Y] =
6116 g_param_spec_double ("rotation-angle-y",
6117 P_("Rotation Angle Y"),
6118 P_("The rotation angle on the Y axis"),
6119 -G_MAXDOUBLE, G_MAXDOUBLE,
6122 G_PARAM_STATIC_STRINGS |
6123 CLUTTER_PARAM_ANIMATABLE);
6126 * ClutterActor:rotation-angle-z:
6128 * The rotation angle on the Z axis
6130 * The #ClutterActor:rotation-angle-z property is animatable.
6134 obj_props[PROP_ROTATION_ANGLE_Z] =
6135 g_param_spec_double ("rotation-angle-z",
6136 P_("Rotation Angle Z"),
6137 P_("The rotation angle on the Z axis"),
6138 -G_MAXDOUBLE, G_MAXDOUBLE,
6141 G_PARAM_STATIC_STRINGS |
6142 CLUTTER_PARAM_ANIMATABLE);
6145 * ClutterActor:rotation-center-x:
6147 * The rotation center on the X axis.
6151 obj_props[PROP_ROTATION_CENTER_X] =
6152 g_param_spec_boxed ("rotation-center-x",
6153 P_("Rotation Center X"),
6154 P_("The rotation center on the X axis"),
6155 CLUTTER_TYPE_VERTEX,
6156 CLUTTER_PARAM_READWRITE);
6159 * ClutterActor:rotation-center-y:
6161 * The rotation center on the Y axis.
6165 obj_props[PROP_ROTATION_CENTER_Y] =
6166 g_param_spec_boxed ("rotation-center-y",
6167 P_("Rotation Center Y"),
6168 P_("The rotation center on the Y axis"),
6169 CLUTTER_TYPE_VERTEX,
6170 CLUTTER_PARAM_READWRITE);
6173 * ClutterActor:rotation-center-z:
6175 * The rotation center on the Z axis.
6179 obj_props[PROP_ROTATION_CENTER_Z] =
6180 g_param_spec_boxed ("rotation-center-z",
6181 P_("Rotation Center Z"),
6182 P_("The rotation center on the Z axis"),
6183 CLUTTER_TYPE_VERTEX,
6184 CLUTTER_PARAM_READWRITE);
6187 * ClutterActor:rotation-center-z-gravity:
6189 * The rotation center on the Z axis expressed as a #ClutterGravity.
6193 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6194 g_param_spec_enum ("rotation-center-z-gravity",
6195 P_("Rotation Center Z Gravity"),
6196 P_("Center point for rotation around the Z axis"),
6197 CLUTTER_TYPE_GRAVITY,
6198 CLUTTER_GRAVITY_NONE,
6199 CLUTTER_PARAM_READWRITE);
6202 * ClutterActor:anchor-x:
6204 * The X coordinate of an actor's anchor point, relative to
6205 * the actor coordinate space, in pixels
6209 obj_props[PROP_ANCHOR_X] =
6210 g_param_spec_float ("anchor-x",
6212 P_("X coordinate of the anchor point"),
6213 -G_MAXFLOAT, G_MAXFLOAT,
6215 CLUTTER_PARAM_READWRITE);
6218 * ClutterActor:anchor-y:
6220 * The Y coordinate of an actor's anchor point, relative to
6221 * the actor coordinate space, in pixels
6225 obj_props[PROP_ANCHOR_Y] =
6226 g_param_spec_float ("anchor-y",
6228 P_("Y coordinate of the anchor point"),
6229 -G_MAXFLOAT, G_MAXFLOAT,
6231 CLUTTER_PARAM_READWRITE);
6234 * ClutterActor:anchor-gravity:
6236 * The anchor point expressed as a #ClutterGravity
6240 obj_props[PROP_ANCHOR_GRAVITY] =
6241 g_param_spec_enum ("anchor-gravity",
6242 P_("Anchor Gravity"),
6243 P_("The anchor point as a ClutterGravity"),
6244 CLUTTER_TYPE_GRAVITY,
6245 CLUTTER_GRAVITY_NONE,
6246 CLUTTER_PARAM_READWRITE);
6249 * ClutterActor:show-on-set-parent:
6251 * If %TRUE, the actor is automatically shown when parented.
6253 * Calling clutter_actor_hide() on an actor which has not been
6254 * parented will set this property to %FALSE as a side effect.
6258 obj_props[PROP_SHOW_ON_SET_PARENT] =
6259 g_param_spec_boolean ("show-on-set-parent",
6260 P_("Show on set parent"),
6261 P_("Whether the actor is shown when parented"),
6263 CLUTTER_PARAM_READWRITE);
6266 * ClutterActor:clip-to-allocation:
6268 * Whether the clip region should track the allocated area
6271 * This property is ignored if a clip area has been explicitly
6272 * set using clutter_actor_set_clip().
6276 obj_props[PROP_CLIP_TO_ALLOCATION] =
6277 g_param_spec_boolean ("clip-to-allocation",
6278 P_("Clip to Allocation"),
6279 P_("Sets the clip region to track the actor's allocation"),
6281 CLUTTER_PARAM_READWRITE);
6284 * ClutterActor:text-direction:
6286 * The direction of the text inside a #ClutterActor.
6290 obj_props[PROP_TEXT_DIRECTION] =
6291 g_param_spec_enum ("text-direction",
6292 P_("Text Direction"),
6293 P_("Direction of the text"),
6294 CLUTTER_TYPE_TEXT_DIRECTION,
6295 CLUTTER_TEXT_DIRECTION_LTR,
6296 CLUTTER_PARAM_READWRITE);
6299 * ClutterActor:has-pointer:
6301 * Whether the actor contains the pointer of a #ClutterInputDevice
6306 obj_props[PROP_HAS_POINTER] =
6307 g_param_spec_boolean ("has-pointer",
6309 P_("Whether the actor contains the pointer of an input device"),
6311 CLUTTER_PARAM_READABLE);
6314 * ClutterActor:actions:
6316 * Adds a #ClutterAction to the actor
6320 obj_props[PROP_ACTIONS] =
6321 g_param_spec_object ("actions",
6323 P_("Adds an action to the actor"),
6324 CLUTTER_TYPE_ACTION,
6325 CLUTTER_PARAM_WRITABLE);
6328 * ClutterActor:constraints:
6330 * Adds a #ClutterConstraint to the actor
6334 obj_props[PROP_CONSTRAINTS] =
6335 g_param_spec_object ("constraints",
6337 P_("Adds a constraint to the actor"),
6338 CLUTTER_TYPE_CONSTRAINT,
6339 CLUTTER_PARAM_WRITABLE);
6342 * ClutterActor:effect:
6344 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6348 obj_props[PROP_EFFECT] =
6349 g_param_spec_object ("effect",
6351 P_("Add an effect to be applied on the actor"),
6352 CLUTTER_TYPE_EFFECT,
6353 CLUTTER_PARAM_WRITABLE);
6356 * ClutterActor:layout-manager:
6358 * A delegate object for controlling the layout of the children of
6363 obj_props[PROP_LAYOUT_MANAGER] =
6364 g_param_spec_object ("layout-manager",
6365 P_("Layout Manager"),
6366 P_("The object controlling the layout of an actor's children"),
6367 CLUTTER_TYPE_LAYOUT_MANAGER,
6368 CLUTTER_PARAM_READWRITE);
6372 * ClutterActor:x-align:
6374 * The alignment of an actor on the X axis, if the actor has been given
6375 * extra space for its allocation.
6379 obj_props[PROP_X_ALIGN] =
6380 g_param_spec_enum ("x-align",
6382 P_("The alignment of the actor on the X axis within its allocation"),
6383 CLUTTER_TYPE_ACTOR_ALIGN,
6384 CLUTTER_ACTOR_ALIGN_FILL,
6385 CLUTTER_PARAM_READWRITE);
6388 * ClutterActor:y-align:
6390 * The alignment of an actor on the Y axis, if the actor has been given
6391 * extra space for its allocation.
6395 obj_props[PROP_Y_ALIGN] =
6396 g_param_spec_enum ("y-align",
6398 P_("The alignment of the actor on the Y axis within its allocation"),
6399 CLUTTER_TYPE_ACTOR_ALIGN,
6400 CLUTTER_ACTOR_ALIGN_FILL,
6401 CLUTTER_PARAM_READWRITE);
6404 * ClutterActor:margin-top:
6406 * The margin (in pixels) from the top of the actor.
6408 * This property adds a margin to the actor's preferred size; the margin
6409 * will be automatically taken into account when allocating the actor.
6413 obj_props[PROP_MARGIN_TOP] =
6414 g_param_spec_float ("margin-top",
6416 P_("Extra space at the top"),
6419 CLUTTER_PARAM_READWRITE);
6422 * ClutterActor:margin-bottom:
6424 * The margin (in pixels) from the bottom of the actor.
6426 * This property adds a margin to the actor's preferred size; the margin
6427 * will be automatically taken into account when allocating the actor.
6431 obj_props[PROP_MARGIN_BOTTOM] =
6432 g_param_spec_float ("margin-bottom",
6433 P_("Margin Bottom"),
6434 P_("Extra space at the bottom"),
6437 CLUTTER_PARAM_READWRITE);
6440 * ClutterActor:margin-left:
6442 * The margin (in pixels) from the left of the actor.
6444 * This property adds a margin to the actor's preferred size; the margin
6445 * will be automatically taken into account when allocating the actor.
6449 obj_props[PROP_MARGIN_LEFT] =
6450 g_param_spec_float ("margin-left",
6452 P_("Extra space at the left"),
6455 CLUTTER_PARAM_READWRITE);
6458 * ClutterActor:margin-right:
6460 * The margin (in pixels) from the right of the actor.
6462 * This property adds a margin to the actor's preferred size; the margin
6463 * will be automatically taken into account when allocating the actor.
6467 obj_props[PROP_MARGIN_RIGHT] =
6468 g_param_spec_float ("margin-right",
6470 P_("Extra space at the right"),
6473 CLUTTER_PARAM_READWRITE);
6476 * ClutterActor:background-color-set:
6478 * Whether the #ClutterActor:background-color property has been set.
6482 obj_props[PROP_BACKGROUND_COLOR_SET] =
6483 g_param_spec_boolean ("background-color-set",
6484 P_("Background Color Set"),
6485 P_("Whether the background color is set"),
6487 CLUTTER_PARAM_READABLE);
6490 * ClutterActor:background-color:
6492 * Paints a solid fill of the actor's allocation using the specified
6495 * The #ClutterActor:background-color property is animatable.
6499 obj_props[PROP_BACKGROUND_COLOR] =
6500 clutter_param_spec_color ("background-color",
6501 P_("Background color"),
6502 P_("The actor's background color"),
6503 CLUTTER_COLOR_Transparent,
6505 G_PARAM_STATIC_STRINGS |
6506 CLUTTER_PARAM_ANIMATABLE);
6509 * ClutterActor:first-child:
6511 * The actor's first child.
6515 obj_props[PROP_FIRST_CHILD] =
6516 g_param_spec_object ("first-child",
6518 P_("The actor's first child"),
6520 CLUTTER_PARAM_READABLE);
6523 * ClutterActor:last-child:
6525 * The actor's last child.
6529 obj_props[PROP_LAST_CHILD] =
6530 g_param_spec_object ("last-child",
6532 P_("The actor's last child"),
6534 CLUTTER_PARAM_READABLE);
6537 * ClutterActor:content:
6539 * The #ClutterContent implementation that controls the content
6544 obj_props[PROP_CONTENT] =
6545 g_param_spec_object ("content",
6547 P_("Delegate object for painting the actor's content"),
6548 CLUTTER_TYPE_CONTENT,
6549 CLUTTER_PARAM_READWRITE);
6552 * ClutterActor:content-gravity:
6554 * The alignment that should be honoured by the #ClutterContent
6555 * set with the #ClutterActor:content property.
6557 * Changing the value of this property will change the bounding box of
6558 * the content; you can use the #ClutterActor:content-box property to
6559 * get the position and size of the content within the actor's
6562 * This property is meaningful only for #ClutterContent implementations
6563 * that have a preferred size, and if the preferred size is smaller than
6564 * the actor's allocation.
6566 * The #ClutterActor:content-gravity property is animatable.
6570 obj_props[PROP_CONTENT_GRAVITY] =
6571 g_param_spec_enum ("content-gravity",
6572 P_("Content Gravity"),
6573 P_("Alignment of the actor's content"),
6574 CLUTTER_TYPE_CONTENT_GRAVITY,
6575 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6576 CLUTTER_PARAM_READWRITE);
6579 * ClutterActor:content-box:
6581 * The bounding box for the #ClutterContent used by the actor.
6583 * The value of this property is controlled by the #ClutterActor:allocation
6584 * and #ClutterActor:content-gravity properties of #ClutterActor.
6586 * The bounding box for the content is guaranteed to never exceed the
6587 * allocation's of the actor.
6591 obj_props[PROP_CONTENT_BOX] =
6592 g_param_spec_boxed ("content-box",
6594 P_("The bounding box of the actor's content"),
6595 CLUTTER_TYPE_ACTOR_BOX,
6597 G_PARAM_STATIC_STRINGS |
6598 CLUTTER_PARAM_ANIMATABLE);
6600 obj_props[PROP_MINIFICATION_FILTER] =
6601 g_param_spec_enum ("minification-filter",
6602 P_("Minification Filter"),
6603 P_("The filter used when reducing the size of the content"),
6604 CLUTTER_TYPE_SCALING_FILTER,
6605 CLUTTER_SCALING_FILTER_LINEAR,
6606 CLUTTER_PARAM_READWRITE);
6608 obj_props[PROP_MAGNIFICATION_FILTER] =
6609 g_param_spec_enum ("magnification-filter",
6610 P_("Magnification Filter"),
6611 P_("The filter used when increasing the size of the content"),
6612 CLUTTER_TYPE_SCALING_FILTER,
6613 CLUTTER_SCALING_FILTER_LINEAR,
6614 CLUTTER_PARAM_READWRITE);
6616 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6619 * ClutterActor::destroy:
6620 * @actor: the #ClutterActor which emitted the signal
6622 * The ::destroy signal notifies that all references held on the
6623 * actor which emitted it should be released.
6625 * The ::destroy signal should be used by all holders of a reference
6628 * This signal might result in the finalization of the #ClutterActor
6629 * if all references are released.
6631 * Composite actors and actors implementing the #ClutterContainer
6632 * interface should override the default implementation of the
6633 * class handler of this signal and call clutter_actor_destroy() on
6634 * their children. When overriding the default class handler, it is
6635 * required to chain up to the parent's implementation.
6639 actor_signals[DESTROY] =
6640 g_signal_new (I_("destroy"),
6641 G_TYPE_FROM_CLASS (object_class),
6642 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6643 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6645 _clutter_marshal_VOID__VOID,
6648 * ClutterActor::show:
6649 * @actor: the object which received the signal
6651 * The ::show signal is emitted when an actor is visible and
6652 * rendered on the stage.
6656 actor_signals[SHOW] =
6657 g_signal_new (I_("show"),
6658 G_TYPE_FROM_CLASS (object_class),
6660 G_STRUCT_OFFSET (ClutterActorClass, show),
6662 _clutter_marshal_VOID__VOID,
6665 * ClutterActor::hide:
6666 * @actor: the object which received the signal
6668 * The ::hide signal is emitted when an actor is no longer rendered
6673 actor_signals[HIDE] =
6674 g_signal_new (I_("hide"),
6675 G_TYPE_FROM_CLASS (object_class),
6677 G_STRUCT_OFFSET (ClutterActorClass, hide),
6679 _clutter_marshal_VOID__VOID,
6682 * ClutterActor::parent-set:
6683 * @actor: the object which received the signal
6684 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6686 * This signal is emitted when the parent of the actor changes.
6690 actor_signals[PARENT_SET] =
6691 g_signal_new (I_("parent-set"),
6692 G_TYPE_FROM_CLASS (object_class),
6694 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6696 _clutter_marshal_VOID__OBJECT,
6698 CLUTTER_TYPE_ACTOR);
6701 * ClutterActor::queue-redraw:
6702 * @actor: the actor we're bubbling the redraw request through
6703 * @origin: the actor which initiated the redraw request
6705 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6706 * is called on @origin.
6708 * The default implementation for #ClutterActor chains up to the
6709 * parent actor and queues a redraw on the parent, thus "bubbling"
6710 * the redraw queue up through the actor graph. The default
6711 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6712 * in a main loop idle handler.
6714 * Note that the @origin actor may be the stage, or a container; it
6715 * does not have to be a leaf node in the actor graph.
6717 * Toolkits embedding a #ClutterStage which require a redraw and
6718 * relayout cycle can stop the emission of this signal using the
6719 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6724 * on_redraw_complete (gpointer data)
6726 * ClutterStage *stage = data;
6728 * /* execute the Clutter drawing pipeline */
6729 * clutter_stage_ensure_redraw (stage);
6733 * on_stage_queue_redraw (ClutterStage *stage)
6735 * /* this prevents the default handler to run */
6736 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6738 * /* queue a redraw with the host toolkit and call
6739 * * a function when the redraw has been completed
6741 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6745 * <note><para>This signal is emitted before the Clutter paint
6746 * pipeline is executed. If you want to know when the pipeline has
6747 * been completed you should connect to the ::paint signal on the
6748 * Stage with g_signal_connect_after().</para></note>
6752 actor_signals[QUEUE_REDRAW] =
6753 g_signal_new (I_("queue-redraw"),
6754 G_TYPE_FROM_CLASS (object_class),
6757 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6759 _clutter_marshal_VOID__OBJECT,
6761 CLUTTER_TYPE_ACTOR);
6764 * ClutterActor::queue-relayout
6765 * @actor: the actor being queued for relayout
6767 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6768 * is called on an actor.
6770 * The default implementation for #ClutterActor chains up to the
6771 * parent actor and queues a relayout on the parent, thus "bubbling"
6772 * the relayout queue up through the actor graph.
6774 * The main purpose of this signal is to allow relayout to be propagated
6775 * properly in the procense of #ClutterClone actors. Applications will
6776 * not normally need to connect to this signal.
6780 actor_signals[QUEUE_RELAYOUT] =
6781 g_signal_new (I_("queue-relayout"),
6782 G_TYPE_FROM_CLASS (object_class),
6785 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6787 _clutter_marshal_VOID__VOID,
6791 * ClutterActor::event:
6792 * @actor: the actor which received the event
6793 * @event: a #ClutterEvent
6795 * The ::event signal is emitted each time an event is received
6796 * by the @actor. This signal will be emitted on every actor,
6797 * following the hierarchy chain, until it reaches the top-level
6798 * container (the #ClutterStage).
6800 * Return value: %TRUE if the event has been handled by the actor,
6801 * or %FALSE to continue the emission.
6805 actor_signals[EVENT] =
6806 g_signal_new (I_("event"),
6807 G_TYPE_FROM_CLASS (object_class),
6809 G_STRUCT_OFFSET (ClutterActorClass, event),
6810 _clutter_boolean_handled_accumulator, NULL,
6811 _clutter_marshal_BOOLEAN__BOXED,
6813 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6815 * ClutterActor::button-press-event:
6816 * @actor: the actor which received the event
6817 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6819 * The ::button-press-event signal is emitted each time a mouse button
6820 * is pressed on @actor.
6822 * Return value: %TRUE if the event has been handled by the actor,
6823 * or %FALSE to continue the emission.
6827 actor_signals[BUTTON_PRESS_EVENT] =
6828 g_signal_new (I_("button-press-event"),
6829 G_TYPE_FROM_CLASS (object_class),
6831 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6832 _clutter_boolean_handled_accumulator, NULL,
6833 _clutter_marshal_BOOLEAN__BOXED,
6835 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6837 * ClutterActor::button-release-event:
6838 * @actor: the actor which received the event
6839 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6841 * The ::button-release-event signal is emitted each time a mouse button
6842 * is released on @actor.
6844 * Return value: %TRUE if the event has been handled by the actor,
6845 * or %FALSE to continue the emission.
6849 actor_signals[BUTTON_RELEASE_EVENT] =
6850 g_signal_new (I_("button-release-event"),
6851 G_TYPE_FROM_CLASS (object_class),
6853 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6854 _clutter_boolean_handled_accumulator, NULL,
6855 _clutter_marshal_BOOLEAN__BOXED,
6857 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6859 * ClutterActor::scroll-event:
6860 * @actor: the actor which received the event
6861 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6863 * The ::scroll-event signal is emitted each time the mouse is
6864 * scrolled on @actor
6866 * Return value: %TRUE if the event has been handled by the actor,
6867 * or %FALSE to continue the emission.
6871 actor_signals[SCROLL_EVENT] =
6872 g_signal_new (I_("scroll-event"),
6873 G_TYPE_FROM_CLASS (object_class),
6875 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6876 _clutter_boolean_handled_accumulator, NULL,
6877 _clutter_marshal_BOOLEAN__BOXED,
6879 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6881 * ClutterActor::key-press-event:
6882 * @actor: the actor which received the event
6883 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6885 * The ::key-press-event signal is emitted each time a keyboard button
6886 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6888 * Return value: %TRUE if the event has been handled by the actor,
6889 * or %FALSE to continue the emission.
6893 actor_signals[KEY_PRESS_EVENT] =
6894 g_signal_new (I_("key-press-event"),
6895 G_TYPE_FROM_CLASS (object_class),
6897 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6898 _clutter_boolean_handled_accumulator, NULL,
6899 _clutter_marshal_BOOLEAN__BOXED,
6901 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6903 * ClutterActor::key-release-event:
6904 * @actor: the actor which received the event
6905 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6907 * The ::key-release-event signal is emitted each time a keyboard button
6908 * is released while @actor has key focus (see
6909 * clutter_stage_set_key_focus()).
6911 * Return value: %TRUE if the event has been handled by the actor,
6912 * or %FALSE to continue the emission.
6916 actor_signals[KEY_RELEASE_EVENT] =
6917 g_signal_new (I_("key-release-event"),
6918 G_TYPE_FROM_CLASS (object_class),
6920 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6921 _clutter_boolean_handled_accumulator, NULL,
6922 _clutter_marshal_BOOLEAN__BOXED,
6924 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6926 * ClutterActor::motion-event:
6927 * @actor: the actor which received the event
6928 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6930 * The ::motion-event signal is emitted each time the mouse pointer is
6931 * moved over @actor.
6933 * Return value: %TRUE if the event has been handled by the actor,
6934 * or %FALSE to continue the emission.
6938 actor_signals[MOTION_EVENT] =
6939 g_signal_new (I_("motion-event"),
6940 G_TYPE_FROM_CLASS (object_class),
6942 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6943 _clutter_boolean_handled_accumulator, NULL,
6944 _clutter_marshal_BOOLEAN__BOXED,
6946 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6949 * ClutterActor::key-focus-in:
6950 * @actor: the actor which now has key focus
6952 * The ::key-focus-in signal is emitted when @actor receives key focus.
6956 actor_signals[KEY_FOCUS_IN] =
6957 g_signal_new (I_("key-focus-in"),
6958 G_TYPE_FROM_CLASS (object_class),
6960 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6962 _clutter_marshal_VOID__VOID,
6966 * ClutterActor::key-focus-out:
6967 * @actor: the actor which now has key focus
6969 * The ::key-focus-out signal is emitted when @actor loses key focus.
6973 actor_signals[KEY_FOCUS_OUT] =
6974 g_signal_new (I_("key-focus-out"),
6975 G_TYPE_FROM_CLASS (object_class),
6977 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6979 _clutter_marshal_VOID__VOID,
6983 * ClutterActor::enter-event:
6984 * @actor: the actor which the pointer has entered.
6985 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6987 * The ::enter-event signal is emitted when the pointer enters the @actor
6989 * Return value: %TRUE if the event has been handled by the actor,
6990 * or %FALSE to continue the emission.
6994 actor_signals[ENTER_EVENT] =
6995 g_signal_new (I_("enter-event"),
6996 G_TYPE_FROM_CLASS (object_class),
6998 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6999 _clutter_boolean_handled_accumulator, NULL,
7000 _clutter_marshal_BOOLEAN__BOXED,
7002 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7005 * ClutterActor::leave-event:
7006 * @actor: the actor which the pointer has left
7007 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7009 * The ::leave-event signal is emitted when the pointer leaves the @actor.
7011 * Return value: %TRUE if the event has been handled by the actor,
7012 * or %FALSE to continue the emission.
7016 actor_signals[LEAVE_EVENT] =
7017 g_signal_new (I_("leave-event"),
7018 G_TYPE_FROM_CLASS (object_class),
7020 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7021 _clutter_boolean_handled_accumulator, NULL,
7022 _clutter_marshal_BOOLEAN__BOXED,
7024 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7027 * ClutterActor::captured-event:
7028 * @actor: the actor which received the signal
7029 * @event: a #ClutterEvent
7031 * The ::captured-event signal is emitted when an event is captured
7032 * by Clutter. This signal will be emitted starting from the top-level
7033 * container (the #ClutterStage) to the actor which received the event
7034 * going down the hierarchy. This signal can be used to intercept every
7035 * event before the specialized events (like
7036 * ClutterActor::button-press-event or ::key-released-event) are
7039 * Return value: %TRUE if the event has been handled by the actor,
7040 * or %FALSE to continue the emission.
7044 actor_signals[CAPTURED_EVENT] =
7045 g_signal_new (I_("captured-event"),
7046 G_TYPE_FROM_CLASS (object_class),
7048 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7049 _clutter_boolean_handled_accumulator, NULL,
7050 _clutter_marshal_BOOLEAN__BOXED,
7052 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7055 * ClutterActor::paint:
7056 * @actor: the #ClutterActor that received the signal
7058 * The ::paint signal is emitted each time an actor is being painted.
7060 * Subclasses of #ClutterActor should override the class signal handler
7061 * and paint themselves in that function.
7063 * It is possible to connect a handler to the ::paint signal in order
7064 * to set up some custom aspect of a paint.
7068 actor_signals[PAINT] =
7069 g_signal_new (I_("paint"),
7070 G_TYPE_FROM_CLASS (object_class),
7073 G_STRUCT_OFFSET (ClutterActorClass, paint),
7075 _clutter_marshal_VOID__VOID,
7078 * ClutterActor::realize:
7079 * @actor: the #ClutterActor that received the signal
7081 * The ::realize signal is emitted each time an actor is being
7086 actor_signals[REALIZE] =
7087 g_signal_new (I_("realize"),
7088 G_TYPE_FROM_CLASS (object_class),
7090 G_STRUCT_OFFSET (ClutterActorClass, realize),
7092 _clutter_marshal_VOID__VOID,
7095 * ClutterActor::unrealize:
7096 * @actor: the #ClutterActor that received the signal
7098 * The ::unrealize signal is emitted each time an actor is being
7103 actor_signals[UNREALIZE] =
7104 g_signal_new (I_("unrealize"),
7105 G_TYPE_FROM_CLASS (object_class),
7107 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7109 _clutter_marshal_VOID__VOID,
7113 * ClutterActor::pick:
7114 * @actor: the #ClutterActor that received the signal
7115 * @color: the #ClutterColor to be used when picking
7117 * The ::pick signal is emitted each time an actor is being painted
7118 * in "pick mode". The pick mode is used to identify the actor during
7119 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7120 * The actor should paint its shape using the passed @pick_color.
7122 * Subclasses of #ClutterActor should override the class signal handler
7123 * and paint themselves in that function.
7125 * It is possible to connect a handler to the ::pick signal in order
7126 * to set up some custom aspect of a paint in pick mode.
7130 actor_signals[PICK] =
7131 g_signal_new (I_("pick"),
7132 G_TYPE_FROM_CLASS (object_class),
7134 G_STRUCT_OFFSET (ClutterActorClass, pick),
7136 _clutter_marshal_VOID__BOXED,
7138 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7141 * ClutterActor::allocation-changed:
7142 * @actor: the #ClutterActor that emitted the signal
7143 * @box: a #ClutterActorBox with the new allocation
7144 * @flags: #ClutterAllocationFlags for the allocation
7146 * The ::allocation-changed signal is emitted when the
7147 * #ClutterActor:allocation property changes. Usually, application
7148 * code should just use the notifications for the :allocation property
7149 * but if you want to track the allocation flags as well, for instance
7150 * to know whether the absolute origin of @actor changed, then you might
7151 * want use this signal instead.
7155 actor_signals[ALLOCATION_CHANGED] =
7156 g_signal_new (I_("allocation-changed"),
7157 G_TYPE_FROM_CLASS (object_class),
7161 _clutter_marshal_VOID__BOXED_FLAGS,
7163 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7164 CLUTTER_TYPE_ALLOCATION_FLAGS);
7167 * ClutterActor::transitions-completed:
7168 * @actor: a #ClutterActor
7170 * The ::transitions-completed signal is emitted once all transitions
7171 * involving @actor are complete.
7175 actor_signals[TRANSITIONS_COMPLETED] =
7176 g_signal_new (I_("transitions-completed"),
7177 G_TYPE_FROM_CLASS (object_class),
7181 _clutter_marshal_VOID__VOID,
7186 clutter_actor_init (ClutterActor *self)
7188 ClutterActorPrivate *priv;
7190 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7192 priv->id = _clutter_context_acquire_id (self);
7195 priv->opacity = 0xff;
7196 priv->show_on_set_parent = TRUE;
7198 priv->needs_width_request = TRUE;
7199 priv->needs_height_request = TRUE;
7200 priv->needs_allocation = TRUE;
7202 priv->cached_width_age = 1;
7203 priv->cached_height_age = 1;
7205 priv->opacity_override = -1;
7206 priv->enable_model_view_transform = TRUE;
7208 /* Initialize an empty paint volume to start with */
7209 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7210 priv->last_paint_volume_valid = TRUE;
7212 priv->transform_valid = FALSE;
7214 /* the default is to stretch the content, to match the
7215 * current behaviour of basically all actors. also, it's
7216 * the easiest thing to compute.
7218 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7219 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7220 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7224 * clutter_actor_new:
7226 * Creates a new #ClutterActor.
7228 * A newly created actor has a floating reference, which will be sunk
7229 * when it is added to another actor.
7231 * Return value: (transfer full): the newly created #ClutterActor
7236 clutter_actor_new (void)
7238 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7242 * clutter_actor_destroy:
7243 * @self: a #ClutterActor
7245 * Destroys an actor. When an actor is destroyed, it will break any
7246 * references it holds to other objects. If the actor is inside a
7247 * container, the actor will be removed.
7249 * When you destroy a container, its children will be destroyed as well.
7251 * Note: you cannot destroy the #ClutterStage returned by
7252 * clutter_stage_get_default().
7255 clutter_actor_destroy (ClutterActor *self)
7257 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7259 g_object_ref (self);
7261 /* avoid recursion while destroying */
7262 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7264 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7266 g_object_run_dispose (G_OBJECT (self));
7268 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7271 g_object_unref (self);
7275 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7276 ClutterPaintVolume *clip)
7278 ClutterActorPrivate *priv = self->priv;
7279 ClutterPaintVolume *pv;
7282 /* Remove queue entry early in the process, otherwise a new
7283 queue_redraw() during signal handling could put back this
7284 object in the stage redraw list (but the entry is freed as
7285 soon as we return from this function, causing a segfault
7288 priv->queue_redraw_entry = NULL;
7290 /* If we've been explicitly passed a clip volume then there's
7291 * nothing more to calculate, but otherwise the only thing we know
7292 * is that the change is constrained to the given actor.
7294 * The idea is that if we know the paint volume for where the actor
7295 * was last drawn (in eye coordinates) and we also have the paint
7296 * volume for where it will be drawn next (in actor coordinates)
7297 * then if we queue a redraw for both these volumes that will cover
7298 * everything that needs to be redrawn to clear the old view and
7299 * show the latest view of the actor.
7301 * Don't clip this redraw if we don't know what position we had for
7302 * the previous redraw since we don't know where to set the clip so
7303 * it will clear the actor as it is currently.
7307 _clutter_actor_set_queue_redraw_clip (self, clip);
7310 else if (G_LIKELY (priv->last_paint_volume_valid))
7312 pv = _clutter_actor_get_paint_volume_mutable (self);
7315 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7317 /* make sure we redraw the actors old position... */
7318 _clutter_actor_set_queue_redraw_clip (stage,
7319 &priv->last_paint_volume);
7320 _clutter_actor_signal_queue_redraw (stage, stage);
7321 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7323 /* XXX: Ideally the redraw signal would take a clip volume
7324 * argument, but that would be an ABI break. Until we can
7325 * break the ABI we pass the argument out-of-band
7328 /* setup the clip for the actors new position... */
7329 _clutter_actor_set_queue_redraw_clip (self, pv);
7338 _clutter_actor_signal_queue_redraw (self, self);
7340 /* Just in case anyone is manually firing redraw signals without
7341 * using the public queue_redraw() API we are careful to ensure that
7342 * our out-of-band clip member is cleared before returning...
7344 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7346 if (G_LIKELY (clipped))
7347 _clutter_actor_set_queue_redraw_clip (self, NULL);
7351 _clutter_actor_get_allocation_clip (ClutterActor *self,
7352 ClutterActorBox *clip)
7354 ClutterActorBox allocation;
7356 /* XXX: we don't care if we get an out of date allocation here
7357 * because clutter_actor_queue_redraw_with_clip knows to ignore
7358 * the clip if the actor's allocation is invalid.
7360 * This is noted because clutter_actor_get_allocation_box does some
7361 * unnecessary work to support buggy code with a comment suggesting
7362 * that it could be changed later which would be good for this use
7365 clutter_actor_get_allocation_box (self, &allocation);
7367 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7368 * actor's own coordinate space but the allocation is in parent
7372 clip->x2 = allocation.x2 - allocation.x1;
7373 clip->y2 = allocation.y2 - allocation.y1;
7377 _clutter_actor_queue_redraw_full (ClutterActor *self,
7378 ClutterRedrawFlags flags,
7379 ClutterPaintVolume *volume,
7380 ClutterEffect *effect)
7382 ClutterActorPrivate *priv = self->priv;
7383 ClutterPaintVolume allocation_pv;
7384 ClutterPaintVolume *pv;
7385 gboolean should_free_pv;
7386 ClutterActor *stage;
7388 /* Here's an outline of the actor queue redraw mechanism:
7390 * The process starts in one of the following two functions which
7391 * are wrappers for this function:
7392 * clutter_actor_queue_redraw
7393 * _clutter_actor_queue_redraw_with_clip
7395 * additionally, an effect can queue a redraw by wrapping this
7396 * function in clutter_effect_queue_rerun
7398 * This functions queues an entry in a list associated with the
7399 * stage which is a list of actors that queued a redraw while
7400 * updating the timelines, performing layouting and processing other
7401 * mainloop sources before the next paint starts.
7403 * We aim to minimize the processing done at this point because
7404 * there is a good chance other events will happen while updating
7405 * the scenegraph that would invalidate any expensive work we might
7406 * otherwise try to do here. For example we don't try and resolve
7407 * the screen space bounding box of an actor at this stage so as to
7408 * minimize how much of the screen redraw because it's possible
7409 * something else will happen which will force a full redraw anyway.
7411 * When all updates are complete and we come to paint the stage then
7412 * we iterate this list and actually emit the "queue-redraw" signals
7413 * for each of the listed actors which will bubble up to the stage
7414 * for each actor and at that point we will transform the actors
7415 * paint volume into screen coordinates to determine the clip region
7416 * for what needs to be redrawn in the next paint.
7418 * Besides minimizing redundant work another reason for this
7419 * deferred design is that it's more likely we will be able to
7420 * determine the paint volume of an actor once we've finished
7421 * updating the scenegraph because its allocation should be up to
7422 * date. NB: If we can't determine an actors paint volume then we
7423 * can't automatically queue a clipped redraw which can make a big
7424 * difference to performance.
7426 * So the control flow goes like this:
7427 * One of clutter_actor_queue_redraw,
7428 * _clutter_actor_queue_redraw_with_clip
7429 * or clutter_effect_queue_rerun
7431 * then control moves to:
7432 * _clutter_stage_queue_actor_redraw
7434 * later during _clutter_stage_do_update, once relayouting is done
7435 * and the scenegraph has been updated we will call:
7436 * _clutter_stage_finish_queue_redraws
7438 * _clutter_stage_finish_queue_redraws will call
7439 * _clutter_actor_finish_queue_redraw for each listed actor.
7440 * Note: actors *are* allowed to queue further redraws during this
7441 * process (considering clone actors or texture_new_from_actor which
7442 * respond to their source queueing a redraw by queuing a redraw
7443 * themselves). We repeat the process until the list is empty.
7445 * This will result in the "queue-redraw" signal being fired for
7446 * each actor which will pass control to the default signal handler:
7447 * clutter_actor_real_queue_redraw
7449 * This will bubble up to the stages handler:
7450 * clutter_stage_real_queue_redraw
7452 * clutter_stage_real_queue_redraw will transform the actors paint
7453 * volume into screen space and add it as a clip region for the next
7457 /* ignore queueing a redraw for actors being destroyed */
7458 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7461 stage = _clutter_actor_get_stage_internal (self);
7463 /* Ignore queueing a redraw for actors not descended from a stage */
7467 /* ignore queueing a redraw on stages that are being destroyed */
7468 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7471 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7473 ClutterActorBox allocation_clip;
7474 ClutterVertex origin;
7476 /* If the actor doesn't have a valid allocation then we will
7477 * queue a full stage redraw. */
7478 if (priv->needs_allocation)
7480 /* NB: NULL denotes an undefined clip which will result in a
7482 _clutter_actor_set_queue_redraw_clip (self, NULL);
7483 _clutter_actor_signal_queue_redraw (self, self);
7487 _clutter_paint_volume_init_static (&allocation_pv, self);
7488 pv = &allocation_pv;
7490 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7492 origin.x = allocation_clip.x1;
7493 origin.y = allocation_clip.y1;
7495 clutter_paint_volume_set_origin (pv, &origin);
7496 clutter_paint_volume_set_width (pv,
7497 allocation_clip.x2 - allocation_clip.x1);
7498 clutter_paint_volume_set_height (pv,
7499 allocation_clip.y2 -
7500 allocation_clip.y1);
7501 should_free_pv = TRUE;
7506 should_free_pv = FALSE;
7509 self->priv->queue_redraw_entry =
7510 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7511 priv->queue_redraw_entry,
7516 clutter_paint_volume_free (pv);
7518 /* If this is the first redraw queued then we can directly use the
7520 if (!priv->is_dirty)
7521 priv->effect_to_redraw = effect;
7522 /* Otherwise we need to merge it with the existing effect parameter */
7523 else if (effect != NULL)
7525 /* If there's already an effect then we need to use whichever is
7526 later in the chain of actors. Otherwise a full redraw has
7527 already been queued on the actor so we need to ignore the
7529 if (priv->effect_to_redraw != NULL)
7531 if (priv->effects == NULL)
7532 g_warning ("Redraw queued with an effect that is "
7533 "not applied to the actor");
7538 for (l = _clutter_meta_group_peek_metas (priv->effects);
7542 if (l->data == priv->effect_to_redraw ||
7544 priv->effect_to_redraw = l->data;
7551 /* If no effect is specified then we need to redraw the whole
7553 priv->effect_to_redraw = NULL;
7556 priv->is_dirty = TRUE;
7560 * clutter_actor_queue_redraw:
7561 * @self: A #ClutterActor
7563 * Queues up a redraw of an actor and any children. The redraw occurs
7564 * once the main loop becomes idle (after the current batch of events
7565 * has been processed, roughly).
7567 * Applications rarely need to call this, as redraws are handled
7568 * automatically by modification functions.
7570 * This function will not do anything if @self is not visible, or
7571 * if the actor is inside an invisible part of the scenegraph.
7573 * Also be aware that painting is a NOP for actors with an opacity of
7576 * When you are implementing a custom actor you must queue a redraw
7577 * whenever some private state changes that will affect painting or
7578 * picking of your actor.
7581 clutter_actor_queue_redraw (ClutterActor *self)
7583 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7585 _clutter_actor_queue_redraw_full (self,
7587 NULL, /* clip volume */
7592 * _clutter_actor_queue_redraw_with_clip:
7593 * @self: A #ClutterActor
7594 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7595 * this queue redraw.
7596 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7597 * redrawn or %NULL if you are just using a @flag to state your
7600 * Queues up a clipped redraw of an actor and any children. The redraw
7601 * occurs once the main loop becomes idle (after the current batch of
7602 * events has been processed, roughly).
7604 * If no flags are given the clip volume is defined by @volume
7605 * specified in actor coordinates and tells Clutter that only content
7606 * within this volume has been changed so Clutter can optionally
7607 * optimize the redraw.
7609 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7610 * should be %NULL and this tells Clutter to use the actor's current
7611 * allocation as a clip box. This flag can only be used for 2D actors,
7612 * because any actor with depth may be projected outside its
7615 * Applications rarely need to call this, as redraws are handled
7616 * automatically by modification functions.
7618 * This function will not do anything if @self is not visible, or if
7619 * the actor is inside an invisible part of the scenegraph.
7621 * Also be aware that painting is a NOP for actors with an opacity of
7624 * When you are implementing a custom actor you must queue a redraw
7625 * whenever some private state changes that will affect painting or
7626 * picking of your actor.
7629 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7630 ClutterRedrawFlags flags,
7631 ClutterPaintVolume *volume)
7633 _clutter_actor_queue_redraw_full (self,
7635 volume, /* clip volume */
7640 _clutter_actor_queue_only_relayout (ClutterActor *self)
7642 ClutterActorPrivate *priv = self->priv;
7644 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7647 if (priv->needs_width_request &&
7648 priv->needs_height_request &&
7649 priv->needs_allocation)
7650 return; /* save some cpu cycles */
7652 #if CLUTTER_ENABLE_DEBUG
7653 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7655 g_warning ("The actor '%s' is currently inside an allocation "
7656 "cycle; calling clutter_actor_queue_relayout() is "
7658 _clutter_actor_get_debug_name (self));
7660 #endif /* CLUTTER_ENABLE_DEBUG */
7662 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7666 * clutter_actor_queue_redraw_with_clip:
7667 * @self: a #ClutterActor
7668 * @clip: (allow-none): a rectangular clip region, or %NULL
7670 * Queues a redraw on @self limited to a specific, actor-relative
7673 * If @clip is %NULL this function is equivalent to
7674 * clutter_actor_queue_redraw().
7679 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7680 const cairo_rectangle_int_t *clip)
7682 ClutterPaintVolume volume;
7683 ClutterVertex origin;
7685 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7689 clutter_actor_queue_redraw (self);
7693 _clutter_paint_volume_init_static (&volume, self);
7699 clutter_paint_volume_set_origin (&volume, &origin);
7700 clutter_paint_volume_set_width (&volume, clip->width);
7701 clutter_paint_volume_set_height (&volume, clip->height);
7703 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7705 clutter_paint_volume_free (&volume);
7709 * clutter_actor_queue_relayout:
7710 * @self: A #ClutterActor
7712 * Indicates that the actor's size request or other layout-affecting
7713 * properties may have changed. This function is used inside #ClutterActor
7714 * subclass implementations, not by applications directly.
7716 * Queueing a new layout automatically queues a redraw as well.
7721 clutter_actor_queue_relayout (ClutterActor *self)
7723 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7725 _clutter_actor_queue_only_relayout (self);
7726 clutter_actor_queue_redraw (self);
7730 * clutter_actor_get_preferred_size:
7731 * @self: a #ClutterActor
7732 * @min_width_p: (out) (allow-none): return location for the minimum
7734 * @min_height_p: (out) (allow-none): return location for the minimum
7736 * @natural_width_p: (out) (allow-none): return location for the natural
7738 * @natural_height_p: (out) (allow-none): return location for the natural
7741 * Computes the preferred minimum and natural size of an actor, taking into
7742 * account the actor's geometry management (either height-for-width
7743 * or width-for-height).
7745 * The width and height used to compute the preferred height and preferred
7746 * width are the actor's natural ones.
7748 * If you need to control the height for the preferred width, or the width for
7749 * the preferred height, you should use clutter_actor_get_preferred_width()
7750 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7751 * geometry management using the #ClutterActor:request-mode property.
7756 clutter_actor_get_preferred_size (ClutterActor *self,
7757 gfloat *min_width_p,
7758 gfloat *min_height_p,
7759 gfloat *natural_width_p,
7760 gfloat *natural_height_p)
7762 ClutterActorPrivate *priv;
7763 gfloat min_width, min_height;
7764 gfloat natural_width, natural_height;
7766 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7770 min_width = min_height = 0;
7771 natural_width = natural_height = 0;
7773 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7775 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7776 clutter_actor_get_preferred_width (self, -1,
7779 clutter_actor_get_preferred_height (self, natural_width,
7785 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7786 clutter_actor_get_preferred_height (self, -1,
7789 clutter_actor_get_preferred_width (self, natural_height,
7795 *min_width_p = min_width;
7798 *min_height_p = min_height;
7800 if (natural_width_p)
7801 *natural_width_p = natural_width;
7803 if (natural_height_p)
7804 *natural_height_p = natural_height;
7809 * @align: a #ClutterActorAlign
7810 * @direction: a #ClutterTextDirection
7812 * Retrieves the correct alignment depending on the text direction
7814 * Return value: the effective alignment
7816 static ClutterActorAlign
7817 effective_align (ClutterActorAlign align,
7818 ClutterTextDirection direction)
7820 ClutterActorAlign res;
7824 case CLUTTER_ACTOR_ALIGN_START:
7825 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7826 ? CLUTTER_ACTOR_ALIGN_END
7827 : CLUTTER_ACTOR_ALIGN_START;
7830 case CLUTTER_ACTOR_ALIGN_END:
7831 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7832 ? CLUTTER_ACTOR_ALIGN_START
7833 : CLUTTER_ACTOR_ALIGN_END;
7845 adjust_for_margin (float margin_start,
7847 float *minimum_size,
7848 float *natural_size,
7849 float *allocated_start,
7850 float *allocated_end)
7852 *minimum_size -= (margin_start + margin_end);
7853 *natural_size -= (margin_start + margin_end);
7854 *allocated_start += margin_start;
7855 *allocated_end -= margin_end;
7859 adjust_for_alignment (ClutterActorAlign alignment,
7861 float *allocated_start,
7862 float *allocated_end)
7864 float allocated_size = *allocated_end - *allocated_start;
7868 case CLUTTER_ACTOR_ALIGN_FILL:
7872 case CLUTTER_ACTOR_ALIGN_START:
7874 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7877 case CLUTTER_ACTOR_ALIGN_END:
7878 if (allocated_size > natural_size)
7880 *allocated_start += (allocated_size - natural_size);
7881 *allocated_end = *allocated_start + natural_size;
7885 case CLUTTER_ACTOR_ALIGN_CENTER:
7886 if (allocated_size > natural_size)
7888 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7889 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7896 * clutter_actor_adjust_width:
7897 * @self: a #ClutterActor
7898 * @minimum_width: (inout): the actor's preferred minimum width, which
7899 * will be adjusted depending on the margin
7900 * @natural_width: (inout): the actor's preferred natural width, which
7901 * will be adjusted depending on the margin
7902 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7903 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7905 * Adjusts the preferred and allocated position and size of an actor,
7906 * depending on the margin and alignment properties.
7909 clutter_actor_adjust_width (ClutterActor *self,
7910 gfloat *minimum_width,
7911 gfloat *natural_width,
7912 gfloat *adjusted_x1,
7913 gfloat *adjusted_x2)
7915 ClutterTextDirection text_dir;
7916 const ClutterLayoutInfo *info;
7918 info = _clutter_actor_get_layout_info_or_defaults (self);
7919 text_dir = clutter_actor_get_text_direction (self);
7921 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7923 /* this will tweak natural_width to remove the margin, so that
7924 * adjust_for_alignment() will use the correct size
7926 adjust_for_margin (info->margin.left, info->margin.right,
7927 minimum_width, natural_width,
7928 adjusted_x1, adjusted_x2);
7930 adjust_for_alignment (effective_align (info->x_align, text_dir),
7932 adjusted_x1, adjusted_x2);
7936 * clutter_actor_adjust_height:
7937 * @self: a #ClutterActor
7938 * @minimum_height: (inout): the actor's preferred minimum height, which
7939 * will be adjusted depending on the margin
7940 * @natural_height: (inout): the actor's preferred natural height, which
7941 * will be adjusted depending on the margin
7942 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7943 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7945 * Adjusts the preferred and allocated position and size of an actor,
7946 * depending on the margin and alignment properties.
7949 clutter_actor_adjust_height (ClutterActor *self,
7950 gfloat *minimum_height,
7951 gfloat *natural_height,
7952 gfloat *adjusted_y1,
7953 gfloat *adjusted_y2)
7955 const ClutterLayoutInfo *info;
7957 info = _clutter_actor_get_layout_info_or_defaults (self);
7959 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7961 /* this will tweak natural_height to remove the margin, so that
7962 * adjust_for_alignment() will use the correct size
7964 adjust_for_margin (info->margin.top, info->margin.bottom,
7965 minimum_height, natural_height,
7969 /* we don't use effective_align() here, because text direction
7970 * only affects the horizontal axis
7972 adjust_for_alignment (info->y_align,
7979 /* looks for a cached size request for this for_size. If not
7980 * found, returns the oldest entry so it can be overwritten */
7982 _clutter_actor_get_cached_size_request (gfloat for_size,
7983 SizeRequest *cached_size_requests,
7984 SizeRequest **result)
7988 *result = &cached_size_requests[0];
7990 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7994 sr = &cached_size_requests[i];
7997 sr->for_size == for_size)
7999 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8003 else if (sr->age < (*result)->age)
8009 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8015 * clutter_actor_get_preferred_width:
8016 * @self: A #ClutterActor
8017 * @for_height: available height when computing the preferred width,
8018 * or a negative value to indicate that no height is defined
8019 * @min_width_p: (out) (allow-none): return location for minimum width,
8021 * @natural_width_p: (out) (allow-none): return location for the natural
8024 * Computes the requested minimum and natural widths for an actor,
8025 * optionally depending on the specified height, or if they are
8026 * already computed, returns the cached values.
8028 * An actor may not get its request - depending on the layout
8029 * manager that's in effect.
8031 * A request should not incorporate the actor's scale or anchor point;
8032 * those transformations do not affect layout, only rendering.
8037 clutter_actor_get_preferred_width (ClutterActor *self,
8039 gfloat *min_width_p,
8040 gfloat *natural_width_p)
8042 float request_min_width, request_natural_width;
8043 SizeRequest *cached_size_request;
8044 const ClutterLayoutInfo *info;
8045 ClutterActorPrivate *priv;
8046 gboolean found_in_cache;
8048 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8052 info = _clutter_actor_get_layout_info_or_defaults (self);
8054 /* we shortcircuit the case of a fixed size set using set_width() */
8055 if (priv->min_width_set && priv->natural_width_set)
8057 if (min_width_p != NULL)
8058 *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8060 if (natural_width_p != NULL)
8061 *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8066 /* the remaining cases are:
8068 * - either min_width or natural_width have been set
8069 * - neither min_width or natural_width have been set
8071 * in both cases, we go through the cache (and through the actor in case
8072 * of cache misses) and determine the authoritative value depending on
8076 if (!priv->needs_width_request)
8079 _clutter_actor_get_cached_size_request (for_height,
8080 priv->width_requests,
8081 &cached_size_request);
8085 /* if the actor needs a width request we use the first slot */
8086 found_in_cache = FALSE;
8087 cached_size_request = &priv->width_requests[0];
8090 if (!found_in_cache)
8092 gfloat minimum_width, natural_width;
8093 ClutterActorClass *klass;
8095 minimum_width = natural_width = 0;
8097 /* adjust for the margin */
8098 if (for_height >= 0)
8100 for_height -= (info->margin.top + info->margin.bottom);
8105 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8107 klass = CLUTTER_ACTOR_GET_CLASS (self);
8108 klass->get_preferred_width (self, for_height,
8112 /* adjust for the margin */
8113 minimum_width += (info->margin.left + info->margin.right);
8114 natural_width += (info->margin.left + info->margin.right);
8116 /* Due to accumulated float errors, it's better not to warn
8117 * on this, but just fix it.
8119 if (natural_width < minimum_width)
8120 natural_width = minimum_width;
8122 cached_size_request->min_size = minimum_width;
8123 cached_size_request->natural_size = natural_width;
8124 cached_size_request->for_size = for_height;
8125 cached_size_request->age = priv->cached_width_age;
8127 priv->cached_width_age += 1;
8128 priv->needs_width_request = FALSE;
8131 if (!priv->min_width_set)
8132 request_min_width = cached_size_request->min_size;
8134 request_min_width = info->minimum.width;
8136 if (!priv->natural_width_set)
8137 request_natural_width = cached_size_request->natural_size;
8139 request_natural_width = info->natural.width;
8142 *min_width_p = request_min_width;
8144 if (natural_width_p)
8145 *natural_width_p = request_natural_width;
8149 * clutter_actor_get_preferred_height:
8150 * @self: A #ClutterActor
8151 * @for_width: available width to assume in computing desired height,
8152 * or a negative value to indicate that no width is defined
8153 * @min_height_p: (out) (allow-none): return location for minimum height,
8155 * @natural_height_p: (out) (allow-none): return location for natural
8158 * Computes the requested minimum and natural heights for an actor,
8159 * or if they are already computed, returns the cached values.
8161 * An actor may not get its request - depending on the layout
8162 * manager that's in effect.
8164 * A request should not incorporate the actor's scale or anchor point;
8165 * those transformations do not affect layout, only rendering.
8170 clutter_actor_get_preferred_height (ClutterActor *self,
8172 gfloat *min_height_p,
8173 gfloat *natural_height_p)
8175 float request_min_height, request_natural_height;
8176 SizeRequest *cached_size_request;
8177 const ClutterLayoutInfo *info;
8178 ClutterActorPrivate *priv;
8179 gboolean found_in_cache;
8181 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8185 info = _clutter_actor_get_layout_info_or_defaults (self);
8187 /* we shortcircuit the case of a fixed size set using set_height() */
8188 if (priv->min_height_set && priv->natural_height_set)
8190 if (min_height_p != NULL)
8191 *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8193 if (natural_height_p != NULL)
8194 *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8199 /* the remaining cases are:
8201 * - either min_height or natural_height have been set
8202 * - neither min_height or natural_height have been set
8204 * in both cases, we go through the cache (and through the actor in case
8205 * of cache misses) and determine the authoritative value depending on
8209 if (!priv->needs_height_request)
8212 _clutter_actor_get_cached_size_request (for_width,
8213 priv->height_requests,
8214 &cached_size_request);
8218 found_in_cache = FALSE;
8219 cached_size_request = &priv->height_requests[0];
8222 if (!found_in_cache)
8224 gfloat minimum_height, natural_height;
8225 ClutterActorClass *klass;
8227 minimum_height = natural_height = 0;
8229 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8231 /* adjust for margin */
8234 for_width -= (info->margin.left + info->margin.right);
8239 klass = CLUTTER_ACTOR_GET_CLASS (self);
8240 klass->get_preferred_height (self, for_width,
8244 /* adjust for margin */
8245 minimum_height += (info->margin.top + info->margin.bottom);
8246 natural_height += (info->margin.top + info->margin.bottom);
8248 /* Due to accumulated float errors, it's better not to warn
8249 * on this, but just fix it.
8251 if (natural_height < minimum_height)
8252 natural_height = minimum_height;
8254 cached_size_request->min_size = minimum_height;
8255 cached_size_request->natural_size = natural_height;
8256 cached_size_request->for_size = for_width;
8257 cached_size_request->age = priv->cached_height_age;
8259 priv->cached_height_age += 1;
8260 priv->needs_height_request = FALSE;
8263 if (!priv->min_height_set)
8264 request_min_height = cached_size_request->min_size;
8266 request_min_height = info->minimum.height;
8268 if (!priv->natural_height_set)
8269 request_natural_height = cached_size_request->natural_size;
8271 request_natural_height = info->natural.height;
8274 *min_height_p = request_min_height;
8276 if (natural_height_p)
8277 *natural_height_p = request_natural_height;
8281 * clutter_actor_get_allocation_box:
8282 * @self: A #ClutterActor
8283 * @box: (out): the function fills this in with the actor's allocation
8285 * Gets the layout box an actor has been assigned. The allocation can
8286 * only be assumed valid inside a paint() method; anywhere else, it
8287 * may be out-of-date.
8289 * An allocation does not incorporate the actor's scale or anchor point;
8290 * those transformations do not affect layout, only rendering.
8292 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8293 * of functions inside the implementation of the get_preferred_width()
8294 * or get_preferred_height() virtual functions.</note>
8299 clutter_actor_get_allocation_box (ClutterActor *self,
8300 ClutterActorBox *box)
8302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8304 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8305 * which limits calling get_allocation to inside paint() basically; or
8306 * we can 2) force a layout, which could be expensive if someone calls
8307 * get_allocation somewhere silly; or we can 3) just return the latest
8308 * value, allowing it to be out-of-date, and assume people know what
8311 * The least-surprises approach that keeps existing code working is
8312 * likely to be 2). People can end up doing some inefficient things,
8313 * though, and in general code that requires 2) is probably broken.
8316 /* this implements 2) */
8317 if (G_UNLIKELY (self->priv->needs_allocation))
8319 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8321 /* do not queue a relayout on an unparented actor */
8323 _clutter_stage_maybe_relayout (stage);
8326 /* commenting out the code above and just keeping this assigment
8329 *box = self->priv->allocation;
8333 * clutter_actor_get_allocation_geometry:
8334 * @self: A #ClutterActor
8335 * @geom: (out): allocation geometry in pixels
8337 * Gets the layout box an actor has been assigned. The allocation can
8338 * only be assumed valid inside a paint() method; anywhere else, it
8339 * may be out-of-date.
8341 * An allocation does not incorporate the actor's scale or anchor point;
8342 * those transformations do not affect layout, only rendering.
8344 * The returned rectangle is in pixels.
8349 clutter_actor_get_allocation_geometry (ClutterActor *self,
8350 ClutterGeometry *geom)
8352 ClutterActorBox box;
8354 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8355 g_return_if_fail (geom != NULL);
8357 clutter_actor_get_allocation_box (self, &box);
8359 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8360 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8361 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8362 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8366 clutter_actor_update_constraints (ClutterActor *self,
8367 ClutterActorBox *allocation)
8369 ClutterActorPrivate *priv = self->priv;
8370 const GList *constraints, *l;
8372 if (priv->constraints == NULL)
8375 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8376 for (l = constraints; l != NULL; l = l->next)
8378 ClutterConstraint *constraint = l->data;
8379 ClutterActorMeta *meta = l->data;
8381 if (clutter_actor_meta_get_enabled (meta))
8383 _clutter_constraint_update_allocation (constraint,
8387 CLUTTER_NOTE (LAYOUT,
8388 "Allocation of '%s' after constraint '%s': "
8389 "{ %.2f, %.2f, %.2f, %.2f }",
8390 _clutter_actor_get_debug_name (self),
8391 _clutter_actor_meta_get_debug_name (meta),
8401 * clutter_actor_adjust_allocation:
8402 * @self: a #ClutterActor
8403 * @allocation: (inout): the allocation to adjust
8405 * Adjusts the passed allocation box taking into account the actor's
8406 * layout information, like alignment, expansion, and margin.
8409 clutter_actor_adjust_allocation (ClutterActor *self,
8410 ClutterActorBox *allocation)
8412 ClutterActorBox adj_allocation;
8413 float alloc_width, alloc_height;
8414 float min_width, min_height;
8415 float nat_width, nat_height;
8416 ClutterRequestMode req_mode;
8418 adj_allocation = *allocation;
8420 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8422 /* we want to hit the cache, so we use the public API */
8423 req_mode = clutter_actor_get_request_mode (self);
8425 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8427 clutter_actor_get_preferred_width (self, -1,
8430 clutter_actor_get_preferred_height (self, alloc_width,
8434 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8436 clutter_actor_get_preferred_height (self, -1,
8439 clutter_actor_get_preferred_height (self, alloc_height,
8444 #ifdef CLUTTER_ENABLE_DEBUG
8445 /* warn about underallocations */
8446 if (_clutter_diagnostic_enabled () &&
8447 (floorf (min_width - alloc_width) > 0 ||
8448 floorf (min_height - alloc_height) > 0))
8450 ClutterActor *parent = clutter_actor_get_parent (self);
8452 /* the only actors that are allowed to be underallocated are the Stage,
8453 * as it doesn't have an implicit size, and Actors that specifically
8454 * told us that they want to opt-out from layout control mechanisms
8455 * through the NO_LAYOUT escape hatch.
8457 if (parent != NULL &&
8458 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8460 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8461 "of %.2f x %.2f from its parent actor '%s', but its "
8462 "requested minimum size is of %.2f x %.2f",
8463 _clutter_actor_get_debug_name (self),
8464 alloc_width, alloc_height,
8465 _clutter_actor_get_debug_name (parent),
8466 min_width, min_height);
8471 clutter_actor_adjust_width (self,
8475 &adj_allocation.x2);
8477 clutter_actor_adjust_height (self,
8481 &adj_allocation.y2);
8483 /* we maintain the invariant that an allocation cannot be adjusted
8484 * to be outside the parent-given box
8486 if (adj_allocation.x1 < allocation->x1 ||
8487 adj_allocation.y1 < allocation->y1 ||
8488 adj_allocation.x2 > allocation->x2 ||
8489 adj_allocation.y2 > allocation->y2)
8491 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8492 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8493 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8494 _clutter_actor_get_debug_name (self),
8495 adj_allocation.x1, adj_allocation.y1,
8496 adj_allocation.x2 - adj_allocation.x1,
8497 adj_allocation.y2 - adj_allocation.y1,
8498 allocation->x1, allocation->y1,
8499 allocation->x2 - allocation->x1,
8500 allocation->y2 - allocation->y1);
8504 *allocation = adj_allocation;
8508 * clutter_actor_allocate:
8509 * @self: A #ClutterActor
8510 * @box: new allocation of the actor, in parent-relative coordinates
8511 * @flags: flags that control the allocation
8513 * Called by the parent of an actor to assign the actor its size.
8514 * Should never be called by applications (except when implementing
8515 * a container or layout manager).
8517 * Actors can know from their allocation box whether they have moved
8518 * with respect to their parent actor. The @flags parameter describes
8519 * additional information about the allocation, for instance whether
8520 * the parent has moved with respect to the stage, for example because
8521 * a grandparent's origin has moved.
8526 clutter_actor_allocate (ClutterActor *self,
8527 const ClutterActorBox *box,
8528 ClutterAllocationFlags flags)
8530 ClutterActorPrivate *priv;
8531 ClutterActorClass *klass;
8532 ClutterActorBox old_allocation, real_allocation;
8533 gboolean origin_changed, child_moved, size_changed;
8534 gboolean stage_allocation_changed;
8536 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8537 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8539 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8540 "which isn't a descendent of the stage!\n",
8541 self, _clutter_actor_get_debug_name (self));
8547 old_allocation = priv->allocation;
8548 real_allocation = *box;
8550 /* constraints are allowed to modify the allocation only here; we do
8551 * this prior to all the other checks so that we can bail out if the
8552 * allocation did not change
8554 clutter_actor_update_constraints (self, &real_allocation);
8556 /* adjust the allocation depending on the align/margin properties */
8557 clutter_actor_adjust_allocation (self, &real_allocation);
8559 if (real_allocation.x2 < real_allocation.x1 ||
8560 real_allocation.y2 < real_allocation.y1)
8562 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8563 _clutter_actor_get_debug_name (self),
8564 real_allocation.x2 - real_allocation.x1,
8565 real_allocation.y2 - real_allocation.y1);
8568 /* we allow 0-sized actors, but not negative-sized ones */
8569 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8570 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8572 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8574 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8575 real_allocation.y1 != old_allocation.y1);
8577 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8578 real_allocation.y2 != old_allocation.y2);
8580 if (origin_changed || child_moved || size_changed)
8581 stage_allocation_changed = TRUE;
8583 stage_allocation_changed = FALSE;
8585 /* If we get an allocation "out of the blue"
8586 * (we did not queue relayout), then we want to
8587 * ignore it. But if we have needs_allocation set,
8588 * we want to guarantee that allocate() virtual
8589 * method is always called, i.e. that queue_relayout()
8590 * always results in an allocate() invocation on
8593 * The optimization here is to avoid re-allocating
8594 * actors that did not queue relayout and were
8597 if (!priv->needs_allocation && !stage_allocation_changed)
8599 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8603 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8604 * clutter_actor_allocate(), it indicates whether the parent has its
8605 * absolute origin moved; when passed in to ClutterActor::allocate()
8606 * virtual method though, it indicates whether the child has its
8607 * absolute origin moved. So we set it when child_moved is TRUE
8610 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8612 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8614 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8615 _clutter_actor_get_debug_name (self));
8617 klass = CLUTTER_ACTOR_GET_CLASS (self);
8618 klass->allocate (self, &real_allocation, flags);
8620 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8622 if (stage_allocation_changed)
8623 clutter_actor_queue_redraw (self);
8627 * clutter_actor_set_allocation:
8628 * @self: a #ClutterActor
8629 * @box: a #ClutterActorBox
8630 * @flags: allocation flags
8632 * Stores the allocation of @self as defined by @box.
8634 * This function can only be called from within the implementation of
8635 * the #ClutterActorClass.allocate() virtual function.
8637 * The allocation should have been adjusted to take into account constraints,
8638 * alignment, and margin properties. If you are implementing a #ClutterActor
8639 * subclass that provides its own layout management policy for its children
8640 * instead of using a #ClutterLayoutManager delegate, you should not call
8641 * this function on the children of @self; instead, you should call
8642 * clutter_actor_allocate(), which will adjust the allocation box for
8645 * This function should only be used by subclasses of #ClutterActor
8646 * that wish to store their allocation but cannot chain up to the
8647 * parent's implementation; the default implementation of the
8648 * #ClutterActorClass.allocate() virtual function will call this
8651 * It is important to note that, while chaining up was the recommended
8652 * behaviour for #ClutterActor subclasses prior to the introduction of
8653 * this function, it is recommended to call clutter_actor_set_allocation()
8656 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8657 * to handle the allocation of its children, this function will call
8658 * the clutter_layout_manager_allocate() function only if the
8659 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8660 * expected that the subclass will call clutter_layout_manager_allocate()
8661 * by itself. For instance, the following code:
8665 * my_actor_allocate (ClutterActor *actor,
8666 * const ClutterActorBox *allocation,
8667 * ClutterAllocationFlags flags)
8669 * ClutterActorBox new_alloc;
8670 * ClutterAllocationFlags new_flags;
8672 * adjust_allocation (allocation, &new_alloc);
8674 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8676 * /* this will use the layout manager set on the actor */
8677 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8681 * is equivalent to this:
8685 * my_actor_allocate (ClutterActor *actor,
8686 * const ClutterActorBox *allocation,
8687 * ClutterAllocationFlags flags)
8689 * ClutterLayoutManager *layout;
8690 * ClutterActorBox new_alloc;
8692 * adjust_allocation (allocation, &new_alloc);
8694 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8696 * layout = clutter_actor_get_layout_manager (actor);
8697 * clutter_layout_manager_allocate (layout,
8698 * CLUTTER_CONTAINER (actor),
8707 clutter_actor_set_allocation (ClutterActor *self,
8708 const ClutterActorBox *box,
8709 ClutterAllocationFlags flags)
8711 ClutterActorPrivate *priv;
8714 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8715 g_return_if_fail (box != NULL);
8717 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8719 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8720 "can only be called from within the implementation of "
8721 "the ClutterActor::allocate() virtual function.");
8727 g_object_freeze_notify (G_OBJECT (self));
8729 changed = clutter_actor_set_allocation_internal (self, box, flags);
8731 /* we allocate our children before we notify changes in our geometry,
8732 * so that people connecting to properties will be able to get valid
8733 * data out of the sub-tree of the scene graph that has this actor at
8736 clutter_actor_maybe_layout_children (self, box, flags);
8740 ClutterActorBox signal_box = priv->allocation;
8741 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8743 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8748 g_object_thaw_notify (G_OBJECT (self));
8752 * clutter_actor_set_geometry:
8753 * @self: A #ClutterActor
8754 * @geometry: A #ClutterGeometry
8756 * Sets the actor's fixed position and forces its minimum and natural
8757 * size, in pixels. This means the untransformed actor will have the
8758 * given geometry. This is the same as calling clutter_actor_set_position()
8759 * and clutter_actor_set_size().
8761 * Deprecated: 1.10: Use clutter_actor_set_position() and
8762 * clutter_actor_set_size() instead.
8765 clutter_actor_set_geometry (ClutterActor *self,
8766 const ClutterGeometry *geometry)
8768 g_object_freeze_notify (G_OBJECT (self));
8770 clutter_actor_set_position (self, geometry->x, geometry->y);
8771 clutter_actor_set_size (self, geometry->width, geometry->height);
8773 g_object_thaw_notify (G_OBJECT (self));
8777 * clutter_actor_get_geometry:
8778 * @self: A #ClutterActor
8779 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8781 * Gets the size and position of an actor relative to its parent
8782 * actor. This is the same as calling clutter_actor_get_position() and
8783 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8784 * requested size and position if the actor's allocation is invalid.
8786 * Deprecated: 1.10: Use clutter_actor_get_position() and
8787 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8791 clutter_actor_get_geometry (ClutterActor *self,
8792 ClutterGeometry *geometry)
8794 gfloat x, y, width, height;
8796 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8797 g_return_if_fail (geometry != NULL);
8799 clutter_actor_get_position (self, &x, &y);
8800 clutter_actor_get_size (self, &width, &height);
8802 geometry->x = (int) x;
8803 geometry->y = (int) y;
8804 geometry->width = (int) width;
8805 geometry->height = (int) height;
8809 * clutter_actor_set_position:
8810 * @self: A #ClutterActor
8811 * @x: New left position of actor in pixels.
8812 * @y: New top position of actor in pixels.
8814 * Sets the actor's fixed position in pixels relative to any parent
8817 * If a layout manager is in use, this position will override the
8818 * layout manager and force a fixed position.
8821 clutter_actor_set_position (ClutterActor *self,
8825 ClutterPoint new_position;
8827 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8829 clutter_point_init (&new_position, x, y);
8831 if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
8833 ClutterPoint cur_position;
8835 cur_position.x = clutter_actor_get_x (self);
8836 cur_position.y = clutter_actor_get_y (self);
8838 _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
8843 _clutter_actor_update_transition (self,
8844 obj_props[PROP_POSITION],
8847 clutter_actor_queue_relayout (self);
8851 * clutter_actor_get_fixed_position_set:
8852 * @self: A #ClutterActor
8854 * Checks whether an actor has a fixed position set (and will thus be
8855 * unaffected by any layout manager).
8857 * Return value: %TRUE if the fixed position is set on the actor
8862 clutter_actor_get_fixed_position_set (ClutterActor *self)
8864 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8866 return self->priv->position_set;
8870 * clutter_actor_set_fixed_position_set:
8871 * @self: A #ClutterActor
8872 * @is_set: whether to use fixed position
8874 * Sets whether an actor has a fixed position set (and will thus be
8875 * unaffected by any layout manager).
8880 clutter_actor_set_fixed_position_set (ClutterActor *self,
8883 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8885 if (self->priv->position_set == (is_set != FALSE))
8888 self->priv->position_set = is_set != FALSE;
8889 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8891 clutter_actor_queue_relayout (self);
8895 * clutter_actor_move_by:
8896 * @self: A #ClutterActor
8897 * @dx: Distance to move Actor on X axis.
8898 * @dy: Distance to move Actor on Y axis.
8900 * Moves an actor by the specified distance relative to its current
8901 * position in pixels.
8903 * This function modifies the fixed position of an actor and thus removes
8904 * it from any layout management. Another way to move an actor is with an
8905 * anchor point, see clutter_actor_set_anchor_point().
8910 clutter_actor_move_by (ClutterActor *self,
8914 const ClutterLayoutInfo *info;
8917 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8919 info = _clutter_actor_get_layout_info_or_defaults (self);
8920 x = info->fixed_pos.x;
8921 y = info->fixed_pos.y;
8923 clutter_actor_set_position (self, x + dx, y + dy);
8927 clutter_actor_set_min_width (ClutterActor *self,
8930 ClutterActorPrivate *priv = self->priv;
8931 ClutterActorBox old = { 0, };
8932 ClutterLayoutInfo *info;
8934 /* if we are setting the size on a top-level actor and the
8935 * backend only supports static top-levels (e.g. framebuffers)
8936 * then we ignore the passed value and we override it with
8937 * the stage implementation's preferred size.
8939 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8940 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8943 info = _clutter_actor_get_layout_info (self);
8945 if (priv->min_width_set && min_width == info->minimum.width)
8948 g_object_freeze_notify (G_OBJECT (self));
8950 clutter_actor_store_old_geometry (self, &old);
8952 info->minimum.width = min_width;
8953 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8954 clutter_actor_set_min_width_set (self, TRUE);
8956 clutter_actor_notify_if_geometry_changed (self, &old);
8958 g_object_thaw_notify (G_OBJECT (self));
8960 clutter_actor_queue_relayout (self);
8964 clutter_actor_set_min_height (ClutterActor *self,
8968 ClutterActorPrivate *priv = self->priv;
8969 ClutterActorBox old = { 0, };
8970 ClutterLayoutInfo *info;
8972 /* if we are setting the size on a top-level actor and the
8973 * backend only supports static top-levels (e.g. framebuffers)
8974 * then we ignore the passed value and we override it with
8975 * the stage implementation's preferred size.
8977 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8978 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8981 info = _clutter_actor_get_layout_info (self);
8983 if (priv->min_height_set && min_height == info->minimum.height)
8986 g_object_freeze_notify (G_OBJECT (self));
8988 clutter_actor_store_old_geometry (self, &old);
8990 info->minimum.height = min_height;
8991 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8992 clutter_actor_set_min_height_set (self, TRUE);
8994 clutter_actor_notify_if_geometry_changed (self, &old);
8996 g_object_thaw_notify (G_OBJECT (self));
8998 clutter_actor_queue_relayout (self);
9002 clutter_actor_set_natural_width (ClutterActor *self,
9003 gfloat natural_width)
9005 ClutterActorPrivate *priv = self->priv;
9006 ClutterActorBox old = { 0, };
9007 ClutterLayoutInfo *info;
9009 /* if we are setting the size on a top-level actor and the
9010 * backend only supports static top-levels (e.g. framebuffers)
9011 * then we ignore the passed value and we override it with
9012 * the stage implementation's preferred size.
9014 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9015 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9018 info = _clutter_actor_get_layout_info (self);
9020 if (priv->natural_width_set && natural_width == info->natural.width)
9023 g_object_freeze_notify (G_OBJECT (self));
9025 clutter_actor_store_old_geometry (self, &old);
9027 info->natural.width = natural_width;
9028 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9029 clutter_actor_set_natural_width_set (self, TRUE);
9031 clutter_actor_notify_if_geometry_changed (self, &old);
9033 g_object_thaw_notify (G_OBJECT (self));
9035 clutter_actor_queue_relayout (self);
9039 clutter_actor_set_natural_height (ClutterActor *self,
9040 gfloat natural_height)
9042 ClutterActorPrivate *priv = self->priv;
9043 ClutterActorBox old = { 0, };
9044 ClutterLayoutInfo *info;
9046 /* if we are setting the size on a top-level actor and the
9047 * backend only supports static top-levels (e.g. framebuffers)
9048 * then we ignore the passed value and we override it with
9049 * the stage implementation's preferred size.
9051 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9052 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9055 info = _clutter_actor_get_layout_info (self);
9057 if (priv->natural_height_set && natural_height == info->natural.height)
9060 g_object_freeze_notify (G_OBJECT (self));
9062 clutter_actor_store_old_geometry (self, &old);
9064 info->natural.height = natural_height;
9065 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9066 clutter_actor_set_natural_height_set (self, TRUE);
9068 clutter_actor_notify_if_geometry_changed (self, &old);
9070 g_object_thaw_notify (G_OBJECT (self));
9072 clutter_actor_queue_relayout (self);
9076 clutter_actor_set_min_width_set (ClutterActor *self,
9077 gboolean use_min_width)
9079 ClutterActorPrivate *priv = self->priv;
9080 ClutterActorBox old = { 0, };
9082 if (priv->min_width_set == (use_min_width != FALSE))
9085 clutter_actor_store_old_geometry (self, &old);
9087 priv->min_width_set = use_min_width != FALSE;
9088 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9090 clutter_actor_notify_if_geometry_changed (self, &old);
9092 clutter_actor_queue_relayout (self);
9096 clutter_actor_set_min_height_set (ClutterActor *self,
9097 gboolean use_min_height)
9099 ClutterActorPrivate *priv = self->priv;
9100 ClutterActorBox old = { 0, };
9102 if (priv->min_height_set == (use_min_height != FALSE))
9105 clutter_actor_store_old_geometry (self, &old);
9107 priv->min_height_set = use_min_height != FALSE;
9108 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9110 clutter_actor_notify_if_geometry_changed (self, &old);
9112 clutter_actor_queue_relayout (self);
9116 clutter_actor_set_natural_width_set (ClutterActor *self,
9117 gboolean use_natural_width)
9119 ClutterActorPrivate *priv = self->priv;
9120 ClutterActorBox old = { 0, };
9122 if (priv->natural_width_set == (use_natural_width != FALSE))
9125 clutter_actor_store_old_geometry (self, &old);
9127 priv->natural_width_set = use_natural_width != FALSE;
9128 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9130 clutter_actor_notify_if_geometry_changed (self, &old);
9132 clutter_actor_queue_relayout (self);
9136 clutter_actor_set_natural_height_set (ClutterActor *self,
9137 gboolean use_natural_height)
9139 ClutterActorPrivate *priv = self->priv;
9140 ClutterActorBox old = { 0, };
9142 if (priv->natural_height_set == (use_natural_height != FALSE))
9145 clutter_actor_store_old_geometry (self, &old);
9147 priv->natural_height_set = use_natural_height != FALSE;
9148 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9150 clutter_actor_notify_if_geometry_changed (self, &old);
9152 clutter_actor_queue_relayout (self);
9156 * clutter_actor_set_request_mode:
9157 * @self: a #ClutterActor
9158 * @mode: the request mode
9160 * Sets the geometry request mode of @self.
9162 * The @mode determines the order for invoking
9163 * clutter_actor_get_preferred_width() and
9164 * clutter_actor_get_preferred_height()
9169 clutter_actor_set_request_mode (ClutterActor *self,
9170 ClutterRequestMode mode)
9172 ClutterActorPrivate *priv;
9174 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9178 if (priv->request_mode == mode)
9181 priv->request_mode = mode;
9183 priv->needs_width_request = TRUE;
9184 priv->needs_height_request = TRUE;
9186 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9188 clutter_actor_queue_relayout (self);
9192 * clutter_actor_get_request_mode:
9193 * @self: a #ClutterActor
9195 * Retrieves the geometry request mode of @self
9197 * Return value: the request mode for the actor
9202 clutter_actor_get_request_mode (ClutterActor *self)
9204 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9205 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9207 return self->priv->request_mode;
9210 /* variant of set_width() without checks and without notification
9211 * freeze+thaw, for internal usage only
9214 clutter_actor_set_width_internal (ClutterActor *self,
9219 /* the Stage will use the :min-width to control the minimum
9220 * width to be resized to, so we should not be setting it
9221 * along with the :natural-width
9223 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9224 clutter_actor_set_min_width (self, width);
9226 clutter_actor_set_natural_width (self, width);
9230 /* we only unset the :natural-width for the Stage */
9231 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9232 clutter_actor_set_min_width_set (self, FALSE);
9234 clutter_actor_set_natural_width_set (self, FALSE);
9238 /* variant of set_height() without checks and without notification
9239 * freeze+thaw, for internal usage only
9242 clutter_actor_set_height_internal (ClutterActor *self,
9247 /* see the comment above in set_width_internal() */
9248 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9249 clutter_actor_set_min_height (self, height);
9251 clutter_actor_set_natural_height (self, height);
9255 /* see the comment above in set_width_internal() */
9256 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9257 clutter_actor_set_min_height_set (self, FALSE);
9259 clutter_actor_set_natural_height_set (self, FALSE);
9264 clutter_actor_set_size_internal (ClutterActor *self,
9265 const ClutterSize *size)
9269 clutter_actor_set_width_internal (self, size->width);
9270 clutter_actor_set_height_internal (self, size->height);
9274 clutter_actor_set_width_internal (self, -1);
9275 clutter_actor_set_height_internal (self, -1);
9280 * clutter_actor_set_size:
9281 * @self: A #ClutterActor
9282 * @width: New width of actor in pixels, or -1
9283 * @height: New height of actor in pixels, or -1
9285 * Sets the actor's size request in pixels. This overrides any
9286 * "normal" size request the actor would have. For example
9287 * a text actor might normally request the size of the text;
9288 * this function would force a specific size instead.
9290 * If @width and/or @height are -1 the actor will use its
9291 * "normal" size request instead of overriding it, i.e.
9292 * you can "unset" the size with -1.
9294 * This function sets or unsets both the minimum and natural size.
9297 clutter_actor_set_size (ClutterActor *self,
9301 ClutterSize new_size;
9303 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9305 clutter_size_init (&new_size, width, height);
9307 if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9309 /* minor optimization: if we don't have a duration then we can
9310 * skip the get_size() below, to avoid the chance of going through
9311 * get_preferred_width() and get_preferred_height() just to jump to
9312 * a new desired size
9314 if (clutter_actor_get_easing_duration (self) == 0)
9316 g_object_freeze_notify (G_OBJECT (self));
9318 clutter_actor_set_size_internal (self, &new_size);
9320 g_object_thaw_notify (G_OBJECT (self));
9326 ClutterSize cur_size;
9328 clutter_size_init (&cur_size,
9329 clutter_actor_get_width (self),
9330 clutter_actor_get_height (self));
9332 _clutter_actor_create_transition (self,
9333 obj_props[PROP_SIZE],
9339 _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9341 clutter_actor_queue_relayout (self);
9345 * clutter_actor_get_size:
9346 * @self: A #ClutterActor
9347 * @width: (out) (allow-none): return location for the width, or %NULL.
9348 * @height: (out) (allow-none): return location for the height, or %NULL.
9350 * This function tries to "do what you mean" and return
9351 * the size an actor will have. If the actor has a valid
9352 * allocation, the allocation will be returned; otherwise,
9353 * the actors natural size request will be returned.
9355 * If you care whether you get the request vs. the allocation, you
9356 * should probably call a different function like
9357 * clutter_actor_get_allocation_box() or
9358 * clutter_actor_get_preferred_width().
9363 clutter_actor_get_size (ClutterActor *self,
9367 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9370 *width = clutter_actor_get_width (self);
9373 *height = clutter_actor_get_height (self);
9377 * clutter_actor_get_position:
9378 * @self: a #ClutterActor
9379 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9380 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9382 * This function tries to "do what you mean" and tell you where the
9383 * actor is, prior to any transformations. Retrieves the fixed
9384 * position of an actor in pixels, if one has been set; otherwise, if
9385 * the allocation is valid, returns the actor's allocated position;
9386 * otherwise, returns 0,0.
9388 * The returned position is in pixels.
9393 clutter_actor_get_position (ClutterActor *self,
9397 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9400 *x = clutter_actor_get_x (self);
9403 *y = clutter_actor_get_y (self);
9407 * clutter_actor_get_transformed_position:
9408 * @self: A #ClutterActor
9409 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9410 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9412 * Gets the absolute position of an actor, in pixels relative to the stage.
9417 clutter_actor_get_transformed_position (ClutterActor *self,
9424 v1.x = v1.y = v1.z = 0;
9425 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9435 * clutter_actor_get_transformed_size:
9436 * @self: A #ClutterActor
9437 * @width: (out) (allow-none): return location for the width, or %NULL
9438 * @height: (out) (allow-none): return location for the height, or %NULL
9440 * Gets the absolute size of an actor in pixels, taking into account the
9443 * If the actor has a valid allocation, the allocated size will be used.
9444 * If the actor has not a valid allocation then the preferred size will
9445 * be transformed and returned.
9447 * If you want the transformed allocation, see
9448 * clutter_actor_get_abs_allocation_vertices() instead.
9450 * <note>When the actor (or one of its ancestors) is rotated around the
9451 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9452 * as a generic quadrangle; in that case this function returns the size
9453 * of the smallest rectangle that encapsulates the entire quad. Please
9454 * note that in this case no assumptions can be made about the relative
9455 * position of this envelope to the absolute position of the actor, as
9456 * returned by clutter_actor_get_transformed_position(); if you need this
9457 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9458 * to get the coords of the actual quadrangle.</note>
9463 clutter_actor_get_transformed_size (ClutterActor *self,
9467 ClutterActorPrivate *priv;
9469 gfloat x_min, x_max, y_min, y_max;
9472 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9476 /* if the actor hasn't been allocated yet, get the preferred
9477 * size and transform that
9479 if (priv->needs_allocation)
9481 gfloat natural_width, natural_height;
9482 ClutterActorBox box;
9484 /* Make a fake allocation to transform.
9486 * NB: _clutter_actor_transform_and_project_box expects a box in
9487 * the actor's coordinate space... */
9492 natural_width = natural_height = 0;
9493 clutter_actor_get_preferred_size (self, NULL, NULL,
9497 box.x2 = natural_width;
9498 box.y2 = natural_height;
9500 _clutter_actor_transform_and_project_box (self, &box, v);
9503 clutter_actor_get_abs_allocation_vertices (self, v);
9505 x_min = x_max = v[0].x;
9506 y_min = y_max = v[0].y;
9508 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9524 *width = x_max - x_min;
9527 *height = y_max - y_min;
9531 * clutter_actor_get_width:
9532 * @self: A #ClutterActor
9534 * Retrieves the width of a #ClutterActor.
9536 * If the actor has a valid allocation, this function will return the
9537 * width of the allocated area given to the actor.
9539 * If the actor does not have a valid allocation, this function will
9540 * return the actor's natural width, that is the preferred width of
9543 * If you care whether you get the preferred width or the width that
9544 * has been assigned to the actor, you should probably call a different
9545 * function like clutter_actor_get_allocation_box() to retrieve the
9546 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9549 * If an actor has a fixed width, for instance a width that has been
9550 * assigned using clutter_actor_set_width(), the width returned will
9551 * be the same value.
9553 * Return value: the width of the actor, in pixels
9556 clutter_actor_get_width (ClutterActor *self)
9558 ClutterActorPrivate *priv;
9560 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9564 if (priv->needs_allocation)
9566 gfloat natural_width = 0;
9568 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9569 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9572 gfloat natural_height = 0;
9574 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9575 clutter_actor_get_preferred_width (self, natural_height,
9580 return natural_width;
9583 return priv->allocation.x2 - priv->allocation.x1;
9587 * clutter_actor_get_height:
9588 * @self: A #ClutterActor
9590 * Retrieves the height of a #ClutterActor.
9592 * If the actor has a valid allocation, this function will return the
9593 * height of the allocated area given to the actor.
9595 * If the actor does not have a valid allocation, this function will
9596 * return the actor's natural height, that is the preferred height of
9599 * If you care whether you get the preferred height or the height that
9600 * has been assigned to the actor, you should probably call a different
9601 * function like clutter_actor_get_allocation_box() to retrieve the
9602 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9605 * If an actor has a fixed height, for instance a height that has been
9606 * assigned using clutter_actor_set_height(), the height returned will
9607 * be the same value.
9609 * Return value: the height of the actor, in pixels
9612 clutter_actor_get_height (ClutterActor *self)
9614 ClutterActorPrivate *priv;
9616 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9620 if (priv->needs_allocation)
9622 gfloat natural_height = 0;
9624 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9626 gfloat natural_width = 0;
9628 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9629 clutter_actor_get_preferred_height (self, natural_width,
9630 NULL, &natural_height);
9633 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9635 return natural_height;
9638 return priv->allocation.y2 - priv->allocation.y1;
9642 * clutter_actor_set_width:
9643 * @self: A #ClutterActor
9644 * @width: Requested new width for the actor, in pixels, or -1
9646 * Forces a width on an actor, causing the actor's preferred width
9647 * and height (if any) to be ignored.
9649 * If @width is -1 the actor will use its preferred width request
9650 * instead of overriding it, i.e. you can "unset" the width with -1.
9652 * This function sets both the minimum and natural size of the actor.
9657 clutter_actor_set_width (ClutterActor *self,
9660 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9662 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9666 /* minor optimization: if we don't have a duration
9667 * then we can skip the get_width() below, to avoid
9668 * the chance of going through get_preferred_width()
9669 * just to jump to a new desired width.
9671 if (clutter_actor_get_easing_duration (self) == 0)
9673 g_object_freeze_notify (G_OBJECT (self));
9675 clutter_actor_set_width_internal (self, width);
9677 g_object_thaw_notify (G_OBJECT (self));
9682 cur_size = clutter_actor_get_width (self);
9684 _clutter_actor_create_transition (self,
9685 obj_props[PROP_WIDTH],
9690 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9694 * clutter_actor_set_height:
9695 * @self: A #ClutterActor
9696 * @height: Requested new height for the actor, in pixels, or -1
9698 * Forces a height on an actor, causing the actor's preferred width
9699 * and height (if any) to be ignored.
9701 * If @height is -1 the actor will use its preferred height instead of
9702 * overriding it, i.e. you can "unset" the height with -1.
9704 * This function sets both the minimum and natural size of the actor.
9709 clutter_actor_set_height (ClutterActor *self,
9712 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9714 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9718 /* see the comment in clutter_actor_set_width() above */
9719 if (clutter_actor_get_easing_duration (self) == 0)
9721 g_object_freeze_notify (G_OBJECT (self));
9723 clutter_actor_set_height_internal (self, height);
9725 g_object_thaw_notify (G_OBJECT (self));
9730 cur_size = clutter_actor_get_height (self);
9732 _clutter_actor_create_transition (self,
9733 obj_props[PROP_HEIGHT],
9738 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9742 clutter_actor_set_x_internal (ClutterActor *self,
9745 ClutterActorPrivate *priv = self->priv;
9746 ClutterLayoutInfo *linfo;
9747 ClutterActorBox old = { 0, };
9749 linfo = _clutter_actor_get_layout_info (self);
9751 if (priv->position_set && linfo->fixed_pos.x == x)
9754 clutter_actor_store_old_geometry (self, &old);
9756 linfo->fixed_pos.x = x;
9757 clutter_actor_set_fixed_position_set (self, TRUE);
9759 clutter_actor_notify_if_geometry_changed (self, &old);
9761 clutter_actor_queue_relayout (self);
9765 clutter_actor_set_y_internal (ClutterActor *self,
9768 ClutterActorPrivate *priv = self->priv;
9769 ClutterLayoutInfo *linfo;
9770 ClutterActorBox old = { 0, };
9772 linfo = _clutter_actor_get_layout_info (self);
9774 if (priv->position_set && linfo->fixed_pos.y == y)
9777 clutter_actor_store_old_geometry (self, &old);
9779 linfo->fixed_pos.y = y;
9780 clutter_actor_set_fixed_position_set (self, TRUE);
9782 clutter_actor_notify_if_geometry_changed (self, &old);
9784 clutter_actor_queue_relayout (self);
9788 clutter_actor_set_position_internal (ClutterActor *self,
9789 const ClutterPoint *position)
9791 ClutterActorPrivate *priv = self->priv;
9792 ClutterLayoutInfo *linfo;
9793 ClutterActorBox old = { 0, };
9795 linfo = _clutter_actor_get_layout_info (self);
9797 if (priv->position_set &&
9798 clutter_point_equals (position, &linfo->fixed_pos))
9801 clutter_actor_store_old_geometry (self, &old);
9803 if (position != NULL)
9805 linfo->fixed_pos = *position;
9806 clutter_actor_set_fixed_position_set (self, TRUE);
9809 clutter_actor_set_fixed_position_set (self, FALSE);
9811 clutter_actor_notify_if_geometry_changed (self, &old);
9813 clutter_actor_queue_relayout (self);
9817 * clutter_actor_set_x:
9818 * @self: a #ClutterActor
9819 * @x: the actor's position on the X axis
9821 * Sets the actor's X coordinate, relative to its parent, in pixels.
9823 * Overrides any layout manager and forces a fixed position for
9826 * The #ClutterActor:x property is animatable.
9831 clutter_actor_set_x (ClutterActor *self,
9834 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9836 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9838 float cur_position = clutter_actor_get_x (self);
9840 _clutter_actor_create_transition (self, obj_props[PROP_X],
9845 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9849 * clutter_actor_set_y:
9850 * @self: a #ClutterActor
9851 * @y: the actor's position on the Y axis
9853 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9855 * Overrides any layout manager and forces a fixed position for
9858 * The #ClutterActor:y property is animatable.
9863 clutter_actor_set_y (ClutterActor *self,
9866 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9868 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9870 float cur_position = clutter_actor_get_y (self);
9872 _clutter_actor_create_transition (self, obj_props[PROP_Y],
9877 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9881 * clutter_actor_get_x:
9882 * @self: A #ClutterActor
9884 * Retrieves the X coordinate of a #ClutterActor.
9886 * This function tries to "do what you mean", by returning the
9887 * correct value depending on the actor's state.
9889 * If the actor has a valid allocation, this function will return
9890 * the X coordinate of the origin of the allocation box.
9892 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9893 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9894 * function will return that coordinate.
9896 * If both the allocation and a fixed position are missing, this function
9899 * Return value: the X coordinate, in pixels, ignoring any
9900 * transformation (i.e. scaling, rotation)
9903 clutter_actor_get_x (ClutterActor *self)
9905 ClutterActorPrivate *priv;
9907 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9911 if (priv->needs_allocation)
9913 if (priv->position_set)
9915 const ClutterLayoutInfo *info;
9917 info = _clutter_actor_get_layout_info_or_defaults (self);
9919 return info->fixed_pos.x;
9925 return priv->allocation.x1;
9929 * clutter_actor_get_y:
9930 * @self: A #ClutterActor
9932 * Retrieves the Y coordinate of a #ClutterActor.
9934 * This function tries to "do what you mean", by returning the
9935 * correct value depending on the actor's state.
9937 * If the actor has a valid allocation, this function will return
9938 * the Y coordinate of the origin of the allocation box.
9940 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9941 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9942 * function will return that coordinate.
9944 * If both the allocation and a fixed position are missing, this function
9947 * Return value: the Y coordinate, in pixels, ignoring any
9948 * transformation (i.e. scaling, rotation)
9951 clutter_actor_get_y (ClutterActor *self)
9953 ClutterActorPrivate *priv;
9955 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9959 if (priv->needs_allocation)
9961 if (priv->position_set)
9963 const ClutterLayoutInfo *info;
9965 info = _clutter_actor_get_layout_info_or_defaults (self);
9967 return info->fixed_pos.y;
9973 return priv->allocation.y1;
9977 * clutter_actor_set_scale:
9978 * @self: A #ClutterActor
9979 * @scale_x: double factor to scale actor by horizontally.
9980 * @scale_y: double factor to scale actor by vertically.
9982 * Scales an actor with the given factors. The scaling is relative to
9983 * the scale center and the anchor point. The scale center is
9984 * unchanged by this function and defaults to 0,0.
9986 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9992 clutter_actor_set_scale (ClutterActor *self,
9996 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9998 g_object_freeze_notify (G_OBJECT (self));
10000 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10001 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10003 g_object_thaw_notify (G_OBJECT (self));
10007 * clutter_actor_set_scale_full:
10008 * @self: A #ClutterActor
10009 * @scale_x: double factor to scale actor by horizontally.
10010 * @scale_y: double factor to scale actor by vertically.
10011 * @center_x: X coordinate of the center of the scale.
10012 * @center_y: Y coordinate of the center of the scale
10014 * Scales an actor with the given factors around the given center
10015 * point. The center point is specified in pixels relative to the
10016 * anchor point (usually the top left corner of the actor).
10018 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10024 clutter_actor_set_scale_full (ClutterActor *self,
10030 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10032 g_object_freeze_notify (G_OBJECT (self));
10034 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10035 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10036 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10037 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10039 g_object_thaw_notify (G_OBJECT (self));
10043 * clutter_actor_set_scale_with_gravity:
10044 * @self: A #ClutterActor
10045 * @scale_x: double factor to scale actor by horizontally.
10046 * @scale_y: double factor to scale actor by vertically.
10047 * @gravity: the location of the scale center expressed as a compass
10050 * Scales an actor with the given factors around the given
10051 * center point. The center point is specified as one of the compass
10052 * directions in #ClutterGravity. For example, setting it to north
10053 * will cause the top of the actor to remain unchanged and the rest of
10054 * the actor to expand left, right and downwards.
10056 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10062 clutter_actor_set_scale_with_gravity (ClutterActor *self,
10065 ClutterGravity gravity)
10067 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10069 g_object_freeze_notify (G_OBJECT (self));
10071 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10072 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10073 clutter_actor_set_scale_gravity (self, gravity);
10075 g_object_thaw_notify (G_OBJECT (self));
10079 * clutter_actor_get_scale:
10080 * @self: A #ClutterActor
10081 * @scale_x: (out) (allow-none): Location to store horizonal
10082 * scale factor, or %NULL.
10083 * @scale_y: (out) (allow-none): Location to store vertical
10084 * scale factor, or %NULL.
10086 * Retrieves an actors scale factors.
10091 clutter_actor_get_scale (ClutterActor *self,
10095 const ClutterTransformInfo *info;
10097 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10099 info = _clutter_actor_get_transform_info_or_defaults (self);
10102 *scale_x = info->scale_x;
10105 *scale_y = info->scale_y;
10109 * clutter_actor_get_scale_center:
10110 * @self: A #ClutterActor
10111 * @center_x: (out) (allow-none): Location to store the X position
10112 * of the scale center, or %NULL.
10113 * @center_y: (out) (allow-none): Location to store the Y position
10114 * of the scale center, or %NULL.
10116 * Retrieves the scale center coordinate in pixels relative to the top
10117 * left corner of the actor. If the scale center was specified using a
10118 * #ClutterGravity this will calculate the pixel offset using the
10119 * current size of the actor.
10124 clutter_actor_get_scale_center (ClutterActor *self,
10128 const ClutterTransformInfo *info;
10130 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10132 info = _clutter_actor_get_transform_info_or_defaults (self);
10134 clutter_anchor_coord_get_units (self, &info->scale_center,
10141 * clutter_actor_get_scale_gravity:
10142 * @self: A #ClutterActor
10144 * Retrieves the scale center as a compass direction. If the scale
10145 * center was specified in pixels or units this will return
10146 * %CLUTTER_GRAVITY_NONE.
10148 * Return value: the scale gravity
10153 clutter_actor_get_scale_gravity (ClutterActor *self)
10155 const ClutterTransformInfo *info;
10157 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10159 info = _clutter_actor_get_transform_info_or_defaults (self);
10161 return clutter_anchor_coord_get_gravity (&info->scale_center);
10165 clutter_actor_set_opacity_internal (ClutterActor *self,
10168 ClutterActorPrivate *priv = self->priv;
10170 if (priv->opacity != opacity)
10172 priv->opacity = opacity;
10174 /* Queue a redraw from the flatten effect so that it can use
10175 its cached image if available instead of having to redraw the
10176 actual actor. If it doesn't end up using the FBO then the
10177 effect is still able to continue the paint anyway. If there
10178 is no flatten effect yet then this is equivalent to queueing
10180 _clutter_actor_queue_redraw_full (self,
10183 priv->flatten_effect);
10185 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10190 * clutter_actor_set_opacity:
10191 * @self: A #ClutterActor
10192 * @opacity: New opacity value for the actor.
10194 * Sets the actor's opacity, with zero being completely transparent and
10195 * 255 (0xff) being fully opaque.
10197 * The #ClutterActor:opacity property is animatable.
10200 clutter_actor_set_opacity (ClutterActor *self,
10203 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10205 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10207 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10208 self->priv->opacity,
10212 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10216 * clutter_actor_get_paint_opacity_internal:
10217 * @self: a #ClutterActor
10219 * Retrieves the absolute opacity of the actor, as it appears on the stage
10221 * This function does not do type checks
10223 * Return value: the absolute opacity of the actor
10226 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10228 ClutterActorPrivate *priv = self->priv;
10229 ClutterActor *parent;
10231 /* override the top-level opacity to always be 255; even in
10232 * case of ClutterStage:use-alpha being TRUE we want the rest
10233 * of the scene to be painted
10235 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10238 if (priv->opacity_override >= 0)
10239 return priv->opacity_override;
10241 parent = priv->parent;
10243 /* Factor in the actual actors opacity with parents */
10244 if (parent != NULL)
10246 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10248 if (opacity != 0xff)
10249 return (opacity * priv->opacity) / 0xff;
10252 return priv->opacity;
10257 * clutter_actor_get_paint_opacity:
10258 * @self: A #ClutterActor
10260 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10262 * This function traverses the hierarchy chain and composites the opacity of
10263 * the actor with that of its parents.
10265 * This function is intended for subclasses to use in the paint virtual
10266 * function, to paint themselves with the correct opacity.
10268 * Return value: The actor opacity value.
10273 clutter_actor_get_paint_opacity (ClutterActor *self)
10275 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10277 return clutter_actor_get_paint_opacity_internal (self);
10281 * clutter_actor_get_opacity:
10282 * @self: a #ClutterActor
10284 * Retrieves the opacity value of an actor, as set by
10285 * clutter_actor_set_opacity().
10287 * For retrieving the absolute opacity of the actor inside a paint
10288 * virtual function, see clutter_actor_get_paint_opacity().
10290 * Return value: the opacity of the actor
10293 clutter_actor_get_opacity (ClutterActor *self)
10295 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10297 return self->priv->opacity;
10301 * clutter_actor_set_offscreen_redirect:
10302 * @self: A #ClutterActor
10303 * @redirect: New offscreen redirect flags for the actor.
10305 * Defines the circumstances where the actor should be redirected into
10306 * an offscreen image. The offscreen image is used to flatten the
10307 * actor into a single image while painting for two main reasons.
10308 * Firstly, when the actor is painted a second time without any of its
10309 * contents changing it can simply repaint the cached image without
10310 * descending further down the actor hierarchy. Secondly, it will make
10311 * the opacity look correct even if there are overlapping primitives
10314 * Caching the actor could in some cases be a performance win and in
10315 * some cases be a performance lose so it is important to determine
10316 * which value is right for an actor before modifying this value. For
10317 * example, there is never any reason to flatten an actor that is just
10318 * a single texture (such as a #ClutterTexture) because it is
10319 * effectively already cached in an image so the offscreen would be
10320 * redundant. Also if the actor contains primitives that are far apart
10321 * with a large transparent area in the middle (such as a large
10322 * CluterGroup with a small actor in the top left and a small actor in
10323 * the bottom right) then the cached image will contain the entire
10324 * image of the large area and the paint will waste time blending all
10325 * of the transparent pixels in the middle.
10327 * The default method of implementing opacity on a container simply
10328 * forwards on the opacity to all of the children. If the children are
10329 * overlapping then it will appear as if they are two separate glassy
10330 * objects and there will be a break in the color where they
10331 * overlap. By redirecting to an offscreen buffer it will be as if the
10332 * two opaque objects are combined into one and then made transparent
10333 * which is usually what is expected.
10335 * The image below demonstrates the difference between redirecting and
10336 * not. The image shows two Clutter groups, each containing a red and
10337 * a green rectangle which overlap. The opacity on the group is set to
10338 * 128 (which is 50%). When the offscreen redirect is not used, the
10339 * red rectangle can be seen through the blue rectangle as if the two
10340 * rectangles were separately transparent. When the redirect is used
10341 * the group as a whole is transparent instead so the red rectangle is
10342 * not visible where they overlap.
10344 * <figure id="offscreen-redirect">
10345 * <title>Sample of using an offscreen redirect for transparency</title>
10346 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10349 * The default value for this property is 0, so we effectively will
10350 * never redirect an actor offscreen by default. This means that there
10351 * are times that transparent actors may look glassy as described
10352 * above. The reason this is the default is because there is a
10353 * performance trade off between quality and performance here. In many
10354 * cases the default form of glassy opacity looks good enough, but if
10355 * it's not you will need to set the
10356 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10357 * redirection for opacity.
10359 * Custom actors that don't contain any overlapping primitives are
10360 * recommended to override the has_overlaps() virtual to return %FALSE
10361 * for maximum efficiency.
10366 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10367 ClutterOffscreenRedirect redirect)
10369 ClutterActorPrivate *priv;
10371 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10375 if (priv->offscreen_redirect != redirect)
10377 priv->offscreen_redirect = redirect;
10379 /* Queue a redraw from the effect so that it can use its cached
10380 image if available instead of having to redraw the actual
10381 actor. If it doesn't end up using the FBO then the effect is
10382 still able to continue the paint anyway. If there is no
10383 effect then this is equivalent to queuing a full redraw */
10384 _clutter_actor_queue_redraw_full (self,
10387 priv->flatten_effect);
10389 g_object_notify_by_pspec (G_OBJECT (self),
10390 obj_props[PROP_OFFSCREEN_REDIRECT]);
10395 * clutter_actor_get_offscreen_redirect:
10396 * @self: a #ClutterActor
10398 * Retrieves whether to redirect the actor to an offscreen buffer, as
10399 * set by clutter_actor_set_offscreen_redirect().
10401 * Return value: the value of the offscreen-redirect property of the actor
10405 ClutterOffscreenRedirect
10406 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10408 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10410 return self->priv->offscreen_redirect;
10414 * clutter_actor_set_name:
10415 * @self: A #ClutterActor
10416 * @name: Textual tag to apply to actor
10418 * Sets the given name to @self. The name can be used to identify
10422 clutter_actor_set_name (ClutterActor *self,
10425 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10427 g_free (self->priv->name);
10428 self->priv->name = g_strdup (name);
10430 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10434 * clutter_actor_get_name:
10435 * @self: A #ClutterActor
10437 * Retrieves the name of @self.
10439 * Return value: the name of the actor, or %NULL. The returned string is
10440 * owned by the actor and should not be modified or freed.
10443 clutter_actor_get_name (ClutterActor *self)
10445 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10447 return self->priv->name;
10451 * clutter_actor_get_gid:
10452 * @self: A #ClutterActor
10454 * Retrieves the unique id for @self.
10456 * Return value: Globally unique value for this object instance.
10460 * Deprecated: 1.8: The id is not used any longer.
10463 clutter_actor_get_gid (ClutterActor *self)
10465 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10467 return self->priv->id;
10471 clutter_actor_set_depth_internal (ClutterActor *self,
10474 ClutterTransformInfo *info;
10476 info = _clutter_actor_get_transform_info (self);
10478 if (info->depth != depth)
10480 /* Sets Z value - XXX 2.0: should we invert? */
10481 info->depth = depth;
10483 self->priv->transform_valid = FALSE;
10485 /* FIXME - remove this crap; sadly, there are still containers
10486 * in Clutter that depend on this utter brain damage
10488 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10490 clutter_actor_queue_redraw (self);
10492 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10497 * clutter_actor_set_depth:
10498 * @self: a #ClutterActor
10501 * Sets the Z coordinate of @self to @depth.
10503 * The unit used by @depth is dependant on the perspective setup. See
10504 * also clutter_stage_set_perspective().
10507 clutter_actor_set_depth (ClutterActor *self,
10510 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10512 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10514 const ClutterTransformInfo *info;
10516 info = _clutter_actor_get_transform_info_or_defaults (self);
10518 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10523 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10525 clutter_actor_queue_redraw (self);
10529 * clutter_actor_get_depth:
10530 * @self: a #ClutterActor
10532 * Retrieves the depth of @self.
10534 * Return value: the depth of the actor
10537 clutter_actor_get_depth (ClutterActor *self)
10539 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10541 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10545 * clutter_actor_set_rotation:
10546 * @self: a #ClutterActor
10547 * @axis: the axis of rotation
10548 * @angle: the angle of rotation
10549 * @x: X coordinate of the rotation center
10550 * @y: Y coordinate of the rotation center
10551 * @z: Z coordinate of the rotation center
10553 * Sets the rotation angle of @self around the given axis.
10555 * The rotation center coordinates used depend on the value of @axis:
10557 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10558 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10559 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10562 * The rotation coordinates are relative to the anchor point of the
10563 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10564 * point is set, the upper left corner is assumed as the origin.
10569 clutter_actor_set_rotation (ClutterActor *self,
10570 ClutterRotateAxis axis,
10578 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10584 g_object_freeze_notify (G_OBJECT (self));
10586 clutter_actor_set_rotation_angle (self, axis, angle);
10587 clutter_actor_set_rotation_center_internal (self, axis, &v);
10589 g_object_thaw_notify (G_OBJECT (self));
10593 * clutter_actor_set_z_rotation_from_gravity:
10594 * @self: a #ClutterActor
10595 * @angle: the angle of rotation
10596 * @gravity: the center point of the rotation
10598 * Sets the rotation angle of @self around the Z axis using the center
10599 * point specified as a compass point. For example to rotate such that
10600 * the center of the actor remains static you can use
10601 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10602 * will move accordingly.
10607 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10609 ClutterGravity gravity)
10611 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10613 if (gravity == CLUTTER_GRAVITY_NONE)
10614 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10617 GObject *obj = G_OBJECT (self);
10618 ClutterTransformInfo *info;
10620 info = _clutter_actor_get_transform_info (self);
10622 g_object_freeze_notify (obj);
10624 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10626 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10627 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10628 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10630 g_object_thaw_notify (obj);
10635 * clutter_actor_get_rotation:
10636 * @self: a #ClutterActor
10637 * @axis: the axis of rotation
10638 * @x: (out): return value for the X coordinate of the center of rotation
10639 * @y: (out): return value for the Y coordinate of the center of rotation
10640 * @z: (out): return value for the Z coordinate of the center of rotation
10642 * Retrieves the angle and center of rotation on the given axis,
10643 * set using clutter_actor_set_rotation().
10645 * Return value: the angle of rotation
10650 clutter_actor_get_rotation (ClutterActor *self,
10651 ClutterRotateAxis axis,
10656 const ClutterTransformInfo *info;
10657 const AnchorCoord *anchor_coord;
10658 gdouble retval = 0;
10660 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10662 info = _clutter_actor_get_transform_info_or_defaults (self);
10666 case CLUTTER_X_AXIS:
10667 anchor_coord = &info->rx_center;
10668 retval = info->rx_angle;
10671 case CLUTTER_Y_AXIS:
10672 anchor_coord = &info->ry_center;
10673 retval = info->ry_angle;
10676 case CLUTTER_Z_AXIS:
10677 anchor_coord = &info->rz_center;
10678 retval = info->rz_angle;
10682 anchor_coord = NULL;
10687 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10693 * clutter_actor_get_z_rotation_gravity:
10694 * @self: A #ClutterActor
10696 * Retrieves the center for the rotation around the Z axis as a
10697 * compass direction. If the center was specified in pixels or units
10698 * this will return %CLUTTER_GRAVITY_NONE.
10700 * Return value: the Z rotation center
10705 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10707 const ClutterTransformInfo *info;
10709 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10711 info = _clutter_actor_get_transform_info_or_defaults (self);
10713 return clutter_anchor_coord_get_gravity (&info->rz_center);
10717 * clutter_actor_set_clip:
10718 * @self: A #ClutterActor
10719 * @xoff: X offset of the clip rectangle
10720 * @yoff: Y offset of the clip rectangle
10721 * @width: Width of the clip rectangle
10722 * @height: Height of the clip rectangle
10724 * Sets clip area for @self. The clip area is always computed from the
10725 * upper left corner of the actor, even if the anchor point is set
10731 clutter_actor_set_clip (ClutterActor *self,
10737 ClutterActorPrivate *priv;
10739 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10743 if (priv->has_clip &&
10744 priv->clip.x == xoff &&
10745 priv->clip.y == yoff &&
10746 priv->clip.width == width &&
10747 priv->clip.height == height)
10750 priv->clip.x = xoff;
10751 priv->clip.y = yoff;
10752 priv->clip.width = width;
10753 priv->clip.height = height;
10755 priv->has_clip = TRUE;
10757 clutter_actor_queue_redraw (self);
10759 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10760 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10764 * clutter_actor_remove_clip:
10765 * @self: A #ClutterActor
10767 * Removes clip area from @self.
10770 clutter_actor_remove_clip (ClutterActor *self)
10772 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10774 if (!self->priv->has_clip)
10777 self->priv->has_clip = FALSE;
10779 clutter_actor_queue_redraw (self);
10781 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10785 * clutter_actor_has_clip:
10786 * @self: a #ClutterActor
10788 * Determines whether the actor has a clip area set or not.
10790 * Return value: %TRUE if the actor has a clip area set.
10795 clutter_actor_has_clip (ClutterActor *self)
10797 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10799 return self->priv->has_clip;
10803 * clutter_actor_get_clip:
10804 * @self: a #ClutterActor
10805 * @xoff: (out) (allow-none): return location for the X offset of
10806 * the clip rectangle, or %NULL
10807 * @yoff: (out) (allow-none): return location for the Y offset of
10808 * the clip rectangle, or %NULL
10809 * @width: (out) (allow-none): return location for the width of
10810 * the clip rectangle, or %NULL
10811 * @height: (out) (allow-none): return location for the height of
10812 * the clip rectangle, or %NULL
10814 * Gets the clip area for @self, if any is set
10819 clutter_actor_get_clip (ClutterActor *self,
10825 ClutterActorPrivate *priv;
10827 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10831 if (!priv->has_clip)
10835 *xoff = priv->clip.x;
10838 *yoff = priv->clip.y;
10841 *width = priv->clip.width;
10843 if (height != NULL)
10844 *height = priv->clip.height;
10848 * clutter_actor_get_children:
10849 * @self: a #ClutterActor
10851 * Retrieves the list of children of @self.
10853 * Return value: (transfer container) (element-type ClutterActor): A newly
10854 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10860 clutter_actor_get_children (ClutterActor *self)
10862 ClutterActor *iter;
10865 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10867 /* we walk the list backward so that we can use prepend(),
10870 for (iter = self->priv->last_child, res = NULL;
10872 iter = iter->priv->prev_sibling)
10874 res = g_list_prepend (res, iter);
10881 * insert_child_at_depth:
10882 * @self: a #ClutterActor
10883 * @child: a #ClutterActor
10885 * Inserts @child inside the list of children held by @self, using
10886 * the depth as the insertion criteria.
10888 * This sadly makes the insertion not O(1), but we can keep the
10889 * list sorted so that the painters algorithm we use for painting
10890 * the children will work correctly.
10893 insert_child_at_depth (ClutterActor *self,
10894 ClutterActor *child,
10895 gpointer dummy G_GNUC_UNUSED)
10897 ClutterActor *iter;
10900 child->priv->parent = self;
10903 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10905 /* special-case the first child */
10906 if (self->priv->n_children == 0)
10908 self->priv->first_child = child;
10909 self->priv->last_child = child;
10911 child->priv->next_sibling = NULL;
10912 child->priv->prev_sibling = NULL;
10917 /* Find the right place to insert the child so that it will still be
10918 sorted and the child will be after all of the actors at the same
10920 for (iter = self->priv->first_child;
10922 iter = iter->priv->next_sibling)
10927 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10929 if (iter_depth > child_depth)
10935 ClutterActor *tmp = iter->priv->prev_sibling;
10938 tmp->priv->next_sibling = child;
10940 /* Insert the node before the found one */
10941 child->priv->prev_sibling = iter->priv->prev_sibling;
10942 child->priv->next_sibling = iter;
10943 iter->priv->prev_sibling = child;
10947 ClutterActor *tmp = self->priv->last_child;
10950 tmp->priv->next_sibling = child;
10952 /* insert the node at the end of the list */
10953 child->priv->prev_sibling = self->priv->last_child;
10954 child->priv->next_sibling = NULL;
10957 if (child->priv->prev_sibling == NULL)
10958 self->priv->first_child = child;
10960 if (child->priv->next_sibling == NULL)
10961 self->priv->last_child = child;
10965 insert_child_at_index (ClutterActor *self,
10966 ClutterActor *child,
10969 gint index_ = GPOINTER_TO_INT (data_);
10971 child->priv->parent = self;
10975 ClutterActor *tmp = self->priv->first_child;
10978 tmp->priv->prev_sibling = child;
10980 child->priv->prev_sibling = NULL;
10981 child->priv->next_sibling = tmp;
10983 else if (index_ < 0 || index_ >= self->priv->n_children)
10985 ClutterActor *tmp = self->priv->last_child;
10988 tmp->priv->next_sibling = child;
10990 child->priv->prev_sibling = tmp;
10991 child->priv->next_sibling = NULL;
10995 ClutterActor *iter;
10998 for (iter = self->priv->first_child, i = 0;
11000 iter = iter->priv->next_sibling, i += 1)
11004 ClutterActor *tmp = iter->priv->prev_sibling;
11006 child->priv->prev_sibling = tmp;
11007 child->priv->next_sibling = iter;
11009 iter->priv->prev_sibling = child;
11012 tmp->priv->next_sibling = child;
11019 if (child->priv->prev_sibling == NULL)
11020 self->priv->first_child = child;
11022 if (child->priv->next_sibling == NULL)
11023 self->priv->last_child = child;
11027 insert_child_above (ClutterActor *self,
11028 ClutterActor *child,
11031 ClutterActor *sibling = data;
11033 child->priv->parent = self;
11035 if (sibling == NULL)
11036 sibling = self->priv->last_child;
11038 child->priv->prev_sibling = sibling;
11040 if (sibling != NULL)
11042 ClutterActor *tmp = sibling->priv->next_sibling;
11044 child->priv->next_sibling = tmp;
11047 tmp->priv->prev_sibling = child;
11049 sibling->priv->next_sibling = child;
11052 child->priv->next_sibling = NULL;
11054 if (child->priv->prev_sibling == NULL)
11055 self->priv->first_child = child;
11057 if (child->priv->next_sibling == NULL)
11058 self->priv->last_child = child;
11062 insert_child_below (ClutterActor *self,
11063 ClutterActor *child,
11066 ClutterActor *sibling = data;
11068 child->priv->parent = self;
11070 if (sibling == NULL)
11071 sibling = self->priv->first_child;
11073 child->priv->next_sibling = sibling;
11075 if (sibling != NULL)
11077 ClutterActor *tmp = sibling->priv->prev_sibling;
11079 child->priv->prev_sibling = tmp;
11082 tmp->priv->next_sibling = child;
11084 sibling->priv->prev_sibling = child;
11087 child->priv->prev_sibling = NULL;
11089 if (child->priv->prev_sibling == NULL)
11090 self->priv->first_child = child;
11092 if (child->priv->next_sibling == NULL)
11093 self->priv->last_child = child;
11096 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11097 ClutterActor *child,
11101 ADD_CHILD_CREATE_META = 1 << 0,
11102 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
11103 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
11104 ADD_CHILD_CHECK_STATE = 1 << 3,
11105 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
11106 ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11108 /* default flags for public API */
11109 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
11110 ADD_CHILD_EMIT_PARENT_SET |
11111 ADD_CHILD_EMIT_ACTOR_ADDED |
11112 ADD_CHILD_CHECK_STATE |
11113 ADD_CHILD_NOTIFY_FIRST_LAST |
11114 ADD_CHILD_SHOW_ON_SET_PARENT,
11116 /* flags for legacy/deprecated API */
11117 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
11118 ADD_CHILD_CHECK_STATE |
11119 ADD_CHILD_NOTIFY_FIRST_LAST |
11120 ADD_CHILD_SHOW_ON_SET_PARENT
11121 } ClutterActorAddChildFlags;
11124 * clutter_actor_add_child_internal:
11125 * @self: a #ClutterActor
11126 * @child: a #ClutterActor
11127 * @flags: control flags for actions
11128 * @add_func: delegate function
11129 * @data: (closure): data to pass to @add_func
11131 * Adds @child to the list of children of @self.
11133 * The actual insertion inside the list is delegated to @add_func: this
11134 * function will just set up the state, perform basic checks, and emit
11137 * The @flags argument is used to perform additional operations.
11140 clutter_actor_add_child_internal (ClutterActor *self,
11141 ClutterActor *child,
11142 ClutterActorAddChildFlags flags,
11143 ClutterActorAddChildFunc add_func,
11146 ClutterTextDirection text_dir;
11147 gboolean create_meta;
11148 gboolean emit_parent_set, emit_actor_added;
11149 gboolean check_state;
11150 gboolean notify_first_last;
11151 gboolean show_on_set_parent;
11152 ClutterActor *old_first_child, *old_last_child;
11154 if (child->priv->parent != NULL)
11156 g_warning ("The actor '%s' already has a parent, '%s'. You must "
11157 "use clutter_actor_remove_child() first.",
11158 _clutter_actor_get_debug_name (child),
11159 _clutter_actor_get_debug_name (child->priv->parent));
11163 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11165 g_warning ("The actor '%s' is a top-level actor, and cannot be "
11166 "a child of another actor.",
11167 _clutter_actor_get_debug_name (child));
11172 /* XXX - this check disallows calling methods that change the stacking
11173 * order within the destruction sequence, by triggering a critical
11174 * warning first, and leaving the actor in an undefined state, which
11175 * then ends up being caught by an assertion.
11177 * the reproducible sequence is:
11179 * - actor gets destroyed;
11180 * - another actor, linked to the first, will try to change the
11181 * stacking order of the first actor;
11182 * - changing the stacking order is a composite operation composed
11183 * by the following steps:
11184 * 1. ref() the child;
11185 * 2. remove_child_internal(), which removes the reference;
11186 * 3. add_child_internal(), which adds a reference;
11187 * - the state of the actor is not changed between (2) and (3), as
11188 * it could be an expensive recomputation;
11189 * - if (3) bails out, then the actor is in an undefined state, but
11191 * - the destruction sequence terminates, but the actor is unparented
11192 * while its state indicates being parented instead.
11193 * - assertion failure.
11195 * the obvious fix would be to decompose each set_child_*_sibling()
11196 * method into proper remove_child()/add_child(), with state validation;
11197 * this may cause excessive work, though, and trigger a cascade of other
11198 * bugs in code that assumes that a change in the stacking order is an
11199 * atomic operation.
11201 * another potential fix is to just remove this check here, and let
11202 * code doing stacking order changes inside the destruction sequence
11203 * of an actor continue doing the work.
11205 * the third fix is to silently bail out early from every
11206 * set_child_*_sibling() and set_child_at_index() method, and avoid
11209 * I have a preference for the second solution, since it involves the
11210 * least amount of work, and the least amount of code duplication.
11212 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11214 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11216 g_warning ("The actor '%s' is currently being destroyed, and "
11217 "cannot be added as a child of another actor.",
11218 _clutter_actor_get_debug_name (child));
11223 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11224 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11225 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11226 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11227 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11228 show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11230 old_first_child = self->priv->first_child;
11231 old_last_child = self->priv->last_child;
11233 g_object_freeze_notify (G_OBJECT (self));
11236 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11238 g_object_ref_sink (child);
11239 child->priv->parent = NULL;
11240 child->priv->next_sibling = NULL;
11241 child->priv->prev_sibling = NULL;
11243 /* delegate the actual insertion */
11244 add_func (self, child, data);
11246 g_assert (child->priv->parent == self);
11248 self->priv->n_children += 1;
11250 self->priv->age += 1;
11252 /* if push_internal() has been called then we automatically set
11253 * the flag on the actor
11255 if (self->priv->internal_child)
11256 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11258 /* clutter_actor_reparent() will emit ::parent-set for us */
11259 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11260 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11264 /* If parent is mapped or realized, we need to also be mapped or
11265 * realized once we're inside the parent.
11267 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11269 /* propagate the parent's text direction to the child */
11270 text_dir = clutter_actor_get_text_direction (self);
11271 clutter_actor_set_text_direction (child, text_dir);
11274 if (show_on_set_parent && child->priv->show_on_set_parent)
11275 clutter_actor_show (child);
11277 if (CLUTTER_ACTOR_IS_MAPPED (child))
11278 clutter_actor_queue_redraw (child);
11280 /* maintain the invariant that if an actor needs layout,
11281 * its parents do as well
11283 if (child->priv->needs_width_request ||
11284 child->priv->needs_height_request ||
11285 child->priv->needs_allocation)
11287 /* we work around the short-circuiting we do
11288 * in clutter_actor_queue_relayout() since we
11289 * want to force a relayout
11291 child->priv->needs_width_request = TRUE;
11292 child->priv->needs_height_request = TRUE;
11293 child->priv->needs_allocation = TRUE;
11295 clutter_actor_queue_relayout (child->priv->parent);
11298 if (emit_actor_added)
11299 g_signal_emit_by_name (self, "actor-added", child);
11301 if (notify_first_last)
11303 if (old_first_child != self->priv->first_child)
11304 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11306 if (old_last_child != self->priv->last_child)
11307 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11310 g_object_thaw_notify (G_OBJECT (self));
11314 * clutter_actor_add_child:
11315 * @self: a #ClutterActor
11316 * @child: a #ClutterActor
11318 * Adds @child to the children of @self.
11320 * This function will acquire a reference on @child that will only
11321 * be released when calling clutter_actor_remove_child().
11323 * This function will take into consideration the #ClutterActor:depth
11324 * of @child, and will keep the list of children sorted.
11326 * This function will emit the #ClutterContainer::actor-added signal
11332 clutter_actor_add_child (ClutterActor *self,
11333 ClutterActor *child)
11335 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11336 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11337 g_return_if_fail (self != child);
11338 g_return_if_fail (child->priv->parent == NULL);
11340 clutter_actor_add_child_internal (self, child,
11341 ADD_CHILD_DEFAULT_FLAGS,
11342 insert_child_at_depth,
11347 * clutter_actor_insert_child_at_index:
11348 * @self: a #ClutterActor
11349 * @child: a #ClutterActor
11350 * @index_: the index
11352 * Inserts @child into the list of children of @self, using the
11353 * given @index_. If @index_ is greater than the number of children
11354 * in @self, or is less than 0, then the new child is added at the end.
11356 * This function will acquire a reference on @child that will only
11357 * be released when calling clutter_actor_remove_child().
11359 * This function will not take into consideration the #ClutterActor:depth
11362 * This function will emit the #ClutterContainer::actor-added signal
11368 clutter_actor_insert_child_at_index (ClutterActor *self,
11369 ClutterActor *child,
11372 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11373 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11374 g_return_if_fail (self != child);
11375 g_return_if_fail (child->priv->parent == NULL);
11377 clutter_actor_add_child_internal (self, child,
11378 ADD_CHILD_DEFAULT_FLAGS,
11379 insert_child_at_index,
11380 GINT_TO_POINTER (index_));
11384 * clutter_actor_insert_child_above:
11385 * @self: a #ClutterActor
11386 * @child: a #ClutterActor
11387 * @sibling: (allow-none): a child of @self, or %NULL
11389 * Inserts @child into the list of children of @self, above another
11390 * child of @self or, if @sibling is %NULL, above all the children
11393 * This function will acquire a reference on @child that will only
11394 * be released when calling clutter_actor_remove_child().
11396 * This function will not take into consideration the #ClutterActor:depth
11399 * This function will emit the #ClutterContainer::actor-added signal
11405 clutter_actor_insert_child_above (ClutterActor *self,
11406 ClutterActor *child,
11407 ClutterActor *sibling)
11409 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11410 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11411 g_return_if_fail (self != child);
11412 g_return_if_fail (child != sibling);
11413 g_return_if_fail (child->priv->parent == NULL);
11414 g_return_if_fail (sibling == NULL ||
11415 (CLUTTER_IS_ACTOR (sibling) &&
11416 sibling->priv->parent == self));
11418 clutter_actor_add_child_internal (self, child,
11419 ADD_CHILD_DEFAULT_FLAGS,
11420 insert_child_above,
11425 * clutter_actor_insert_child_below:
11426 * @self: a #ClutterActor
11427 * @child: a #ClutterActor
11428 * @sibling: (allow-none): a child of @self, or %NULL
11430 * Inserts @child into the list of children of @self, below another
11431 * child of @self or, if @sibling is %NULL, below all the children
11434 * This function will acquire a reference on @child that will only
11435 * be released when calling clutter_actor_remove_child().
11437 * This function will not take into consideration the #ClutterActor:depth
11440 * This function will emit the #ClutterContainer::actor-added signal
11446 clutter_actor_insert_child_below (ClutterActor *self,
11447 ClutterActor *child,
11448 ClutterActor *sibling)
11450 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11451 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11452 g_return_if_fail (self != child);
11453 g_return_if_fail (child != sibling);
11454 g_return_if_fail (child->priv->parent == NULL);
11455 g_return_if_fail (sibling == NULL ||
11456 (CLUTTER_IS_ACTOR (sibling) &&
11457 sibling->priv->parent == self));
11459 clutter_actor_add_child_internal (self, child,
11460 ADD_CHILD_DEFAULT_FLAGS,
11461 insert_child_below,
11466 * clutter_actor_set_parent:
11467 * @self: A #ClutterActor
11468 * @parent: A new #ClutterActor parent
11470 * Sets the parent of @self to @parent.
11472 * This function will result in @parent acquiring a reference on @self,
11473 * eventually by sinking its floating reference first. The reference
11474 * will be released by clutter_actor_unparent().
11476 * This function should only be called by legacy #ClutterActor<!-- -->s
11477 * implementing the #ClutterContainer interface.
11479 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11482 clutter_actor_set_parent (ClutterActor *self,
11483 ClutterActor *parent)
11485 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11486 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11487 g_return_if_fail (self != parent);
11488 g_return_if_fail (self->priv->parent == NULL);
11490 /* as this function will be called inside ClutterContainer::add
11491 * implementations or when building up a composite actor, we have
11492 * to preserve the old behaviour, and not create child meta or
11493 * emit the ::actor-added signal, to avoid recursion or double
11496 clutter_actor_add_child_internal (parent, self,
11497 ADD_CHILD_LEGACY_FLAGS,
11498 insert_child_at_depth,
11503 * clutter_actor_get_parent:
11504 * @self: A #ClutterActor
11506 * Retrieves the parent of @self.
11508 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11509 * if no parent is set
11512 clutter_actor_get_parent (ClutterActor *self)
11514 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11516 return self->priv->parent;
11520 * clutter_actor_get_paint_visibility:
11521 * @self: A #ClutterActor
11523 * Retrieves the 'paint' visibility of an actor recursively checking for non
11526 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11528 * Return Value: %TRUE if the actor is visibile and will be painted.
11533 clutter_actor_get_paint_visibility (ClutterActor *actor)
11535 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11537 return CLUTTER_ACTOR_IS_MAPPED (actor);
11541 * clutter_actor_remove_child:
11542 * @self: a #ClutterActor
11543 * @child: a #ClutterActor
11545 * Removes @child from the children of @self.
11547 * This function will release the reference added by
11548 * clutter_actor_add_child(), so if you want to keep using @child
11549 * you will have to acquire a referenced on it before calling this
11552 * This function will emit the #ClutterContainer::actor-removed
11558 clutter_actor_remove_child (ClutterActor *self,
11559 ClutterActor *child)
11561 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11562 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11563 g_return_if_fail (self != child);
11564 g_return_if_fail (child->priv->parent != NULL);
11565 g_return_if_fail (child->priv->parent == self);
11567 clutter_actor_remove_child_internal (self, child,
11568 REMOVE_CHILD_DEFAULT_FLAGS);
11572 * clutter_actor_remove_all_children:
11573 * @self: a #ClutterActor
11575 * Removes all children of @self.
11577 * This function releases the reference added by inserting a child actor
11578 * in the list of children of @self.
11580 * If the reference count of a child drops to zero, the child will be
11581 * destroyed. If you want to ensure the destruction of all the children
11582 * of @self, use clutter_actor_destroy_all_children().
11587 clutter_actor_remove_all_children (ClutterActor *self)
11589 ClutterActorIter iter;
11591 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11593 if (self->priv->n_children == 0)
11596 g_object_freeze_notify (G_OBJECT (self));
11598 clutter_actor_iter_init (&iter, self);
11599 while (clutter_actor_iter_next (&iter, NULL))
11600 clutter_actor_iter_remove (&iter);
11602 g_object_thaw_notify (G_OBJECT (self));
11605 g_assert (self->priv->first_child == NULL);
11606 g_assert (self->priv->last_child == NULL);
11607 g_assert (self->priv->n_children == 0);
11611 * clutter_actor_destroy_all_children:
11612 * @self: a #ClutterActor
11614 * Destroys all children of @self.
11616 * This function releases the reference added by inserting a child
11617 * actor in the list of children of @self, and ensures that the
11618 * #ClutterActor::destroy signal is emitted on each child of the
11621 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11622 * when its reference count drops to 0; the default handler of the
11623 * #ClutterActor::destroy signal will destroy all the children of an
11624 * actor. This function ensures that all children are destroyed, instead
11625 * of just removed from @self, unlike clutter_actor_remove_all_children()
11626 * which will merely release the reference and remove each child.
11628 * Unless you acquired an additional reference on each child of @self
11629 * prior to calling clutter_actor_remove_all_children() and want to reuse
11630 * the actors, you should use clutter_actor_destroy_all_children() in
11631 * order to make sure that children are destroyed and signal handlers
11632 * are disconnected even in cases where circular references prevent this
11633 * from automatically happening through reference counting alone.
11638 clutter_actor_destroy_all_children (ClutterActor *self)
11640 ClutterActorIter iter;
11642 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11644 if (self->priv->n_children == 0)
11647 g_object_freeze_notify (G_OBJECT (self));
11649 clutter_actor_iter_init (&iter, self);
11650 while (clutter_actor_iter_next (&iter, NULL))
11651 clutter_actor_iter_destroy (&iter);
11653 g_object_thaw_notify (G_OBJECT (self));
11656 g_assert (self->priv->first_child == NULL);
11657 g_assert (self->priv->last_child == NULL);
11658 g_assert (self->priv->n_children == 0);
11661 typedef struct _InsertBetweenData {
11662 ClutterActor *prev_sibling;
11663 ClutterActor *next_sibling;
11664 } InsertBetweenData;
11667 insert_child_between (ClutterActor *self,
11668 ClutterActor *child,
11671 InsertBetweenData *data = data_;
11672 ClutterActor *prev_sibling = data->prev_sibling;
11673 ClutterActor *next_sibling = data->next_sibling;
11675 child->priv->parent = self;
11676 child->priv->prev_sibling = prev_sibling;
11677 child->priv->next_sibling = next_sibling;
11679 if (prev_sibling != NULL)
11680 prev_sibling->priv->next_sibling = child;
11682 if (next_sibling != NULL)
11683 next_sibling->priv->prev_sibling = child;
11685 if (child->priv->prev_sibling == NULL)
11686 self->priv->first_child = child;
11688 if (child->priv->next_sibling == NULL)
11689 self->priv->last_child = child;
11693 * clutter_actor_replace_child:
11694 * @self: a #ClutterActor
11695 * @old_child: the child of @self to replace
11696 * @new_child: the #ClutterActor to replace @old_child
11698 * Replaces @old_child with @new_child in the list of children of @self.
11703 clutter_actor_replace_child (ClutterActor *self,
11704 ClutterActor *old_child,
11705 ClutterActor *new_child)
11707 ClutterActor *prev_sibling, *next_sibling;
11708 InsertBetweenData clos;
11710 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11711 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11712 g_return_if_fail (old_child->priv->parent == self);
11713 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11714 g_return_if_fail (old_child != new_child);
11715 g_return_if_fail (new_child != self);
11716 g_return_if_fail (new_child->priv->parent == NULL);
11718 prev_sibling = old_child->priv->prev_sibling;
11719 next_sibling = old_child->priv->next_sibling;
11720 clutter_actor_remove_child_internal (self, old_child,
11721 REMOVE_CHILD_DEFAULT_FLAGS);
11723 clos.prev_sibling = prev_sibling;
11724 clos.next_sibling = next_sibling;
11725 clutter_actor_add_child_internal (self, new_child,
11726 ADD_CHILD_DEFAULT_FLAGS,
11727 insert_child_between,
11732 * clutter_actor_unparent:
11733 * @self: a #ClutterActor
11735 * Removes the parent of @self.
11737 * This will cause the parent of @self to release the reference
11738 * acquired when calling clutter_actor_set_parent(), so if you
11739 * want to keep @self you will have to acquire a reference of
11740 * your own, through g_object_ref().
11742 * This function should only be called by legacy #ClutterActor<!-- -->s
11743 * implementing the #ClutterContainer interface.
11747 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11750 clutter_actor_unparent (ClutterActor *self)
11752 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11754 if (self->priv->parent == NULL)
11757 clutter_actor_remove_child_internal (self->priv->parent, self,
11758 REMOVE_CHILD_LEGACY_FLAGS);
11762 * clutter_actor_reparent:
11763 * @self: a #ClutterActor
11764 * @new_parent: the new #ClutterActor parent
11766 * Resets the parent actor of @self.
11768 * This function is logically equivalent to calling clutter_actor_unparent()
11769 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11770 * ensures the child is not finalized when unparented, and emits the
11771 * #ClutterActor::parent-set signal only once.
11773 * In reality, calling this function is less useful than it sounds, as some
11774 * application code may rely on changes in the intermediate state between
11775 * removal and addition of the actor from its old parent to the @new_parent.
11776 * Thus, it is strongly encouraged to avoid using this function in application
11781 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11782 * clutter_actor_add_child() instead; remember to take a reference on
11783 * the actor being removed before calling clutter_actor_remove_child()
11784 * to avoid the reference count dropping to zero and the actor being
11788 clutter_actor_reparent (ClutterActor *self,
11789 ClutterActor *new_parent)
11791 ClutterActorPrivate *priv;
11793 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11794 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11795 g_return_if_fail (self != new_parent);
11797 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11799 g_warning ("Cannot set a parent on a toplevel actor");
11803 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11805 g_warning ("Cannot set a parent currently being destroyed");
11811 if (priv->parent != new_parent)
11813 ClutterActor *old_parent;
11815 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11817 old_parent = priv->parent;
11819 g_object_ref (self);
11821 if (old_parent != NULL)
11823 /* go through the Container implementation if this is a regular
11824 * child and not an internal one
11826 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11828 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11830 /* this will have to call unparent() */
11831 clutter_container_remove_actor (parent, self);
11834 clutter_actor_remove_child_internal (old_parent, self,
11835 REMOVE_CHILD_LEGACY_FLAGS);
11838 /* Note, will call set_parent() */
11839 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11840 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11842 clutter_actor_add_child_internal (new_parent, self,
11843 ADD_CHILD_LEGACY_FLAGS,
11844 insert_child_at_depth,
11847 /* we emit the ::parent-set signal once */
11848 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11850 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11852 /* the IN_REPARENT flag suspends state updates */
11853 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11855 g_object_unref (self);
11860 * clutter_actor_contains:
11861 * @self: A #ClutterActor
11862 * @descendant: A #ClutterActor, possibly contained in @self
11864 * Determines if @descendant is contained inside @self (either as an
11865 * immediate child, or as a deeper descendant). If @self and
11866 * @descendant point to the same actor then it will also return %TRUE.
11868 * Return value: whether @descendent is contained within @self
11873 clutter_actor_contains (ClutterActor *self,
11874 ClutterActor *descendant)
11876 ClutterActor *actor;
11878 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11879 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11881 for (actor = descendant; actor; actor = actor->priv->parent)
11889 * clutter_actor_set_child_above_sibling:
11890 * @self: a #ClutterActor
11891 * @child: a #ClutterActor child of @self
11892 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11894 * Sets @child to be above @sibling in the list of children of @self.
11896 * If @sibling is %NULL, @child will be the new last child of @self.
11898 * This function is logically equivalent to removing @child and using
11899 * clutter_actor_insert_child_above(), but it will not emit signals
11900 * or change state on @child.
11905 clutter_actor_set_child_above_sibling (ClutterActor *self,
11906 ClutterActor *child,
11907 ClutterActor *sibling)
11909 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11910 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11911 g_return_if_fail (child->priv->parent == self);
11912 g_return_if_fail (child != sibling);
11913 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11915 if (sibling != NULL)
11916 g_return_if_fail (sibling->priv->parent == self);
11918 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11919 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11920 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11923 /* we don't want to change the state of child, or emit signals, or
11924 * regenerate ChildMeta instances here, but we still want to follow
11925 * the correct sequence of steps encoded in remove_child() and
11926 * add_child(), so that correctness is ensured, and we only go
11927 * through one known code path.
11929 g_object_ref (child);
11930 clutter_actor_remove_child_internal (self, child, 0);
11931 clutter_actor_add_child_internal (self, child,
11932 ADD_CHILD_NOTIFY_FIRST_LAST,
11933 insert_child_above,
11936 clutter_actor_queue_relayout (self);
11940 * clutter_actor_set_child_below_sibling:
11941 * @self: a #ClutterActor
11942 * @child: a #ClutterActor child of @self
11943 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11945 * Sets @child to be below @sibling in the list of children of @self.
11947 * If @sibling is %NULL, @child will be the new first child of @self.
11949 * This function is logically equivalent to removing @self and using
11950 * clutter_actor_insert_child_below(), but it will not emit signals
11951 * or change state on @child.
11956 clutter_actor_set_child_below_sibling (ClutterActor *self,
11957 ClutterActor *child,
11958 ClutterActor *sibling)
11960 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11961 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11962 g_return_if_fail (child->priv->parent == self);
11963 g_return_if_fail (child != sibling);
11964 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11966 if (sibling != NULL)
11967 g_return_if_fail (sibling->priv->parent == self);
11969 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11970 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11971 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11974 /* see the comment in set_child_above_sibling() */
11975 g_object_ref (child);
11976 clutter_actor_remove_child_internal (self, child, 0);
11977 clutter_actor_add_child_internal (self, child,
11978 ADD_CHILD_NOTIFY_FIRST_LAST,
11979 insert_child_below,
11982 clutter_actor_queue_relayout (self);
11986 * clutter_actor_set_child_at_index:
11987 * @self: a #ClutterActor
11988 * @child: a #ClutterActor child of @self
11989 * @index_: the new index for @child
11991 * Changes the index of @child in the list of children of @self.
11993 * This function is logically equivalent to removing @child and
11994 * calling clutter_actor_insert_child_at_index(), but it will not
11995 * emit signals or change state on @child.
12000 clutter_actor_set_child_at_index (ClutterActor *self,
12001 ClutterActor *child,
12004 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12005 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12006 g_return_if_fail (child->priv->parent == self);
12007 g_return_if_fail (index_ <= self->priv->n_children);
12009 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12010 CLUTTER_ACTOR_IN_DESTRUCTION (child))
12013 g_object_ref (child);
12014 clutter_actor_remove_child_internal (self, child, 0);
12015 clutter_actor_add_child_internal (self, child,
12016 ADD_CHILD_NOTIFY_FIRST_LAST,
12017 insert_child_at_index,
12018 GINT_TO_POINTER (index_));
12020 clutter_actor_queue_relayout (self);
12024 * clutter_actor_raise:
12025 * @self: A #ClutterActor
12026 * @below: (allow-none): A #ClutterActor to raise above.
12028 * Puts @self above @below.
12030 * Both actors must have the same parent, and the parent must implement
12031 * the #ClutterContainer interface
12033 * This function calls clutter_container_raise_child() internally.
12035 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12038 clutter_actor_raise (ClutterActor *self,
12039 ClutterActor *below)
12041 ClutterActor *parent;
12043 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12045 parent = clutter_actor_get_parent (self);
12046 if (parent == NULL)
12048 g_warning ("%s: Actor '%s' is not inside a container",
12050 _clutter_actor_get_debug_name (self));
12056 if (parent != clutter_actor_get_parent (below))
12058 g_warning ("%s Actor '%s' is not in the same container as "
12061 _clutter_actor_get_debug_name (self),
12062 _clutter_actor_get_debug_name (below));
12067 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12071 * clutter_actor_lower:
12072 * @self: A #ClutterActor
12073 * @above: (allow-none): A #ClutterActor to lower below
12075 * Puts @self below @above.
12077 * Both actors must have the same parent, and the parent must implement
12078 * the #ClutterContainer interface.
12080 * This function calls clutter_container_lower_child() internally.
12082 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12085 clutter_actor_lower (ClutterActor *self,
12086 ClutterActor *above)
12088 ClutterActor *parent;
12090 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12092 parent = clutter_actor_get_parent (self);
12093 if (parent == NULL)
12095 g_warning ("%s: Actor of type %s is not inside a container",
12097 _clutter_actor_get_debug_name (self));
12103 if (parent != clutter_actor_get_parent (above))
12105 g_warning ("%s: Actor '%s' is not in the same container as "
12108 _clutter_actor_get_debug_name (self),
12109 _clutter_actor_get_debug_name (above));
12114 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12118 * clutter_actor_raise_top:
12119 * @self: A #ClutterActor
12121 * Raises @self to the top.
12123 * This function calls clutter_actor_raise() internally.
12125 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12126 * a %NULL sibling, instead.
12129 clutter_actor_raise_top (ClutterActor *self)
12131 clutter_actor_raise (self, NULL);
12135 * clutter_actor_lower_bottom:
12136 * @self: A #ClutterActor
12138 * Lowers @self to the bottom.
12140 * This function calls clutter_actor_lower() internally.
12142 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12143 * a %NULL sibling, instead.
12146 clutter_actor_lower_bottom (ClutterActor *self)
12148 clutter_actor_lower (self, NULL);
12156 * clutter_actor_event:
12157 * @actor: a #ClutterActor
12158 * @event: a #ClutterEvent
12159 * @capture: TRUE if event in in capture phase, FALSE otherwise.
12161 * This function is used to emit an event on the main stage.
12162 * You should rarely need to use this function, except for
12163 * synthetising events.
12165 * Return value: the return value from the signal emission: %TRUE
12166 * if the actor handled the event, or %FALSE if the event was
12172 clutter_actor_event (ClutterActor *actor,
12173 ClutterEvent *event,
12176 gboolean retval = FALSE;
12177 gint signal_num = -1;
12179 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12180 g_return_val_if_fail (event != NULL, FALSE);
12182 g_object_ref (actor);
12186 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12192 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12196 switch (event->type)
12198 case CLUTTER_NOTHING:
12200 case CLUTTER_BUTTON_PRESS:
12201 signal_num = BUTTON_PRESS_EVENT;
12203 case CLUTTER_BUTTON_RELEASE:
12204 signal_num = BUTTON_RELEASE_EVENT;
12206 case CLUTTER_SCROLL:
12207 signal_num = SCROLL_EVENT;
12209 case CLUTTER_KEY_PRESS:
12210 signal_num = KEY_PRESS_EVENT;
12212 case CLUTTER_KEY_RELEASE:
12213 signal_num = KEY_RELEASE_EVENT;
12215 case CLUTTER_MOTION:
12216 signal_num = MOTION_EVENT;
12218 case CLUTTER_ENTER:
12219 signal_num = ENTER_EVENT;
12221 case CLUTTER_LEAVE:
12222 signal_num = LEAVE_EVENT;
12224 case CLUTTER_DELETE:
12225 case CLUTTER_DESTROY_NOTIFY:
12226 case CLUTTER_CLIENT_MESSAGE:
12232 if (signal_num != -1)
12233 g_signal_emit (actor, actor_signals[signal_num], 0,
12238 g_object_unref (actor);
12244 * clutter_actor_set_reactive:
12245 * @actor: a #ClutterActor
12246 * @reactive: whether the actor should be reactive to events
12248 * Sets @actor as reactive. Reactive actors will receive events.
12253 clutter_actor_set_reactive (ClutterActor *actor,
12256 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12258 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12262 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12264 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12266 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12270 * clutter_actor_get_reactive:
12271 * @actor: a #ClutterActor
12273 * Checks whether @actor is marked as reactive.
12275 * Return value: %TRUE if the actor is reactive
12280 clutter_actor_get_reactive (ClutterActor *actor)
12282 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12284 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12288 * clutter_actor_get_anchor_point:
12289 * @self: a #ClutterActor
12290 * @anchor_x: (out): return location for the X coordinate of the anchor point
12291 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12293 * Gets the current anchor point of the @actor in pixels.
12298 clutter_actor_get_anchor_point (ClutterActor *self,
12302 const ClutterTransformInfo *info;
12304 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12306 info = _clutter_actor_get_transform_info_or_defaults (self);
12307 clutter_anchor_coord_get_units (self, &info->anchor,
12314 * clutter_actor_set_anchor_point:
12315 * @self: a #ClutterActor
12316 * @anchor_x: X coordinate of the anchor point
12317 * @anchor_y: Y coordinate of the anchor point
12319 * Sets an anchor point for @self. The anchor point is a point in the
12320 * coordinate space of an actor to which the actor position within its
12321 * parent is relative; the default is (0, 0), i.e. the top-left corner
12327 clutter_actor_set_anchor_point (ClutterActor *self,
12331 ClutterTransformInfo *info;
12332 ClutterActorPrivate *priv;
12333 gboolean changed = FALSE;
12334 gfloat old_anchor_x, old_anchor_y;
12337 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12339 obj = G_OBJECT (self);
12341 info = _clutter_actor_get_transform_info (self);
12343 g_object_freeze_notify (obj);
12345 clutter_anchor_coord_get_units (self, &info->anchor,
12350 if (info->anchor.is_fractional)
12351 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12353 if (old_anchor_x != anchor_x)
12355 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12359 if (old_anchor_y != anchor_y)
12361 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12365 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12369 priv->transform_valid = FALSE;
12370 clutter_actor_queue_redraw (self);
12373 g_object_thaw_notify (obj);
12377 * clutter_actor_get_anchor_point_gravity:
12378 * @self: a #ClutterActor
12380 * Retrieves the anchor position expressed as a #ClutterGravity. If
12381 * the anchor point was specified using pixels or units this will
12382 * return %CLUTTER_GRAVITY_NONE.
12384 * Return value: the #ClutterGravity used by the anchor point
12389 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12391 const ClutterTransformInfo *info;
12393 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12395 info = _clutter_actor_get_transform_info_or_defaults (self);
12397 return clutter_anchor_coord_get_gravity (&info->anchor);
12401 * clutter_actor_move_anchor_point:
12402 * @self: a #ClutterActor
12403 * @anchor_x: X coordinate of the anchor point
12404 * @anchor_y: Y coordinate of the anchor point
12406 * Sets an anchor point for the actor, and adjusts the actor postion so that
12407 * the relative position of the actor toward its parent remains the same.
12412 clutter_actor_move_anchor_point (ClutterActor *self,
12416 gfloat old_anchor_x, old_anchor_y;
12417 const ClutterTransformInfo *info;
12419 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12421 info = _clutter_actor_get_transform_info (self);
12422 clutter_anchor_coord_get_units (self, &info->anchor,
12427 g_object_freeze_notify (G_OBJECT (self));
12429 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12431 if (self->priv->position_set)
12432 clutter_actor_move_by (self,
12433 anchor_x - old_anchor_x,
12434 anchor_y - old_anchor_y);
12436 g_object_thaw_notify (G_OBJECT (self));
12440 * clutter_actor_move_anchor_point_from_gravity:
12441 * @self: a #ClutterActor
12442 * @gravity: #ClutterGravity.
12444 * Sets an anchor point on the actor based on the given gravity, adjusting the
12445 * actor postion so that its relative position within its parent remains
12448 * Since version 1.0 the anchor point will be stored as a gravity so
12449 * that if the actor changes size then the anchor point will move. For
12450 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12451 * and later double the size of the actor, the anchor point will move
12452 * to the bottom right.
12457 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12458 ClutterGravity gravity)
12460 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12461 const ClutterTransformInfo *info;
12462 ClutterActorPrivate *priv;
12464 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12467 info = _clutter_actor_get_transform_info (self);
12469 g_object_freeze_notify (G_OBJECT (self));
12471 clutter_anchor_coord_get_units (self, &info->anchor,
12475 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12476 clutter_anchor_coord_get_units (self, &info->anchor,
12481 if (priv->position_set)
12482 clutter_actor_move_by (self,
12483 new_anchor_x - old_anchor_x,
12484 new_anchor_y - old_anchor_y);
12486 g_object_thaw_notify (G_OBJECT (self));
12490 * clutter_actor_set_anchor_point_from_gravity:
12491 * @self: a #ClutterActor
12492 * @gravity: #ClutterGravity.
12494 * Sets an anchor point on the actor, based on the given gravity (this is a
12495 * convenience function wrapping clutter_actor_set_anchor_point()).
12497 * Since version 1.0 the anchor point will be stored as a gravity so
12498 * that if the actor changes size then the anchor point will move. For
12499 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12500 * and later double the size of the actor, the anchor point will move
12501 * to the bottom right.
12506 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12507 ClutterGravity gravity)
12509 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12511 if (gravity == CLUTTER_GRAVITY_NONE)
12512 clutter_actor_set_anchor_point (self, 0, 0);
12515 GObject *obj = G_OBJECT (self);
12516 ClutterTransformInfo *info;
12518 g_object_freeze_notify (obj);
12520 info = _clutter_actor_get_transform_info (self);
12521 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12523 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12524 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12525 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12527 self->priv->transform_valid = FALSE;
12529 clutter_actor_queue_redraw (self);
12531 g_object_thaw_notify (obj);
12536 clutter_actor_store_content_box (ClutterActor *self,
12537 const ClutterActorBox *box)
12541 self->priv->content_box = *box;
12542 self->priv->content_box_valid = TRUE;
12545 self->priv->content_box_valid = FALSE;
12547 clutter_actor_queue_redraw (self);
12549 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12553 clutter_container_iface_init (ClutterContainerIface *iface)
12555 /* we don't override anything, as ClutterContainer already has a default
12556 * implementation that we can use, and which calls into our own API.
12571 parse_units (ClutterActor *self,
12572 ParseDimension dimension,
12575 GValue value = G_VALUE_INIT;
12578 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12581 json_node_get_value (node, &value);
12583 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12585 retval = (gfloat) g_value_get_int64 (&value);
12587 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12589 retval = g_value_get_double (&value);
12591 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12593 ClutterUnits units;
12596 res = clutter_units_from_string (&units, g_value_get_string (&value));
12598 retval = clutter_units_to_pixels (&units);
12601 g_warning ("Invalid value '%s': integers, strings or floating point "
12602 "values can be used for the x, y, width and height "
12603 "properties. Valid modifiers for strings are 'px', 'mm', "
12605 g_value_get_string (&value));
12611 g_warning ("Invalid value of type '%s': integers, strings of floating "
12612 "point values can be used for the x, y, width, height "
12613 "anchor-x and anchor-y properties.",
12614 g_type_name (G_VALUE_TYPE (&value)));
12617 g_value_unset (&value);
12623 ClutterRotateAxis axis;
12632 static inline gboolean
12633 parse_rotation_array (ClutterActor *actor,
12635 RotationInfo *info)
12639 if (json_array_get_length (array) != 2)
12643 element = json_array_get_element (array, 0);
12644 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12645 info->angle = json_node_get_double (element);
12650 element = json_array_get_element (array, 1);
12651 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12653 JsonArray *center = json_node_get_array (element);
12655 if (json_array_get_length (center) != 2)
12658 switch (info->axis)
12660 case CLUTTER_X_AXIS:
12661 info->center_y = parse_units (actor, PARSE_Y,
12662 json_array_get_element (center, 0));
12663 info->center_z = parse_units (actor, PARSE_Y,
12664 json_array_get_element (center, 1));
12667 case CLUTTER_Y_AXIS:
12668 info->center_x = parse_units (actor, PARSE_X,
12669 json_array_get_element (center, 0));
12670 info->center_z = parse_units (actor, PARSE_X,
12671 json_array_get_element (center, 1));
12674 case CLUTTER_Z_AXIS:
12675 info->center_x = parse_units (actor, PARSE_X,
12676 json_array_get_element (center, 0));
12677 info->center_y = parse_units (actor, PARSE_Y,
12678 json_array_get_element (center, 1));
12687 parse_rotation (ClutterActor *actor,
12689 RotationInfo *info)
12693 gboolean retval = FALSE;
12695 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12697 g_warning ("Invalid node of type '%s' found, expecting an array",
12698 json_node_type_name (node));
12702 array = json_node_get_array (node);
12703 len = json_array_get_length (array);
12705 for (i = 0; i < len; i++)
12707 JsonNode *element = json_array_get_element (array, i);
12708 JsonObject *object;
12711 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12713 g_warning ("Invalid node of type '%s' found, expecting an object",
12714 json_node_type_name (element));
12718 object = json_node_get_object (element);
12720 if (json_object_has_member (object, "x-axis"))
12722 member = json_object_get_member (object, "x-axis");
12724 info->axis = CLUTTER_X_AXIS;
12726 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12728 info->angle = json_node_get_double (member);
12731 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12732 retval = parse_rotation_array (actor,
12733 json_node_get_array (member),
12738 else if (json_object_has_member (object, "y-axis"))
12740 member = json_object_get_member (object, "y-axis");
12742 info->axis = CLUTTER_Y_AXIS;
12744 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12746 info->angle = json_node_get_double (member);
12749 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12750 retval = parse_rotation_array (actor,
12751 json_node_get_array (member),
12756 else if (json_object_has_member (object, "z-axis"))
12758 member = json_object_get_member (object, "z-axis");
12760 info->axis = CLUTTER_Z_AXIS;
12762 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12764 info->angle = json_node_get_double (member);
12767 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12768 retval = parse_rotation_array (actor,
12769 json_node_get_array (member),
12780 parse_actor_metas (ClutterScript *script,
12781 ClutterActor *actor,
12784 GList *elements, *l;
12785 GSList *retval = NULL;
12787 if (!JSON_NODE_HOLDS_ARRAY (node))
12790 elements = json_array_get_elements (json_node_get_array (node));
12792 for (l = elements; l != NULL; l = l->next)
12794 JsonNode *element = l->data;
12795 const gchar *id_ = _clutter_script_get_id_from_node (element);
12798 if (id_ == NULL || *id_ == '\0')
12801 meta = clutter_script_get_object (script, id_);
12805 retval = g_slist_prepend (retval, meta);
12808 g_list_free (elements);
12810 return g_slist_reverse (retval);
12814 parse_behaviours (ClutterScript *script,
12815 ClutterActor *actor,
12818 GList *elements, *l;
12819 GSList *retval = NULL;
12821 if (!JSON_NODE_HOLDS_ARRAY (node))
12824 elements = json_array_get_elements (json_node_get_array (node));
12826 for (l = elements; l != NULL; l = l->next)
12828 JsonNode *element = l->data;
12829 const gchar *id_ = _clutter_script_get_id_from_node (element);
12830 GObject *behaviour;
12832 if (id_ == NULL || *id_ == '\0')
12835 behaviour = clutter_script_get_object (script, id_);
12836 if (behaviour == NULL)
12839 retval = g_slist_prepend (retval, behaviour);
12842 g_list_free (elements);
12844 return g_slist_reverse (retval);
12848 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12849 ClutterScript *script,
12854 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12855 gboolean retval = FALSE;
12857 if ((name[0] == 'x' && name[1] == '\0') ||
12858 (name[0] == 'y' && name[1] == '\0') ||
12859 (strcmp (name, "width") == 0) ||
12860 (strcmp (name, "height") == 0) ||
12861 (strcmp (name, "anchor_x") == 0) ||
12862 (strcmp (name, "anchor_y") == 0))
12864 ParseDimension dimension;
12867 if (name[0] == 'x')
12868 dimension = PARSE_X;
12869 else if (name[0] == 'y')
12870 dimension = PARSE_Y;
12871 else if (name[0] == 'w')
12872 dimension = PARSE_WIDTH;
12873 else if (name[0] == 'h')
12874 dimension = PARSE_HEIGHT;
12875 else if (name[0] == 'a' && name[7] == 'x')
12876 dimension = PARSE_ANCHOR_X;
12877 else if (name[0] == 'a' && name[7] == 'y')
12878 dimension = PARSE_ANCHOR_Y;
12882 units = parse_units (actor, dimension, node);
12884 /* convert back to pixels: all properties are pixel-based */
12885 g_value_init (value, G_TYPE_FLOAT);
12886 g_value_set_float (value, units);
12890 else if (strcmp (name, "rotation") == 0)
12892 RotationInfo *info;
12894 info = g_slice_new0 (RotationInfo);
12895 retval = parse_rotation (actor, node, info);
12899 g_value_init (value, G_TYPE_POINTER);
12900 g_value_set_pointer (value, info);
12903 g_slice_free (RotationInfo, info);
12905 else if (strcmp (name, "behaviours") == 0)
12909 #ifdef CLUTTER_ENABLE_DEBUG
12910 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12911 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12912 "and it should not be used in newly "
12913 "written ClutterScript definitions.");
12916 l = parse_behaviours (script, actor, node);
12918 g_value_init (value, G_TYPE_POINTER);
12919 g_value_set_pointer (value, l);
12923 else if (strcmp (name, "actions") == 0 ||
12924 strcmp (name, "constraints") == 0 ||
12925 strcmp (name, "effects") == 0)
12929 l = parse_actor_metas (script, actor, node);
12931 g_value_init (value, G_TYPE_POINTER);
12932 g_value_set_pointer (value, l);
12941 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12942 ClutterScript *script,
12944 const GValue *value)
12946 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12948 #ifdef CLUTTER_ENABLE_DEBUG
12949 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12951 gchar *tmp = g_strdup_value_contents (value);
12953 CLUTTER_NOTE (SCRIPT,
12954 "in ClutterActor::set_custom_property('%s') = %s",
12960 #endif /* CLUTTER_ENABLE_DEBUG */
12962 if (strcmp (name, "rotation") == 0)
12964 RotationInfo *info;
12966 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12969 info = g_value_get_pointer (value);
12971 clutter_actor_set_rotation (actor,
12972 info->axis, info->angle,
12977 g_slice_free (RotationInfo, info);
12982 if (strcmp (name, "behaviours") == 0)
12984 GSList *behaviours, *l;
12986 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12989 behaviours = g_value_get_pointer (value);
12990 for (l = behaviours; l != NULL; l = l->next)
12992 ClutterBehaviour *behaviour = l->data;
12994 clutter_behaviour_apply (behaviour, actor);
12997 g_slist_free (behaviours);
13002 if (strcmp (name, "actions") == 0 ||
13003 strcmp (name, "constraints") == 0 ||
13004 strcmp (name, "effects") == 0)
13008 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13011 metas = g_value_get_pointer (value);
13012 for (l = metas; l != NULL; l = l->next)
13014 if (name[0] == 'a')
13015 clutter_actor_add_action (actor, l->data);
13017 if (name[0] == 'c')
13018 clutter_actor_add_constraint (actor, l->data);
13020 if (name[0] == 'e')
13021 clutter_actor_add_effect (actor, l->data);
13024 g_slist_free (metas);
13029 g_object_set_property (G_OBJECT (scriptable), name, value);
13033 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13035 iface->parse_custom_node = clutter_actor_parse_custom_node;
13036 iface->set_custom_property = clutter_actor_set_custom_property;
13039 static ClutterActorMeta *
13040 get_meta_from_animation_property (ClutterActor *actor,
13044 ClutterActorPrivate *priv = actor->priv;
13045 ClutterActorMeta *meta = NULL;
13048 /* if this is not a special property, fall through */
13049 if (name[0] != '@')
13052 /* detect the properties named using the following spec:
13054 * @<section>.<meta-name>.<property-name>
13056 * where <section> can be one of the following:
13062 * and <meta-name> is the name set on a specific ActorMeta
13065 tokens = g_strsplit (name + 1, ".", -1);
13066 if (tokens == NULL || g_strv_length (tokens) != 3)
13068 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13070 g_strfreev (tokens);
13074 if (strcmp (tokens[0], "actions") == 0)
13075 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13077 if (strcmp (tokens[0], "constraints") == 0)
13078 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13080 if (strcmp (tokens[0], "effects") == 0)
13081 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13083 if (name_p != NULL)
13084 *name_p = g_strdup (tokens[2]);
13086 CLUTTER_NOTE (ANIMATION,
13087 "Looking for property '%s' of object '%s' in section '%s'",
13092 g_strfreev (tokens);
13097 static GParamSpec *
13098 clutter_actor_find_property (ClutterAnimatable *animatable,
13099 const gchar *property_name)
13101 ClutterActorMeta *meta = NULL;
13102 GObjectClass *klass = NULL;
13103 GParamSpec *pspec = NULL;
13104 gchar *p_name = NULL;
13106 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13112 klass = G_OBJECT_GET_CLASS (meta);
13114 pspec = g_object_class_find_property (klass, p_name);
13118 klass = G_OBJECT_GET_CLASS (animatable);
13120 pspec = g_object_class_find_property (klass, property_name);
13129 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13130 const gchar *property_name,
13133 ClutterActorMeta *meta = NULL;
13134 gchar *p_name = NULL;
13136 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13141 g_object_get_property (G_OBJECT (meta), p_name, initial);
13143 g_object_get_property (G_OBJECT (animatable), property_name, initial);
13149 * clutter_actor_set_animatable_property:
13150 * @actor: a #ClutterActor
13151 * @prop_id: the paramspec id
13152 * @value: the value to set
13153 * @pspec: the paramspec
13155 * Sets values of animatable properties.
13157 * This is a variant of clutter_actor_set_property() that gets called
13158 * by the #ClutterAnimatable implementation of #ClutterActor for the
13159 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13162 * Unlike the implementation of #GObjectClass.set_property(), this
13163 * function will not update the interval if a transition involving an
13164 * animatable property is in progress - this avoids cycles with the
13165 * transition API calling the public API.
13168 clutter_actor_set_animatable_property (ClutterActor *actor,
13170 const GValue *value,
13173 GObject *obj = G_OBJECT (actor);
13175 g_object_freeze_notify (obj);
13180 clutter_actor_set_x_internal (actor, g_value_get_float (value));
13184 clutter_actor_set_y_internal (actor, g_value_get_float (value));
13187 case PROP_POSITION:
13188 clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13192 clutter_actor_set_width_internal (actor, g_value_get_float (value));
13196 clutter_actor_set_height_internal (actor, g_value_get_float (value));
13200 clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13204 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13208 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13211 case PROP_BACKGROUND_COLOR:
13212 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13216 clutter_actor_set_scale_factor_internal (actor,
13217 g_value_get_double (value),
13222 clutter_actor_set_scale_factor_internal (actor,
13223 g_value_get_double (value),
13227 case PROP_ROTATION_ANGLE_X:
13228 clutter_actor_set_rotation_angle_internal (actor,
13230 g_value_get_double (value));
13233 case PROP_ROTATION_ANGLE_Y:
13234 clutter_actor_set_rotation_angle_internal (actor,
13236 g_value_get_double (value));
13239 case PROP_ROTATION_ANGLE_Z:
13240 clutter_actor_set_rotation_angle_internal (actor,
13242 g_value_get_double (value));
13245 case PROP_CONTENT_BOX:
13246 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13250 g_object_set_property (obj, pspec->name, value);
13254 g_object_thaw_notify (obj);
13258 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13259 const gchar *property_name,
13260 const GValue *final)
13262 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13263 ClutterActorMeta *meta = NULL;
13264 gchar *p_name = NULL;
13266 meta = get_meta_from_animation_property (actor,
13270 g_object_set_property (G_OBJECT (meta), p_name, final);
13273 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13276 pspec = g_object_class_find_property (obj_class, property_name);
13278 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13280 /* XXX - I'm going to the special hell for this */
13281 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13284 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13291 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13293 iface->find_property = clutter_actor_find_property;
13294 iface->get_initial_state = clutter_actor_get_initial_state;
13295 iface->set_final_state = clutter_actor_set_final_state;
13299 * clutter_actor_transform_stage_point:
13300 * @self: A #ClutterActor
13301 * @x: (in): x screen coordinate of the point to unproject
13302 * @y: (in): y screen coordinate of the point to unproject
13303 * @x_out: (out): return location for the unprojected x coordinance
13304 * @y_out: (out): return location for the unprojected y coordinance
13306 * This function translates screen coordinates (@x, @y) to
13307 * coordinates relative to the actor. For example, it can be used to translate
13308 * screen events from global screen coordinates into actor-local coordinates.
13310 * The conversion can fail, notably if the transform stack results in the
13311 * actor being projected on the screen as a mere line.
13313 * The conversion should not be expected to be pixel-perfect due to the
13314 * nature of the operation. In general the error grows when the skewing
13315 * of the actor rectangle on screen increases.
13317 * <note><para>This function can be computationally intensive.</para></note>
13319 * <note><para>This function only works when the allocation is up-to-date,
13320 * i.e. inside of paint().</para></note>
13322 * Return value: %TRUE if conversion was successful.
13327 clutter_actor_transform_stage_point (ClutterActor *self,
13333 ClutterVertex v[4];
13336 int du, dv, xi, yi;
13338 float xf, yf, wf, det;
13339 ClutterActorPrivate *priv;
13341 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13345 /* This implementation is based on the quad -> quad projection algorithm
13346 * described by Paul Heckbert in:
13348 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13350 * and the sample implementation at:
13352 * http://www.cs.cmu.edu/~ph/src/texfund/
13354 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13355 * quad to rectangle only, which significantly simplifies things; the
13356 * function calls have been unrolled, and most of the math is done in fixed
13360 clutter_actor_get_abs_allocation_vertices (self, v);
13362 /* Keeping these as ints simplifies the multiplication (no significant
13363 * loss of precision here).
13365 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13366 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13371 #define UX2FP(x) (x)
13372 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13374 /* First, find mapping from unit uv square to xy quadrilateral; this
13375 * equivalent to the pmap_square_quad() functions in the sample
13376 * implementation, which we can simplify, since our target is always
13379 px = v[0].x - v[1].x + v[3].x - v[2].x;
13380 py = v[0].y - v[1].y + v[3].y - v[2].y;
13384 /* affine transform */
13385 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13386 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13387 RQ[2][0] = UX2FP (v[0].x);
13388 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13389 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13390 RQ[2][1] = UX2FP (v[0].y);
13397 /* projective transform */
13398 double dx1, dx2, dy1, dy2, del;
13400 dx1 = UX2FP (v[1].x - v[3].x);
13401 dx2 = UX2FP (v[2].x - v[3].x);
13402 dy1 = UX2FP (v[1].y - v[3].y);
13403 dy2 = UX2FP (v[2].y - v[3].y);
13405 del = DET2FP (dx1, dx2, dy1, dy2);
13410 * The division here needs to be done in floating point for
13411 * precisions reasons.
13413 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13414 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13415 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13417 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13418 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13419 RQ[2][0] = UX2FP (v[0].x);
13420 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13421 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13422 RQ[2][1] = UX2FP (v[0].y);
13426 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13427 * square. Since our rectangle is based at 0,0 we only need to scale.
13437 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13440 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13441 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13442 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13443 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13444 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13445 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13446 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13447 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13448 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13451 * Check the resulting matrix is OK.
13453 det = (RQ[0][0] * ST[0][0])
13454 + (RQ[0][1] * ST[0][1])
13455 + (RQ[0][2] * ST[0][2]);
13460 * Now transform our point with the ST matrix; the notional w
13461 * coordinate is 1, hence the last part is simply added.
13466 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13467 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13468 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13483 * clutter_actor_is_rotated:
13484 * @self: a #ClutterActor
13486 * Checks whether any rotation is applied to the actor.
13488 * Return value: %TRUE if the actor is rotated.
13493 clutter_actor_is_rotated (ClutterActor *self)
13495 const ClutterTransformInfo *info;
13497 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13499 info = _clutter_actor_get_transform_info_or_defaults (self);
13501 if (info->rx_angle || info->ry_angle || info->rz_angle)
13508 * clutter_actor_is_scaled:
13509 * @self: a #ClutterActor
13511 * Checks whether the actor is scaled in either dimension.
13513 * Return value: %TRUE if the actor is scaled.
13518 clutter_actor_is_scaled (ClutterActor *self)
13520 const ClutterTransformInfo *info;
13522 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13524 info = _clutter_actor_get_transform_info_or_defaults (self);
13526 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13533 _clutter_actor_get_stage_internal (ClutterActor *actor)
13535 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13536 actor = actor->priv->parent;
13542 * clutter_actor_get_stage:
13543 * @actor: a #ClutterActor
13545 * Retrieves the #ClutterStage where @actor is contained.
13547 * Return value: (transfer none) (type Clutter.Stage): the stage
13548 * containing the actor, or %NULL
13553 clutter_actor_get_stage (ClutterActor *actor)
13555 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13557 return _clutter_actor_get_stage_internal (actor);
13561 * clutter_actor_allocate_available_size:
13562 * @self: a #ClutterActor
13563 * @x: the actor's X coordinate
13564 * @y: the actor's Y coordinate
13565 * @available_width: the maximum available width, or -1 to use the
13566 * actor's natural width
13567 * @available_height: the maximum available height, or -1 to use the
13568 * actor's natural height
13569 * @flags: flags controlling the allocation
13571 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13572 * preferred size, but limiting it to the maximum available width
13573 * and height provided.
13575 * This function will do the right thing when dealing with the
13576 * actor's request mode.
13578 * The implementation of this function is equivalent to:
13581 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13583 * clutter_actor_get_preferred_width (self, available_height,
13585 * &natural_width);
13586 * width = CLAMP (natural_width, min_width, available_width);
13588 * clutter_actor_get_preferred_height (self, width,
13590 * &natural_height);
13591 * height = CLAMP (natural_height, min_height, available_height);
13595 * clutter_actor_get_preferred_height (self, available_width,
13597 * &natural_height);
13598 * height = CLAMP (natural_height, min_height, available_height);
13600 * clutter_actor_get_preferred_width (self, height,
13602 * &natural_width);
13603 * width = CLAMP (natural_width, min_width, available_width);
13606 * box.x1 = x; box.y1 = y;
13607 * box.x2 = box.x1 + available_width;
13608 * box.y2 = box.y1 + available_height;
13609 * clutter_actor_allocate (self, &box, flags);
13612 * This function can be used by fluid layout managers to allocate
13613 * an actor's preferred size without making it bigger than the area
13614 * available for the container.
13619 clutter_actor_allocate_available_size (ClutterActor *self,
13622 gfloat available_width,
13623 gfloat available_height,
13624 ClutterAllocationFlags flags)
13626 ClutterActorPrivate *priv;
13627 gfloat width, height;
13628 gfloat min_width, min_height;
13629 gfloat natural_width, natural_height;
13630 ClutterActorBox box;
13632 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13636 width = height = 0.0;
13638 switch (priv->request_mode)
13640 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13641 clutter_actor_get_preferred_width (self, available_height,
13644 width = CLAMP (natural_width, min_width, available_width);
13646 clutter_actor_get_preferred_height (self, width,
13649 height = CLAMP (natural_height, min_height, available_height);
13652 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13653 clutter_actor_get_preferred_height (self, available_width,
13656 height = CLAMP (natural_height, min_height, available_height);
13658 clutter_actor_get_preferred_width (self, height,
13661 width = CLAMP (natural_width, min_width, available_width);
13668 box.x2 = box.x1 + width;
13669 box.y2 = box.y1 + height;
13670 clutter_actor_allocate (self, &box, flags);
13674 * clutter_actor_allocate_preferred_size:
13675 * @self: a #ClutterActor
13676 * @flags: flags controlling the allocation
13678 * Allocates the natural size of @self.
13680 * This function is a utility call for #ClutterActor implementations
13681 * that allocates the actor's preferred natural size. It can be used
13682 * by fixed layout managers (like #ClutterGroup or so called
13683 * 'composite actors') inside the ClutterActor::allocate
13684 * implementation to give each child exactly how much space it
13687 * This function is not meant to be used by applications. It is also
13688 * not meant to be used outside the implementation of the
13689 * ClutterActor::allocate virtual function.
13694 clutter_actor_allocate_preferred_size (ClutterActor *self,
13695 ClutterAllocationFlags flags)
13697 gfloat actor_x, actor_y;
13698 gfloat natural_width, natural_height;
13699 ClutterActorBox actor_box;
13701 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13703 actor_x = clutter_actor_get_x (self);
13704 actor_y = clutter_actor_get_y (self);
13706 clutter_actor_get_preferred_size (self,
13711 actor_box.x1 = actor_x;
13712 actor_box.y1 = actor_y;
13713 actor_box.x2 = actor_box.x1 + natural_width;
13714 actor_box.y2 = actor_box.y1 + natural_height;
13716 clutter_actor_allocate (self, &actor_box, flags);
13720 * clutter_actor_allocate_align_fill:
13721 * @self: a #ClutterActor
13722 * @box: a #ClutterActorBox, containing the available width and height
13723 * @x_align: the horizontal alignment, between 0 and 1
13724 * @y_align: the vertical alignment, between 0 and 1
13725 * @x_fill: whether the actor should fill horizontally
13726 * @y_fill: whether the actor should fill vertically
13727 * @flags: allocation flags to be passed to clutter_actor_allocate()
13729 * Allocates @self by taking into consideration the available allocation
13730 * area; an alignment factor on either axis; and whether the actor should
13731 * fill the allocation on either axis.
13733 * The @box should contain the available allocation width and height;
13734 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13735 * allocation will be offset by their value.
13737 * This function takes into consideration the geometry request specified by
13738 * the #ClutterActor:request-mode property, and the text direction.
13740 * This function is useful for fluid layout managers, like #ClutterBinLayout
13741 * or #ClutterTableLayout
13746 clutter_actor_allocate_align_fill (ClutterActor *self,
13747 const ClutterActorBox *box,
13752 ClutterAllocationFlags flags)
13754 ClutterActorPrivate *priv;
13755 ClutterActorBox allocation = { 0, };
13756 gfloat x_offset, y_offset;
13757 gfloat available_width, available_height;
13758 gfloat child_width, child_height;
13760 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13761 g_return_if_fail (box != NULL);
13762 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13763 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13767 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13768 clutter_actor_box_get_size (box, &available_width, &available_height);
13770 if (available_width < 0)
13771 available_width = 0;
13773 if (available_height < 0)
13774 available_height = 0;
13778 allocation.x1 = x_offset;
13779 allocation.x2 = allocation.x1 + available_width;
13784 allocation.y1 = y_offset;
13785 allocation.y2 = allocation.y1 + available_height;
13788 /* if we are filling horizontally and vertically then we're done */
13789 if (x_fill && y_fill)
13792 child_width = child_height = 0.0f;
13794 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13796 gfloat min_width, natural_width;
13797 gfloat min_height, natural_height;
13799 clutter_actor_get_preferred_width (self, available_height,
13803 child_width = CLAMP (natural_width, min_width, available_width);
13807 clutter_actor_get_preferred_height (self, child_width,
13811 child_height = CLAMP (natural_height, min_height, available_height);
13816 gfloat min_width, natural_width;
13817 gfloat min_height, natural_height;
13819 clutter_actor_get_preferred_height (self, available_width,
13823 child_height = CLAMP (natural_height, min_height, available_height);
13827 clutter_actor_get_preferred_width (self, child_height,
13831 child_width = CLAMP (natural_width, min_width, available_width);
13835 /* invert the horizontal alignment for RTL languages */
13836 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13837 x_align = 1.0 - x_align;
13841 allocation.x1 = x_offset
13842 + ((available_width - child_width) * x_align);
13843 allocation.x2 = allocation.x1 + child_width;
13848 allocation.y1 = y_offset
13849 + ((available_height - child_height) * y_align);
13850 allocation.y2 = allocation.y1 + child_height;
13854 clutter_actor_box_clamp_to_pixel (&allocation);
13855 clutter_actor_allocate (self, &allocation, flags);
13859 * clutter_actor_grab_key_focus:
13860 * @self: a #ClutterActor
13862 * Sets the key focus of the #ClutterStage including @self
13863 * to this #ClutterActor.
13868 clutter_actor_grab_key_focus (ClutterActor *self)
13870 ClutterActor *stage;
13872 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13874 stage = _clutter_actor_get_stage_internal (self);
13876 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13880 * clutter_actor_get_pango_context:
13881 * @self: a #ClutterActor
13883 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13884 * is already configured using the appropriate font map, resolution
13885 * and font options.
13887 * Unlike clutter_actor_create_pango_context(), this context is owend
13888 * by the #ClutterActor and it will be updated each time the options
13889 * stored by the #ClutterBackend change.
13891 * You can use the returned #PangoContext to create a #PangoLayout
13892 * and render text using cogl_pango_render_layout() to reuse the
13893 * glyphs cache also used by Clutter.
13895 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13896 * The returned #PangoContext is owned by the actor and should not be
13897 * unreferenced by the application code
13902 clutter_actor_get_pango_context (ClutterActor *self)
13904 ClutterActorPrivate *priv;
13906 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13910 if (priv->pango_context != NULL)
13911 return priv->pango_context;
13913 priv->pango_context = _clutter_context_get_pango_context ();
13914 g_object_ref (priv->pango_context);
13916 return priv->pango_context;
13920 * clutter_actor_create_pango_context:
13921 * @self: a #ClutterActor
13923 * Creates a #PangoContext for the given actor. The #PangoContext
13924 * is already configured using the appropriate font map, resolution
13925 * and font options.
13927 * See also clutter_actor_get_pango_context().
13929 * Return value: (transfer full): the newly created #PangoContext.
13930 * Use g_object_unref() on the returned value to deallocate its
13936 clutter_actor_create_pango_context (ClutterActor *self)
13938 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13940 return _clutter_context_create_pango_context ();
13944 * clutter_actor_create_pango_layout:
13945 * @self: a #ClutterActor
13946 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13948 * Creates a new #PangoLayout from the same #PangoContext used
13949 * by the #ClutterActor. The #PangoLayout is already configured
13950 * with the font map, resolution and font options, and the
13953 * If you want to keep around a #PangoLayout created by this
13954 * function you will have to connect to the #ClutterBackend::font-changed
13955 * and #ClutterBackend::resolution-changed signals, and call
13956 * pango_layout_context_changed() in response to them.
13958 * Return value: (transfer full): the newly created #PangoLayout.
13959 * Use g_object_unref() when done
13964 clutter_actor_create_pango_layout (ClutterActor *self,
13967 PangoContext *context;
13968 PangoLayout *layout;
13970 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13972 context = clutter_actor_get_pango_context (self);
13973 layout = pango_layout_new (context);
13976 pango_layout_set_text (layout, text, -1);
13981 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13982 * ClutterOffscreenEffect.
13985 _clutter_actor_set_opacity_override (ClutterActor *self,
13988 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13990 self->priv->opacity_override = opacity;
13994 _clutter_actor_get_opacity_override (ClutterActor *self)
13996 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13998 return self->priv->opacity_override;
14001 /* Allows you to disable applying the actors model view transform during
14002 * a paint. Used by ClutterClone. */
14004 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14007 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14009 self->priv->enable_model_view_transform = enable;
14013 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14016 ClutterActorPrivate *priv;
14018 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14022 priv->enable_paint_unmapped = enable;
14024 if (priv->enable_paint_unmapped)
14026 /* Make sure that the parents of the widget are realized first;
14027 * otherwise checks in clutter_actor_update_map_state() will
14030 clutter_actor_realize (self);
14032 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14036 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14041 clutter_anchor_coord_get_units (ClutterActor *self,
14042 const AnchorCoord *coord,
14047 if (coord->is_fractional)
14049 gfloat actor_width, actor_height;
14051 clutter_actor_get_size (self, &actor_width, &actor_height);
14054 *x = actor_width * coord->v.fraction.x;
14057 *y = actor_height * coord->v.fraction.y;
14065 *x = coord->v.units.x;
14068 *y = coord->v.units.y;
14071 *z = coord->v.units.z;
14076 clutter_anchor_coord_set_units (AnchorCoord *coord,
14081 coord->is_fractional = FALSE;
14082 coord->v.units.x = x;
14083 coord->v.units.y = y;
14084 coord->v.units.z = z;
14087 static ClutterGravity
14088 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14090 if (coord->is_fractional)
14092 if (coord->v.fraction.x == 0.0)
14094 if (coord->v.fraction.y == 0.0)
14095 return CLUTTER_GRAVITY_NORTH_WEST;
14096 else if (coord->v.fraction.y == 0.5)
14097 return CLUTTER_GRAVITY_WEST;
14098 else if (coord->v.fraction.y == 1.0)
14099 return CLUTTER_GRAVITY_SOUTH_WEST;
14101 return CLUTTER_GRAVITY_NONE;
14103 else if (coord->v.fraction.x == 0.5)
14105 if (coord->v.fraction.y == 0.0)
14106 return CLUTTER_GRAVITY_NORTH;
14107 else if (coord->v.fraction.y == 0.5)
14108 return CLUTTER_GRAVITY_CENTER;
14109 else if (coord->v.fraction.y == 1.0)
14110 return CLUTTER_GRAVITY_SOUTH;
14112 return CLUTTER_GRAVITY_NONE;
14114 else if (coord->v.fraction.x == 1.0)
14116 if (coord->v.fraction.y == 0.0)
14117 return CLUTTER_GRAVITY_NORTH_EAST;
14118 else if (coord->v.fraction.y == 0.5)
14119 return CLUTTER_GRAVITY_EAST;
14120 else if (coord->v.fraction.y == 1.0)
14121 return CLUTTER_GRAVITY_SOUTH_EAST;
14123 return CLUTTER_GRAVITY_NONE;
14126 return CLUTTER_GRAVITY_NONE;
14129 return CLUTTER_GRAVITY_NONE;
14133 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14134 ClutterGravity gravity)
14138 case CLUTTER_GRAVITY_NORTH:
14139 coord->v.fraction.x = 0.5;
14140 coord->v.fraction.y = 0.0;
14143 case CLUTTER_GRAVITY_NORTH_EAST:
14144 coord->v.fraction.x = 1.0;
14145 coord->v.fraction.y = 0.0;
14148 case CLUTTER_GRAVITY_EAST:
14149 coord->v.fraction.x = 1.0;
14150 coord->v.fraction.y = 0.5;
14153 case CLUTTER_GRAVITY_SOUTH_EAST:
14154 coord->v.fraction.x = 1.0;
14155 coord->v.fraction.y = 1.0;
14158 case CLUTTER_GRAVITY_SOUTH:
14159 coord->v.fraction.x = 0.5;
14160 coord->v.fraction.y = 1.0;
14163 case CLUTTER_GRAVITY_SOUTH_WEST:
14164 coord->v.fraction.x = 0.0;
14165 coord->v.fraction.y = 1.0;
14168 case CLUTTER_GRAVITY_WEST:
14169 coord->v.fraction.x = 0.0;
14170 coord->v.fraction.y = 0.5;
14173 case CLUTTER_GRAVITY_NORTH_WEST:
14174 coord->v.fraction.x = 0.0;
14175 coord->v.fraction.y = 0.0;
14178 case CLUTTER_GRAVITY_CENTER:
14179 coord->v.fraction.x = 0.5;
14180 coord->v.fraction.y = 0.5;
14184 coord->v.fraction.x = 0.0;
14185 coord->v.fraction.y = 0.0;
14189 coord->is_fractional = TRUE;
14193 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14195 if (coord->is_fractional)
14196 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14198 return (coord->v.units.x == 0.0
14199 && coord->v.units.y == 0.0
14200 && coord->v.units.z == 0.0);
14204 * clutter_actor_get_flags:
14205 * @self: a #ClutterActor
14207 * Retrieves the flags set on @self
14209 * Return value: a bitwise or of #ClutterActorFlags or 0
14214 clutter_actor_get_flags (ClutterActor *self)
14216 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14218 return self->flags;
14222 * clutter_actor_set_flags:
14223 * @self: a #ClutterActor
14224 * @flags: the flags to set
14226 * Sets @flags on @self
14228 * This function will emit notifications for the changed properties
14233 clutter_actor_set_flags (ClutterActor *self,
14234 ClutterActorFlags flags)
14236 ClutterActorFlags old_flags;
14238 gboolean was_reactive_set, reactive_set;
14239 gboolean was_realized_set, realized_set;
14240 gboolean was_mapped_set, mapped_set;
14241 gboolean was_visible_set, visible_set;
14243 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14245 if (self->flags == flags)
14248 obj = G_OBJECT (self);
14249 g_object_ref (obj);
14250 g_object_freeze_notify (obj);
14252 old_flags = self->flags;
14254 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14255 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14256 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14257 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14259 self->flags |= flags;
14261 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14262 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14263 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14264 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14266 if (reactive_set != was_reactive_set)
14267 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14269 if (realized_set != was_realized_set)
14270 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14272 if (mapped_set != was_mapped_set)
14273 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14275 if (visible_set != was_visible_set)
14276 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14278 g_object_thaw_notify (obj);
14279 g_object_unref (obj);
14283 * clutter_actor_unset_flags:
14284 * @self: a #ClutterActor
14285 * @flags: the flags to unset
14287 * Unsets @flags on @self
14289 * This function will emit notifications for the changed properties
14294 clutter_actor_unset_flags (ClutterActor *self,
14295 ClutterActorFlags flags)
14297 ClutterActorFlags old_flags;
14299 gboolean was_reactive_set, reactive_set;
14300 gboolean was_realized_set, realized_set;
14301 gboolean was_mapped_set, mapped_set;
14302 gboolean was_visible_set, visible_set;
14304 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14306 obj = G_OBJECT (self);
14307 g_object_freeze_notify (obj);
14309 old_flags = self->flags;
14311 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14312 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14313 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14314 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14316 self->flags &= ~flags;
14318 if (self->flags == old_flags)
14321 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14322 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14323 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14324 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14326 if (reactive_set != was_reactive_set)
14327 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14329 if (realized_set != was_realized_set)
14330 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14332 if (mapped_set != was_mapped_set)
14333 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14335 if (visible_set != was_visible_set)
14336 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14338 g_object_thaw_notify (obj);
14342 * clutter_actor_get_transformation_matrix:
14343 * @self: a #ClutterActor
14344 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14346 * Retrieves the transformations applied to @self relative to its
14352 clutter_actor_get_transformation_matrix (ClutterActor *self,
14353 CoglMatrix *matrix)
14355 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14357 cogl_matrix_init_identity (matrix);
14359 _clutter_actor_apply_modelview_transform (self, matrix);
14363 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14364 gboolean is_in_clone_paint)
14366 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14367 self->priv->in_clone_paint = is_in_clone_paint;
14371 * clutter_actor_is_in_clone_paint:
14372 * @self: a #ClutterActor
14374 * Checks whether @self is being currently painted by a #ClutterClone
14376 * This function is useful only inside the ::paint virtual function
14377 * implementations or within handlers for the #ClutterActor::paint
14380 * This function should not be used by applications
14382 * Return value: %TRUE if the #ClutterActor is currently being painted
14383 * by a #ClutterClone, and %FALSE otherwise
14388 clutter_actor_is_in_clone_paint (ClutterActor *self)
14390 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14392 return self->priv->in_clone_paint;
14396 set_direction_recursive (ClutterActor *actor,
14397 gpointer user_data)
14399 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14401 clutter_actor_set_text_direction (actor, text_dir);
14407 * clutter_actor_set_text_direction:
14408 * @self: a #ClutterActor
14409 * @text_dir: the text direction for @self
14411 * Sets the #ClutterTextDirection for an actor
14413 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14415 * If @self implements #ClutterContainer then this function will recurse
14416 * inside all the children of @self (including the internal ones).
14418 * Composite actors not implementing #ClutterContainer, or actors requiring
14419 * special handling when the text direction changes, should connect to
14420 * the #GObject::notify signal for the #ClutterActor:text-direction property
14425 clutter_actor_set_text_direction (ClutterActor *self,
14426 ClutterTextDirection text_dir)
14428 ClutterActorPrivate *priv;
14430 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14431 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14435 if (priv->text_direction != text_dir)
14437 priv->text_direction = text_dir;
14439 /* we need to emit the notify::text-direction first, so that
14440 * the sub-classes can catch that and do specific handling of
14441 * the text direction; see clutter_text_direction_changed_cb()
14442 * inside clutter-text.c
14444 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14446 _clutter_actor_foreach_child (self, set_direction_recursive,
14447 GINT_TO_POINTER (text_dir));
14449 clutter_actor_queue_relayout (self);
14454 _clutter_actor_set_has_pointer (ClutterActor *self,
14455 gboolean has_pointer)
14457 ClutterActorPrivate *priv = self->priv;
14459 if (priv->has_pointer != has_pointer)
14461 priv->has_pointer = has_pointer;
14463 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14468 * clutter_actor_get_text_direction:
14469 * @self: a #ClutterActor
14471 * Retrieves the value set using clutter_actor_set_text_direction()
14473 * If no text direction has been previously set, the default text
14474 * direction, as returned by clutter_get_default_text_direction(), will
14475 * be returned instead
14477 * Return value: the #ClutterTextDirection for the actor
14481 ClutterTextDirection
14482 clutter_actor_get_text_direction (ClutterActor *self)
14484 ClutterActorPrivate *priv;
14486 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14487 CLUTTER_TEXT_DIRECTION_LTR);
14491 /* if no direction has been set yet use the default */
14492 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14493 priv->text_direction = clutter_get_default_text_direction ();
14495 return priv->text_direction;
14499 * clutter_actor_push_internal:
14500 * @self: a #ClutterActor
14502 * Should be used by actors implementing the #ClutterContainer and with
14503 * internal children added through clutter_actor_set_parent(), for instance:
14507 * my_actor_init (MyActor *self)
14509 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14511 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14513 * /* calling clutter_actor_set_parent() now will result in
14514 * * the internal flag being set on a child of MyActor
14517 * /* internal child - a background texture */
14518 * self->priv->background_tex = clutter_texture_new ();
14519 * clutter_actor_set_parent (self->priv->background_tex,
14520 * CLUTTER_ACTOR (self));
14522 * /* internal child - a label */
14523 * self->priv->label = clutter_text_new ();
14524 * clutter_actor_set_parent (self->priv->label,
14525 * CLUTTER_ACTOR (self));
14527 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14529 * /* calling clutter_actor_set_parent() now will not result in
14530 * * the internal flag being set on a child of MyActor
14535 * This function will be used by Clutter to toggle an "internal child"
14536 * flag whenever clutter_actor_set_parent() is called; internal children
14537 * are handled differently by Clutter, specifically when destroying their
14540 * Call clutter_actor_pop_internal() when you finished adding internal
14543 * Nested calls to clutter_actor_push_internal() are allowed, but each
14544 * one must by followed by a clutter_actor_pop_internal() call.
14548 * Deprecated: 1.10: All children of an actor are accessible through
14549 * the #ClutterActor API, and #ClutterActor implements the
14550 * #ClutterContainer interface, so this function is only useful
14551 * for legacy containers overriding the default implementation.
14554 clutter_actor_push_internal (ClutterActor *self)
14556 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14558 self->priv->internal_child += 1;
14562 * clutter_actor_pop_internal:
14563 * @self: a #ClutterActor
14565 * Disables the effects of clutter_actor_push_internal().
14569 * Deprecated: 1.10: All children of an actor are accessible through
14570 * the #ClutterActor API. This function is only useful for legacy
14571 * containers overriding the default implementation of the
14572 * #ClutterContainer interface.
14575 clutter_actor_pop_internal (ClutterActor *self)
14577 ClutterActorPrivate *priv;
14579 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14583 if (priv->internal_child == 0)
14585 g_warning ("Mismatched %s: you need to call "
14586 "clutter_actor_push_composite() at least once before "
14587 "calling this function", G_STRFUNC);
14591 priv->internal_child -= 1;
14595 * clutter_actor_has_pointer:
14596 * @self: a #ClutterActor
14598 * Checks whether an actor contains the pointer of a
14599 * #ClutterInputDevice
14601 * Return value: %TRUE if the actor contains the pointer, and
14607 clutter_actor_has_pointer (ClutterActor *self)
14609 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14611 return self->priv->has_pointer;
14614 /* XXX: This is a workaround for not being able to break the ABI of
14615 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14616 * clutter_actor_queue_clipped_redraw() for details.
14618 ClutterPaintVolume *
14619 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14621 return g_object_get_data (G_OBJECT (self),
14622 "-clutter-actor-queue-redraw-clip");
14626 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14627 ClutterPaintVolume *clip)
14629 g_object_set_data (G_OBJECT (self),
14630 "-clutter-actor-queue-redraw-clip",
14635 * clutter_actor_has_allocation:
14636 * @self: a #ClutterActor
14638 * Checks if the actor has an up-to-date allocation assigned to
14639 * it. This means that the actor should have an allocation: it's
14640 * visible and has a parent. It also means that there is no
14641 * outstanding relayout request in progress for the actor or its
14642 * children (There might be other outstanding layout requests in
14643 * progress that will cause the actor to get a new allocation
14644 * when the stage is laid out, however).
14646 * If this function returns %FALSE, then the actor will normally
14647 * be allocated before it is next drawn on the screen.
14649 * Return value: %TRUE if the actor has an up-to-date allocation
14654 clutter_actor_has_allocation (ClutterActor *self)
14656 ClutterActorPrivate *priv;
14658 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14662 return priv->parent != NULL &&
14663 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14664 !priv->needs_allocation;
14668 * clutter_actor_add_action:
14669 * @self: a #ClutterActor
14670 * @action: a #ClutterAction
14672 * Adds @action to the list of actions applied to @self
14674 * A #ClutterAction can only belong to one actor at a time
14676 * The #ClutterActor will hold a reference on @action until either
14677 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14683 clutter_actor_add_action (ClutterActor *self,
14684 ClutterAction *action)
14686 ClutterActorPrivate *priv;
14688 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14689 g_return_if_fail (CLUTTER_IS_ACTION (action));
14693 if (priv->actions == NULL)
14695 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14696 priv->actions->actor = self;
14699 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14701 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14705 * clutter_actor_add_action_with_name:
14706 * @self: a #ClutterActor
14707 * @name: the name to set on the action
14708 * @action: a #ClutterAction
14710 * A convenience function for setting the name of a #ClutterAction
14711 * while adding it to the list of actions applied to @self
14713 * This function is the logical equivalent of:
14716 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14717 * clutter_actor_add_action (self, action);
14723 clutter_actor_add_action_with_name (ClutterActor *self,
14725 ClutterAction *action)
14727 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14728 g_return_if_fail (name != NULL);
14729 g_return_if_fail (CLUTTER_IS_ACTION (action));
14731 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14732 clutter_actor_add_action (self, action);
14736 * clutter_actor_remove_action:
14737 * @self: a #ClutterActor
14738 * @action: a #ClutterAction
14740 * Removes @action from the list of actions applied to @self
14742 * The reference held by @self on the #ClutterAction will be released
14747 clutter_actor_remove_action (ClutterActor *self,
14748 ClutterAction *action)
14750 ClutterActorPrivate *priv;
14752 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14753 g_return_if_fail (CLUTTER_IS_ACTION (action));
14757 if (priv->actions == NULL)
14760 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14762 if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14763 g_clear_object (&priv->actions);
14765 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14769 * clutter_actor_remove_action_by_name:
14770 * @self: a #ClutterActor
14771 * @name: the name of the action to remove
14773 * Removes the #ClutterAction with the given name from the list
14774 * of actions applied to @self
14779 clutter_actor_remove_action_by_name (ClutterActor *self,
14782 ClutterActorPrivate *priv;
14783 ClutterActorMeta *meta;
14785 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14786 g_return_if_fail (name != NULL);
14790 if (priv->actions == NULL)
14793 meta = _clutter_meta_group_get_meta (priv->actions, name);
14797 _clutter_meta_group_remove_meta (priv->actions, meta);
14799 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14803 * clutter_actor_get_actions:
14804 * @self: a #ClutterActor
14806 * Retrieves the list of actions applied to @self
14808 * Return value: (transfer container) (element-type Clutter.Action): a copy
14809 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14810 * owned by the #ClutterActor. Use g_list_free() to free the resources
14811 * allocated by the returned #GList
14816 clutter_actor_get_actions (ClutterActor *self)
14818 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14820 if (self->priv->actions == NULL)
14823 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14827 * clutter_actor_get_action:
14828 * @self: a #ClutterActor
14829 * @name: the name of the action to retrieve
14831 * Retrieves the #ClutterAction with the given name in the list
14832 * of actions applied to @self
14834 * Return value: (transfer none): a #ClutterAction for the given
14835 * name, or %NULL. The returned #ClutterAction is owned by the
14836 * actor and it should not be unreferenced directly
14841 clutter_actor_get_action (ClutterActor *self,
14844 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14845 g_return_val_if_fail (name != NULL, NULL);
14847 if (self->priv->actions == NULL)
14850 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14854 * clutter_actor_clear_actions:
14855 * @self: a #ClutterActor
14857 * Clears the list of actions applied to @self
14862 clutter_actor_clear_actions (ClutterActor *self)
14864 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14866 if (self->priv->actions == NULL)
14869 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14873 * clutter_actor_add_constraint:
14874 * @self: a #ClutterActor
14875 * @constraint: a #ClutterConstraint
14877 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14880 * The #ClutterActor will hold a reference on the @constraint until
14881 * either clutter_actor_remove_constraint() or
14882 * clutter_actor_clear_constraints() is called.
14887 clutter_actor_add_constraint (ClutterActor *self,
14888 ClutterConstraint *constraint)
14890 ClutterActorPrivate *priv;
14892 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14893 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14897 if (priv->constraints == NULL)
14899 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14900 priv->constraints->actor = self;
14903 _clutter_meta_group_add_meta (priv->constraints,
14904 CLUTTER_ACTOR_META (constraint));
14905 clutter_actor_queue_relayout (self);
14907 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14911 * clutter_actor_add_constraint_with_name:
14912 * @self: a #ClutterActor
14913 * @name: the name to set on the constraint
14914 * @constraint: a #ClutterConstraint
14916 * A convenience function for setting the name of a #ClutterConstraint
14917 * while adding it to the list of constraints applied to @self
14919 * This function is the logical equivalent of:
14922 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14923 * clutter_actor_add_constraint (self, constraint);
14929 clutter_actor_add_constraint_with_name (ClutterActor *self,
14931 ClutterConstraint *constraint)
14933 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14934 g_return_if_fail (name != NULL);
14935 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14937 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14938 clutter_actor_add_constraint (self, constraint);
14942 * clutter_actor_remove_constraint:
14943 * @self: a #ClutterActor
14944 * @constraint: a #ClutterConstraint
14946 * Removes @constraint from the list of constraints applied to @self
14948 * The reference held by @self on the #ClutterConstraint will be released
14953 clutter_actor_remove_constraint (ClutterActor *self,
14954 ClutterConstraint *constraint)
14956 ClutterActorPrivate *priv;
14958 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14959 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14963 if (priv->constraints == NULL)
14966 _clutter_meta_group_remove_meta (priv->constraints,
14967 CLUTTER_ACTOR_META (constraint));
14969 if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
14970 g_clear_object (&priv->constraints);
14972 clutter_actor_queue_relayout (self);
14974 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14978 * clutter_actor_remove_constraint_by_name:
14979 * @self: a #ClutterActor
14980 * @name: the name of the constraint to remove
14982 * Removes the #ClutterConstraint with the given name from the list
14983 * of constraints applied to @self
14988 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14991 ClutterActorPrivate *priv;
14992 ClutterActorMeta *meta;
14994 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14995 g_return_if_fail (name != NULL);
14999 if (priv->constraints == NULL)
15002 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15006 _clutter_meta_group_remove_meta (priv->constraints, meta);
15007 clutter_actor_queue_relayout (self);
15011 * clutter_actor_get_constraints:
15012 * @self: a #ClutterActor
15014 * Retrieves the list of constraints applied to @self
15016 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15017 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15018 * owned by the #ClutterActor. Use g_list_free() to free the resources
15019 * allocated by the returned #GList
15024 clutter_actor_get_constraints (ClutterActor *self)
15026 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15028 if (self->priv->constraints == NULL)
15031 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15035 * clutter_actor_get_constraint:
15036 * @self: a #ClutterActor
15037 * @name: the name of the constraint to retrieve
15039 * Retrieves the #ClutterConstraint with the given name in the list
15040 * of constraints applied to @self
15042 * Return value: (transfer none): a #ClutterConstraint for the given
15043 * name, or %NULL. The returned #ClutterConstraint is owned by the
15044 * actor and it should not be unreferenced directly
15048 ClutterConstraint *
15049 clutter_actor_get_constraint (ClutterActor *self,
15052 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15053 g_return_val_if_fail (name != NULL, NULL);
15055 if (self->priv->constraints == NULL)
15058 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15062 * clutter_actor_clear_constraints:
15063 * @self: a #ClutterActor
15065 * Clears the list of constraints applied to @self
15070 clutter_actor_clear_constraints (ClutterActor *self)
15072 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15074 if (self->priv->constraints == NULL)
15077 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15079 clutter_actor_queue_relayout (self);
15083 * clutter_actor_set_clip_to_allocation:
15084 * @self: a #ClutterActor
15085 * @clip_set: %TRUE to apply a clip tracking the allocation
15087 * Sets whether @self should be clipped to the same size as its
15093 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15096 ClutterActorPrivate *priv;
15098 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15100 clip_set = !!clip_set;
15104 if (priv->clip_to_allocation != clip_set)
15106 priv->clip_to_allocation = clip_set;
15108 clutter_actor_queue_redraw (self);
15110 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15115 * clutter_actor_get_clip_to_allocation:
15116 * @self: a #ClutterActor
15118 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15120 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15125 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15127 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15129 return self->priv->clip_to_allocation;
15133 * clutter_actor_add_effect:
15134 * @self: a #ClutterActor
15135 * @effect: a #ClutterEffect
15137 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15139 * The #ClutterActor will hold a reference on the @effect until either
15140 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15146 clutter_actor_add_effect (ClutterActor *self,
15147 ClutterEffect *effect)
15149 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15150 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15152 _clutter_actor_add_effect_internal (self, effect);
15154 clutter_actor_queue_redraw (self);
15156 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15160 * clutter_actor_add_effect_with_name:
15161 * @self: a #ClutterActor
15162 * @name: the name to set on the effect
15163 * @effect: a #ClutterEffect
15165 * A convenience function for setting the name of a #ClutterEffect
15166 * while adding it to the list of effectss applied to @self
15168 * This function is the logical equivalent of:
15171 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15172 * clutter_actor_add_effect (self, effect);
15178 clutter_actor_add_effect_with_name (ClutterActor *self,
15180 ClutterEffect *effect)
15182 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15183 g_return_if_fail (name != NULL);
15184 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15186 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15187 clutter_actor_add_effect (self, effect);
15191 * clutter_actor_remove_effect:
15192 * @self: a #ClutterActor
15193 * @effect: a #ClutterEffect
15195 * Removes @effect from the list of effects applied to @self
15197 * The reference held by @self on the #ClutterEffect will be released
15202 clutter_actor_remove_effect (ClutterActor *self,
15203 ClutterEffect *effect)
15205 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15206 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15208 _clutter_actor_remove_effect_internal (self, effect);
15210 clutter_actor_queue_redraw (self);
15212 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15216 * clutter_actor_remove_effect_by_name:
15217 * @self: a #ClutterActor
15218 * @name: the name of the effect to remove
15220 * Removes the #ClutterEffect with the given name from the list
15221 * of effects applied to @self
15226 clutter_actor_remove_effect_by_name (ClutterActor *self,
15229 ClutterActorPrivate *priv;
15230 ClutterActorMeta *meta;
15232 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15233 g_return_if_fail (name != NULL);
15237 if (priv->effects == NULL)
15240 meta = _clutter_meta_group_get_meta (priv->effects, name);
15244 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15248 * clutter_actor_get_effects:
15249 * @self: a #ClutterActor
15251 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15253 * Return value: (transfer container) (element-type Clutter.Effect): a list
15254 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15255 * list are owned by Clutter and they should not be freed. You should
15256 * free the returned list using g_list_free() when done
15261 clutter_actor_get_effects (ClutterActor *self)
15263 ClutterActorPrivate *priv;
15265 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15269 if (priv->effects == NULL)
15272 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15276 * clutter_actor_get_effect:
15277 * @self: a #ClutterActor
15278 * @name: the name of the effect to retrieve
15280 * Retrieves the #ClutterEffect with the given name in the list
15281 * of effects applied to @self
15283 * Return value: (transfer none): a #ClutterEffect for the given
15284 * name, or %NULL. The returned #ClutterEffect is owned by the
15285 * actor and it should not be unreferenced directly
15290 clutter_actor_get_effect (ClutterActor *self,
15293 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15294 g_return_val_if_fail (name != NULL, NULL);
15296 if (self->priv->effects == NULL)
15299 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15303 * clutter_actor_clear_effects:
15304 * @self: a #ClutterActor
15306 * Clears the list of effects applied to @self
15311 clutter_actor_clear_effects (ClutterActor *self)
15313 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15315 if (self->priv->effects == NULL)
15318 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15320 clutter_actor_queue_redraw (self);
15324 * clutter_actor_has_key_focus:
15325 * @self: a #ClutterActor
15327 * Checks whether @self is the #ClutterActor that has key focus
15329 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15334 clutter_actor_has_key_focus (ClutterActor *self)
15336 ClutterActor *stage;
15338 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15340 stage = _clutter_actor_get_stage_internal (self);
15344 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15348 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15349 ClutterPaintVolume *pv)
15351 ClutterActorPrivate *priv = self->priv;
15353 /* Actors are only expected to report a valid paint volume
15354 * while they have a valid allocation. */
15355 if (G_UNLIKELY (priv->needs_allocation))
15357 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15358 "Actor needs allocation",
15359 _clutter_actor_get_debug_name (self));
15363 /* Check if there are any handlers connected to the paint
15364 * signal. If there are then all bets are off for what the paint
15365 * volume for this actor might possibly be!
15367 * XXX: It's expected that this is going to end up being quite a
15368 * costly check to have to do here, but we haven't come up with
15369 * another solution that can reliably catch paint signal handlers at
15370 * the right time to either avoid artefacts due to invalid stage
15371 * clipping or due to incorrect culling.
15373 * Previously we checked in clutter_actor_paint(), but at that time
15374 * we may already be using a stage clip that could be derived from
15375 * an invalid paint-volume. We used to try and handle that by
15376 * queuing a follow up, unclipped, redraw but still the previous
15377 * checking wasn't enough to catch invalid volumes involved in
15378 * culling (considering that containers may derive their volume from
15379 * children that haven't yet been painted)
15381 * Longer term, improved solutions could be:
15382 * - Disallow painting in the paint signal, only allow using it
15383 * for tracking when paints happen. We can add another API that
15384 * allows monkey patching the paint of arbitrary actors but in a
15385 * more controlled way and that also supports modifying the
15387 * - If we could be notified somehow when signal handlers are
15388 * connected we wouldn't have to poll for handlers like this.
15390 if (g_signal_has_handler_pending (self,
15391 actor_signals[PAINT],
15395 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15396 "Actor has \"paint\" signal handlers",
15397 _clutter_actor_get_debug_name (self));
15401 _clutter_paint_volume_init_static (pv, self);
15403 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15405 clutter_paint_volume_free (pv);
15406 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15407 "Actor failed to report a volume",
15408 _clutter_actor_get_debug_name (self));
15412 /* since effects can modify the paint volume, we allow them to actually
15413 * do this by making get_paint_volume() "context sensitive"
15415 if (priv->effects != NULL)
15417 if (priv->current_effect != NULL)
15419 const GList *effects, *l;
15421 /* if we are being called from within the paint sequence of
15422 * an actor, get the paint volume up to the current effect
15424 effects = _clutter_meta_group_peek_metas (priv->effects);
15426 l != NULL || (l != NULL && l->data != priv->current_effect);
15429 if (!_clutter_effect_get_paint_volume (l->data, pv))
15431 clutter_paint_volume_free (pv);
15432 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15433 "Effect (%s) failed to report a volume",
15434 _clutter_actor_get_debug_name (self),
15435 _clutter_actor_meta_get_debug_name (l->data));
15442 const GList *effects, *l;
15444 /* otherwise, get the cumulative volume */
15445 effects = _clutter_meta_group_peek_metas (priv->effects);
15446 for (l = effects; l != NULL; l = l->next)
15447 if (!_clutter_effect_get_paint_volume (l->data, pv))
15449 clutter_paint_volume_free (pv);
15450 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15451 "Effect (%s) failed to report a volume",
15452 _clutter_actor_get_debug_name (self),
15453 _clutter_actor_meta_get_debug_name (l->data));
15462 /* The public clutter_actor_get_paint_volume API returns a const
15463 * pointer since we return a pointer directly to the cached
15464 * PaintVolume associated with the actor and don't want the user to
15465 * inadvertently modify it, but for internal uses we sometimes need
15466 * access to the same PaintVolume but need to apply some book-keeping
15467 * modifications to it so we don't want a const pointer.
15469 static ClutterPaintVolume *
15470 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15472 ClutterActorPrivate *priv;
15476 if (priv->paint_volume_valid)
15477 clutter_paint_volume_free (&priv->paint_volume);
15479 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15481 priv->paint_volume_valid = TRUE;
15482 return &priv->paint_volume;
15486 priv->paint_volume_valid = FALSE;
15492 * clutter_actor_get_paint_volume:
15493 * @self: a #ClutterActor
15495 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15496 * when a paint volume can't be determined.
15498 * The paint volume is defined as the 3D space occupied by an actor
15499 * when being painted.
15501 * This function will call the <function>get_paint_volume()</function>
15502 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15503 * should not usually care about overriding the default implementation,
15504 * unless they are, for instance: painting outside their allocation, or
15505 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15508 * <note>2D actors overriding <function>get_paint_volume()</function>
15509 * ensure their volume has a depth of 0. (This will be true so long as
15510 * you don't call clutter_paint_volume_set_depth().)</note>
15512 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15513 * or %NULL if no volume could be determined. The returned pointer
15514 * is not guaranteed to be valid across multiple frames; if you want
15515 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15519 const ClutterPaintVolume *
15520 clutter_actor_get_paint_volume (ClutterActor *self)
15522 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15524 return _clutter_actor_get_paint_volume_mutable (self);
15528 * clutter_actor_get_transformed_paint_volume:
15529 * @self: a #ClutterActor
15530 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15531 * (or %NULL for the stage)
15533 * Retrieves the 3D paint volume of an actor like
15534 * clutter_actor_get_paint_volume() does (Please refer to the
15535 * documentation of clutter_actor_get_paint_volume() for more
15536 * details.) and it additionally transforms the paint volume into the
15537 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15538 * is passed for @relative_to_ancestor)
15540 * This can be used by containers that base their paint volume on
15541 * the volume of their children. Such containers can query the
15542 * transformed paint volume of all of its children and union them
15543 * together using clutter_paint_volume_union().
15545 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15546 * or %NULL if no volume could be determined. The returned pointer is
15547 * not guaranteed to be valid across multiple frames; if you wish to
15548 * keep it, you will have to copy it using clutter_paint_volume_copy().
15552 const ClutterPaintVolume *
15553 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15554 ClutterActor *relative_to_ancestor)
15556 const ClutterPaintVolume *volume;
15557 ClutterActor *stage;
15558 ClutterPaintVolume *transformed_volume;
15560 stage = _clutter_actor_get_stage_internal (self);
15561 if (G_UNLIKELY (stage == NULL))
15564 if (relative_to_ancestor == NULL)
15565 relative_to_ancestor = stage;
15567 volume = clutter_actor_get_paint_volume (self);
15568 if (volume == NULL)
15571 transformed_volume =
15572 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15574 _clutter_paint_volume_copy_static (volume, transformed_volume);
15576 _clutter_paint_volume_transform_relative (transformed_volume,
15577 relative_to_ancestor);
15579 return transformed_volume;
15583 * clutter_actor_get_paint_box:
15584 * @self: a #ClutterActor
15585 * @box: (out): return location for a #ClutterActorBox
15587 * Retrieves the paint volume of the passed #ClutterActor, and
15588 * transforms it into a 2D bounding box in stage coordinates.
15590 * This function is useful to determine the on screen area occupied by
15591 * the actor. The box is only an approximation and may often be
15592 * considerably larger due to the optimizations used to calculate the
15593 * box. The box is never smaller though, so it can reliably be used
15596 * There are times when a 2D paint box can't be determined, e.g.
15597 * because the actor isn't yet parented under a stage or because
15598 * the actor is unable to determine a paint volume.
15600 * Return value: %TRUE if a 2D paint box could be determined, else
15606 clutter_actor_get_paint_box (ClutterActor *self,
15607 ClutterActorBox *box)
15609 ClutterActor *stage;
15610 ClutterPaintVolume *pv;
15612 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15613 g_return_val_if_fail (box != NULL, FALSE);
15615 stage = _clutter_actor_get_stage_internal (self);
15616 if (G_UNLIKELY (!stage))
15619 pv = _clutter_actor_get_paint_volume_mutable (self);
15620 if (G_UNLIKELY (!pv))
15623 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15629 * clutter_actor_has_overlaps:
15630 * @self: A #ClutterActor
15632 * Asks the actor's implementation whether it may contain overlapping
15635 * For example; Clutter may use this to determine whether the painting
15636 * should be redirected to an offscreen buffer to correctly implement
15637 * the opacity property.
15639 * Custom actors can override the default response by implementing the
15640 * #ClutterActor <function>has_overlaps</function> virtual function. See
15641 * clutter_actor_set_offscreen_redirect() for more information.
15643 * Return value: %TRUE if the actor may have overlapping primitives, and
15649 clutter_actor_has_overlaps (ClutterActor *self)
15651 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15653 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15657 * clutter_actor_has_effects:
15658 * @self: A #ClutterActor
15660 * Returns whether the actor has any effects applied.
15662 * Return value: %TRUE if the actor has any effects,
15668 clutter_actor_has_effects (ClutterActor *self)
15670 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15672 if (self->priv->effects == NULL)
15675 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15679 * clutter_actor_has_constraints:
15680 * @self: A #ClutterActor
15682 * Returns whether the actor has any constraints applied.
15684 * Return value: %TRUE if the actor has any constraints,
15690 clutter_actor_has_constraints (ClutterActor *self)
15692 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15694 return self->priv->constraints != NULL;
15698 * clutter_actor_has_actions:
15699 * @self: A #ClutterActor
15701 * Returns whether the actor has any actions applied.
15703 * Return value: %TRUE if the actor has any actions,
15709 clutter_actor_has_actions (ClutterActor *self)
15711 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15713 return self->priv->actions != NULL;
15717 * clutter_actor_get_n_children:
15718 * @self: a #ClutterActor
15720 * Retrieves the number of children of @self.
15722 * Return value: the number of children of an actor
15727 clutter_actor_get_n_children (ClutterActor *self)
15729 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15731 return self->priv->n_children;
15735 * clutter_actor_get_child_at_index:
15736 * @self: a #ClutterActor
15737 * @index_: the position in the list of children
15739 * Retrieves the actor at the given @index_ inside the list of
15740 * children of @self.
15742 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15747 clutter_actor_get_child_at_index (ClutterActor *self,
15750 ClutterActor *iter;
15753 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15754 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15756 for (iter = self->priv->first_child, i = 0;
15757 iter != NULL && i < index_;
15758 iter = iter->priv->next_sibling, i += 1)
15765 * _clutter_actor_foreach_child:
15766 * @actor: The actor whos children you want to iterate
15767 * @callback: The function to call for each child
15768 * @user_data: Private data to pass to @callback
15770 * Calls a given @callback once for each child of the specified @actor and
15771 * passing the @user_data pointer each time.
15773 * Return value: returns %TRUE if all children were iterated, else
15774 * %FALSE if a callback broke out of iteration early.
15777 _clutter_actor_foreach_child (ClutterActor *self,
15778 ClutterForeachCallback callback,
15779 gpointer user_data)
15781 ClutterActor *iter;
15784 if (self->priv->first_child == NULL)
15788 iter = self->priv->first_child;
15790 /* we use this form so that it's safe to change the children
15791 * list while iterating it
15793 while (cont && iter != NULL)
15795 ClutterActor *next = iter->priv->next_sibling;
15797 cont = callback (iter, user_data);
15806 /* For debugging purposes this gives us a simple way to print out
15807 * the scenegraph e.g in gdb using:
15809 * _clutter_actor_traverse (stage,
15811 * clutter_debug_print_actor_cb,
15816 static ClutterActorTraverseVisitFlags
15817 clutter_debug_print_actor_cb (ClutterActor *actor,
15821 g_print ("%*s%s:%p\n",
15823 _clutter_actor_get_debug_name (actor),
15826 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15831 _clutter_actor_traverse_breadth (ClutterActor *actor,
15832 ClutterTraverseCallback callback,
15833 gpointer user_data)
15835 GQueue *queue = g_queue_new ();
15836 ClutterActor dummy;
15837 int current_depth = 0;
15839 g_queue_push_tail (queue, actor);
15840 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15842 while ((actor = g_queue_pop_head (queue)))
15844 ClutterActorTraverseVisitFlags flags;
15846 if (actor == &dummy)
15849 g_queue_push_tail (queue, &dummy);
15853 flags = callback (actor, current_depth, user_data);
15854 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15856 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15858 ClutterActor *iter;
15860 for (iter = actor->priv->first_child;
15862 iter = iter->priv->next_sibling)
15864 g_queue_push_tail (queue, iter);
15869 g_queue_free (queue);
15872 static ClutterActorTraverseVisitFlags
15873 _clutter_actor_traverse_depth (ClutterActor *actor,
15874 ClutterTraverseCallback before_children_callback,
15875 ClutterTraverseCallback after_children_callback,
15877 gpointer user_data)
15879 ClutterActorTraverseVisitFlags flags;
15881 flags = before_children_callback (actor, current_depth, user_data);
15882 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15883 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15885 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15887 ClutterActor *iter;
15889 for (iter = actor->priv->first_child;
15891 iter = iter->priv->next_sibling)
15893 flags = _clutter_actor_traverse_depth (iter,
15894 before_children_callback,
15895 after_children_callback,
15899 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15900 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15904 if (after_children_callback)
15905 return after_children_callback (actor, current_depth, user_data);
15907 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15910 /* _clutter_actor_traverse:
15911 * @actor: The actor to start traversing the graph from
15912 * @flags: These flags may affect how the traversal is done
15913 * @before_children_callback: A function to call before visiting the
15914 * children of the current actor.
15915 * @after_children_callback: A function to call after visiting the
15916 * children of the current actor. (Ignored if
15917 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15918 * @user_data: The private data to pass to the callbacks
15920 * Traverses the scenegraph starting at the specified @actor and
15921 * descending through all its children and its children's children.
15922 * For each actor traversed @before_children_callback and
15923 * @after_children_callback are called with the specified
15924 * @user_data, before and after visiting that actor's children.
15926 * The callbacks can return flags that affect the ongoing traversal
15927 * such as by skipping over an actors children or bailing out of
15928 * any further traversing.
15931 _clutter_actor_traverse (ClutterActor *actor,
15932 ClutterActorTraverseFlags flags,
15933 ClutterTraverseCallback before_children_callback,
15934 ClutterTraverseCallback after_children_callback,
15935 gpointer user_data)
15937 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15938 _clutter_actor_traverse_breadth (actor,
15939 before_children_callback,
15941 else /* DEPTH_FIRST */
15942 _clutter_actor_traverse_depth (actor,
15943 before_children_callback,
15944 after_children_callback,
15945 0, /* start depth */
15950 on_layout_manager_changed (ClutterLayoutManager *manager,
15951 ClutterActor *self)
15953 clutter_actor_queue_relayout (self);
15957 * clutter_actor_set_layout_manager:
15958 * @self: a #ClutterActor
15959 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15961 * Sets the #ClutterLayoutManager delegate object that will be used to
15962 * lay out the children of @self.
15964 * The #ClutterActor will take a reference on the passed @manager which
15965 * will be released either when the layout manager is removed, or when
15966 * the actor is destroyed.
15971 clutter_actor_set_layout_manager (ClutterActor *self,
15972 ClutterLayoutManager *manager)
15974 ClutterActorPrivate *priv;
15976 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15977 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15981 if (priv->layout_manager != NULL)
15983 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15984 G_CALLBACK (on_layout_manager_changed),
15986 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15987 g_clear_object (&priv->layout_manager);
15990 priv->layout_manager = manager;
15992 if (priv->layout_manager != NULL)
15994 g_object_ref_sink (priv->layout_manager);
15995 clutter_layout_manager_set_container (priv->layout_manager,
15996 CLUTTER_CONTAINER (self));
15997 g_signal_connect (priv->layout_manager, "layout-changed",
15998 G_CALLBACK (on_layout_manager_changed),
16002 clutter_actor_queue_relayout (self);
16004 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16008 * clutter_actor_get_layout_manager:
16009 * @self: a #ClutterActor
16011 * Retrieves the #ClutterLayoutManager used by @self.
16013 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16018 ClutterLayoutManager *
16019 clutter_actor_get_layout_manager (ClutterActor *self)
16021 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16023 return self->priv->layout_manager;
16026 static const ClutterLayoutInfo default_layout_info = {
16027 CLUTTER_POINT_INIT_ZERO, /* fixed-pos */
16028 { 0, 0, 0, 0 }, /* margin */
16029 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16030 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16031 CLUTTER_SIZE_INIT_ZERO, /* minimum */
16032 CLUTTER_SIZE_INIT_ZERO, /* natural */
16036 layout_info_free (gpointer data)
16038 if (G_LIKELY (data != NULL))
16039 g_slice_free (ClutterLayoutInfo, data);
16043 * _clutter_actor_get_layout_info:
16044 * @self: a #ClutterActor
16046 * Retrieves a pointer to the ClutterLayoutInfo structure.
16048 * If the actor does not have a ClutterLayoutInfo associated to it, one
16049 * will be created and initialized to the default values.
16051 * This function should be used for setters.
16053 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16056 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16058 ClutterLayoutInfo *
16059 _clutter_actor_get_layout_info (ClutterActor *self)
16061 ClutterLayoutInfo *retval;
16063 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16064 if (retval == NULL)
16066 retval = g_slice_new (ClutterLayoutInfo);
16068 *retval = default_layout_info;
16070 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16079 * _clutter_actor_get_layout_info_or_defaults:
16080 * @self: a #ClutterActor
16082 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16084 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16085 * then the default structure will be returned.
16087 * This function should only be used for getters.
16089 * Return value: a const pointer to the ClutterLayoutInfo structure
16091 const ClutterLayoutInfo *
16092 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16094 const ClutterLayoutInfo *info;
16096 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16098 return &default_layout_info;
16104 * clutter_actor_set_x_align:
16105 * @self: a #ClutterActor
16106 * @x_align: the horizontal alignment policy
16108 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16109 * actor received extra horizontal space.
16111 * See also the #ClutterActor:x-align property.
16116 clutter_actor_set_x_align (ClutterActor *self,
16117 ClutterActorAlign x_align)
16119 ClutterLayoutInfo *info;
16121 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16123 info = _clutter_actor_get_layout_info (self);
16125 if (info->x_align != x_align)
16127 info->x_align = x_align;
16129 clutter_actor_queue_relayout (self);
16131 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16136 * clutter_actor_get_x_align:
16137 * @self: a #ClutterActor
16139 * Retrieves the horizontal alignment policy set using
16140 * clutter_actor_set_x_align().
16142 * Return value: the horizontal alignment policy.
16147 clutter_actor_get_x_align (ClutterActor *self)
16149 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16151 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16155 * clutter_actor_set_y_align:
16156 * @self: a #ClutterActor
16157 * @y_align: the vertical alignment policy
16159 * Sets the vertical alignment policy of a #ClutterActor, in case the
16160 * actor received extra vertical space.
16162 * See also the #ClutterActor:y-align property.
16167 clutter_actor_set_y_align (ClutterActor *self,
16168 ClutterActorAlign y_align)
16170 ClutterLayoutInfo *info;
16172 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16174 info = _clutter_actor_get_layout_info (self);
16176 if (info->y_align != y_align)
16178 info->y_align = y_align;
16180 clutter_actor_queue_relayout (self);
16182 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16187 * clutter_actor_get_y_align:
16188 * @self: a #ClutterActor
16190 * Retrieves the vertical alignment policy set using
16191 * clutter_actor_set_y_align().
16193 * Return value: the vertical alignment policy.
16198 clutter_actor_get_y_align (ClutterActor *self)
16200 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16202 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16206 * clutter_actor_set_margin:
16207 * @self: a #ClutterActor
16208 * @margin: a #ClutterMargin
16210 * Sets all the components of the margin of a #ClutterActor.
16215 clutter_actor_set_margin (ClutterActor *self,
16216 const ClutterMargin *margin)
16218 ClutterLayoutInfo *info;
16222 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16223 g_return_if_fail (margin != NULL);
16225 obj = G_OBJECT (self);
16228 g_object_freeze_notify (obj);
16230 info = _clutter_actor_get_layout_info (self);
16232 if (info->margin.top != margin->top)
16234 info->margin.top = margin->top;
16235 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16239 if (info->margin.right != margin->right)
16241 info->margin.right = margin->right;
16242 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16246 if (info->margin.bottom != margin->bottom)
16248 info->margin.bottom = margin->bottom;
16249 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16253 if (info->margin.left != margin->left)
16255 info->margin.left = margin->left;
16256 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16261 clutter_actor_queue_relayout (self);
16263 g_object_thaw_notify (obj);
16267 * clutter_actor_get_margin:
16268 * @self: a #ClutterActor
16269 * @margin: (out caller-allocates): return location for a #ClutterMargin
16271 * Retrieves all the components of the margin of a #ClutterActor.
16276 clutter_actor_get_margin (ClutterActor *self,
16277 ClutterMargin *margin)
16279 const ClutterLayoutInfo *info;
16281 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16282 g_return_if_fail (margin != NULL);
16284 info = _clutter_actor_get_layout_info_or_defaults (self);
16286 *margin = info->margin;
16290 * clutter_actor_set_margin_top:
16291 * @self: a #ClutterActor
16292 * @margin: the top margin
16294 * Sets the margin from the top of a #ClutterActor.
16299 clutter_actor_set_margin_top (ClutterActor *self,
16302 ClutterLayoutInfo *info;
16304 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16305 g_return_if_fail (margin >= 0.f);
16307 info = _clutter_actor_get_layout_info (self);
16309 if (info->margin.top == margin)
16312 info->margin.top = margin;
16314 clutter_actor_queue_relayout (self);
16316 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16320 * clutter_actor_get_margin_top:
16321 * @self: a #ClutterActor
16323 * Retrieves the top margin of a #ClutterActor.
16325 * Return value: the top margin
16330 clutter_actor_get_margin_top (ClutterActor *self)
16332 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16334 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16338 * clutter_actor_set_margin_bottom:
16339 * @self: a #ClutterActor
16340 * @margin: the bottom margin
16342 * Sets the margin from the bottom of a #ClutterActor.
16347 clutter_actor_set_margin_bottom (ClutterActor *self,
16350 ClutterLayoutInfo *info;
16352 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16353 g_return_if_fail (margin >= 0.f);
16355 info = _clutter_actor_get_layout_info (self);
16357 if (info->margin.bottom == margin)
16360 info->margin.bottom = margin;
16362 clutter_actor_queue_relayout (self);
16364 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16368 * clutter_actor_get_margin_bottom:
16369 * @self: a #ClutterActor
16371 * Retrieves the bottom margin of a #ClutterActor.
16373 * Return value: the bottom margin
16378 clutter_actor_get_margin_bottom (ClutterActor *self)
16380 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16382 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16386 * clutter_actor_set_margin_left:
16387 * @self: a #ClutterActor
16388 * @margin: the left margin
16390 * Sets the margin from the left of a #ClutterActor.
16395 clutter_actor_set_margin_left (ClutterActor *self,
16398 ClutterLayoutInfo *info;
16400 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16401 g_return_if_fail (margin >= 0.f);
16403 info = _clutter_actor_get_layout_info (self);
16405 if (info->margin.left == margin)
16408 info->margin.left = margin;
16410 clutter_actor_queue_relayout (self);
16412 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16416 * clutter_actor_get_margin_left:
16417 * @self: a #ClutterActor
16419 * Retrieves the left margin of a #ClutterActor.
16421 * Return value: the left margin
16426 clutter_actor_get_margin_left (ClutterActor *self)
16428 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16430 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16434 * clutter_actor_set_margin_right:
16435 * @self: a #ClutterActor
16436 * @margin: the right margin
16438 * Sets the margin from the right of a #ClutterActor.
16443 clutter_actor_set_margin_right (ClutterActor *self,
16446 ClutterLayoutInfo *info;
16448 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16449 g_return_if_fail (margin >= 0.f);
16451 info = _clutter_actor_get_layout_info (self);
16453 if (info->margin.right == margin)
16456 info->margin.right = margin;
16458 clutter_actor_queue_relayout (self);
16460 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16464 * clutter_actor_get_margin_right:
16465 * @self: a #ClutterActor
16467 * Retrieves the right margin of a #ClutterActor.
16469 * Return value: the right margin
16474 clutter_actor_get_margin_right (ClutterActor *self)
16476 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16478 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16482 clutter_actor_set_background_color_internal (ClutterActor *self,
16483 const ClutterColor *color)
16485 ClutterActorPrivate *priv = self->priv;
16488 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16491 obj = G_OBJECT (self);
16493 priv->bg_color = *color;
16494 priv->bg_color_set = TRUE;
16496 clutter_actor_queue_redraw (self);
16498 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16499 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16503 * clutter_actor_set_background_color:
16504 * @self: a #ClutterActor
16505 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16508 * Sets the background color of a #ClutterActor.
16510 * The background color will be used to cover the whole allocation of the
16511 * actor. The default background color of an actor is transparent.
16513 * To check whether an actor has a background color, you can use the
16514 * #ClutterActor:background-color-set actor property.
16516 * The #ClutterActor:background-color property is animatable.
16521 clutter_actor_set_background_color (ClutterActor *self,
16522 const ClutterColor *color)
16524 ClutterActorPrivate *priv;
16526 GParamSpec *bg_color_pspec;
16528 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16530 obj = G_OBJECT (self);
16536 priv->bg_color_set = FALSE;
16537 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16538 clutter_actor_queue_redraw (self);
16542 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16543 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16545 _clutter_actor_create_transition (self, bg_color_pspec,
16550 _clutter_actor_update_transition (self, bg_color_pspec, color);
16552 clutter_actor_queue_redraw (self);
16556 * clutter_actor_get_background_color:
16557 * @self: a #ClutterActor
16558 * @color: (out caller-allocates): return location for a #ClutterColor
16560 * Retrieves the color set using clutter_actor_set_background_color().
16565 clutter_actor_get_background_color (ClutterActor *self,
16566 ClutterColor *color)
16568 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16569 g_return_if_fail (color != NULL);
16571 *color = self->priv->bg_color;
16575 * clutter_actor_get_previous_sibling:
16576 * @self: a #ClutterActor
16578 * Retrieves the sibling of @self that comes before it in the list
16579 * of children of @self's parent.
16581 * The returned pointer is only valid until the scene graph changes; it
16582 * is not safe to modify the list of children of @self while iterating
16585 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16590 clutter_actor_get_previous_sibling (ClutterActor *self)
16592 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16594 return self->priv->prev_sibling;
16598 * clutter_actor_get_next_sibling:
16599 * @self: a #ClutterActor
16601 * Retrieves the sibling of @self that comes after it in the list
16602 * of children of @self's parent.
16604 * The returned pointer is only valid until the scene graph changes; it
16605 * is not safe to modify the list of children of @self while iterating
16608 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16613 clutter_actor_get_next_sibling (ClutterActor *self)
16615 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16617 return self->priv->next_sibling;
16621 * clutter_actor_get_first_child:
16622 * @self: a #ClutterActor
16624 * Retrieves the first child of @self.
16626 * The returned pointer is only valid until the scene graph changes; it
16627 * is not safe to modify the list of children of @self while iterating
16630 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16635 clutter_actor_get_first_child (ClutterActor *self)
16637 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16639 return self->priv->first_child;
16643 * clutter_actor_get_last_child:
16644 * @self: a #ClutterActor
16646 * Retrieves the last child of @self.
16648 * The returned pointer is only valid until the scene graph changes; it
16649 * is not safe to modify the list of children of @self while iterating
16652 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16657 clutter_actor_get_last_child (ClutterActor *self)
16659 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16661 return self->priv->last_child;
16664 /* easy way to have properly named fields instead of the dummy ones
16665 * we use in the public structure
16667 typedef struct _RealActorIter
16669 ClutterActor *root; /* dummy1 */
16670 ClutterActor *current; /* dummy2 */
16671 gpointer padding_1; /* dummy3 */
16672 gint age; /* dummy4 */
16673 gpointer padding_2; /* dummy5 */
16677 * clutter_actor_iter_init:
16678 * @iter: a #ClutterActorIter
16679 * @root: a #ClutterActor
16681 * Initializes a #ClutterActorIter, which can then be used to iterate
16682 * efficiently over a section of the scene graph, and associates it
16685 * Modifying the scene graph section that contains @root will invalidate
16689 * ClutterActorIter iter;
16690 * ClutterActor *child;
16692 * clutter_actor_iter_init (&iter, container);
16693 * while (clutter_actor_iter_next (&iter, &child))
16695 * /* do something with child */
16702 clutter_actor_iter_init (ClutterActorIter *iter,
16703 ClutterActor *root)
16705 RealActorIter *ri = (RealActorIter *) iter;
16707 g_return_if_fail (iter != NULL);
16708 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16711 ri->current = NULL;
16712 ri->age = root->priv->age;
16716 * clutter_actor_iter_next:
16717 * @iter: a #ClutterActorIter
16718 * @child: (out): return location for a #ClutterActor
16720 * Advances the @iter and retrieves the next child of the root #ClutterActor
16721 * that was used to initialize the #ClutterActorIterator.
16723 * If the iterator can advance, this function returns %TRUE and sets the
16726 * If the iterator cannot advance, this function returns %FALSE, and
16727 * the contents of @child are undefined.
16729 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16734 clutter_actor_iter_next (ClutterActorIter *iter,
16735 ClutterActor **child)
16737 RealActorIter *ri = (RealActorIter *) iter;
16739 g_return_val_if_fail (iter != NULL, FALSE);
16740 g_return_val_if_fail (ri->root != NULL, FALSE);
16741 #ifndef G_DISABLE_ASSERT
16742 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16745 if (ri->current == NULL)
16746 ri->current = ri->root->priv->first_child;
16748 ri->current = ri->current->priv->next_sibling;
16751 *child = ri->current;
16753 return ri->current != NULL;
16757 * clutter_actor_iter_prev:
16758 * @iter: a #ClutterActorIter
16759 * @child: (out): return location for a #ClutterActor
16761 * Advances the @iter and retrieves the previous child of the root
16762 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16764 * If the iterator can advance, this function returns %TRUE and sets the
16767 * If the iterator cannot advance, this function returns %FALSE, and
16768 * the contents of @child are undefined.
16770 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16775 clutter_actor_iter_prev (ClutterActorIter *iter,
16776 ClutterActor **child)
16778 RealActorIter *ri = (RealActorIter *) iter;
16780 g_return_val_if_fail (iter != NULL, FALSE);
16781 g_return_val_if_fail (ri->root != NULL, FALSE);
16782 #ifndef G_DISABLE_ASSERT
16783 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16786 if (ri->current == NULL)
16787 ri->current = ri->root->priv->last_child;
16789 ri->current = ri->current->priv->prev_sibling;
16792 *child = ri->current;
16794 return ri->current != NULL;
16798 * clutter_actor_iter_remove:
16799 * @iter: a #ClutterActorIter
16801 * Safely removes the #ClutterActor currently pointer to by the iterator
16804 * This function can only be called after clutter_actor_iter_next() or
16805 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16806 * than once for the same actor.
16808 * This function will call clutter_actor_remove_child() internally.
16813 clutter_actor_iter_remove (ClutterActorIter *iter)
16815 RealActorIter *ri = (RealActorIter *) iter;
16818 g_return_if_fail (iter != NULL);
16819 g_return_if_fail (ri->root != NULL);
16820 #ifndef G_DISABLE_ASSERT
16821 g_return_if_fail (ri->age == ri->root->priv->age);
16823 g_return_if_fail (ri->current != NULL);
16829 ri->current = cur->priv->prev_sibling;
16831 clutter_actor_remove_child_internal (ri->root, cur,
16832 REMOVE_CHILD_DEFAULT_FLAGS);
16839 * clutter_actor_iter_destroy:
16840 * @iter: a #ClutterActorIter
16842 * Safely destroys the #ClutterActor currently pointer to by the iterator
16845 * This function can only be called after clutter_actor_iter_next() or
16846 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16847 * than once for the same actor.
16849 * This function will call clutter_actor_destroy() internally.
16854 clutter_actor_iter_destroy (ClutterActorIter *iter)
16856 RealActorIter *ri = (RealActorIter *) iter;
16859 g_return_if_fail (iter != NULL);
16860 g_return_if_fail (ri->root != NULL);
16861 #ifndef G_DISABLE_ASSERT
16862 g_return_if_fail (ri->age == ri->root->priv->age);
16864 g_return_if_fail (ri->current != NULL);
16870 ri->current = cur->priv->prev_sibling;
16872 clutter_actor_destroy (cur);
16878 static const ClutterAnimationInfo default_animation_info = {
16879 NULL, /* transitions */
16881 NULL, /* cur_state */
16885 clutter_animation_info_free (gpointer data)
16889 ClutterAnimationInfo *info = data;
16891 if (info->transitions != NULL)
16892 g_hash_table_unref (info->transitions);
16894 if (info->states != NULL)
16895 g_array_unref (info->states);
16897 g_slice_free (ClutterAnimationInfo, info);
16901 const ClutterAnimationInfo *
16902 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16904 const ClutterAnimationInfo *res;
16905 GObject *obj = G_OBJECT (self);
16907 res = g_object_get_qdata (obj, quark_actor_animation_info);
16911 return &default_animation_info;
16914 ClutterAnimationInfo *
16915 _clutter_actor_get_animation_info (ClutterActor *self)
16917 GObject *obj = G_OBJECT (self);
16918 ClutterAnimationInfo *res;
16920 res = g_object_get_qdata (obj, quark_actor_animation_info);
16923 res = g_slice_new (ClutterAnimationInfo);
16925 *res = default_animation_info;
16927 g_object_set_qdata_full (obj, quark_actor_animation_info,
16929 clutter_animation_info_free);
16935 ClutterTransition *
16936 _clutter_actor_get_transition (ClutterActor *actor,
16939 const ClutterAnimationInfo *info;
16941 info = _clutter_actor_get_animation_info_or_defaults (actor);
16943 if (info->transitions == NULL)
16946 return g_hash_table_lookup (info->transitions, pspec->name);
16949 typedef struct _TransitionClosure
16951 ClutterActor *actor;
16952 ClutterTransition *transition;
16954 gulong completed_id;
16955 } TransitionClosure;
16958 transition_closure_free (gpointer data)
16960 if (G_LIKELY (data != NULL))
16962 TransitionClosure *clos = data;
16963 ClutterTimeline *timeline;
16965 timeline = CLUTTER_TIMELINE (clos->transition);
16967 if (clutter_timeline_is_playing (timeline))
16968 clutter_timeline_stop (timeline);
16970 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16972 g_object_unref (clos->transition);
16973 g_free (clos->name);
16975 g_slice_free (TransitionClosure, clos);
16980 on_transition_completed (ClutterTransition *transition,
16981 TransitionClosure *clos)
16983 ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
16984 ClutterActor *actor = clos->actor;
16985 ClutterAnimationInfo *info;
16986 gint n_repeats, cur_repeat;
16988 info = _clutter_actor_get_animation_info (actor);
16990 /* reset the caches used by animations */
16991 clutter_actor_store_content_box (actor, NULL);
16993 /* ensure that we remove the transition only at the end
16994 * of its run; we emit ::completed for every repeat
16996 n_repeats = clutter_timeline_get_repeat_count (timeline);
16997 cur_repeat = clutter_timeline_get_current_repeat (timeline);
16999 if (cur_repeat == n_repeats)
17001 if (clutter_transition_get_remove_on_complete (transition))
17003 /* we take a reference here because removing the closure
17004 * will release the reference on the transition, and we
17005 * want the transition to survive the signal emission;
17006 * the master clock will release the last reference at
17007 * the end of the frame processing.
17009 g_object_ref (transition);
17010 g_hash_table_remove (info->transitions, clos->name);
17014 /* if it's the last transition then we clean up */
17015 if (g_hash_table_size (info->transitions) == 0)
17017 g_hash_table_unref (info->transitions);
17018 info->transitions = NULL;
17020 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17021 _clutter_actor_get_debug_name (actor));
17023 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17028 _clutter_actor_update_transition (ClutterActor *actor,
17032 TransitionClosure *clos;
17033 ClutterTimeline *timeline;
17034 ClutterInterval *interval;
17035 const ClutterAnimationInfo *info;
17038 GValue initial = G_VALUE_INIT;
17039 GValue final = G_VALUE_INIT;
17040 char *error = NULL;
17042 info = _clutter_actor_get_animation_info_or_defaults (actor);
17044 if (info->transitions == NULL)
17047 clos = g_hash_table_lookup (info->transitions, pspec->name);
17051 timeline = CLUTTER_TIMELINE (clos->transition);
17053 va_start (var_args, pspec);
17055 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17057 g_value_init (&initial, ptype);
17058 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17062 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17065 g_critical ("%s: %s", G_STRLOC, error);
17070 interval = clutter_transition_get_interval (clos->transition);
17071 clutter_interval_set_initial_value (interval, &initial);
17072 clutter_interval_set_final_value (interval, &final);
17074 /* if we're updating with an easing duration of zero milliseconds,
17075 * we just jump the timeline to the end and let it run its course
17077 if (info->cur_state != NULL &&
17078 info->cur_state->easing_duration != 0)
17080 guint cur_duration = clutter_timeline_get_duration (timeline);
17081 ClutterAnimationMode cur_mode =
17082 clutter_timeline_get_progress_mode (timeline);
17084 if (cur_duration != info->cur_state->easing_duration)
17085 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17087 if (cur_mode != info->cur_state->easing_mode)
17088 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17090 clutter_timeline_rewind (timeline);
17094 guint duration = clutter_timeline_get_duration (timeline);
17096 clutter_timeline_advance (timeline, duration);
17100 g_value_unset (&initial);
17101 g_value_unset (&final);
17107 * _clutter_actor_create_transition:
17108 * @actor: a #ClutterActor
17109 * @pspec: the property used for the transition
17110 * @...: initial and final state
17112 * Creates a #ClutterTransition for the property represented by @pspec.
17114 * Return value: a #ClutterTransition
17116 ClutterTransition *
17117 _clutter_actor_create_transition (ClutterActor *actor,
17121 ClutterAnimationInfo *info;
17122 ClutterTransition *res = NULL;
17123 gboolean call_restore = FALSE;
17124 TransitionClosure *clos;
17127 info = _clutter_actor_get_animation_info (actor);
17129 /* XXX - this will go away in 2.0
17131 * if no state has been pushed, we assume that the easing state is
17132 * in "compatibility mode": all transitions have a duration of 0
17133 * msecs, which means that they happen immediately. in Clutter 2.0
17134 * this will turn into a g_assert(info->states != NULL), as every
17135 * actor will start with a predefined easing state
17137 if (info->states == NULL)
17139 clutter_actor_save_easing_state (actor);
17140 clutter_actor_set_easing_duration (actor, 0);
17141 call_restore = TRUE;
17144 if (info->transitions == NULL)
17145 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17147 transition_closure_free);
17149 va_start (var_args, pspec);
17151 clos = g_hash_table_lookup (info->transitions, pspec->name);
17154 ClutterInterval *interval;
17155 GValue initial = G_VALUE_INIT;
17156 GValue final = G_VALUE_INIT;
17160 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17162 G_VALUE_COLLECT_INIT (&initial, ptype,
17167 g_critical ("%s: %s", G_STRLOC, error);
17172 G_VALUE_COLLECT_INIT (&final, ptype,
17178 g_critical ("%s: %s", G_STRLOC, error);
17179 g_value_unset (&initial);
17184 /* if the current easing state has a duration of 0, then we don't
17185 * bother to create the transition, and we just set the final value
17186 * directly on the actor; we don't go through the Animatable
17187 * interface because we know we got here through an animatable
17190 if (info->cur_state->easing_duration == 0)
17192 clutter_actor_set_animatable_property (actor,
17196 g_value_unset (&initial);
17197 g_value_unset (&final);
17202 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17204 g_value_unset (&initial);
17205 g_value_unset (&final);
17207 res = clutter_property_transition_new (pspec->name);
17209 clutter_transition_set_interval (res, interval);
17210 clutter_transition_set_remove_on_complete (res, TRUE);
17212 /* this will start the transition as well */
17213 clutter_actor_add_transition (actor, pspec->name, res);
17215 /* the actor now owns the transition */
17216 g_object_unref (res);
17219 res = clos->transition;
17223 clutter_actor_restore_easing_state (actor);
17231 * clutter_actor_add_transition:
17232 * @self: a #ClutterActor
17233 * @name: the name of the transition to add
17234 * @transition: the #ClutterTransition to add
17236 * Adds a @transition to the #ClutterActor's list of animations.
17238 * The @name string is a per-actor unique identifier of the @transition: only
17239 * one #ClutterTransition can be associated to the specified @name.
17241 * The @transition will be given the easing duration, mode, and delay
17242 * associated to the actor's current easing state; it is possible to modify
17243 * these values after calling clutter_actor_add_transition().
17245 * The @transition will be started once added.
17247 * This function will take a reference on the @transition.
17249 * This function is usually called implicitly when modifying an animatable
17255 clutter_actor_add_transition (ClutterActor *self,
17257 ClutterTransition *transition)
17259 ClutterTimeline *timeline;
17260 TransitionClosure *clos;
17261 ClutterAnimationInfo *info;
17263 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17264 g_return_if_fail (name != NULL);
17265 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17267 info = _clutter_actor_get_animation_info (self);
17269 if (info->cur_state == NULL)
17271 g_warning ("No easing state is defined for the actor '%s'; you "
17272 "must call clutter_actor_save_easing_state() before "
17273 "calling clutter_actor_add_transition().",
17274 _clutter_actor_get_debug_name (self));
17278 if (info->transitions == NULL)
17279 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17281 transition_closure_free);
17283 if (g_hash_table_lookup (info->transitions, name) != NULL)
17285 g_warning ("A transition with name '%s' already exists for "
17288 _clutter_actor_get_debug_name (self));
17292 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17294 timeline = CLUTTER_TIMELINE (transition);
17296 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17297 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17298 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17300 clos = g_slice_new (TransitionClosure);
17301 clos->actor = self;
17302 clos->transition = g_object_ref (transition);
17303 clos->name = g_strdup (name);
17304 clos->completed_id = g_signal_connect (timeline, "completed",
17305 G_CALLBACK (on_transition_completed),
17308 CLUTTER_NOTE (ANIMATION,
17309 "Adding transition '%s' [%p] to actor '%s'",
17312 _clutter_actor_get_debug_name (self));
17314 g_hash_table_insert (info->transitions, clos->name, clos);
17315 clutter_timeline_start (timeline);
17319 * clutter_actor_remove_transition:
17320 * @self: a #ClutterActor
17321 * @name: the name of the transition to remove
17323 * Removes the transition stored inside a #ClutterActor using @name
17326 * If the transition is currently in progress, it will be stopped.
17328 * This function releases the reference acquired when the transition
17329 * was added to the #ClutterActor.
17334 clutter_actor_remove_transition (ClutterActor *self,
17337 const ClutterAnimationInfo *info;
17339 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17340 g_return_if_fail (name != NULL);
17342 info = _clutter_actor_get_animation_info_or_defaults (self);
17344 if (info->transitions == NULL)
17347 g_hash_table_remove (info->transitions, name);
17351 * clutter_actor_remove_all_transitions:
17352 * @self: a #ClutterActor
17354 * Removes all transitions associated to @self.
17359 clutter_actor_remove_all_transitions (ClutterActor *self)
17361 const ClutterAnimationInfo *info;
17363 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17365 info = _clutter_actor_get_animation_info_or_defaults (self);
17366 if (info->transitions == NULL)
17369 g_hash_table_remove_all (info->transitions);
17373 * clutter_actor_set_easing_duration:
17374 * @self: a #ClutterActor
17375 * @msecs: the duration of the easing, or %NULL
17377 * Sets the duration of the tweening for animatable properties
17378 * of @self for the current easing state.
17383 clutter_actor_set_easing_duration (ClutterActor *self,
17386 ClutterAnimationInfo *info;
17388 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17390 info = _clutter_actor_get_animation_info (self);
17392 if (info->cur_state == NULL)
17394 g_warning ("You must call clutter_actor_save_easing_state() prior "
17395 "to calling clutter_actor_set_easing_duration().");
17399 if (info->cur_state->easing_duration != msecs)
17400 info->cur_state->easing_duration = msecs;
17404 * clutter_actor_get_easing_duration:
17405 * @self: a #ClutterActor
17407 * Retrieves the duration of the tweening for animatable
17408 * properties of @self for the current easing state.
17410 * Return value: the duration of the tweening, in milliseconds
17415 clutter_actor_get_easing_duration (ClutterActor *self)
17417 const ClutterAnimationInfo *info;
17419 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17421 info = _clutter_actor_get_animation_info_or_defaults (self);
17423 if (info->cur_state != NULL)
17424 return info->cur_state->easing_duration;
17430 * clutter_actor_set_easing_mode:
17431 * @self: a #ClutterActor
17432 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17434 * Sets the easing mode for the tweening of animatable properties
17440 clutter_actor_set_easing_mode (ClutterActor *self,
17441 ClutterAnimationMode mode)
17443 ClutterAnimationInfo *info;
17445 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17446 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17447 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17449 info = _clutter_actor_get_animation_info (self);
17451 if (info->cur_state == NULL)
17453 g_warning ("You must call clutter_actor_save_easing_state() prior "
17454 "to calling clutter_actor_set_easing_mode().");
17458 if (info->cur_state->easing_mode != mode)
17459 info->cur_state->easing_mode = mode;
17463 * clutter_actor_get_easing_mode:
17464 * @self: a #ClutterActor
17466 * Retrieves the easing mode for the tweening of animatable properties
17467 * of @self for the current easing state.
17469 * Return value: an easing mode
17473 ClutterAnimationMode
17474 clutter_actor_get_easing_mode (ClutterActor *self)
17476 const ClutterAnimationInfo *info;
17478 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17480 info = _clutter_actor_get_animation_info_or_defaults (self);
17482 if (info->cur_state != NULL)
17483 return info->cur_state->easing_mode;
17485 return CLUTTER_EASE_OUT_CUBIC;
17489 * clutter_actor_set_easing_delay:
17490 * @self: a #ClutterActor
17491 * @msecs: the delay before the start of the tweening, in milliseconds
17493 * Sets the delay that should be applied before tweening animatable
17499 clutter_actor_set_easing_delay (ClutterActor *self,
17502 ClutterAnimationInfo *info;
17504 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17506 info = _clutter_actor_get_animation_info (self);
17508 if (info->cur_state == NULL)
17510 g_warning ("You must call clutter_actor_save_easing_state() prior "
17511 "to calling clutter_actor_set_easing_delay().");
17515 if (info->cur_state->easing_delay != msecs)
17516 info->cur_state->easing_delay = msecs;
17520 * clutter_actor_get_easing_delay:
17521 * @self: a #ClutterActor
17523 * Retrieves the delay that should be applied when tweening animatable
17526 * Return value: a delay, in milliseconds
17531 clutter_actor_get_easing_delay (ClutterActor *self)
17533 const ClutterAnimationInfo *info;
17535 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17537 info = _clutter_actor_get_animation_info_or_defaults (self);
17539 if (info->cur_state != NULL)
17540 return info->cur_state->easing_delay;
17546 * clutter_actor_get_transition:
17547 * @self: a #ClutterActor
17548 * @name: the name of the transition
17550 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17551 * transition @name.
17553 * Transitions created for animatable properties use the name of the
17554 * property itself, for instance the code below:
17557 * clutter_actor_set_easing_duration (actor, 1000);
17558 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17560 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17561 * g_signal_connect (transition, "completed",
17562 * G_CALLBACK (on_transition_complete),
17566 * will call the <function>on_transition_complete</function> callback when
17567 * the transition is complete.
17569 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17570 * was found to match the passed name; the returned instance is owned
17571 * by Clutter and it should not be freed
17575 ClutterTransition *
17576 clutter_actor_get_transition (ClutterActor *self,
17579 TransitionClosure *clos;
17580 const ClutterAnimationInfo *info;
17582 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17583 g_return_val_if_fail (name != NULL, NULL);
17585 info = _clutter_actor_get_animation_info_or_defaults (self);
17586 if (info->transitions == NULL)
17589 clos = g_hash_table_lookup (info->transitions, name);
17593 return clos->transition;
17597 * clutter_actor_save_easing_state:
17598 * @self: a #ClutterActor
17600 * Saves the current easing state for animatable properties, and creates
17601 * a new state with the default values for easing mode and duration.
17606 clutter_actor_save_easing_state (ClutterActor *self)
17608 ClutterAnimationInfo *info;
17611 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17613 info = _clutter_actor_get_animation_info (self);
17615 if (info->states == NULL)
17616 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17618 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17619 new_state.easing_duration = 250;
17620 new_state.easing_delay = 0;
17622 g_array_append_val (info->states, new_state);
17624 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17628 * clutter_actor_restore_easing_state:
17629 * @self: a #ClutterActor
17631 * Restores the easing state as it was prior to a call to
17632 * clutter_actor_save_easing_state().
17637 clutter_actor_restore_easing_state (ClutterActor *self)
17639 ClutterAnimationInfo *info;
17641 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17643 info = _clutter_actor_get_animation_info (self);
17645 if (info->states == NULL)
17647 g_critical ("The function clutter_actor_restore_easing_state() has "
17648 "called without a previous call to "
17649 "clutter_actor_save_easing_state().");
17653 g_array_remove_index (info->states, info->states->len - 1);
17655 if (info->states->len > 0)
17656 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17659 g_array_unref (info->states);
17660 info->states = NULL;
17661 info->cur_state = NULL;
17666 * clutter_actor_set_content:
17667 * @self: a #ClutterActor
17668 * @content: (allow-none): a #ClutterContent, or %NULL
17670 * Sets the contents of a #ClutterActor.
17675 clutter_actor_set_content (ClutterActor *self,
17676 ClutterContent *content)
17678 ClutterActorPrivate *priv;
17680 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17681 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17685 if (priv->content != NULL)
17687 _clutter_content_detached (priv->content, self);
17688 g_clear_object (&priv->content);
17691 priv->content = content;
17693 if (priv->content != NULL)
17695 g_object_ref (priv->content);
17696 _clutter_content_attached (priv->content, self);
17699 /* given that the content is always painted within the allocation,
17700 * we only need to queue a redraw here
17702 clutter_actor_queue_redraw (self);
17704 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17706 /* if the content gravity is not resize-fill, and the new content has a
17707 * different preferred size than the previous one, then the content box
17708 * may have been changed. since we compute that lazily, we just notify
17709 * here, and let whomever watches :content-box do whatever they need to
17712 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17713 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17717 * clutter_actor_get_content:
17718 * @self: a #ClutterActor
17720 * Retrieves the contents of @self.
17722 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17723 * or %NULL if none was set
17728 clutter_actor_get_content (ClutterActor *self)
17730 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17732 return self->priv->content;
17736 * clutter_actor_set_content_gravity:
17737 * @self: a #ClutterActor
17738 * @gravity: the #ClutterContentGravity
17740 * Sets the gravity of the #ClutterContent used by @self.
17742 * See the description of the #ClutterActor:content-gravity property for
17743 * more information.
17745 * The #ClutterActor:content-gravity property is animatable.
17750 clutter_actor_set_content_gravity (ClutterActor *self,
17751 ClutterContentGravity gravity)
17753 ClutterActorPrivate *priv;
17755 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17759 if (priv->content_gravity == gravity)
17762 priv->content_box_valid = FALSE;
17764 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17766 ClutterActorBox from_box, to_box;
17768 clutter_actor_get_content_box (self, &from_box);
17770 priv->content_gravity = gravity;
17772 clutter_actor_get_content_box (self, &to_box);
17774 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17780 ClutterActorBox to_box;
17782 priv->content_gravity = gravity;
17784 clutter_actor_get_content_box (self, &to_box);
17786 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17790 clutter_actor_queue_redraw (self);
17792 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17796 * clutter_actor_get_content_gravity:
17797 * @self: a #ClutterActor
17799 * Retrieves the content gravity as set using
17800 * clutter_actor_get_content_gravity().
17802 * Return value: the content gravity
17806 ClutterContentGravity
17807 clutter_actor_get_content_gravity (ClutterActor *self)
17809 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17810 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17812 return self->priv->content_gravity;
17816 * clutter_actor_get_content_box:
17817 * @self: a #ClutterActor
17818 * @box: (out caller-allocates): the return location for the bounding
17819 * box for the #ClutterContent
17821 * Retrieves the bounding box for the #ClutterContent of @self.
17823 * The bounding box is relative to the actor's allocation.
17825 * If no #ClutterContent is set for @self, or if @self has not been
17826 * allocated yet, then the result is undefined.
17828 * The content box is guaranteed to be, at most, as big as the allocation
17829 * of the #ClutterActor.
17831 * If the #ClutterContent used by the actor has a preferred size, then
17832 * it is possible to modify the content box by using the
17833 * #ClutterActor:content-gravity property.
17838 clutter_actor_get_content_box (ClutterActor *self,
17839 ClutterActorBox *box)
17841 ClutterActorPrivate *priv;
17842 gfloat content_w, content_h;
17843 gfloat alloc_w, alloc_h;
17845 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17846 g_return_if_fail (box != NULL);
17852 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17853 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17855 if (priv->content_box_valid)
17857 *box = priv->content_box;
17861 /* no need to do any more work */
17862 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17865 if (priv->content == NULL)
17868 /* if the content does not have a preferred size then there is
17869 * no point in computing the content box
17871 if (!clutter_content_get_preferred_size (priv->content,
17879 switch (priv->content_gravity)
17881 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17882 box->x2 = box->x1 + MIN (content_w, alloc_w);
17883 box->y2 = box->y1 + MIN (content_h, alloc_h);
17886 case CLUTTER_CONTENT_GRAVITY_TOP:
17887 if (alloc_w > content_w)
17889 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17890 box->x2 = box->x1 + content_w;
17892 box->y2 = box->y1 + MIN (content_h, alloc_h);
17895 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17896 if (alloc_w > content_w)
17898 box->x1 += (alloc_w - content_w);
17899 box->x2 = box->x1 + content_w;
17901 box->y2 = box->y1 + MIN (content_h, alloc_h);
17904 case CLUTTER_CONTENT_GRAVITY_LEFT:
17905 box->x2 = box->x1 + MIN (content_w, alloc_w);
17906 if (alloc_h > content_h)
17908 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17909 box->y2 = box->y1 + content_h;
17913 case CLUTTER_CONTENT_GRAVITY_CENTER:
17914 if (alloc_w > content_w)
17916 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17917 box->x2 = box->x1 + content_w;
17919 if (alloc_h > content_h)
17921 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17922 box->y2 = box->y1 + content_h;
17926 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17927 if (alloc_w > content_w)
17929 box->x1 += (alloc_w - content_w);
17930 box->x2 = box->x1 + content_w;
17932 if (alloc_h > content_h)
17934 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17935 box->y2 = box->y1 + content_h;
17939 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17940 box->x2 = box->x1 + MIN (content_w, alloc_w);
17941 if (alloc_h > content_h)
17943 box->y1 += (alloc_h - content_h);
17944 box->y2 = box->y1 + content_h;
17948 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17949 if (alloc_w > content_w)
17951 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17952 box->x2 = box->x1 + content_w;
17954 if (alloc_h > content_h)
17956 box->y1 += (alloc_h - content_h);
17957 box->y2 = box->y1 + content_h;
17961 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17962 if (alloc_w > content_w)
17964 box->x1 += (alloc_w - content_w);
17965 box->x2 = box->x1 + content_w;
17967 if (alloc_h > content_h)
17969 box->y1 += (alloc_h - content_h);
17970 box->y2 = box->y1 + content_h;
17974 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17975 g_assert_not_reached ();
17978 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17980 double r_c = content_w / content_h;
17981 double r_a = alloc_w / alloc_h;
17990 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17991 box->y2 = box->y1 + (alloc_w * r_c);
17998 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17999 box->x2 = box->x1 + (alloc_h * r_c);
18009 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18010 box->x2 = box->x1 + (alloc_h * r_c);
18017 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18018 box->y2 = box->y1 + (alloc_w * r_c);
18027 * clutter_actor_set_content_scaling_filters:
18028 * @self: a #ClutterActor
18029 * @min_filter: the minification filter for the content
18030 * @mag_filter: the magnification filter for the content
18032 * Sets the minification and magnification filter to be applied when
18033 * scaling the #ClutterActor:content of a #ClutterActor.
18035 * The #ClutterActor:minification-filter will be used when reducing
18036 * the size of the content; the #ClutterActor:magnification-filter
18037 * will be used when increasing the size of the content.
18042 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18043 ClutterScalingFilter min_filter,
18044 ClutterScalingFilter mag_filter)
18046 ClutterActorPrivate *priv;
18050 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18053 obj = G_OBJECT (self);
18055 g_object_freeze_notify (obj);
18059 if (priv->min_filter != min_filter)
18061 priv->min_filter = min_filter;
18064 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18067 if (priv->mag_filter != mag_filter)
18069 priv->mag_filter = mag_filter;
18072 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18076 clutter_actor_queue_redraw (self);
18078 g_object_thaw_notify (obj);
18082 * clutter_actor_get_content_scaling_filters:
18083 * @self: a #ClutterActor
18084 * @min_filter: (out) (allow-none): return location for the minification
18086 * @mag_filter: (out) (allow-none): return location for the magnification
18089 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18094 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18095 ClutterScalingFilter *min_filter,
18096 ClutterScalingFilter *mag_filter)
18098 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18100 if (min_filter != NULL)
18101 *min_filter = self->priv->min_filter;
18103 if (mag_filter != NULL)
18104 *mag_filter = self->priv->mag_filter;