4 * An OpenGL based 'interactive canvas' library.
6 * Authored By Matthew Allum <mallum@openedhand.com>
8 * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9 * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
26 * SECTION:clutter-actor
27 * @short_description: The basic element of the scene graph
29 * The ClutterActor class is the basic element of the scene graph in Clutter,
30 * and it encapsulates the position, size, and transformations of a node in
33 * <refsect2 id="ClutterActor-transformations">
34 * <title>Actor transformations</title>
35 * <para>Each actor can be transformed using methods like
36 * clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37 * in which the transformations are applied is decided by Clutter and it is
38 * the following:</para>
40 * <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41 * <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42 * <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43 * <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44 * <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45 * <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46 * <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
50 * <refsect2 id="ClutterActor-geometry">
51 * <title>Modifying an actor's geometry</title>
52 * <para>Each actor has a bounding box, called #ClutterActor:allocation
53 * which is either set by its parent or explicitly through the
54 * clutter_actor_set_position() and clutter_actor_set_size() methods.
55 * Each actor also has an implicit preferred size.</para>
56 * <para>An actor’s preferred size can be defined by any subclass by
57 * overriding the #ClutterActorClass.get_preferred_width() and the
58 * #ClutterActorClass.get_preferred_height() virtual functions, or it can
59 * be explicitly set by using clutter_actor_set_width() and
60 * clutter_actor_set_height().</para>
61 * <para>An actor’s position can be set explicitly by using
62 * clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63 * relative to the origin of the actor’s parent.</para>
66 * <refsect2 id="ClutterActor-children">
67 * <title>Managing actor children</title>
68 * <para>Each actor can have multiple children, by calling
69 * clutter_actor_add_child() to add a new child actor, and
70 * clutter_actor_remove_child() to remove an existing child. #ClutterActor
71 * will hold a reference on each child actor, which will be released when
72 * the child is removed from its parent, or destroyed using
73 * clutter_actor_destroy().</para>
74 * <informalexample><programlisting>
75 * ClutterActor *actor = clutter_actor_new ();
77 * /* set the bounding box of the actor */
78 * clutter_actor_set_position (actor, 0, 0);
79 * clutter_actor_set_size (actor, 480, 640);
81 * /* set the background color of the actor */
82 * clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
84 * /* set the bounding box of the child, relative to the parent */
85 * ClutterActor *child = clutter_actor_new ();
86 * clutter_actor_set_position (child, 20, 20);
87 * clutter_actor_set_size (child, 80, 240);
89 * /* set the background color of the child */
90 * clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
92 * /* add the child to the actor */
93 * clutter_actor_add_child (actor, child);
94 * </programlisting></informalexample>
95 * <para>Children can be inserted at a given index, or above and below
96 * another child actor. The order of insertion determines the order of the
97 * children when iterating over them. Iterating over children is performed
98 * by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99 * clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100 * also possible to retrieve a list of children by using
101 * clutter_actor_get_children(), as well as retrieving a specific child at a
102 * given index by using clutter_actor_get_child_at_index().</para>
103 * <para>If you need to track additions of children to a #ClutterActor, use
104 * the #ClutterContainer::actor-added signal; similarly, to track removals
105 * of children from a ClutterActor, use the #ClutterContainer::actor-removed
107 * <informalexample><programlisting>
108 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
111 * </programlisting></informalexample>
112 * <figure id="actor-example-image">
113 * <title>Actors</title>
114 * <graphic fileref="actor-example.png" format="PNG"/>
118 * <refsect2 id="ClutterActor-painting">
119 * <title>Painting an actor</title>
120 * <para>There are three ways to paint an actor:</para>
122 * <listitem><para>set a delegate #ClutterContent as the value for the
123 * #ClutterActor:content property of the actor;</para></listitem>
124 * <listitem><para>subclass #ClutterActor and override the
125 * #ClutterActorClass.paint_node() virtual function;</para></listitem>
126 * <listitem><para>subclass #ClutterActor and override the
127 * #ClutterActorClass.paint() virtual function.</para></listitem>
130 * <title>Setting the Content property</title>
131 * <para>A #ClutterContent is a delegate object that takes over the
132 * painting operation of one, or more actors. The #ClutterContent
133 * painting will be performed on top of the #ClutterActor:background-color
134 * of the actor, and before calling the #ClutterActorClass.paint_node()
135 * virtual function.</para>
136 * <informalexample><programlisting>
137 * ClutterActor *actor = clutter_actor_new ();
139 * /* set the bounding box */
140 * clutter_actor_set_position (actor, 50, 50);
141 * clutter_actor_set_size (actor, 100, 100);
143 * /* set the content; the image_content variable is set elsewhere */
144 * clutter_actor_set_content (actor, image_content);
145 * </programlisting></informalexample>
148 * <title>Overriding the paint_node virtual function</title>
149 * <para>The #ClutterActorClass.paint_node() virtual function is invoked
150 * whenever an actor needs to be painted. The implementation of the
151 * virtual function must only paint the contents of the actor itself,
152 * and not the contents of its children, if the actor has any.</para>
153 * <para>The #ClutterPaintNode passed to the virtual function is the
154 * local root of the render tree; any node added to it will be
155 * rendered at the correct position, as defined by the actor's
156 * #ClutterActor:allocation.</para>
157 * <informalexample><programlisting>
159 * my_actor_paint_node (ClutterActor *actor,
160 * ClutterPaintNode *root)
162 * ClutterPaintNode *node;
163 * ClutterActorBox box;
165 * /* where the content of the actor should be painted */
166 * clutter_actor_get_allocation_box (actor, &box);
168 * /* the cogl_texture variable is set elsewhere */
169 * node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170 * CLUTTER_SCALING_FILTER_TRILINEAR,
171 * CLUTTER_SCALING_FILTER_LINEAR);
173 * /* paint the content of the node using the allocation */
174 * clutter_paint_node_add_rectangle (node, &box);
176 * /* add the node, and transfer ownership */
177 * clutter_paint_node_add_child (root, node);
178 * clutter_paint_node_unref (node);
180 * </programlisting></informalexample>
183 * <title>Overriding the paint virtual function</title>
184 * <para>The #ClutterActorClass.paint() virtual function is invoked
185 * when the #ClutterActor::paint signal is emitted, and after the other
186 * signal handlers have been invoked. Overriding the paint virtual
187 * function gives total control to the paint sequence of the actor
188 * itself, including the children of the actor, if any.</para>
189 * <warning><para>It is strongly discouraged to override the
190 * #ClutterActorClass.paint() virtual function, as well as connecting
191 * to the #ClutterActor::paint signal. These hooks into the paint
192 * sequence are considered legacy, and will be removed when the Clutter
193 * API changes.</para></warning>
197 * <refsect2 id="ClutterActor-events">
198 * <title>Handling events on an actor</title>
199 * <para>A #ClutterActor can receive and handle input device events, for
200 * instance pointer events and key events, as long as its
201 * #ClutterActor:reactive property is set to %TRUE.</para>
202 * <para>Once an actor has been determined to be the source of an event,
203 * Clutter will traverse the scene graph from the top-level actor towards the
204 * event source, emitting the #ClutterActor::captured-event signal on each
205 * ancestor until it reaches the source; this phase is also called
206 * <emphasis>the capture phase</emphasis>. If the event propagation was not
207 * stopped, the graph is walked backwards, from the source actor to the
208 * top-level, and the #ClutterActor::event signal, along with other event
209 * signals if needed, is emitted; this phase is also called <emphasis>the
210 * bubble phase</emphasis>. At any point of the signal emission, signal
211 * handlers can stop the propagation through the scene graph by returning
212 * %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213 * returning %CLUTTER_EVENT_PROPAGATE.</para>
216 * <refsect2 id="ClutterActor-animation">
217 * <title>Animation</title>
218 * <para>Animation is a core concept of modern user interfaces; Clutter
219 * provides a complete and powerful animation framework that automatically
220 * tweens the actor's state without requiring direct, frame by frame
221 * manipulation from your application code.</para>
223 * <title>Implicit animations</title>
224 * <para>The implicit animation model of Clutter assumes that all the
225 * changes in an actor state should be gradual and asynchronous; Clutter
226 * will automatically transition an actor's property change between the
227 * current state and the desired one without manual intervention.</para>
228 * <para>By default, in the 1.0 API series, the transition happens with
229 * a duration of zero milliseconds, and the implicit animation is an
230 * opt in feature to retain backwards compatibility. In order to enable
231 * implicit animations, it is necessary to change the easing state of
232 * an actor by using clutter_actor_save_easing_state():</para>
233 * <informalexample><programlisting>
234 * /* assume that the actor is currently positioned at (100, 100) */
235 * clutter_actor_save_easing_state (actor);
236 * clutter_actor_set_position (actor, 500, 500);
237 * clutter_actor_restore_easing_state (actor);
238 * </programlisting></informalexample>
239 * <para>The example above will trigger an implicit animation of the
240 * actor between its current position to a new position.</para>
241 * <para>It is possible to animate multiple properties of an actor
242 * at the same time, and you can animate multiple actors at the same
243 * time as well, for instance:</para>
244 * <informalexample><programlisting>
245 * /* animate the actor's opacity and depth */
246 * clutter_actor_save_easing_state (actor);
247 * clutter_actor_set_opacity (actor, 0);
248 * clutter_actor_set_depth (actor, -100);
249 * clutter_actor_restore_easing_state (actor);
251 * /* animate another actor's opacity */
252 * clutter_actor_save_easing_state (another_actor);
253 * clutter_actor_set_opacity (another_actor, 255);
254 * clutter_actor_set_depth (another_actor, 100);
255 * clutter_actor_restore_easing_state (another_actor);
256 * </programlisting></informalexample>
257 * <para>Implicit animations use a default duration of 250 milliseconds,
258 * and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259 * clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260 * after changing the easing state of the actor.</para>
261 * <para>It is important to note that if you modify the state on an
262 * animatable property while a transition is in flight, the transition's
263 * final value will be updated, as well as its duration and progress
264 * mode by using the current easing state; for instance, in the following
266 * <informalexample><programlisting>
267 * clutter_actor_save_easing_state (actor);
268 * clutter_actor_set_x (actor, 200);
269 * clutter_actor_restore_easing_state (actor);
271 * clutter_actor_save_easing_state (actor);
272 * clutter_actor_set_x (actor, 100);
273 * clutter_actor_restore_easing_state (actor);
274 * </programlisting></informalexample>
275 * <para>the first call to clutter_actor_set_x() will begin a transition
276 * of the #ClutterActor:x property to the value of 200; the second call
277 * to clutter_actor_set_x() will change the transition's final value to
279 * <para>It is possible to retrieve the #ClutterTransition used by the
280 * animatable properties by using clutter_actor_get_transition() and using
281 * the property name as the transition name.</para>
284 * <title>Explicit animations</title>
285 * <para>The explicit animation model supported by Clutter requires that
286 * you create a #ClutterTransition object, and set the initial and
287 * final values. The transition will not start unless you add it to the
288 * #ClutterActor.</para>
289 * <informalexample><programlisting>
290 * ClutterTransition *transition;
292 * transition = clutter_property_transition_new ("opacity");
293 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296 * clutter_transition_set_from (transition, G_TYPE_UINT, 255);
297 * clutter_transition_set_to (transition, G_TYPE_UINT, 0);
299 * clutter_actor_add_transition (actor, "animate-opacity", transition);
300 * </programlisting></informalexample>
301 * <para>The example above will animate the #ClutterActor:opacity property
302 * of an actor between fully opaque and fully transparent, and back, over
303 * a span of 3 seconds. The animation does not begin until it is added to
305 * <para>The explicit animation API should also be used when using custom
306 * animatable properties for #ClutterAction, #ClutterConstraint, and
307 * #ClutterEffect instances associated to an actor; see the section on
308 * <ulink linkend="ClutterActor-custom-animatable-properties">custom
309 * animatable properties below</ulink> for an example.</para>
310 * <para>Finally, explicit animations are useful for creating animations
311 * that run continuously, for instance:</para>
312 * <informalexample><programlisting>
313 * /* this animation will pulse the actor's opacity continuously */
314 * ClutterTransition *transition;
315 * ClutterInterval *interval;
317 * transition = clutter_property_transition_new ("opacity");
319 * /* we want to animate the opacity between 0 and 255 */
320 * clutter_transition_set_from (transition, G_TYPE_UINT, 0);
321 * clutter_transition_set_to (transition, G_TYPE_UINT, 255);
323 * /* over a one second duration, running an infinite amount of times */
324 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
325 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
327 * /* we want to fade in and out, so we need to auto-reverse the transition */
328 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
330 * /* and we want to use an easing function that eases both in and out */
331 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
332 * CLUTTER_EASE_IN_OUT_CUBIC);
334 * /* add the transition to the desired actor; this will
335 * * start the animation.
337 * clutter_actor_add_transition (actor, "opacityAnimation", transition);
338 * </programlisting></informalexample>
342 * <refsect2 id="ClutterActor-subclassing">
343 * <title>Implementing an actor</title>
344 * <para>Careful consideration should be given when deciding to implement
345 * a #ClutterActor sub-class. It is generally recommended to implement a
346 * sub-class of #ClutterActor only for actors that should be used as leaf
347 * nodes of a scene graph.</para>
348 * <para>If your actor should be painted in a custom way, you should
349 * override the #ClutterActor::paint signal class handler. You can either
350 * opt to chain up to the parent class implementation or decide to fully
351 * override the default paint implementation; Clutter will set up the
352 * transformations and clip regions prior to emitting the #ClutterActor::paint
354 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
355 * #ClutterActorClass.get_preferred_height() virtual functions it is
356 * possible to change or provide the preferred size of an actor; similarly,
357 * by overriding the #ClutterActorClass.allocate() virtual function it is
358 * possible to control the layout of the children of an actor. Make sure to
359 * always chain up to the parent implementation of the
360 * #ClutterActorClass.allocate() virtual function.</para>
361 * <para>In general, it is strongly encouraged to use delegation and
362 * composition instead of direct subclassing.</para>
365 * <refsect2 id="ClutterActor-script">
366 * <title>ClutterActor custom properties for #ClutterScript</title>
367 * <para>#ClutterActor defines a custom "rotation" property which
368 * allows a short-hand description of the rotations to be applied
369 * to an actor.</para>
370 * <para>The syntax of the "rotation" property is the following:</para>
374 * { "<axis>" : [ <angle>, [ <center> ] ] }
378 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
379 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
380 * floating point value representing the rotation angle on the given axis,
382 * <para>The <emphasis>center</emphasis> array is optional, and if present
383 * it must contain the center of rotation as described by two coordinates:
384 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
386 * <para>#ClutterActor will also parse every positional and dimensional
387 * property defined as a string through clutter_units_from_string(); you
388 * should read the documentation for the #ClutterUnits parser format for
389 * the valid units and syntax.</para>
392 * <refsect2 id="ClutterActor-custom-animatable-properties">
393 * <title>Custom animatable properties</title>
394 * <para>#ClutterActor allows accessing properties of #ClutterAction,
395 * #ClutterEffect, and #ClutterConstraint instances associated to an actor
396 * instance for animation purposes.</para>
397 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
398 * property it is necessary to set the #ClutterActorMeta:name property on the
399 * given action or constraint.</para>
400 * <para>The property can be accessed using the following syntax:</para>
403 * @<section>.<meta-name>.<property-name>
406 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
407 * <para>The <emphasis>section</emphasis> fragment can be one between
408 * "actions", "constraints" and "effects".</para>
409 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
410 * action or constraint, as specified by the #ClutterActorMeta:name
412 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
413 * action or constraint property to be animated.</para>
414 * <para>The example below animates a #ClutterBindConstraint applied to an
415 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
416 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
417 * its initial state is overlapping the actor to which is bound to.</para>
418 * <informalexample><programlisting>
419 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
420 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
421 * clutter_actor_add_constraint (rect, constraint);
423 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
424 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
425 * clutter_actor_add_constraint (rect, constraint);
427 * clutter_actor_set_reactive (origin, TRUE);
429 * g_signal_connect (origin, "button-press-event",
430 * G_CALLBACK (on_button_press),
432 * </programlisting></informalexample>
433 * <para>On button press, the rectangle "slides" from behind the actor to
434 * which is bound to, using the #ClutterBindConstraint:offset property to
435 * achieve the effect:</para>
436 * <informalexample><programlisting>
438 * on_button_press (ClutterActor *origin,
439 * ClutterEvent *event,
440 * ClutterActor *rect)
442 * ClutterTransition *transition;
443 * ClutterInterval *interval;
445 * /* the offset that we want to apply; this will make the actor
446 * * slide in from behind the origin and rest at the right of
447 * * the origin, plus a padding value.
449 * float new_offset = clutter_actor_get_width (origin) + h_padding;
451 * /* the property we wish to animate; the "@constraints" section
452 * * tells Clutter to check inside the constraints associated
453 * * with the actor; the "bind-x" section is the name of the
454 * * constraint; and the "offset" is the name of the property
455 * * on the constraint.
457 * const char *prop = "@constraints.bind-x.offset";
459 * /* create a new transition for the given property */
460 * transition = clutter_property_transition_new (prop);
462 * /* set the easing mode and duration */
463 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
464 * CLUTTER_EASE_OUT_CUBIC);
465 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
467 * /* create the interval with the initial and final values */
468 * interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
469 * clutter_transition_set_interval (transition, interval);
471 * /* add the transition to the actor; this causes the animation
472 * * to start. the name "offsetAnimation" can be used to retrieve
473 * * the transition later.
475 * clutter_actor_add_transition (rect, "offsetAnimation", transition);
477 * /* we handled the event */
478 * return CLUTTER_EVENT_STOP;
480 * </programlisting></informalexample>
485 * CLUTTER_ACTOR_IS_MAPPED:
486 * @a: a #ClutterActor
488 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
490 * The mapped state is set when the actor is visible and all its parents up
491 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
493 * This check can be used to see if an actor is going to be painted, as only
494 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
496 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
497 * not be checked directly; instead, the recommended usage is to connect a
498 * handler on the #GObject::notify signal for the #ClutterActor:mapped
499 * property of #ClutterActor, and check the presence of
500 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
502 * It is also important to note that Clutter may delay the changes of
503 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
504 * limitations, or during the reparenting of an actor, to optimize
505 * unnecessary (and potentially expensive) state changes.
511 * CLUTTER_ACTOR_IS_REALIZED:
512 * @a: a #ClutterActor
514 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
516 * The realized state has an actor-dependant interpretation. If an
517 * actor wants to delay allocating resources until it is attached to a
518 * stage, it may use the realize state to do so. However it is
519 * perfectly acceptable for an actor to allocate Cogl resources before
520 * being realized because there is only one drawing context used by Clutter
521 * so any resources will work on any stage. If an actor is mapped it
522 * must also be realized, but an actor can be realized and unmapped
523 * (this is so hiding an actor temporarily doesn't do an expensive
524 * unrealize/realize).
526 * To be realized an actor must be inside a stage, and all its parents
533 * CLUTTER_ACTOR_IS_VISIBLE:
534 * @a: a #ClutterActor
536 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
537 * Equivalent to the ClutterActor::visible object property.
539 * Note that an actor is only painted onscreen if it's mapped, which
540 * means it's visible, and all its parents are visible, and one of the
541 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
547 * CLUTTER_ACTOR_IS_REACTIVE:
548 * @a: a #ClutterActor
550 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
552 * Only reactive actors will receive event-related signals.
563 #include <gobject/gvaluecollector.h>
565 #include <cogl/cogl.h>
567 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
568 #define CLUTTER_ENABLE_EXPERIMENTAL_API
570 #include "clutter-actor-private.h"
572 #include "clutter-action.h"
573 #include "clutter-actor-meta-private.h"
574 #include "clutter-animatable.h"
575 #include "clutter-color-static.h"
576 #include "clutter-color.h"
577 #include "clutter-constraint.h"
578 #include "clutter-container.h"
579 #include "clutter-content-private.h"
580 #include "clutter-debug.h"
581 #include "clutter-effect-private.h"
582 #include "clutter-enum-types.h"
583 #include "clutter-fixed-layout.h"
584 #include "clutter-flatten-effect.h"
585 #include "clutter-interval.h"
586 #include "clutter-main.h"
587 #include "clutter-marshal.h"
588 #include "clutter-paint-nodes.h"
589 #include "clutter-paint-node-private.h"
590 #include "clutter-paint-volume-private.h"
591 #include "clutter-private.h"
592 #include "clutter-profile.h"
593 #include "clutter-property-transition.h"
594 #include "clutter-scriptable.h"
595 #include "clutter-script-private.h"
596 #include "clutter-stage-private.h"
597 #include "clutter-timeline.h"
598 #include "clutter-transition.h"
599 #include "clutter-units.h"
601 #include "deprecated/clutter-actor.h"
602 #include "deprecated/clutter-behaviour.h"
603 #include "deprecated/clutter-container.h"
605 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
606 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
608 /* Internal enum used to control mapped state update. This is a hint
609 * which indicates when to do something other than just enforce
613 MAP_STATE_CHECK, /* just enforce invariants. */
614 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
615 * used when about to unparent.
617 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
618 * used to set mapped on toplevels.
620 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
621 * used just before unmapping parent.
625 /* 3 entries should be a good compromise, few layout managers
626 * will ask for 3 different preferred size in each allocation cycle */
627 #define N_CACHED_SIZE_REQUESTS 3
629 struct _ClutterActorPrivate
632 ClutterRequestMode request_mode;
634 /* our cached size requests for different width / height */
635 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
636 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
638 /* An age of 0 means the entry is not set */
639 guint cached_height_age;
640 guint cached_width_age;
642 /* the bounding box of the actor, relative to the parent's
645 ClutterActorBox allocation;
646 ClutterAllocationFlags allocation_flags;
648 /* clip, in actor coordinates */
649 cairo_rectangle_t clip;
651 /* the cached transformation matrix; see apply_transform() */
652 CoglMatrix transform;
655 gint opacity_override;
657 ClutterOffscreenRedirect offscreen_redirect;
659 /* This is an internal effect used to implement the
660 offscreen-redirect property */
661 ClutterEffect *flatten_effect;
664 ClutterActor *parent;
665 ClutterActor *prev_sibling;
666 ClutterActor *next_sibling;
667 ClutterActor *first_child;
668 ClutterActor *last_child;
672 /* tracks whenever the children of an actor are changed; the
673 * age is incremented by 1 whenever an actor is added or
674 * removed. the age is not incremented when the first or the
675 * last child pointers are changed, or when grandchildren of
676 * an actor are changed.
680 gchar *name; /* a non-unique name, used for debugging */
681 guint32 id; /* unique id, used for backward compatibility */
683 gint32 pick_id; /* per-stage unique id, used for picking */
685 /* a back-pointer to the Pango context that we can use
686 * to create pre-configured PangoLayout
688 PangoContext *pango_context;
690 /* the text direction configured for this child - either by
691 * application code, or by the actor's parent
693 ClutterTextDirection text_direction;
695 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
699 ClutterMetaGroup *actions;
700 ClutterMetaGroup *constraints;
701 ClutterMetaGroup *effects;
703 /* delegate object used to allocate the children of this actor */
704 ClutterLayoutManager *layout_manager;
706 /* delegate object used to paint the contents of this actor */
707 ClutterContent *content;
709 ClutterActorBox content_box;
710 ClutterContentGravity content_gravity;
711 ClutterScalingFilter min_filter;
712 ClutterScalingFilter mag_filter;
714 /* used when painting, to update the paint volume */
715 ClutterEffect *current_effect;
717 /* This is used to store an effect which needs to be redrawn. A
718 redraw can be queued to start from a particular effect. This is
719 used by parametrised effects that can cache an image of the
720 actor. If a parameter of the effect changes then it only needs to
721 redraw the cached image, not the actual actor. The pointer is
722 only valid if is_dirty == TRUE. If the pointer is NULL then the
723 whole actor is dirty. */
724 ClutterEffect *effect_to_redraw;
726 /* This is used when painting effects to implement the
727 clutter_actor_continue_paint() function. It points to the node in
728 the list of effects that is next in the chain */
729 const GList *next_effect_to_paint;
731 ClutterPaintVolume paint_volume;
733 /* NB: This volume isn't relative to this actor, it is in eye
734 * coordinates so that it can remain valid after the actor changes.
736 ClutterPaintVolume last_paint_volume;
738 ClutterStageQueueRedrawEntry *queue_redraw_entry;
740 ClutterColor bg_color;
744 /* fixed position and sizes */
745 guint position_set : 1;
746 guint min_width_set : 1;
747 guint min_height_set : 1;
748 guint natural_width_set : 1;
749 guint natural_height_set : 1;
750 /* cached request is invalid (implies allocation is too) */
751 guint needs_width_request : 1;
752 /* cached request is invalid (implies allocation is too) */
753 guint needs_height_request : 1;
754 /* cached allocation is invalid (request has changed, probably) */
755 guint needs_allocation : 1;
756 guint show_on_set_parent : 1;
758 guint clip_to_allocation : 1;
759 guint enable_model_view_transform : 1;
760 guint enable_paint_unmapped : 1;
761 guint has_pointer : 1;
762 guint propagated_one_redraw : 1;
763 guint paint_volume_valid : 1;
764 guint last_paint_volume_valid : 1;
765 guint in_clone_paint : 1;
766 guint transform_valid : 1;
767 /* This is TRUE if anything has queued a redraw since we were last
768 painted. In this case effect_to_redraw will point to an effect
769 the redraw was queued from or it will be NULL if the redraw was
770 queued without an effect. */
772 guint bg_color_set : 1;
773 guint content_box_valid : 1;
774 guint x_expand_set : 1;
775 guint y_expand_set : 1;
776 guint needs_compute_expand : 1;
777 guint needs_x_expand : 1;
778 guint needs_y_expand : 1;
787 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
788 * when set they force a size request, when gotten they
789 * get the allocation if the allocation is valid, and the
800 /* Then the rest of these size-related properties are the "actual"
801 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
806 PROP_FIXED_POSITION_SET,
815 PROP_NATURAL_WIDTH_SET,
818 PROP_NATURAL_HEIGHT_SET,
822 /* Allocation properties are read-only */
829 PROP_CLIP_TO_ALLOCATION,
833 PROP_OFFSCREEN_REDIRECT,
846 PROP_ROTATION_ANGLE_X,
847 PROP_ROTATION_ANGLE_Y,
848 PROP_ROTATION_ANGLE_Z,
849 PROP_ROTATION_CENTER_X,
850 PROP_ROTATION_CENTER_Y,
851 PROP_ROTATION_CENTER_Z,
852 /* This property only makes sense for the z rotation because the
853 others would depend on the actor having a size along the
855 PROP_ROTATION_CENTER_Z_GRAVITY,
861 PROP_SHOW_ON_SET_PARENT,
881 PROP_BACKGROUND_COLOR,
882 PROP_BACKGROUND_COLOR_SET,
888 PROP_CONTENT_GRAVITY,
890 PROP_MINIFICATION_FILTER,
891 PROP_MAGNIFICATION_FILTER,
896 static GParamSpec *obj_props[PROP_LAST];
915 BUTTON_RELEASE_EVENT,
923 TRANSITIONS_COMPLETED,
928 static guint actor_signals[LAST_SIGNAL] = { 0, };
930 static void clutter_container_iface_init (ClutterContainerIface *iface);
931 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
932 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
933 static void atk_implementor_iface_init (AtkImplementorIface *iface);
935 /* These setters are all static for now, maybe they should be in the
936 * public API, but they are perhaps obscure enough to leave only as
939 static void clutter_actor_set_min_width (ClutterActor *self,
941 static void clutter_actor_set_min_height (ClutterActor *self,
943 static void clutter_actor_set_natural_width (ClutterActor *self,
944 gfloat natural_width);
945 static void clutter_actor_set_natural_height (ClutterActor *self,
946 gfloat natural_height);
947 static void clutter_actor_set_min_width_set (ClutterActor *self,
948 gboolean use_min_width);
949 static void clutter_actor_set_min_height_set (ClutterActor *self,
950 gboolean use_min_height);
951 static void clutter_actor_set_natural_width_set (ClutterActor *self,
952 gboolean use_natural_width);
953 static void clutter_actor_set_natural_height_set (ClutterActor *self,
954 gboolean use_natural_height);
955 static void clutter_actor_update_map_state (ClutterActor *self,
956 MapStateChange change);
957 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
959 /* Helper routines for managing anchor coords */
960 static void clutter_anchor_coord_get_units (ClutterActor *self,
961 const AnchorCoord *coord,
965 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
970 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
971 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
972 ClutterGravity gravity);
974 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
976 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
978 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
979 ClutterActor *ancestor,
982 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
984 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
986 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
987 const ClutterColor *color);
989 static void on_layout_manager_changed (ClutterLayoutManager *manager,
992 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
994 /* Helper macro which translates by the anchor coord, applies the
995 given transformation and then translates back */
996 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
997 gfloat _tx, _ty, _tz; \
998 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
999 cogl_matrix_translate ((m), _tx, _ty, _tz); \
1001 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
1003 static GQuark quark_shader_data = 0;
1004 static GQuark quark_actor_layout_info = 0;
1005 static GQuark quark_actor_transform_info = 0;
1006 static GQuark quark_actor_animation_info = 0;
1008 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1010 G_TYPE_INITIALLY_UNOWNED,
1011 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1012 clutter_container_iface_init)
1013 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1014 clutter_scriptable_iface_init)
1015 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1016 clutter_animatable_iface_init)
1017 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1018 atk_implementor_iface_init));
1021 * clutter_actor_get_debug_name:
1022 * @actor: a #ClutterActor
1024 * Retrieves a printable name of @actor for debugging messages
1026 * Return value: a string with a printable name
1029 _clutter_actor_get_debug_name (ClutterActor *actor)
1031 return actor->priv->name != NULL ? actor->priv->name
1032 : G_OBJECT_TYPE_NAME (actor);
1035 #ifdef CLUTTER_ENABLE_DEBUG
1036 /* XXX - this is for debugging only, remove once working (or leave
1037 * in only in some debug mode). Should leave it for a little while
1038 * until we're confident in the new map/realize/visible handling.
1041 clutter_actor_verify_map_state (ClutterActor *self)
1043 ClutterActorPrivate *priv = self->priv;
1045 if (CLUTTER_ACTOR_IS_REALIZED (self))
1047 /* all bets are off during reparent when we're potentially realized,
1048 * but should not be according to invariants
1050 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1052 if (priv->parent == NULL)
1054 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1058 g_warning ("Realized non-toplevel actor '%s' should "
1060 _clutter_actor_get_debug_name (self));
1062 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1064 g_warning ("Realized actor %s has an unrealized parent %s",
1065 _clutter_actor_get_debug_name (self),
1066 _clutter_actor_get_debug_name (priv->parent));
1071 if (CLUTTER_ACTOR_IS_MAPPED (self))
1073 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1074 g_warning ("Actor '%s' is mapped but not realized",
1075 _clutter_actor_get_debug_name (self));
1077 /* remaining bets are off during reparent when we're potentially
1078 * mapped, but should not be according to invariants
1080 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1082 if (priv->parent == NULL)
1084 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1086 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1087 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1089 g_warning ("Toplevel actor '%s' is mapped "
1091 _clutter_actor_get_debug_name (self));
1096 g_warning ("Mapped actor '%s' should have a parent",
1097 _clutter_actor_get_debug_name (self));
1102 ClutterActor *iter = self;
1104 /* check for the enable_paint_unmapped flag on the actor
1105 * and parents; if the flag is enabled at any point of this
1106 * branch of the scene graph then all the later checks
1109 while (iter != NULL)
1111 if (iter->priv->enable_paint_unmapped)
1114 iter = iter->priv->parent;
1117 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1119 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1121 _clutter_actor_get_debug_name (self),
1122 _clutter_actor_get_debug_name (priv->parent));
1125 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1127 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1129 _clutter_actor_get_debug_name (self),
1130 _clutter_actor_get_debug_name (priv->parent));
1133 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1135 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1136 g_warning ("Actor '%s' is mapped but its non-toplevel "
1137 "parent '%s' is not mapped",
1138 _clutter_actor_get_debug_name (self),
1139 _clutter_actor_get_debug_name (priv->parent));
1146 #endif /* CLUTTER_ENABLE_DEBUG */
1149 clutter_actor_set_mapped (ClutterActor *self,
1152 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1157 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1158 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1162 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1163 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1167 /* this function updates the mapped and realized states according to
1168 * invariants, in the appropriate order.
1171 clutter_actor_update_map_state (ClutterActor *self,
1172 MapStateChange change)
1174 gboolean was_mapped;
1176 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1178 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1180 /* the mapped flag on top-level actors must be set by the
1181 * per-backend implementation because it might be asynchronous.
1183 * That is, the MAPPED flag on toplevels currently tracks the X
1184 * server mapped-ness of the window, while the expected behavior
1185 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1186 * This creates some weird complexity by breaking the invariant
1187 * that if we're visible and all ancestors shown then we are
1188 * also mapped - instead, we are mapped if all ancestors
1189 * _possibly excepting_ the stage are mapped. The stage
1190 * will map/unmap for example when it is minimized or
1191 * moved to another workspace.
1193 * So, the only invariant on the stage is that if visible it
1194 * should be realized, and that it has to be visible to be
1197 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1198 clutter_actor_realize (self);
1202 case MAP_STATE_CHECK:
1205 case MAP_STATE_MAKE_MAPPED:
1206 g_assert (!was_mapped);
1207 clutter_actor_set_mapped (self, TRUE);
1210 case MAP_STATE_MAKE_UNMAPPED:
1211 g_assert (was_mapped);
1212 clutter_actor_set_mapped (self, FALSE);
1215 case MAP_STATE_MAKE_UNREALIZED:
1216 /* we only use MAKE_UNREALIZED in unparent,
1217 * and unparenting a stage isn't possible.
1218 * If someone wants to just unrealize a stage
1219 * then clutter_actor_unrealize() doesn't
1220 * go through this codepath.
1222 g_warning ("Trying to force unrealize stage is not allowed");
1226 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1227 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1228 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1230 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1231 "it is somehow still mapped",
1232 _clutter_actor_get_debug_name (self));
1237 ClutterActorPrivate *priv = self->priv;
1238 ClutterActor *parent = priv->parent;
1239 gboolean should_be_mapped;
1240 gboolean may_be_realized;
1241 gboolean must_be_realized;
1243 should_be_mapped = FALSE;
1244 may_be_realized = TRUE;
1245 must_be_realized = FALSE;
1247 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1249 may_be_realized = FALSE;
1253 /* Maintain invariant that if parent is mapped, and we are
1254 * visible, then we are mapped ... unless parent is a
1255 * stage, in which case we map regardless of parent's map
1256 * state but do require stage to be visible and realized.
1258 * If parent is realized, that does not force us to be
1259 * realized; but if parent is unrealized, that does force
1260 * us to be unrealized.
1262 * The reason we don't force children to realize with
1263 * parents is _clutter_actor_rerealize(); if we require that
1264 * a realized parent means children are realized, then to
1265 * unrealize an actor we would have to unrealize its
1266 * parents, which would end up meaning unrealizing and
1267 * hiding the entire stage. So we allow unrealizing a
1268 * child (as long as that child is not mapped) while that
1269 * child still has a realized parent.
1271 * Also, if we unrealize from leaf nodes to root, and
1272 * realize from root to leaf, the invariants are never
1273 * violated if we allow children to be unrealized
1274 * while parents are realized.
1276 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1277 * to force us to unmap, even though parent is still
1278 * mapped. This is because we're unmapping from leaf nodes
1281 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1282 change != MAP_STATE_MAKE_UNMAPPED)
1284 gboolean parent_is_visible_realized_toplevel;
1286 parent_is_visible_realized_toplevel =
1287 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1288 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1289 CLUTTER_ACTOR_IS_REALIZED (parent));
1291 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1292 parent_is_visible_realized_toplevel)
1294 must_be_realized = TRUE;
1295 should_be_mapped = TRUE;
1299 /* if the actor has been set to be painted even if unmapped
1300 * then we should map it and check for realization as well;
1301 * this is an override for the branch of the scene graph
1302 * which begins with this node
1304 if (priv->enable_paint_unmapped)
1306 if (priv->parent == NULL)
1307 g_warning ("Attempting to map an unparented actor '%s'",
1308 _clutter_actor_get_debug_name (self));
1310 should_be_mapped = TRUE;
1311 must_be_realized = TRUE;
1314 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1315 may_be_realized = FALSE;
1318 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1321 g_warning ("Attempting to map a child that does not "
1322 "meet the necessary invariants: the actor '%s' "
1324 _clutter_actor_get_debug_name (self));
1326 g_warning ("Attempting to map a child that does not "
1327 "meet the necessary invariants: the actor '%s' "
1328 "is parented to an unmapped actor '%s'",
1329 _clutter_actor_get_debug_name (self),
1330 _clutter_actor_get_debug_name (priv->parent));
1333 /* If in reparent, we temporarily suspend unmap and unrealize.
1335 * We want to go in the order "realize, map" and "unmap, unrealize"
1339 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1340 clutter_actor_set_mapped (self, FALSE);
1343 if (must_be_realized)
1344 clutter_actor_realize (self);
1346 /* if we must be realized then we may be, presumably */
1347 g_assert (!(must_be_realized && !may_be_realized));
1350 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1351 clutter_actor_unrealize_not_hiding (self);
1354 if (should_be_mapped)
1356 if (!must_be_realized)
1357 g_warning ("Somehow we think actor '%s' should be mapped but "
1358 "not realized, which isn't allowed",
1359 _clutter_actor_get_debug_name (self));
1361 /* realization is allowed to fail (though I don't know what
1362 * an app is supposed to do about that - shouldn't it just
1363 * be a g_error? anyway, we have to avoid mapping if this
1366 if (CLUTTER_ACTOR_IS_REALIZED (self))
1367 clutter_actor_set_mapped (self, TRUE);
1371 #ifdef CLUTTER_ENABLE_DEBUG
1372 /* check all invariants were kept */
1373 clutter_actor_verify_map_state (self);
1378 clutter_actor_real_map (ClutterActor *self)
1380 ClutterActorPrivate *priv = self->priv;
1381 ClutterActor *stage, *iter;
1383 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1385 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1386 _clutter_actor_get_debug_name (self));
1388 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1390 stage = _clutter_actor_get_stage_internal (self);
1391 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1393 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1395 _clutter_actor_get_debug_name (self));
1397 /* notify on parent mapped before potentially mapping
1398 * children, so apps see a top-down notification.
1400 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1402 for (iter = self->priv->first_child;
1404 iter = iter->priv->next_sibling)
1406 clutter_actor_map (iter);
1411 * clutter_actor_map:
1412 * @self: A #ClutterActor
1414 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1415 * and realizes its children if they are visible. Does nothing if the
1416 * actor is not visible.
1418 * Calling this function is strongly disencouraged: the default
1419 * implementation of #ClutterActorClass.map() will map all the children
1420 * of an actor when mapping its parent.
1422 * When overriding map, it is mandatory to chain up to the parent
1428 clutter_actor_map (ClutterActor *self)
1430 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1432 if (CLUTTER_ACTOR_IS_MAPPED (self))
1435 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1438 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1442 clutter_actor_real_unmap (ClutterActor *self)
1444 ClutterActorPrivate *priv = self->priv;
1447 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1449 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1450 _clutter_actor_get_debug_name (self));
1452 for (iter = self->priv->first_child;
1454 iter = iter->priv->next_sibling)
1456 clutter_actor_unmap (iter);
1459 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1461 /* clear the contents of the last paint volume, so that hiding + moving +
1462 * showing will not result in the wrong area being repainted
1464 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1465 priv->last_paint_volume_valid = TRUE;
1467 /* notify on parent mapped after potentially unmapping
1468 * children, so apps see a bottom-up notification.
1470 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1472 /* relinquish keyboard focus if we were unmapped while owning it */
1473 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1475 ClutterStage *stage;
1477 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1480 _clutter_stage_release_pick_id (stage, priv->pick_id);
1484 if (stage != NULL &&
1485 clutter_stage_get_key_focus (stage) == self)
1487 clutter_stage_set_key_focus (stage, NULL);
1493 * clutter_actor_unmap:
1494 * @self: A #ClutterActor
1496 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1497 * unmaps its children if they were mapped.
1499 * Calling this function is not encouraged: the default #ClutterActor
1500 * implementation of #ClutterActorClass.unmap() will also unmap any
1501 * eventual children by default when their parent is unmapped.
1503 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1504 * chain up to the parent implementation.
1506 * <note>It is important to note that the implementation of the
1507 * #ClutterActorClass.unmap() virtual function may be called after
1508 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1509 * implementation, but it is guaranteed to be called before the
1510 * #GObjectClass.finalize() implementation.</note>
1515 clutter_actor_unmap (ClutterActor *self)
1517 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1519 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1522 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1526 clutter_actor_real_show (ClutterActor *self)
1528 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1530 ClutterActorPrivate *priv = self->priv;
1532 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1534 /* we notify on the "visible" flag in the clutter_actor_show()
1535 * wrapper so the entire show signal emission completes first
1538 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1540 /* we queue a relayout unless the actor is inside a
1541 * container that explicitly told us not to
1543 if (priv->parent != NULL &&
1544 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1546 /* While an actor is hidden the parent may not have
1547 * allocated/requested so we need to start from scratch
1548 * and avoid the short-circuiting in
1549 * clutter_actor_queue_relayout().
1551 priv->needs_width_request = FALSE;
1552 priv->needs_height_request = FALSE;
1553 priv->needs_allocation = FALSE;
1554 clutter_actor_queue_relayout (self);
1560 set_show_on_set_parent (ClutterActor *self,
1563 ClutterActorPrivate *priv = self->priv;
1565 set_show = !!set_show;
1567 if (priv->show_on_set_parent == set_show)
1570 if (priv->parent == NULL)
1572 priv->show_on_set_parent = set_show;
1573 g_object_notify_by_pspec (G_OBJECT (self),
1574 obj_props[PROP_SHOW_ON_SET_PARENT]);
1579 * clutter_actor_show:
1580 * @self: A #ClutterActor
1582 * Flags an actor to be displayed. An actor that isn't shown will not
1583 * be rendered on the stage.
1585 * Actors are visible by default.
1587 * If this function is called on an actor without a parent, the
1588 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1592 clutter_actor_show (ClutterActor *self)
1594 ClutterActorPrivate *priv;
1596 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1598 /* simple optimization */
1599 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1601 /* we still need to set the :show-on-set-parent property, in
1602 * case show() is called on an unparented actor
1604 set_show_on_set_parent (self, TRUE);
1608 #ifdef CLUTTER_ENABLE_DEBUG
1609 clutter_actor_verify_map_state (self);
1614 g_object_freeze_notify (G_OBJECT (self));
1616 set_show_on_set_parent (self, TRUE);
1618 /* if we're showing a child that needs to expand, or may
1619 * expand, then we need to recompute the expand flags for
1620 * its parent as well
1622 if (priv->needs_compute_expand ||
1623 priv->needs_x_expand ||
1624 priv->needs_y_expand)
1626 clutter_actor_queue_compute_expand (self);
1629 g_signal_emit (self, actor_signals[SHOW], 0);
1630 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1632 if (priv->parent != NULL)
1633 clutter_actor_queue_redraw (priv->parent);
1635 g_object_thaw_notify (G_OBJECT (self));
1639 * clutter_actor_show_all:
1640 * @self: a #ClutterActor
1642 * Calls clutter_actor_show() on all children of an actor (if any).
1646 * Deprecated: 1.10: Actors are visible by default
1649 clutter_actor_show_all (ClutterActor *self)
1651 ClutterActorClass *klass;
1653 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1655 klass = CLUTTER_ACTOR_GET_CLASS (self);
1656 if (klass->show_all)
1657 klass->show_all (self);
1661 clutter_actor_real_hide (ClutterActor *self)
1663 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1665 ClutterActorPrivate *priv = self->priv;
1667 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1669 /* we notify on the "visible" flag in the clutter_actor_hide()
1670 * wrapper so the entire hide signal emission completes first
1673 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1675 /* we queue a relayout unless the actor is inside a
1676 * container that explicitly told us not to
1678 if (priv->parent != NULL &&
1679 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1680 clutter_actor_queue_relayout (priv->parent);
1685 * clutter_actor_hide:
1686 * @self: A #ClutterActor
1688 * Flags an actor to be hidden. A hidden actor will not be
1689 * rendered on the stage.
1691 * Actors are visible by default.
1693 * If this function is called on an actor without a parent, the
1694 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1698 clutter_actor_hide (ClutterActor *self)
1700 ClutterActorPrivate *priv;
1702 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1704 /* simple optimization */
1705 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1707 /* we still need to set the :show-on-set-parent property, in
1708 * case hide() is called on an unparented actor
1710 set_show_on_set_parent (self, FALSE);
1714 #ifdef CLUTTER_ENABLE_DEBUG
1715 clutter_actor_verify_map_state (self);
1720 g_object_freeze_notify (G_OBJECT (self));
1722 set_show_on_set_parent (self, FALSE);
1724 /* if we're hiding a child that needs to expand, or may
1725 * expand, then we need to recompute the expand flags for
1726 * its parent as well
1728 if (priv->needs_compute_expand ||
1729 priv->needs_x_expand ||
1730 priv->needs_y_expand)
1732 clutter_actor_queue_compute_expand (self);
1735 g_signal_emit (self, actor_signals[HIDE], 0);
1736 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1738 if (priv->parent != NULL)
1739 clutter_actor_queue_redraw (priv->parent);
1741 g_object_thaw_notify (G_OBJECT (self));
1745 * clutter_actor_hide_all:
1746 * @self: a #ClutterActor
1748 * Calls clutter_actor_hide() on all child actors (if any).
1752 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1753 * prevent its children from being painted as well.
1756 clutter_actor_hide_all (ClutterActor *self)
1758 ClutterActorClass *klass;
1760 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1762 klass = CLUTTER_ACTOR_GET_CLASS (self);
1763 if (klass->hide_all)
1764 klass->hide_all (self);
1768 * clutter_actor_realize:
1769 * @self: A #ClutterActor
1771 * Realization informs the actor that it is attached to a stage. It
1772 * can use this to allocate resources if it wanted to delay allocation
1773 * until it would be rendered. However it is perfectly acceptable for
1774 * an actor to create resources before being realized because Clutter
1775 * only ever has a single rendering context so that actor is free to
1776 * be moved from one stage to another.
1778 * This function does nothing if the actor is already realized.
1780 * Because a realized actor must have realized parent actors, calling
1781 * clutter_actor_realize() will also realize all parents of the actor.
1783 * This function does not realize child actors, except in the special
1784 * case that realizing the stage, when the stage is visible, will
1785 * suddenly map (and thus realize) the children of the stage.
1788 clutter_actor_realize (ClutterActor *self)
1790 ClutterActorPrivate *priv;
1792 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1796 #ifdef CLUTTER_ENABLE_DEBUG
1797 clutter_actor_verify_map_state (self);
1800 if (CLUTTER_ACTOR_IS_REALIZED (self))
1803 /* To be realized, our parent actors must be realized first.
1804 * This will only succeed if we're inside a toplevel.
1806 if (priv->parent != NULL)
1807 clutter_actor_realize (priv->parent);
1809 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1811 /* toplevels can be realized at any time */
1815 /* "Fail" the realization if parent is missing or unrealized;
1816 * this should really be a g_warning() not some kind of runtime
1817 * failure; how can an app possibly recover? Instead it's a bug
1818 * in the app and the app should get an explanatory warning so
1819 * someone can fix it. But for now it's too hard to fix this
1820 * because e.g. ClutterTexture needs reworking.
1822 if (priv->parent == NULL ||
1823 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1827 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1829 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1830 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1832 g_signal_emit (self, actor_signals[REALIZE], 0);
1834 /* Stage actor is allowed to unset the realized flag again in its
1835 * default signal handler, though that is a pathological situation.
1838 /* If realization "failed" we'll have to update child state. */
1839 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1843 clutter_actor_real_unrealize (ClutterActor *self)
1845 /* we must be unmapped (implying our children are also unmapped) */
1846 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1850 * clutter_actor_unrealize:
1851 * @self: A #ClutterActor
1853 * Unrealization informs the actor that it may be being destroyed or
1854 * moved to another stage. The actor may want to destroy any
1855 * underlying graphics resources at this point. However it is
1856 * perfectly acceptable for it to retain the resources until the actor
1857 * is destroyed because Clutter only ever uses a single rendering
1858 * context and all of the graphics resources are valid on any stage.
1860 * Because mapped actors must be realized, actors may not be
1861 * unrealized if they are mapped. This function hides the actor to be
1862 * sure it isn't mapped, an application-visible side effect that you
1863 * may not be expecting.
1865 * This function should not be called by application code.
1868 clutter_actor_unrealize (ClutterActor *self)
1870 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1871 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1873 /* This function should not really be in the public API, because
1874 * there isn't a good reason to call it. ClutterActor will already
1875 * unrealize things for you when it's important to do so.
1877 * If you were using clutter_actor_unrealize() in a dispose
1878 * implementation, then don't, just chain up to ClutterActor's
1881 * If you were using clutter_actor_unrealize() to implement
1882 * unrealizing children of your container, then don't, ClutterActor
1883 * will already take care of that.
1885 * If you were using clutter_actor_unrealize() to re-realize to
1886 * create your resources in a different way, then use
1887 * _clutter_actor_rerealize() (inside Clutter) or just call your
1888 * code that recreates your resources directly (outside Clutter).
1891 #ifdef CLUTTER_ENABLE_DEBUG
1892 clutter_actor_verify_map_state (self);
1895 clutter_actor_hide (self);
1897 clutter_actor_unrealize_not_hiding (self);
1900 static ClutterActorTraverseVisitFlags
1901 unrealize_actor_before_children_cb (ClutterActor *self,
1905 /* If an actor is already unrealized we know its children have also
1906 * already been unrealized... */
1907 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1908 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1910 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1912 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1915 static ClutterActorTraverseVisitFlags
1916 unrealize_actor_after_children_cb (ClutterActor *self,
1920 /* We want to unset the realized flag only _after_
1921 * child actors are unrealized, to maintain invariants.
1923 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1924 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1925 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1929 * clutter_actor_unrealize_not_hiding:
1930 * @self: A #ClutterActor
1932 * Unrealization informs the actor that it may be being destroyed or
1933 * moved to another stage. The actor may want to destroy any
1934 * underlying graphics resources at this point. However it is
1935 * perfectly acceptable for it to retain the resources until the actor
1936 * is destroyed because Clutter only ever uses a single rendering
1937 * context and all of the graphics resources are valid on any stage.
1939 * Because mapped actors must be realized, actors may not be
1940 * unrealized if they are mapped. You must hide the actor or one of
1941 * its parents before attempting to unrealize.
1943 * This function is separate from clutter_actor_unrealize() because it
1944 * does not automatically hide the actor.
1945 * Actors need not be hidden to be unrealized, they just need to
1946 * be unmapped. In fact we don't want to mess up the application's
1947 * setting of the "visible" flag, so hiding is very undesirable.
1949 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1950 * backward compatibility.
1953 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1955 _clutter_actor_traverse (self,
1956 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1957 unrealize_actor_before_children_cb,
1958 unrealize_actor_after_children_cb,
1963 * _clutter_actor_rerealize:
1964 * @self: A #ClutterActor
1965 * @callback: Function to call while unrealized
1966 * @data: data for callback
1968 * If an actor is already unrealized, this just calls the callback.
1970 * If it is realized, it unrealizes temporarily, calls the callback,
1971 * and then re-realizes the actor.
1973 * As a side effect, leaves all children of the actor unrealized if
1974 * the actor was realized but not showing. This is because when we
1975 * unrealize the actor temporarily we must unrealize its children
1976 * (e.g. children of a stage can't be realized if stage window is
1977 * gone). And we aren't clever enough to save the realization state of
1978 * all children. In most cases this should not matter, because
1979 * the children will automatically realize when they next become mapped.
1982 _clutter_actor_rerealize (ClutterActor *self,
1983 ClutterCallback callback,
1986 gboolean was_mapped;
1987 gboolean was_showing;
1988 gboolean was_realized;
1990 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1992 #ifdef CLUTTER_ENABLE_DEBUG
1993 clutter_actor_verify_map_state (self);
1996 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1997 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1998 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
2000 /* Must be unmapped to unrealize. Note we only have to hide this
2001 * actor if it was mapped (if all parents were showing). If actor
2002 * is merely visible (but not mapped), then that's fine, we can
2006 clutter_actor_hide (self);
2008 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2010 /* unrealize self and all children */
2011 clutter_actor_unrealize_not_hiding (self);
2013 if (callback != NULL)
2015 (* callback) (self, data);
2019 clutter_actor_show (self); /* will realize only if mapping implies it */
2020 else if (was_realized)
2021 clutter_actor_realize (self); /* realize self and all parents */
2025 clutter_actor_real_pick (ClutterActor *self,
2026 const ClutterColor *color)
2028 /* the default implementation is just to paint a rectangle
2029 * with the same size of the actor using the passed color
2031 if (clutter_actor_should_pick_paint (self))
2033 ClutterActorBox box = { 0, };
2034 float width, height;
2036 clutter_actor_get_allocation_box (self, &box);
2038 width = box.x2 - box.x1;
2039 height = box.y2 - box.y1;
2041 cogl_set_source_color4ub (color->red,
2046 cogl_rectangle (0, 0, width, height);
2049 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2050 * with existing container classes that override the pick() virtual
2051 * and chain up to the default implementation - otherwise we'll end up
2052 * painting our children twice.
2054 * this has to go away for 2.0; hopefully along the pick() itself.
2056 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2060 for (iter = self->priv->first_child;
2062 iter = iter->priv->next_sibling)
2063 clutter_actor_paint (iter);
2068 * clutter_actor_should_pick_paint:
2069 * @self: A #ClutterActor
2071 * Should be called inside the implementation of the
2072 * #ClutterActor::pick virtual function in order to check whether
2073 * the actor should paint itself in pick mode or not.
2075 * This function should never be called directly by applications.
2077 * Return value: %TRUE if the actor should paint its silhouette,
2081 clutter_actor_should_pick_paint (ClutterActor *self)
2083 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2085 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2086 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2087 CLUTTER_ACTOR_IS_REACTIVE (self)))
2094 clutter_actor_real_get_preferred_width (ClutterActor *self,
2096 gfloat *min_width_p,
2097 gfloat *natural_width_p)
2099 ClutterActorPrivate *priv = self->priv;
2101 if (priv->n_children != 0 &&
2102 priv->layout_manager != NULL)
2104 ClutterContainer *container = CLUTTER_CONTAINER (self);
2106 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2107 "for the preferred width",
2108 G_OBJECT_TYPE_NAME (priv->layout_manager),
2109 priv->layout_manager);
2111 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2120 /* Default implementation is always 0x0, usually an actor
2121 * using this default is relying on someone to set the
2124 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2129 if (natural_width_p)
2130 *natural_width_p = 0;
2134 clutter_actor_real_get_preferred_height (ClutterActor *self,
2136 gfloat *min_height_p,
2137 gfloat *natural_height_p)
2139 ClutterActorPrivate *priv = self->priv;
2141 if (priv->n_children != 0 &&
2142 priv->layout_manager != NULL)
2144 ClutterContainer *container = CLUTTER_CONTAINER (self);
2146 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2147 "for the preferred height",
2148 G_OBJECT_TYPE_NAME (priv->layout_manager),
2149 priv->layout_manager);
2151 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2159 /* Default implementation is always 0x0, usually an actor
2160 * using this default is relying on someone to set the
2163 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2168 if (natural_height_p)
2169 *natural_height_p = 0;
2173 clutter_actor_store_old_geometry (ClutterActor *self,
2174 ClutterActorBox *box)
2176 *box = self->priv->allocation;
2180 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2181 const ClutterActorBox *old)
2183 ClutterActorPrivate *priv = self->priv;
2184 GObject *obj = G_OBJECT (self);
2186 g_object_freeze_notify (obj);
2188 /* to avoid excessive requisition or allocation cycles we
2189 * use the cached values.
2191 * - if we don't have an allocation we assume that we need
2193 * - if we don't have a width or a height request we notify
2195 * - if we have a valid allocation then we check the old
2196 * bounding box with the current allocation and we notify
2199 if (priv->needs_allocation)
2201 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2202 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2203 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2204 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2205 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2206 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2208 else if (priv->needs_width_request || priv->needs_height_request)
2210 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2211 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2212 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2217 gfloat width, height;
2219 x = priv->allocation.x1;
2220 y = priv->allocation.y1;
2221 width = priv->allocation.x2 - priv->allocation.x1;
2222 height = priv->allocation.y2 - priv->allocation.y1;
2226 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2227 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2232 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2233 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2236 if (width != (old->x2 - old->x1))
2238 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2239 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2242 if (height != (old->y2 - old->y1))
2244 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2245 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2249 g_object_thaw_notify (obj);
2253 * clutter_actor_set_allocation_internal:
2254 * @self: a #ClutterActor
2255 * @box: a #ClutterActorBox
2256 * @flags: allocation flags
2258 * Stores the allocation of @self.
2260 * This function only performs basic storage and property notification.
2262 * This function should be called by clutter_actor_set_allocation()
2263 * and by the default implementation of #ClutterActorClass.allocate().
2265 * Return value: %TRUE if the allocation of the #ClutterActor has been
2266 * changed, and %FALSE otherwise
2268 static inline gboolean
2269 clutter_actor_set_allocation_internal (ClutterActor *self,
2270 const ClutterActorBox *box,
2271 ClutterAllocationFlags flags)
2273 ClutterActorPrivate *priv = self->priv;
2275 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2277 ClutterActorBox old_alloc = { 0, };
2279 obj = G_OBJECT (self);
2281 g_object_freeze_notify (obj);
2283 clutter_actor_store_old_geometry (self, &old_alloc);
2285 x1_changed = priv->allocation.x1 != box->x1;
2286 y1_changed = priv->allocation.y1 != box->y1;
2287 x2_changed = priv->allocation.x2 != box->x2;
2288 y2_changed = priv->allocation.y2 != box->y2;
2290 priv->allocation = *box;
2291 priv->allocation_flags = flags;
2293 /* allocation is authoritative */
2294 priv->needs_width_request = FALSE;
2295 priv->needs_height_request = FALSE;
2296 priv->needs_allocation = FALSE;
2303 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2304 _clutter_actor_get_debug_name (self));
2306 priv->transform_valid = FALSE;
2308 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2310 /* if the allocation changes, so does the content box */
2311 if (priv->content != NULL)
2313 priv->content_box_valid = FALSE;
2314 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2322 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2324 g_object_thaw_notify (obj);
2329 static void clutter_actor_real_allocate (ClutterActor *self,
2330 const ClutterActorBox *box,
2331 ClutterAllocationFlags flags);
2334 clutter_actor_maybe_layout_children (ClutterActor *self,
2335 const ClutterActorBox *allocation,
2336 ClutterAllocationFlags flags)
2338 ClutterActorPrivate *priv = self->priv;
2340 /* this is going to be a bit hard to follow, so let's put an explanation
2343 * we want ClutterActor to have a default layout manager if the actor was
2344 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2346 * we also want any subclass of ClutterActor that does not override the
2347 * ::allocate() virtual function to delegate to a layout manager.
2349 * finally, we want to allow people subclassing ClutterActor and overriding
2350 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2352 * on the other hand, we want existing actor subclasses overriding the
2353 * ::allocate() virtual function and chaining up to the parent's
2354 * implementation to continue working without allocating their children
2355 * twice, or without entering an allocation loop.
2357 * for the first two points, we check if the class of the actor is
2358 * overridding the ::allocate() virtual function; if it isn't, then we
2359 * follow through with checking whether we have children and a layout
2360 * manager, and eventually calling clutter_layout_manager_allocate().
2362 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2363 * allocation flags that we got passed, and if it is present, we continue
2364 * with the check above.
2366 * if neither of these two checks yields a positive result, we just
2367 * assume that the ::allocate() virtual function that resulted in this
2368 * function being called will also allocate the children of the actor.
2371 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2374 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2380 if (priv->n_children != 0 &&
2381 priv->layout_manager != NULL)
2383 ClutterContainer *container = CLUTTER_CONTAINER (self);
2384 ClutterAllocationFlags children_flags;
2385 ClutterActorBox children_box;
2387 /* normalize the box passed to the layout manager */
2388 children_box.x1 = children_box.y1 = 0.f;
2389 children_box.x2 = (allocation->x2 - allocation->x1);
2390 children_box.y2 = (allocation->y2 - allocation->y1);
2392 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2393 * the actor's children, since it refers only to the current
2394 * actor's allocation.
2396 children_flags = flags;
2397 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2399 CLUTTER_NOTE (LAYOUT,
2400 "Allocating %d children of %s "
2401 "at { %.2f, %.2f - %.2f x %.2f } "
2404 _clutter_actor_get_debug_name (self),
2407 (allocation->x2 - allocation->x1),
2408 (allocation->y2 - allocation->y1),
2409 G_OBJECT_TYPE_NAME (priv->layout_manager));
2411 clutter_layout_manager_allocate (priv->layout_manager,
2419 clutter_actor_real_allocate (ClutterActor *self,
2420 const ClutterActorBox *box,
2421 ClutterAllocationFlags flags)
2423 ClutterActorPrivate *priv = self->priv;
2426 g_object_freeze_notify (G_OBJECT (self));
2428 changed = clutter_actor_set_allocation_internal (self, box, flags);
2430 /* we allocate our children before we notify changes in our geometry,
2431 * so that people connecting to properties will be able to get valid
2432 * data out of the sub-tree of the scene graph that has this actor at
2435 clutter_actor_maybe_layout_children (self, box, flags);
2439 ClutterActorBox signal_box = priv->allocation;
2440 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2442 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2447 g_object_thaw_notify (G_OBJECT (self));
2451 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2452 ClutterActor *origin)
2454 /* no point in queuing a redraw on a destroyed actor */
2455 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2458 /* NB: We can't bail out early here if the actor is hidden in case
2459 * the actor bas been cloned. In this case the clone will need to
2460 * receive the signal so it can queue its own redraw.
2463 /* calls klass->queue_redraw in default handler */
2464 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2468 clutter_actor_real_queue_redraw (ClutterActor *self,
2469 ClutterActor *origin)
2471 ClutterActor *parent;
2473 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2474 _clutter_actor_get_debug_name (self),
2475 origin != NULL ? _clutter_actor_get_debug_name (origin)
2478 /* no point in queuing a redraw on a destroyed actor */
2479 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2482 /* If the queue redraw is coming from a child then the actor has
2483 become dirty and any queued effect is no longer valid */
2486 self->priv->is_dirty = TRUE;
2487 self->priv->effect_to_redraw = NULL;
2490 /* If the actor isn't visible, we still had to emit the signal
2491 * to allow for a ClutterClone, but the appearance of the parent
2492 * won't change so we don't have to propagate up the hierarchy.
2494 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2497 /* Although we could determine here that a full stage redraw
2498 * has already been queued and immediately bail out, we actually
2499 * guarantee that we will propagate a queue-redraw signal to our
2500 * parent at least once so that it's possible to implement a
2501 * container that tracks which of its children have queued a
2504 if (self->priv->propagated_one_redraw)
2506 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2507 if (stage != NULL &&
2508 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2512 self->priv->propagated_one_redraw = TRUE;
2514 /* notify parents, if they are all visible eventually we'll
2515 * queue redraw on the stage, which queues the redraw idle.
2517 parent = clutter_actor_get_parent (self);
2520 /* this will go up recursively */
2521 _clutter_actor_signal_queue_redraw (parent, origin);
2526 clutter_actor_real_queue_relayout (ClutterActor *self)
2528 ClutterActorPrivate *priv = self->priv;
2530 /* no point in queueing a redraw on a destroyed actor */
2531 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2534 priv->needs_width_request = TRUE;
2535 priv->needs_height_request = TRUE;
2536 priv->needs_allocation = TRUE;
2538 /* reset the cached size requests */
2539 memset (priv->width_requests, 0,
2540 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2541 memset (priv->height_requests, 0,
2542 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2544 /* We need to go all the way up the hierarchy */
2545 if (priv->parent != NULL)
2546 _clutter_actor_queue_only_relayout (priv->parent);
2550 * clutter_actor_apply_relative_transform_to_point:
2551 * @self: A #ClutterActor
2552 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2553 * default #ClutterStage
2554 * @point: A point as #ClutterVertex
2555 * @vertex: (out caller-allocates): The translated #ClutterVertex
2557 * Transforms @point in coordinates relative to the actor into
2558 * ancestor-relative coordinates using the relevant transform
2559 * stack (i.e. scale, rotation, etc).
2561 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2562 * this case, the coordinates returned will be the coordinates on
2563 * the stage before the projection is applied. This is different from
2564 * the behaviour of clutter_actor_apply_transform_to_point().
2569 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2570 ClutterActor *ancestor,
2571 const ClutterVertex *point,
2572 ClutterVertex *vertex)
2577 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2578 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2579 g_return_if_fail (point != NULL);
2580 g_return_if_fail (vertex != NULL);
2585 if (ancestor == NULL)
2586 ancestor = _clutter_actor_get_stage_internal (self);
2588 if (ancestor == NULL)
2594 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2595 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2599 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2600 const ClutterVertex *vertices_in,
2601 ClutterVertex *vertices_out,
2604 ClutterActor *stage;
2605 CoglMatrix modelview;
2606 CoglMatrix projection;
2609 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2611 stage = _clutter_actor_get_stage_internal (self);
2613 /* We really can't do anything meaningful in this case so don't try
2614 * to do any transform */
2618 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2619 * that gets us to stage coordinates, we want to go all the way to eye
2621 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2623 /* Fetch the projection and viewport */
2624 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2625 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2631 _clutter_util_fully_transform_vertices (&modelview,
2642 * clutter_actor_apply_transform_to_point:
2643 * @self: A #ClutterActor
2644 * @point: A point as #ClutterVertex
2645 * @vertex: (out caller-allocates): The translated #ClutterVertex
2647 * Transforms @point in coordinates relative to the actor
2648 * into screen-relative coordinates with the current actor
2649 * transformation (i.e. scale, rotation, etc)
2654 clutter_actor_apply_transform_to_point (ClutterActor *self,
2655 const ClutterVertex *point,
2656 ClutterVertex *vertex)
2658 g_return_if_fail (point != NULL);
2659 g_return_if_fail (vertex != NULL);
2660 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2664 * _clutter_actor_get_relative_transformation_matrix:
2665 * @self: The actor whose coordinate space you want to transform from.
2666 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2667 * or %NULL if you want to transform all the way to eye coordinates.
2668 * @matrix: A #CoglMatrix to store the transformation
2670 * This gets a transformation @matrix that will transform coordinates from the
2671 * coordinate space of @self into the coordinate space of @ancestor.
2673 * For example if you need a matrix that can transform the local actor
2674 * coordinates of @self into stage coordinates you would pass the actor's stage
2675 * pointer as the @ancestor.
2677 * If you pass %NULL then the transformation will take you all the way through
2678 * to eye coordinates. This can be useful if you want to extract the entire
2679 * modelview transform that Clutter applies before applying the projection
2680 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2681 * using cogl_set_modelview_matrix() for example then you would want a matrix
2682 * that transforms into eye coordinates.
2684 * <note><para>This function explicitly initializes the given @matrix. If you just
2685 * want clutter to multiply a relative transformation with an existing matrix
2686 * you can use clutter_actor_apply_relative_transformation_matrix()
2687 * instead.</para></note>
2690 /* XXX: We should consider caching the stage relative modelview along with
2691 * the actor itself */
2693 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2694 ClutterActor *ancestor,
2697 cogl_matrix_init_identity (matrix);
2699 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2702 /* Project the given @box into stage window coordinates, writing the
2703 * transformed vertices to @verts[]. */
2705 _clutter_actor_transform_and_project_box (ClutterActor *self,
2706 const ClutterActorBox *box,
2707 ClutterVertex verts[])
2709 ClutterVertex box_vertices[4];
2711 box_vertices[0].x = box->x1;
2712 box_vertices[0].y = box->y1;
2713 box_vertices[0].z = 0;
2714 box_vertices[1].x = box->x2;
2715 box_vertices[1].y = box->y1;
2716 box_vertices[1].z = 0;
2717 box_vertices[2].x = box->x1;
2718 box_vertices[2].y = box->y2;
2719 box_vertices[2].z = 0;
2720 box_vertices[3].x = box->x2;
2721 box_vertices[3].y = box->y2;
2722 box_vertices[3].z = 0;
2725 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2729 * clutter_actor_get_allocation_vertices:
2730 * @self: A #ClutterActor
2731 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2732 * against, or %NULL to use the #ClutterStage
2733 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2734 * location for an array of 4 #ClutterVertex in which to store the result
2736 * Calculates the transformed coordinates of the four corners of the
2737 * actor in the plane of @ancestor. The returned vertices relate to
2738 * the #ClutterActorBox coordinates as follows:
2740 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2741 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2742 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2743 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2746 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2747 * this case, the coordinates returned will be the coordinates on
2748 * the stage before the projection is applied. This is different from
2749 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2754 clutter_actor_get_allocation_vertices (ClutterActor *self,
2755 ClutterActor *ancestor,
2756 ClutterVertex verts[])
2758 ClutterActorPrivate *priv;
2759 ClutterActorBox box;
2760 ClutterVertex vertices[4];
2761 CoglMatrix modelview;
2763 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2764 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2766 if (ancestor == NULL)
2767 ancestor = _clutter_actor_get_stage_internal (self);
2769 /* Fallback to a NOP transform if the actor isn't parented under a
2771 if (ancestor == NULL)
2776 /* if the actor needs to be allocated we force a relayout, so that
2777 * we will have valid values to use in the transformations */
2778 if (priv->needs_allocation)
2780 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2782 _clutter_stage_maybe_relayout (stage);
2785 box.x1 = box.y1 = 0;
2786 /* The result isn't really meaningful in this case but at
2787 * least try to do something *vaguely* reasonable... */
2788 clutter_actor_get_size (self, &box.x2, &box.y2);
2792 clutter_actor_get_allocation_box (self, &box);
2794 vertices[0].x = box.x1;
2795 vertices[0].y = box.y1;
2797 vertices[1].x = box.x2;
2798 vertices[1].y = box.y1;
2800 vertices[2].x = box.x1;
2801 vertices[2].y = box.y2;
2803 vertices[3].x = box.x2;
2804 vertices[3].y = box.y2;
2807 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2810 cogl_matrix_transform_points (&modelview,
2812 sizeof (ClutterVertex),
2814 sizeof (ClutterVertex),
2820 * clutter_actor_get_abs_allocation_vertices:
2821 * @self: A #ClutterActor
2822 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2823 * of 4 #ClutterVertex where to store the result.
2825 * Calculates the transformed screen coordinates of the four corners of
2826 * the actor; the returned vertices relate to the #ClutterActorBox
2827 * coordinates as follows:
2829 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2830 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2831 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2832 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2838 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2839 ClutterVertex verts[])
2841 ClutterActorPrivate *priv;
2842 ClutterActorBox actor_space_allocation;
2844 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2848 /* if the actor needs to be allocated we force a relayout, so that
2849 * the actor allocation box will be valid for
2850 * _clutter_actor_transform_and_project_box()
2852 if (priv->needs_allocation)
2854 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2855 /* There's nothing meaningful we can do now */
2859 _clutter_stage_maybe_relayout (stage);
2862 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2863 * own coordinate space... */
2864 actor_space_allocation.x1 = 0;
2865 actor_space_allocation.y1 = 0;
2866 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2867 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2868 _clutter_actor_transform_and_project_box (self,
2869 &actor_space_allocation,
2874 clutter_actor_real_apply_transform (ClutterActor *self,
2877 ClutterActorPrivate *priv = self->priv;
2879 if (!priv->transform_valid)
2881 CoglMatrix *transform = &priv->transform;
2882 const ClutterTransformInfo *info;
2884 info = _clutter_actor_get_transform_info_or_defaults (self);
2886 cogl_matrix_init_identity (transform);
2888 cogl_matrix_translate (transform,
2889 priv->allocation.x1,
2890 priv->allocation.y1,
2894 cogl_matrix_translate (transform, 0, 0, info->depth);
2897 * because the rotation involves translations, we must scale
2898 * before applying the rotations (if we apply the scale after
2899 * the rotations, the translations included in the rotation are
2900 * not scaled and so the entire object will move on the screen
2901 * as a result of rotating it).
2903 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2905 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2906 &info->scale_center,
2907 cogl_matrix_scale (transform,
2914 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2916 cogl_matrix_rotate (transform,
2921 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2923 cogl_matrix_rotate (transform,
2928 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2930 cogl_matrix_rotate (transform,
2934 if (!clutter_anchor_coord_is_zero (&info->anchor))
2938 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2939 cogl_matrix_translate (transform, -x, -y, -z);
2942 priv->transform_valid = TRUE;
2945 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2948 /* Applies the transforms associated with this actor to the given
2951 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2954 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2958 * clutter_actor_apply_relative_transformation_matrix:
2959 * @self: The actor whose coordinate space you want to transform from.
2960 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2961 * or %NULL if you want to transform all the way to eye coordinates.
2962 * @matrix: A #CoglMatrix to apply the transformation too.
2964 * This multiplies a transform with @matrix that will transform coordinates
2965 * from the coordinate space of @self into the coordinate space of @ancestor.
2967 * For example if you need a matrix that can transform the local actor
2968 * coordinates of @self into stage coordinates you would pass the actor's stage
2969 * pointer as the @ancestor.
2971 * If you pass %NULL then the transformation will take you all the way through
2972 * to eye coordinates. This can be useful if you want to extract the entire
2973 * modelview transform that Clutter applies before applying the projection
2974 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2975 * using cogl_set_modelview_matrix() for example then you would want a matrix
2976 * that transforms into eye coordinates.
2978 * <note>This function doesn't initialize the given @matrix, it simply
2979 * multiplies the requested transformation matrix with the existing contents of
2980 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2981 * before calling this function, or you can use
2982 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2985 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2986 ClutterActor *ancestor,
2989 ClutterActor *parent;
2991 /* Note we terminate before ever calling stage->apply_transform()
2992 * since that would conceptually be relative to the underlying
2993 * window OpenGL coordinates so we'd need a special @ancestor
2994 * value to represent the fake parent of the stage. */
2995 if (self == ancestor)
2998 parent = clutter_actor_get_parent (self);
3001 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3004 _clutter_actor_apply_modelview_transform (self, matrix);
3008 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3009 ClutterPaintVolume *pv,
3011 const CoglColor *color)
3013 static CoglPipeline *outline = NULL;
3014 CoglPrimitive *prim;
3015 ClutterVertex line_ends[12 * 2];
3018 clutter_backend_get_cogl_context (clutter_get_default_backend ());
3019 /* XXX: at some point we'll query this from the stage but we can't
3020 * do that until the osx backend uses Cogl natively. */
3021 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3023 if (outline == NULL)
3024 outline = cogl_pipeline_new (ctx);
3026 _clutter_paint_volume_complete (pv);
3028 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3031 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3032 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3033 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3034 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3039 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3040 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3041 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3042 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3044 /* Lines connecting front face to back face */
3045 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3046 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3047 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3048 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3051 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3053 (CoglVertexP3 *)line_ends);
3055 cogl_pipeline_set_color (outline, color);
3056 cogl_framebuffer_draw_primitive (fb, outline, prim);
3057 cogl_object_unref (prim);
3061 PangoLayout *layout;
3062 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3063 pango_layout_set_text (layout, label, -1);
3064 cogl_pango_render_layout (layout,
3069 g_object_unref (layout);
3074 _clutter_actor_draw_paint_volume (ClutterActor *self)
3076 ClutterPaintVolume *pv;
3079 pv = _clutter_actor_get_paint_volume_mutable (self);
3082 gfloat width, height;
3083 ClutterPaintVolume fake_pv;
3085 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3086 _clutter_paint_volume_init_static (&fake_pv, stage);
3088 clutter_actor_get_size (self, &width, &height);
3089 clutter_paint_volume_set_width (&fake_pv, width);
3090 clutter_paint_volume_set_height (&fake_pv, height);
3092 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3093 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3094 _clutter_actor_get_debug_name (self),
3097 clutter_paint_volume_free (&fake_pv);
3101 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3102 _clutter_actor_draw_paint_volume_full (self, pv,
3103 _clutter_actor_get_debug_name (self),
3109 _clutter_actor_paint_cull_result (ClutterActor *self,
3111 ClutterCullResult result)
3113 ClutterPaintVolume *pv;
3118 if (result == CLUTTER_CULL_RESULT_IN)
3119 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3120 else if (result == CLUTTER_CULL_RESULT_OUT)
3121 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3123 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3126 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3128 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3129 _clutter_actor_draw_paint_volume_full (self, pv,
3130 _clutter_actor_get_debug_name (self),
3134 PangoLayout *layout;
3136 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3137 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3138 cogl_set_source_color (&color);
3140 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3141 pango_layout_set_text (layout, label, -1);
3142 cogl_pango_render_layout (layout,
3148 g_object_unref (layout);
3152 static int clone_paint_level = 0;
3155 _clutter_actor_push_clone_paint (void)
3157 clone_paint_level++;
3161 _clutter_actor_pop_clone_paint (void)
3163 clone_paint_level--;
3167 in_clone_paint (void)
3169 return clone_paint_level > 0;
3172 /* Returns TRUE if the actor can be ignored */
3173 /* FIXME: we should return a ClutterCullResult, and
3174 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3175 * means there's no point in trying to cull descendants of the current
3178 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3180 ClutterActorPrivate *priv = self->priv;
3181 ClutterActor *stage;
3182 const ClutterPlane *stage_clip;
3184 if (!priv->last_paint_volume_valid)
3186 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3187 "->last_paint_volume_valid == FALSE",
3188 _clutter_actor_get_debug_name (self));
3192 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3195 stage = _clutter_actor_get_stage_internal (self);
3196 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3197 if (G_UNLIKELY (!stage_clip))
3199 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3200 "No stage clip set",
3201 _clutter_actor_get_debug_name (self));
3205 if (cogl_get_draw_framebuffer () !=
3206 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3208 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3209 "Current framebuffer doesn't correspond to stage",
3210 _clutter_actor_get_debug_name (self));
3215 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3220 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3222 ClutterActorPrivate *priv = self->priv;
3223 const ClutterPaintVolume *pv;
3225 if (priv->last_paint_volume_valid)
3227 clutter_paint_volume_free (&priv->last_paint_volume);
3228 priv->last_paint_volume_valid = FALSE;
3231 pv = clutter_actor_get_paint_volume (self);
3234 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3235 "Actor failed to report a paint volume",
3236 _clutter_actor_get_debug_name (self));
3240 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3242 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3243 NULL); /* eye coordinates */
3245 priv->last_paint_volume_valid = TRUE;
3248 static inline gboolean
3249 actor_has_shader_data (ClutterActor *self)
3251 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3255 _clutter_actor_get_pick_id (ClutterActor *self)
3257 if (self->priv->pick_id < 0)
3260 return self->priv->pick_id;
3263 /* This is the same as clutter_actor_add_effect except that it doesn't
3264 queue a redraw and it doesn't notify on the effect property */
3266 _clutter_actor_add_effect_internal (ClutterActor *self,
3267 ClutterEffect *effect)
3269 ClutterActorPrivate *priv = self->priv;
3271 if (priv->effects == NULL)
3273 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3274 priv->effects->actor = self;
3277 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3280 /* This is the same as clutter_actor_remove_effect except that it doesn't
3281 queue a redraw and it doesn't notify on the effect property */
3283 _clutter_actor_remove_effect_internal (ClutterActor *self,
3284 ClutterEffect *effect)
3286 ClutterActorPrivate *priv = self->priv;
3288 if (priv->effects == NULL)
3291 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3293 if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3294 g_clear_object (&priv->effects);
3298 needs_flatten_effect (ClutterActor *self)
3300 ClutterActorPrivate *priv = self->priv;
3302 if (G_UNLIKELY (clutter_paint_debug_flags &
3303 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3306 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3308 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3310 if (clutter_actor_get_paint_opacity (self) < 255 &&
3311 clutter_actor_has_overlaps (self))
3319 add_or_remove_flatten_effect (ClutterActor *self)
3321 ClutterActorPrivate *priv = self->priv;
3323 /* Add or remove the flatten effect depending on the
3324 offscreen-redirect property. */
3325 if (needs_flatten_effect (self))
3327 if (priv->flatten_effect == NULL)
3329 ClutterActorMeta *actor_meta;
3332 priv->flatten_effect = _clutter_flatten_effect_new ();
3333 /* Keep a reference to the effect so that we can queue
3335 g_object_ref_sink (priv->flatten_effect);
3337 /* Set the priority of the effect to high so that it will
3338 always be applied to the actor first. It uses an internal
3339 priority so that it won't be visible to applications */
3340 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3341 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3342 _clutter_actor_meta_set_priority (actor_meta, priority);
3344 /* This will add the effect without queueing a redraw */
3345 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3350 if (priv->flatten_effect != NULL)
3352 /* Destroy the effect so that it will lose its fbo cache of
3354 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3355 g_clear_object (&priv->flatten_effect);
3361 clutter_actor_real_paint (ClutterActor *actor)
3363 ClutterActorPrivate *priv = actor->priv;
3366 for (iter = priv->first_child;
3368 iter = iter->priv->next_sibling)
3370 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3371 _clutter_actor_get_debug_name (iter),
3372 _clutter_actor_get_debug_name (actor),
3373 iter->priv->allocation.x1,
3374 iter->priv->allocation.y1,
3375 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3376 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3378 clutter_actor_paint (iter);
3383 clutter_actor_paint_node (ClutterActor *actor,
3384 ClutterPaintNode *root)
3386 ClutterActorPrivate *priv = actor->priv;
3391 if (priv->bg_color_set &&
3392 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3394 ClutterPaintNode *node;
3395 ClutterColor bg_color;
3396 ClutterActorBox box;
3400 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3401 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3403 bg_color = priv->bg_color;
3404 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3405 * priv->bg_color.alpha
3408 node = clutter_color_node_new (&bg_color);
3409 clutter_paint_node_set_name (node, "backgroundColor");
3410 clutter_paint_node_add_rectangle (node, &box);
3411 clutter_paint_node_add_child (root, node);
3412 clutter_paint_node_unref (node);
3415 if (priv->content != NULL)
3416 _clutter_content_paint_content (priv->content, actor, root);
3418 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3419 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3421 if (clutter_paint_node_get_n_children (root) == 0)
3424 #ifdef CLUTTER_ENABLE_DEBUG
3425 if (CLUTTER_HAS_DEBUG (PAINT))
3427 /* dump the tree only if we have one */
3428 _clutter_paint_node_dump_tree (root);
3430 #endif /* CLUTTER_ENABLE_DEBUG */
3432 _clutter_paint_node_paint (root);
3435 /* XXX: Uncomment this when we disable emitting the paint signal */
3436 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3443 * clutter_actor_paint:
3444 * @self: A #ClutterActor
3446 * Renders the actor to display.
3448 * This function should not be called directly by applications.
3449 * Call clutter_actor_queue_redraw() to queue paints, instead.
3451 * This function is context-aware, and will either cause a
3452 * regular paint or a pick paint.
3454 * This function will emit the #ClutterActor::paint signal or
3455 * the #ClutterActor::pick signal, depending on the context.
3457 * This function does not paint the actor if the actor is set to 0,
3458 * unless it is performing a pick paint.
3461 clutter_actor_paint (ClutterActor *self)
3463 ClutterActorPrivate *priv;
3464 ClutterPickMode pick_mode;
3465 gboolean clip_set = FALSE;
3466 gboolean shader_applied = FALSE;
3468 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3469 "Actor real-paint counter",
3470 "Increments each time any actor is painted",
3471 0 /* no application private data */);
3472 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3473 "Actor pick-paint counter",
3474 "Increments each time any actor is painted "
3476 0 /* no application private data */);
3478 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3480 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3485 pick_mode = _clutter_context_get_pick_mode ();
3487 if (pick_mode == CLUTTER_PICK_NONE)
3488 priv->propagated_one_redraw = FALSE;
3490 /* It's an important optimization that we consider painting of
3491 * actors with 0 opacity to be a NOP... */
3492 if (pick_mode == CLUTTER_PICK_NONE &&
3493 /* ignore top-levels, since they might be transparent */
3494 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3495 /* Use the override opacity if its been set */
3496 ((priv->opacity_override >= 0) ?
3497 priv->opacity_override : priv->opacity) == 0)
3500 /* if we aren't paintable (not in a toplevel with all
3501 * parents paintable) then do nothing.
3503 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3506 /* mark that we are in the paint process */
3507 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3511 if (priv->enable_model_view_transform)
3515 /* XXX: It could be better to cache the modelview with the actor
3516 * instead of progressively building up the transformations on
3517 * the matrix stack every time we paint. */
3518 cogl_get_modelview_matrix (&matrix);
3519 _clutter_actor_apply_modelview_transform (self, &matrix);
3521 #ifdef CLUTTER_ENABLE_DEBUG
3522 /* Catch when out-of-band transforms have been made by actors not as part
3523 * of an apply_transform vfunc... */
3524 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3526 CoglMatrix expected_matrix;
3528 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3531 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3533 GString *buf = g_string_sized_new (1024);
3534 ClutterActor *parent;
3537 while (parent != NULL)
3539 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3541 if (parent->priv->parent != NULL)
3542 g_string_append (buf, "->");
3544 parent = parent->priv->parent;
3547 g_warning ("Unexpected transform found when painting actor "
3548 "\"%s\". This will be caused by one of the actor's "
3549 "ancestors (%s) using the Cogl API directly to transform "
3550 "children instead of using ::apply_transform().",
3551 _clutter_actor_get_debug_name (self),
3554 g_string_free (buf, TRUE);
3557 #endif /* CLUTTER_ENABLE_DEBUG */
3559 cogl_set_modelview_matrix (&matrix);
3564 cogl_clip_push_rectangle (priv->clip.x,
3566 priv->clip.x + priv->clip.width,
3567 priv->clip.y + priv->clip.height);
3570 else if (priv->clip_to_allocation)
3572 gfloat width, height;
3574 width = priv->allocation.x2 - priv->allocation.x1;
3575 height = priv->allocation.y2 - priv->allocation.y1;
3577 cogl_clip_push_rectangle (0, 0, width, height);
3581 if (pick_mode == CLUTTER_PICK_NONE)
3583 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3585 /* We check whether we need to add the flatten effect before
3586 each paint so that we can avoid having a mechanism for
3587 applications to notify when the value of the
3588 has_overlaps virtual changes. */
3589 add_or_remove_flatten_effect (self);
3592 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3594 /* We save the current paint volume so that the next time the
3595 * actor queues a redraw we can constrain the redraw to just
3596 * cover the union of the new bounding box and the old.
3598 * We also fetch the current paint volume to perform culling so
3599 * we can avoid painting actors outside the current clip region.
3601 * If we are painting inside a clone, we should neither update
3602 * the paint volume or use it to cull painting, since the paint
3603 * box represents the location of the source actor on the
3606 * XXX: We are starting to do a lot of vertex transforms on
3607 * the CPU in a typical paint, so at some point we should
3608 * audit these and consider caching some things.
3610 * NB: We don't perform culling while picking at this point because
3611 * clutter-stage.c doesn't setup the clipping planes appropriately.
3613 * NB: We don't want to update the last-paint-volume during picking
3614 * because the last-paint-volume is used to determine the old screen
3615 * space location of an actor that has moved so we can know the
3616 * minimal region to redraw to clear an old view of the actor. If we
3617 * update this during picking then by the time we come around to
3618 * paint then the last-paint-volume would likely represent the new
3619 * actor position not the old.
3621 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3624 /* annoyingly gcc warns if uninitialized even though
3625 * the initialization is redundant :-( */
3626 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3628 if (G_LIKELY ((clutter_paint_debug_flags &
3629 (CLUTTER_DEBUG_DISABLE_CULLING |
3630 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3631 (CLUTTER_DEBUG_DISABLE_CULLING |
3632 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3633 _clutter_actor_update_last_paint_volume (self);
3635 success = cull_actor (self, &result);
3637 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3638 _clutter_actor_paint_cull_result (self, success, result);
3639 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3643 if (priv->effects == NULL)
3645 if (pick_mode == CLUTTER_PICK_NONE &&
3646 actor_has_shader_data (self))
3648 _clutter_actor_shader_pre_paint (self, FALSE);
3649 shader_applied = TRUE;
3652 priv->next_effect_to_paint = NULL;
3655 priv->next_effect_to_paint =
3656 _clutter_meta_group_peek_metas (priv->effects);
3658 clutter_actor_continue_paint (self);
3661 _clutter_actor_shader_post_paint (self);
3663 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3664 pick_mode == CLUTTER_PICK_NONE))
3665 _clutter_actor_draw_paint_volume (self);
3668 /* If we make it here then the actor has run through a complete
3669 paint run including all the effects so it's no longer dirty */
3670 if (pick_mode == CLUTTER_PICK_NONE)
3671 priv->is_dirty = FALSE;
3678 /* paint sequence complete */
3679 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3683 * clutter_actor_continue_paint:
3684 * @self: A #ClutterActor
3686 * Run the next stage of the paint sequence. This function should only
3687 * be called within the implementation of the ‘run’ virtual of a
3688 * #ClutterEffect. It will cause the run method of the next effect to
3689 * be applied, or it will paint the actual actor if the current effect
3690 * is the last effect in the chain.
3695 clutter_actor_continue_paint (ClutterActor *self)
3697 ClutterActorPrivate *priv;
3699 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3700 /* This should only be called from with in the ‘run’ implementation
3701 of a ClutterEffect */
3702 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3706 /* Skip any effects that are disabled */
3707 while (priv->next_effect_to_paint &&
3708 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3709 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3711 /* If this has come from the last effect then we'll just paint the
3713 if (priv->next_effect_to_paint == NULL)
3715 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3717 ClutterPaintNode *dummy;
3719 /* XXX - this will go away in 2.0, when we can get rid of this
3720 * stuff and switch to a pure retained render tree of PaintNodes
3721 * for the entire frame, starting from the Stage; the paint()
3722 * virtual function can then be called directly.
3724 dummy = _clutter_dummy_node_new (self);
3725 clutter_paint_node_set_name (dummy, "Root");
3727 /* XXX - for 1.12, we use the return value of paint_node() to
3728 * decide whether we should emit the ::paint signal.
3730 clutter_actor_paint_node (self, dummy);
3731 clutter_paint_node_unref (dummy);
3733 g_signal_emit (self, actor_signals[PAINT], 0);
3737 ClutterColor col = { 0, };
3739 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3741 /* Actor will then paint silhouette of itself in supplied
3742 * color. See clutter_stage_get_actor_at_pos() for where
3743 * picking is enabled.
3745 g_signal_emit (self, actor_signals[PICK], 0, &col);
3750 ClutterEffect *old_current_effect;
3751 ClutterEffectPaintFlags run_flags = 0;
3753 /* Cache the current effect so that we can put it back before
3755 old_current_effect = priv->current_effect;
3757 priv->current_effect = priv->next_effect_to_paint->data;
3758 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3760 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3764 /* If there's an effect queued with this redraw then all
3765 effects up to that one will be considered dirty. It
3766 is expected the queued effect will paint the cached
3767 image and not call clutter_actor_continue_paint again
3768 (although it should work ok if it does) */
3769 if (priv->effect_to_redraw == NULL ||
3770 priv->current_effect != priv->effect_to_redraw)
3771 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3774 _clutter_effect_paint (priv->current_effect, run_flags);
3778 /* We can't determine when an actor has been modified since
3779 its last pick so lets just assume it has always been
3781 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3783 _clutter_effect_pick (priv->current_effect, run_flags);
3786 priv->current_effect = old_current_effect;
3790 static ClutterActorTraverseVisitFlags
3791 invalidate_queue_redraw_entry (ClutterActor *self,
3795 ClutterActorPrivate *priv = self->priv;
3797 if (priv->queue_redraw_entry != NULL)
3799 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3800 priv->queue_redraw_entry = NULL;
3803 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3807 remove_child (ClutterActor *self,
3808 ClutterActor *child)
3810 ClutterActor *prev_sibling, *next_sibling;
3812 prev_sibling = child->priv->prev_sibling;
3813 next_sibling = child->priv->next_sibling;
3815 if (prev_sibling != NULL)
3816 prev_sibling->priv->next_sibling = next_sibling;
3818 if (next_sibling != NULL)
3819 next_sibling->priv->prev_sibling = prev_sibling;
3821 if (self->priv->first_child == child)
3822 self->priv->first_child = next_sibling;
3824 if (self->priv->last_child == child)
3825 self->priv->last_child = prev_sibling;
3827 child->priv->parent = NULL;
3828 child->priv->prev_sibling = NULL;
3829 child->priv->next_sibling = NULL;
3833 REMOVE_CHILD_DESTROY_META = 1 << 0,
3834 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3835 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3836 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3837 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3838 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3840 /* default flags for public API */
3841 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3842 REMOVE_CHILD_EMIT_PARENT_SET |
3843 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3844 REMOVE_CHILD_CHECK_STATE |
3845 REMOVE_CHILD_FLUSH_QUEUE |
3846 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3848 /* flags for legacy/deprecated API */
3849 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3850 REMOVE_CHILD_FLUSH_QUEUE |
3851 REMOVE_CHILD_EMIT_PARENT_SET |
3852 REMOVE_CHILD_NOTIFY_FIRST_LAST
3853 } ClutterActorRemoveChildFlags;
3856 * clutter_actor_remove_child_internal:
3857 * @self: a #ClutterActor
3858 * @child: the child of @self that has to be removed
3859 * @flags: control the removal operations
3861 * Removes @child from the list of children of @self.
3864 clutter_actor_remove_child_internal (ClutterActor *self,
3865 ClutterActor *child,
3866 ClutterActorRemoveChildFlags flags)
3868 ClutterActor *old_first, *old_last;
3869 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3870 gboolean flush_queue;
3871 gboolean notify_first_last;
3872 gboolean was_mapped;
3874 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3875 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3876 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3877 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3878 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3879 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3881 g_object_freeze_notify (G_OBJECT (self));
3884 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3888 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3890 /* we need to unrealize *before* we set parent_actor to NULL,
3891 * because in an unrealize method actors are dissociating from the
3892 * stage, which means they need to be able to
3893 * clutter_actor_get_stage().
3895 * yhis should unmap and unrealize, unless we're reparenting.
3897 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3904 /* We take this opportunity to invalidate any queue redraw entry
3905 * associated with the actor and descendants since we won't be able to
3906 * determine the appropriate stage after this.
3908 * we do this after we updated the mapped state because actors might
3909 * end up queueing redraws inside their mapped/unmapped virtual
3910 * functions, and if we invalidate the redraw entry we could end up
3911 * with an inconsistent state and weird memory corruption. see
3914 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3915 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3917 _clutter_actor_traverse (child,
3919 invalidate_queue_redraw_entry,
3924 old_first = self->priv->first_child;
3925 old_last = self->priv->last_child;
3927 remove_child (self, child);
3929 self->priv->n_children -= 1;
3931 self->priv->age += 1;
3933 /* if the child that got removed was visible and set to
3934 * expand then we want to reset the parent's state in
3935 * case the child was the only thing that was making it
3938 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
3939 (child->priv->needs_compute_expand ||
3940 child->priv->needs_x_expand ||
3941 child->priv->needs_y_expand))
3943 clutter_actor_queue_compute_expand (self);
3946 /* clutter_actor_reparent() will emit ::parent-set for us */
3947 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3948 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3950 /* if the child was mapped then we need to relayout ourselves to account
3951 * for the removed child
3954 clutter_actor_queue_relayout (self);
3956 /* we need to emit the signal before dropping the reference */
3957 if (emit_actor_removed)
3958 g_signal_emit_by_name (self, "actor-removed", child);
3960 if (notify_first_last)
3962 if (old_first != self->priv->first_child)
3963 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3965 if (old_last != self->priv->last_child)
3966 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3969 g_object_thaw_notify (G_OBJECT (self));
3971 /* remove the reference we acquired in clutter_actor_add_child() */
3972 g_object_unref (child);
3975 static const ClutterTransformInfo default_transform_info = {
3976 0.0, { 0, }, /* rotation-x */
3977 0.0, { 0, }, /* rotation-y */
3978 0.0, { 0, }, /* rotation-z */
3980 1.0, 1.0, { 0, }, /* scale */
3982 { 0, }, /* anchor */
3988 * _clutter_actor_get_transform_info_or_defaults:
3989 * @self: a #ClutterActor
3991 * Retrieves the ClutterTransformInfo structure associated to an actor.
3993 * If the actor does not have a ClutterTransformInfo structure associated
3994 * to it, then the default structure will be returned.
3996 * This function should only be used for getters.
3998 * Return value: a const pointer to the ClutterTransformInfo structure
4000 const ClutterTransformInfo *
4001 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4003 ClutterTransformInfo *info;
4005 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4009 return &default_transform_info;
4013 clutter_transform_info_free (gpointer data)
4016 g_slice_free (ClutterTransformInfo, data);
4020 * _clutter_actor_get_transform_info:
4021 * @self: a #ClutterActor
4023 * Retrieves a pointer to the ClutterTransformInfo structure.
4025 * If the actor does not have a ClutterTransformInfo associated to it, one
4026 * will be created and initialized to the default values.
4028 * This function should be used for setters.
4030 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4033 * Return value: (transfer none): a pointer to the ClutterTransformInfo
4036 ClutterTransformInfo *
4037 _clutter_actor_get_transform_info (ClutterActor *self)
4039 ClutterTransformInfo *info;
4041 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4044 info = g_slice_new (ClutterTransformInfo);
4046 *info = default_transform_info;
4048 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4050 clutter_transform_info_free);
4057 * clutter_actor_set_rotation_angle_internal:
4058 * @self: a #ClutterActor
4059 * @axis: the axis of the angle to change
4060 * @angle: the angle of rotation
4062 * Sets the rotation angle on the given axis without affecting the
4063 * rotation center point.
4066 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4067 ClutterRotateAxis axis,
4070 GObject *obj = G_OBJECT (self);
4071 ClutterTransformInfo *info;
4073 info = _clutter_actor_get_transform_info (self);
4075 g_object_freeze_notify (obj);
4079 case CLUTTER_X_AXIS:
4080 info->rx_angle = angle;
4081 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4084 case CLUTTER_Y_AXIS:
4085 info->ry_angle = angle;
4086 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4089 case CLUTTER_Z_AXIS:
4090 info->rz_angle = angle;
4091 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4095 self->priv->transform_valid = FALSE;
4097 g_object_thaw_notify (obj);
4099 clutter_actor_queue_redraw (self);
4103 clutter_actor_set_rotation_angle (ClutterActor *self,
4104 ClutterRotateAxis axis,
4107 const ClutterTransformInfo *info;
4108 const double *cur_angle_p = NULL;
4109 GParamSpec *pspec = NULL;
4111 info = _clutter_actor_get_transform_info_or_defaults (self);
4115 case CLUTTER_X_AXIS:
4116 cur_angle_p = &info->rx_angle;
4117 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4120 case CLUTTER_Y_AXIS:
4121 cur_angle_p = &info->ry_angle;
4122 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4125 case CLUTTER_Z_AXIS:
4126 cur_angle_p = &info->rz_angle;
4127 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4131 g_assert (pspec != NULL);
4132 g_assert (cur_angle_p != NULL);
4134 if (_clutter_actor_get_transition (self, pspec) == NULL)
4135 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4137 _clutter_actor_update_transition (self, pspec, angle);
4139 clutter_actor_queue_redraw (self);
4143 * clutter_actor_set_rotation_center_internal:
4144 * @self: a #ClutterActor
4145 * @axis: the axis of the center to change
4146 * @center: the coordinates of the rotation center
4148 * Sets the rotation center on the given axis without affecting the
4152 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4153 ClutterRotateAxis axis,
4154 const ClutterVertex *center)
4156 GObject *obj = G_OBJECT (self);
4157 ClutterTransformInfo *info;
4158 ClutterVertex v = { 0, 0, 0 };
4160 info = _clutter_actor_get_transform_info (self);
4165 g_object_freeze_notify (obj);
4169 case CLUTTER_X_AXIS:
4170 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4171 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4174 case CLUTTER_Y_AXIS:
4175 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4176 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4179 case CLUTTER_Z_AXIS:
4180 /* if the previously set rotation center was fractional, then
4181 * setting explicit coordinates will have to notify the
4182 * :rotation-center-z-gravity property as well
4184 if (info->rz_center.is_fractional)
4185 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4187 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4188 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4192 self->priv->transform_valid = FALSE;
4194 g_object_thaw_notify (obj);
4196 clutter_actor_queue_redraw (self);
4200 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4204 GObject *obj = G_OBJECT (self);
4205 ClutterTransformInfo *info;
4207 info = _clutter_actor_get_transform_info (self);
4209 if (pspec == obj_props[PROP_SCALE_X])
4210 info->scale_x = factor;
4212 info->scale_y = factor;
4214 self->priv->transform_valid = FALSE;
4215 clutter_actor_queue_redraw (self);
4216 g_object_notify_by_pspec (obj, pspec);
4220 clutter_actor_set_scale_factor (ClutterActor *self,
4221 ClutterRotateAxis axis,
4224 const ClutterTransformInfo *info;
4225 const double *scale_p = NULL;
4226 GParamSpec *pspec = NULL;
4228 info = _clutter_actor_get_transform_info_or_defaults (self);
4232 case CLUTTER_X_AXIS:
4233 pspec = obj_props[PROP_SCALE_X];
4234 scale_p = &info->scale_x;
4237 case CLUTTER_Y_AXIS:
4238 pspec = obj_props[PROP_SCALE_Y];
4239 scale_p = &info->scale_y;
4242 case CLUTTER_Z_AXIS:
4246 g_assert (pspec != NULL);
4247 g_assert (scale_p != NULL);
4249 if (_clutter_actor_get_transition (self, pspec) == NULL)
4250 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4252 _clutter_actor_update_transition (self, pspec, factor);
4254 clutter_actor_queue_redraw (self);
4258 clutter_actor_set_scale_center (ClutterActor *self,
4259 ClutterRotateAxis axis,
4262 GObject *obj = G_OBJECT (self);
4263 ClutterTransformInfo *info;
4264 gfloat center_x, center_y;
4266 info = _clutter_actor_get_transform_info (self);
4268 g_object_freeze_notify (obj);
4270 /* get the current scale center coordinates */
4271 clutter_anchor_coord_get_units (self, &info->scale_center,
4276 /* we need to notify this too, because setting explicit coordinates will
4277 * change the gravity as a side effect
4279 if (info->scale_center.is_fractional)
4280 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4284 case CLUTTER_X_AXIS:
4285 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4286 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4289 case CLUTTER_Y_AXIS:
4290 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4291 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4295 g_assert_not_reached ();
4298 self->priv->transform_valid = FALSE;
4300 clutter_actor_queue_redraw (self);
4302 g_object_thaw_notify (obj);
4306 clutter_actor_set_scale_gravity (ClutterActor *self,
4307 ClutterGravity gravity)
4309 ClutterTransformInfo *info;
4312 info = _clutter_actor_get_transform_info (self);
4313 obj = G_OBJECT (self);
4315 if (gravity == CLUTTER_GRAVITY_NONE)
4316 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4318 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4320 self->priv->transform_valid = FALSE;
4322 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4323 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4324 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4326 clutter_actor_queue_redraw (self);
4330 clutter_actor_set_anchor_coord (ClutterActor *self,
4331 ClutterRotateAxis axis,
4334 GObject *obj = G_OBJECT (self);
4335 ClutterTransformInfo *info;
4336 gfloat anchor_x, anchor_y;
4338 info = _clutter_actor_get_transform_info (self);
4340 g_object_freeze_notify (obj);
4342 clutter_anchor_coord_get_units (self, &info->anchor,
4347 if (info->anchor.is_fractional)
4348 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4352 case CLUTTER_X_AXIS:
4353 clutter_anchor_coord_set_units (&info->anchor,
4357 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4360 case CLUTTER_Y_AXIS:
4361 clutter_anchor_coord_set_units (&info->anchor,
4365 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4369 g_assert_not_reached ();
4372 self->priv->transform_valid = FALSE;
4374 clutter_actor_queue_redraw (self);
4376 g_object_thaw_notify (obj);
4380 clutter_actor_set_property (GObject *object,
4382 const GValue *value,
4385 ClutterActor *actor = CLUTTER_ACTOR (object);
4386 ClutterActorPrivate *priv = actor->priv;
4391 clutter_actor_set_x (actor, g_value_get_float (value));
4395 clutter_actor_set_y (actor, g_value_get_float (value));
4400 const ClutterPoint *pos = g_value_get_boxed (value);
4403 clutter_actor_set_position (actor, pos->x, pos->y);
4405 clutter_actor_set_fixed_position_set (actor, FALSE);
4410 clutter_actor_set_width (actor, g_value_get_float (value));
4414 clutter_actor_set_height (actor, g_value_get_float (value));
4419 const ClutterSize *size = g_value_get_boxed (value);
4422 clutter_actor_set_size (actor, size->width, size->height);
4424 clutter_actor_set_size (actor, -1, -1);
4429 clutter_actor_set_x (actor, g_value_get_float (value));
4433 clutter_actor_set_y (actor, g_value_get_float (value));
4436 case PROP_FIXED_POSITION_SET:
4437 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4440 case PROP_MIN_WIDTH:
4441 clutter_actor_set_min_width (actor, g_value_get_float (value));
4444 case PROP_MIN_HEIGHT:
4445 clutter_actor_set_min_height (actor, g_value_get_float (value));
4448 case PROP_NATURAL_WIDTH:
4449 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4452 case PROP_NATURAL_HEIGHT:
4453 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4456 case PROP_MIN_WIDTH_SET:
4457 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4460 case PROP_MIN_HEIGHT_SET:
4461 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4464 case PROP_NATURAL_WIDTH_SET:
4465 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4468 case PROP_NATURAL_HEIGHT_SET:
4469 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4472 case PROP_REQUEST_MODE:
4473 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4477 clutter_actor_set_depth (actor, g_value_get_float (value));
4481 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4484 case PROP_OFFSCREEN_REDIRECT:
4485 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4489 clutter_actor_set_name (actor, g_value_get_string (value));
4493 if (g_value_get_boolean (value) == TRUE)
4494 clutter_actor_show (actor);
4496 clutter_actor_hide (actor);
4500 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4501 g_value_get_double (value));
4505 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4506 g_value_get_double (value));
4509 case PROP_SCALE_CENTER_X:
4510 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4511 g_value_get_float (value));
4514 case PROP_SCALE_CENTER_Y:
4515 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4516 g_value_get_float (value));
4519 case PROP_SCALE_GRAVITY:
4520 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4525 const ClutterGeometry *geom = g_value_get_boxed (value);
4527 clutter_actor_set_clip (actor,
4529 geom->width, geom->height);
4533 case PROP_CLIP_TO_ALLOCATION:
4534 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4538 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4541 case PROP_ROTATION_ANGLE_X:
4542 clutter_actor_set_rotation_angle (actor,
4544 g_value_get_double (value));
4547 case PROP_ROTATION_ANGLE_Y:
4548 clutter_actor_set_rotation_angle (actor,
4550 g_value_get_double (value));
4553 case PROP_ROTATION_ANGLE_Z:
4554 clutter_actor_set_rotation_angle (actor,
4556 g_value_get_double (value));
4559 case PROP_ROTATION_CENTER_X:
4560 clutter_actor_set_rotation_center_internal (actor,
4562 g_value_get_boxed (value));
4565 case PROP_ROTATION_CENTER_Y:
4566 clutter_actor_set_rotation_center_internal (actor,
4568 g_value_get_boxed (value));
4571 case PROP_ROTATION_CENTER_Z:
4572 clutter_actor_set_rotation_center_internal (actor,
4574 g_value_get_boxed (value));
4577 case PROP_ROTATION_CENTER_Z_GRAVITY:
4579 const ClutterTransformInfo *info;
4581 info = _clutter_actor_get_transform_info_or_defaults (actor);
4582 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4583 g_value_get_enum (value));
4588 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4589 g_value_get_float (value));
4593 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4594 g_value_get_float (value));
4597 case PROP_ANCHOR_GRAVITY:
4598 clutter_actor_set_anchor_point_from_gravity (actor,
4599 g_value_get_enum (value));
4602 case PROP_SHOW_ON_SET_PARENT:
4603 priv->show_on_set_parent = g_value_get_boolean (value);
4606 case PROP_TEXT_DIRECTION:
4607 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4611 clutter_actor_add_action (actor, g_value_get_object (value));
4614 case PROP_CONSTRAINTS:
4615 clutter_actor_add_constraint (actor, g_value_get_object (value));
4619 clutter_actor_add_effect (actor, g_value_get_object (value));
4622 case PROP_LAYOUT_MANAGER:
4623 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4627 clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4631 clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4635 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4639 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4642 case PROP_MARGIN_TOP:
4643 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4646 case PROP_MARGIN_BOTTOM:
4647 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4650 case PROP_MARGIN_LEFT:
4651 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4654 case PROP_MARGIN_RIGHT:
4655 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4658 case PROP_BACKGROUND_COLOR:
4659 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4663 clutter_actor_set_content (actor, g_value_get_object (value));
4666 case PROP_CONTENT_GRAVITY:
4667 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4670 case PROP_MINIFICATION_FILTER:
4671 clutter_actor_set_content_scaling_filters (actor,
4672 g_value_get_enum (value),
4673 actor->priv->mag_filter);
4676 case PROP_MAGNIFICATION_FILTER:
4677 clutter_actor_set_content_scaling_filters (actor,
4678 actor->priv->min_filter,
4679 g_value_get_enum (value));
4683 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4689 clutter_actor_get_property (GObject *object,
4694 ClutterActor *actor = CLUTTER_ACTOR (object);
4695 ClutterActorPrivate *priv = actor->priv;
4700 g_value_set_float (value, clutter_actor_get_x (actor));
4704 g_value_set_float (value, clutter_actor_get_y (actor));
4709 ClutterPoint position;
4711 clutter_point_init (&position,
4712 clutter_actor_get_x (actor),
4713 clutter_actor_get_y (actor));
4714 g_value_set_boxed (value, &position);
4719 g_value_set_float (value, clutter_actor_get_width (actor));
4723 g_value_set_float (value, clutter_actor_get_height (actor));
4730 clutter_size_init (&size,
4731 clutter_actor_get_width (actor),
4732 clutter_actor_get_height (actor));
4733 g_value_set_boxed (value, &size);
4739 const ClutterLayoutInfo *info;
4741 info = _clutter_actor_get_layout_info_or_defaults (actor);
4742 g_value_set_float (value, info->fixed_pos.x);
4748 const ClutterLayoutInfo *info;
4750 info = _clutter_actor_get_layout_info_or_defaults (actor);
4751 g_value_set_float (value, info->fixed_pos.y);
4755 case PROP_FIXED_POSITION_SET:
4756 g_value_set_boolean (value, priv->position_set);
4759 case PROP_MIN_WIDTH:
4761 const ClutterLayoutInfo *info;
4763 info = _clutter_actor_get_layout_info_or_defaults (actor);
4764 g_value_set_float (value, info->minimum.width);
4768 case PROP_MIN_HEIGHT:
4770 const ClutterLayoutInfo *info;
4772 info = _clutter_actor_get_layout_info_or_defaults (actor);
4773 g_value_set_float (value, info->minimum.height);
4777 case PROP_NATURAL_WIDTH:
4779 const ClutterLayoutInfo *info;
4781 info = _clutter_actor_get_layout_info_or_defaults (actor);
4782 g_value_set_float (value, info->natural.width);
4786 case PROP_NATURAL_HEIGHT:
4788 const ClutterLayoutInfo *info;
4790 info = _clutter_actor_get_layout_info_or_defaults (actor);
4791 g_value_set_float (value, info->natural.height);
4795 case PROP_MIN_WIDTH_SET:
4796 g_value_set_boolean (value, priv->min_width_set);
4799 case PROP_MIN_HEIGHT_SET:
4800 g_value_set_boolean (value, priv->min_height_set);
4803 case PROP_NATURAL_WIDTH_SET:
4804 g_value_set_boolean (value, priv->natural_width_set);
4807 case PROP_NATURAL_HEIGHT_SET:
4808 g_value_set_boolean (value, priv->natural_height_set);
4811 case PROP_REQUEST_MODE:
4812 g_value_set_enum (value, priv->request_mode);
4815 case PROP_ALLOCATION:
4816 g_value_set_boxed (value, &priv->allocation);
4820 g_value_set_float (value, clutter_actor_get_depth (actor));
4824 g_value_set_uint (value, priv->opacity);
4827 case PROP_OFFSCREEN_REDIRECT:
4828 g_value_set_enum (value, priv->offscreen_redirect);
4832 g_value_set_string (value, priv->name);
4836 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4840 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4844 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4848 g_value_set_boolean (value, priv->has_clip);
4853 ClutterGeometry clip;
4855 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4856 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4857 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4858 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4860 g_value_set_boxed (value, &clip);
4864 case PROP_CLIP_TO_ALLOCATION:
4865 g_value_set_boolean (value, priv->clip_to_allocation);
4870 const ClutterTransformInfo *info;
4872 info = _clutter_actor_get_transform_info_or_defaults (actor);
4873 g_value_set_double (value, info->scale_x);
4879 const ClutterTransformInfo *info;
4881 info = _clutter_actor_get_transform_info_or_defaults (actor);
4882 g_value_set_double (value, info->scale_y);
4886 case PROP_SCALE_CENTER_X:
4890 clutter_actor_get_scale_center (actor, ¢er, NULL);
4892 g_value_set_float (value, center);
4896 case PROP_SCALE_CENTER_Y:
4900 clutter_actor_get_scale_center (actor, NULL, ¢er);
4902 g_value_set_float (value, center);
4906 case PROP_SCALE_GRAVITY:
4907 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4911 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4914 case PROP_ROTATION_ANGLE_X:
4916 const ClutterTransformInfo *info;
4918 info = _clutter_actor_get_transform_info_or_defaults (actor);
4919 g_value_set_double (value, info->rx_angle);
4923 case PROP_ROTATION_ANGLE_Y:
4925 const ClutterTransformInfo *info;
4927 info = _clutter_actor_get_transform_info_or_defaults (actor);
4928 g_value_set_double (value, info->ry_angle);
4932 case PROP_ROTATION_ANGLE_Z:
4934 const ClutterTransformInfo *info;
4936 info = _clutter_actor_get_transform_info_or_defaults (actor);
4937 g_value_set_double (value, info->rz_angle);
4941 case PROP_ROTATION_CENTER_X:
4943 ClutterVertex center;
4945 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4950 g_value_set_boxed (value, ¢er);
4954 case PROP_ROTATION_CENTER_Y:
4956 ClutterVertex center;
4958 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4963 g_value_set_boxed (value, ¢er);
4967 case PROP_ROTATION_CENTER_Z:
4969 ClutterVertex center;
4971 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4976 g_value_set_boxed (value, ¢er);
4980 case PROP_ROTATION_CENTER_Z_GRAVITY:
4981 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4986 const ClutterTransformInfo *info;
4989 info = _clutter_actor_get_transform_info_or_defaults (actor);
4990 clutter_anchor_coord_get_units (actor, &info->anchor,
4994 g_value_set_float (value, anchor_x);
5000 const ClutterTransformInfo *info;
5003 info = _clutter_actor_get_transform_info_or_defaults (actor);
5004 clutter_anchor_coord_get_units (actor, &info->anchor,
5008 g_value_set_float (value, anchor_y);
5012 case PROP_ANCHOR_GRAVITY:
5013 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5016 case PROP_SHOW_ON_SET_PARENT:
5017 g_value_set_boolean (value, priv->show_on_set_parent);
5020 case PROP_TEXT_DIRECTION:
5021 g_value_set_enum (value, priv->text_direction);
5024 case PROP_HAS_POINTER:
5025 g_value_set_boolean (value, priv->has_pointer);
5028 case PROP_LAYOUT_MANAGER:
5029 g_value_set_object (value, priv->layout_manager);
5034 const ClutterLayoutInfo *info;
5036 info = _clutter_actor_get_layout_info_or_defaults (actor);
5037 g_value_set_boolean (value, info->x_expand);
5043 const ClutterLayoutInfo *info;
5045 info = _clutter_actor_get_layout_info_or_defaults (actor);
5046 g_value_set_boolean (value, info->y_expand);
5052 const ClutterLayoutInfo *info;
5054 info = _clutter_actor_get_layout_info_or_defaults (actor);
5055 g_value_set_enum (value, info->x_align);
5061 const ClutterLayoutInfo *info;
5063 info = _clutter_actor_get_layout_info_or_defaults (actor);
5064 g_value_set_enum (value, info->y_align);
5068 case PROP_MARGIN_TOP:
5070 const ClutterLayoutInfo *info;
5072 info = _clutter_actor_get_layout_info_or_defaults (actor);
5073 g_value_set_float (value, info->margin.top);
5077 case PROP_MARGIN_BOTTOM:
5079 const ClutterLayoutInfo *info;
5081 info = _clutter_actor_get_layout_info_or_defaults (actor);
5082 g_value_set_float (value, info->margin.bottom);
5086 case PROP_MARGIN_LEFT:
5088 const ClutterLayoutInfo *info;
5090 info = _clutter_actor_get_layout_info_or_defaults (actor);
5091 g_value_set_float (value, info->margin.left);
5095 case PROP_MARGIN_RIGHT:
5097 const ClutterLayoutInfo *info;
5099 info = _clutter_actor_get_layout_info_or_defaults (actor);
5100 g_value_set_float (value, info->margin.right);
5104 case PROP_BACKGROUND_COLOR_SET:
5105 g_value_set_boolean (value, priv->bg_color_set);
5108 case PROP_BACKGROUND_COLOR:
5109 g_value_set_boxed (value, &priv->bg_color);
5112 case PROP_FIRST_CHILD:
5113 g_value_set_object (value, priv->first_child);
5116 case PROP_LAST_CHILD:
5117 g_value_set_object (value, priv->last_child);
5121 g_value_set_object (value, priv->content);
5124 case PROP_CONTENT_GRAVITY:
5125 g_value_set_enum (value, priv->content_gravity);
5128 case PROP_CONTENT_BOX:
5130 ClutterActorBox box = { 0, };
5132 clutter_actor_get_content_box (actor, &box);
5133 g_value_set_boxed (value, &box);
5137 case PROP_MINIFICATION_FILTER:
5138 g_value_set_enum (value, priv->min_filter);
5141 case PROP_MAGNIFICATION_FILTER:
5142 g_value_set_enum (value, priv->mag_filter);
5146 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5152 clutter_actor_dispose (GObject *object)
5154 ClutterActor *self = CLUTTER_ACTOR (object);
5155 ClutterActorPrivate *priv = self->priv;
5157 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5159 g_type_name (G_OBJECT_TYPE (self)),
5162 g_signal_emit (self, actor_signals[DESTROY], 0);
5164 /* avoid recursing when called from clutter_actor_destroy() */
5165 if (priv->parent != NULL)
5167 ClutterActor *parent = priv->parent;
5169 /* go through the Container implementation unless this
5170 * is an internal child and has been marked as such.
5172 * removing the actor from its parent will reset the
5173 * realized and mapped states.
5175 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5176 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5178 clutter_actor_remove_child_internal (parent, self,
5179 REMOVE_CHILD_LEGACY_FLAGS);
5182 /* parent must be gone at this point */
5183 g_assert (priv->parent == NULL);
5185 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5187 /* can't be mapped or realized with no parent */
5188 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5189 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5192 g_clear_object (&priv->pango_context);
5193 g_clear_object (&priv->actions);
5194 g_clear_object (&priv->constraints);
5195 g_clear_object (&priv->effects);
5196 g_clear_object (&priv->flatten_effect);
5198 if (priv->layout_manager != NULL)
5200 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5201 g_clear_object (&priv->layout_manager);
5204 if (priv->content != NULL)
5206 _clutter_content_detached (priv->content, self);
5207 g_clear_object (&priv->content);
5210 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5214 clutter_actor_finalize (GObject *object)
5216 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5218 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5219 priv->name != NULL ? priv->name : "<none>",
5221 g_type_name (G_OBJECT_TYPE (object)));
5223 _clutter_context_release_id (priv->id);
5225 g_free (priv->name);
5227 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5232 * clutter_actor_get_accessible:
5233 * @self: a #ClutterActor
5235 * Returns the accessible object that describes the actor to an
5236 * assistive technology.
5238 * If no class-specific #AtkObject implementation is available for the
5239 * actor instance in question, it will inherit an #AtkObject
5240 * implementation from the first ancestor class for which such an
5241 * implementation is defined.
5243 * The documentation of the <ulink
5244 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5245 * library contains more information about accessible objects and
5248 * Returns: (transfer none): the #AtkObject associated with @actor
5251 clutter_actor_get_accessible (ClutterActor *self)
5253 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5255 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5259 clutter_actor_real_get_accessible (ClutterActor *actor)
5261 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5265 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5267 AtkObject *accessible;
5269 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5270 if (accessible != NULL)
5271 g_object_ref (accessible);
5277 atk_implementor_iface_init (AtkImplementorIface *iface)
5279 iface->ref_accessible = _clutter_actor_ref_accessible;
5283 clutter_actor_update_default_paint_volume (ClutterActor *self,
5284 ClutterPaintVolume *volume)
5286 ClutterActorPrivate *priv = self->priv;
5287 gboolean res = TRUE;
5289 /* we start from the allocation */
5290 clutter_paint_volume_set_width (volume,
5291 priv->allocation.x2 - priv->allocation.x1);
5292 clutter_paint_volume_set_height (volume,
5293 priv->allocation.y2 - priv->allocation.y1);
5295 /* if the actor has a clip set then we have a pretty definite
5296 * size for the paint volume: the actor cannot possibly paint
5297 * outside the clip region.
5299 if (priv->clip_to_allocation)
5301 /* the allocation has already been set, so we just flip the
5308 ClutterActor *child;
5310 if (priv->has_clip &&
5311 priv->clip.width >= 0 &&
5312 priv->clip.height >= 0)
5314 ClutterVertex origin;
5316 origin.x = priv->clip.x;
5317 origin.y = priv->clip.y;
5320 clutter_paint_volume_set_origin (volume, &origin);
5321 clutter_paint_volume_set_width (volume, priv->clip.width);
5322 clutter_paint_volume_set_height (volume, priv->clip.height);
5327 /* if we don't have children we just bail out here... */
5328 if (priv->n_children == 0)
5331 /* ...but if we have children then we ask for their paint volume in
5332 * our coordinates. if any of our children replies that it doesn't
5333 * have a paint volume, we bail out
5335 for (child = priv->first_child;
5337 child = child->priv->next_sibling)
5339 const ClutterPaintVolume *child_volume;
5341 if (!CLUTTER_ACTOR_IS_MAPPED (child))
5344 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5345 if (child_volume == NULL)
5351 clutter_paint_volume_union (volume, child_volume);
5361 clutter_actor_real_get_paint_volume (ClutterActor *self,
5362 ClutterPaintVolume *volume)
5364 ClutterActorClass *klass;
5367 klass = CLUTTER_ACTOR_GET_CLASS (self);
5369 /* XXX - this thoroughly sucks, but we don't want to penalize users
5370 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5371 * redraw. This should go away in 2.0.
5373 if (klass->paint == clutter_actor_real_paint &&
5374 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5380 /* this is the default return value: we cannot know if a class
5381 * is going to paint outside its allocation, so we take the
5382 * conservative approach.
5387 /* update_default_paint_volume() should only fail if one of the children
5388 * reported an invalid, or no, paint volume
5390 if (!clutter_actor_update_default_paint_volume (self, volume))
5397 * clutter_actor_get_default_paint_volume:
5398 * @self: a #ClutterActor
5400 * Retrieves the default paint volume for @self.
5402 * This function provides the same #ClutterPaintVolume that would be
5403 * computed by the default implementation inside #ClutterActor of the
5404 * #ClutterActorClass.get_paint_volume() virtual function.
5406 * This function should only be used by #ClutterActor subclasses that
5407 * cannot chain up to the parent implementation when computing their
5410 * Return value: (transfer none): a pointer to the default
5411 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5412 * the actor could not compute a valid paint volume. The returned value
5413 * is not guaranteed to be stable across multiple frames, so if you
5414 * want to retain it, you will need to copy it using
5415 * clutter_paint_volume_copy().
5419 const ClutterPaintVolume *
5420 clutter_actor_get_default_paint_volume (ClutterActor *self)
5422 ClutterPaintVolume volume;
5423 ClutterPaintVolume *res;
5425 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5428 _clutter_paint_volume_init_static (&volume, self);
5429 if (clutter_actor_update_default_paint_volume (self, &volume))
5431 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5435 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5436 _clutter_paint_volume_copy_static (&volume, res);
5440 clutter_paint_volume_free (&volume);
5446 clutter_actor_real_has_overlaps (ClutterActor *self)
5448 /* By default we'll assume that all actors need an offscreen redirect to get
5449 * the correct opacity. Actors such as ClutterTexture that would never need
5450 * an offscreen redirect can override this to return FALSE. */
5455 clutter_actor_real_destroy (ClutterActor *actor)
5457 ClutterActorIter iter;
5459 g_object_freeze_notify (G_OBJECT (actor));
5461 clutter_actor_iter_init (&iter, actor);
5462 while (clutter_actor_iter_next (&iter, NULL))
5463 clutter_actor_iter_destroy (&iter);
5465 g_object_thaw_notify (G_OBJECT (actor));
5469 clutter_actor_constructor (GType gtype,
5471 GObjectConstructParam *props)
5473 GObjectClass *gobject_class;
5477 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5478 retval = gobject_class->constructor (gtype, n_props, props);
5479 self = CLUTTER_ACTOR (retval);
5481 if (self->priv->layout_manager == NULL)
5483 ClutterLayoutManager *default_layout;
5485 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5487 default_layout = clutter_fixed_layout_new ();
5488 clutter_actor_set_layout_manager (self, default_layout);
5495 clutter_actor_class_init (ClutterActorClass *klass)
5497 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5499 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5500 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5501 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5502 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5504 object_class->constructor = clutter_actor_constructor;
5505 object_class->set_property = clutter_actor_set_property;
5506 object_class->get_property = clutter_actor_get_property;
5507 object_class->dispose = clutter_actor_dispose;
5508 object_class->finalize = clutter_actor_finalize;
5510 klass->show = clutter_actor_real_show;
5511 klass->show_all = clutter_actor_show;
5512 klass->hide = clutter_actor_real_hide;
5513 klass->hide_all = clutter_actor_hide;
5514 klass->map = clutter_actor_real_map;
5515 klass->unmap = clutter_actor_real_unmap;
5516 klass->unrealize = clutter_actor_real_unrealize;
5517 klass->pick = clutter_actor_real_pick;
5518 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5519 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5520 klass->allocate = clutter_actor_real_allocate;
5521 klass->queue_redraw = clutter_actor_real_queue_redraw;
5522 klass->queue_relayout = clutter_actor_real_queue_relayout;
5523 klass->apply_transform = clutter_actor_real_apply_transform;
5524 klass->get_accessible = clutter_actor_real_get_accessible;
5525 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5526 klass->has_overlaps = clutter_actor_real_has_overlaps;
5527 klass->paint = clutter_actor_real_paint;
5528 klass->destroy = clutter_actor_real_destroy;
5530 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5535 * X coordinate of the actor in pixels. If written, forces a fixed
5536 * position for the actor. If read, returns the fixed position if any,
5537 * otherwise the allocation if available, otherwise 0.
5539 * The #ClutterActor:x property is animatable.
5542 g_param_spec_float ("x",
5544 P_("X coordinate of the actor"),
5545 -G_MAXFLOAT, G_MAXFLOAT,
5548 G_PARAM_STATIC_STRINGS |
5549 CLUTTER_PARAM_ANIMATABLE);
5554 * Y coordinate of the actor in pixels. If written, forces a fixed
5555 * position for the actor. If read, returns the fixed position if
5556 * any, otherwise the allocation if available, otherwise 0.
5558 * The #ClutterActor:y property is animatable.
5561 g_param_spec_float ("y",
5563 P_("Y coordinate of the actor"),
5564 -G_MAXFLOAT, G_MAXFLOAT,
5567 G_PARAM_STATIC_STRINGS |
5568 CLUTTER_PARAM_ANIMATABLE);
5571 * ClutterActor:position:
5573 * The position of the origin of the actor.
5575 * This property is a shorthand for setting and getting the
5576 * #ClutterActor:x and #ClutterActor:y properties at the same
5579 * The #ClutterActor:position property is animatable.
5583 obj_props[PROP_POSITION] =
5584 g_param_spec_boxed ("position",
5586 P_("The position of the origin of the actor"),
5589 G_PARAM_STATIC_STRINGS |
5590 CLUTTER_PARAM_ANIMATABLE);
5593 * ClutterActor:width:
5595 * Width of the actor (in pixels). If written, forces the minimum and
5596 * natural size request of the actor to the given width. If read, returns
5597 * the allocated width if available, otherwise the width request.
5599 * The #ClutterActor:width property is animatable.
5601 obj_props[PROP_WIDTH] =
5602 g_param_spec_float ("width",
5604 P_("Width of the actor"),
5608 G_PARAM_STATIC_STRINGS |
5609 CLUTTER_PARAM_ANIMATABLE);
5612 * ClutterActor:height:
5614 * Height of the actor (in pixels). If written, forces the minimum and
5615 * natural size request of the actor to the given height. If read, returns
5616 * the allocated height if available, otherwise the height request.
5618 * The #ClutterActor:height property is animatable.
5620 obj_props[PROP_HEIGHT] =
5621 g_param_spec_float ("height",
5623 P_("Height of the actor"),
5627 G_PARAM_STATIC_STRINGS |
5628 CLUTTER_PARAM_ANIMATABLE);
5631 * ClutterActor:size:
5633 * The size of the actor.
5635 * This property is a shorthand for setting and getting the
5636 * #ClutterActor:width and #ClutterActor:height at the same time.
5638 * The #ClutterActor:size property is animatable.
5642 obj_props[PROP_SIZE] =
5643 g_param_spec_boxed ("size",
5645 P_("The size of the actor"),
5648 G_PARAM_STATIC_STRINGS |
5649 CLUTTER_PARAM_ANIMATABLE);
5652 * ClutterActor:fixed-x:
5654 * The fixed X position of the actor in pixels.
5656 * Writing this property sets #ClutterActor:fixed-position-set
5657 * property as well, as a side effect
5661 obj_props[PROP_FIXED_X] =
5662 g_param_spec_float ("fixed-x",
5664 P_("Forced X position of the actor"),
5665 -G_MAXFLOAT, G_MAXFLOAT,
5667 CLUTTER_PARAM_READWRITE);
5670 * ClutterActor:fixed-y:
5672 * The fixed Y position of the actor in pixels.
5674 * Writing this property sets the #ClutterActor:fixed-position-set
5675 * property as well, as a side effect
5679 obj_props[PROP_FIXED_Y] =
5680 g_param_spec_float ("fixed-y",
5682 P_("Forced Y position of the actor"),
5683 -G_MAXFLOAT, G_MAXFLOAT,
5685 CLUTTER_PARAM_READWRITE);
5688 * ClutterActor:fixed-position-set:
5690 * This flag controls whether the #ClutterActor:fixed-x and
5691 * #ClutterActor:fixed-y properties are used
5695 obj_props[PROP_FIXED_POSITION_SET] =
5696 g_param_spec_boolean ("fixed-position-set",
5697 P_("Fixed position set"),
5698 P_("Whether to use fixed positioning for the actor"),
5700 CLUTTER_PARAM_READWRITE);
5703 * ClutterActor:min-width:
5705 * A forced minimum width request for the actor, in pixels
5707 * Writing this property sets the #ClutterActor:min-width-set property
5708 * as well, as a side effect.
5710 *This property overrides the usual width request of the actor.
5714 obj_props[PROP_MIN_WIDTH] =
5715 g_param_spec_float ("min-width",
5717 P_("Forced minimum width request for the actor"),
5720 CLUTTER_PARAM_READWRITE);
5723 * ClutterActor:min-height:
5725 * A forced minimum height request for the actor, in pixels
5727 * Writing this property sets the #ClutterActor:min-height-set property
5728 * as well, as a side effect. This property overrides the usual height
5729 * request of the actor.
5733 obj_props[PROP_MIN_HEIGHT] =
5734 g_param_spec_float ("min-height",
5736 P_("Forced minimum height request for the actor"),
5739 CLUTTER_PARAM_READWRITE);
5742 * ClutterActor:natural-width:
5744 * A forced natural width request for the actor, in pixels
5746 * Writing this property sets the #ClutterActor:natural-width-set
5747 * property as well, as a side effect. This property overrides the
5748 * usual width request of the actor
5752 obj_props[PROP_NATURAL_WIDTH] =
5753 g_param_spec_float ("natural-width",
5754 P_("Natural Width"),
5755 P_("Forced natural width request for the actor"),
5758 CLUTTER_PARAM_READWRITE);
5761 * ClutterActor:natural-height:
5763 * A forced natural height request for the actor, in pixels
5765 * Writing this property sets the #ClutterActor:natural-height-set
5766 * property as well, as a side effect. This property overrides the
5767 * usual height request of the actor
5771 obj_props[PROP_NATURAL_HEIGHT] =
5772 g_param_spec_float ("natural-height",
5773 P_("Natural Height"),
5774 P_("Forced natural height request for the actor"),
5777 CLUTTER_PARAM_READWRITE);
5780 * ClutterActor:min-width-set:
5782 * This flag controls whether the #ClutterActor:min-width property
5787 obj_props[PROP_MIN_WIDTH_SET] =
5788 g_param_spec_boolean ("min-width-set",
5789 P_("Minimum width set"),
5790 P_("Whether to use the min-width property"),
5792 CLUTTER_PARAM_READWRITE);
5795 * ClutterActor:min-height-set:
5797 * This flag controls whether the #ClutterActor:min-height property
5802 obj_props[PROP_MIN_HEIGHT_SET] =
5803 g_param_spec_boolean ("min-height-set",
5804 P_("Minimum height set"),
5805 P_("Whether to use the min-height property"),
5807 CLUTTER_PARAM_READWRITE);
5810 * ClutterActor:natural-width-set:
5812 * This flag controls whether the #ClutterActor:natural-width property
5817 obj_props[PROP_NATURAL_WIDTH_SET] =
5818 g_param_spec_boolean ("natural-width-set",
5819 P_("Natural width set"),
5820 P_("Whether to use the natural-width property"),
5822 CLUTTER_PARAM_READWRITE);
5825 * ClutterActor:natural-height-set:
5827 * This flag controls whether the #ClutterActor:natural-height property
5832 obj_props[PROP_NATURAL_HEIGHT_SET] =
5833 g_param_spec_boolean ("natural-height-set",
5834 P_("Natural height set"),
5835 P_("Whether to use the natural-height property"),
5837 CLUTTER_PARAM_READWRITE);
5840 * ClutterActor:allocation:
5842 * The allocation for the actor, in pixels
5844 * This is property is read-only, but you might monitor it to know when an
5845 * actor moves or resizes
5849 obj_props[PROP_ALLOCATION] =
5850 g_param_spec_boxed ("allocation",
5852 P_("The actor's allocation"),
5853 CLUTTER_TYPE_ACTOR_BOX,
5854 CLUTTER_PARAM_READABLE);
5857 * ClutterActor:request-mode:
5859 * Request mode for the #ClutterActor. The request mode determines the
5860 * type of geometry management used by the actor, either height for width
5861 * (the default) or width for height.
5863 * For actors implementing height for width, the parent container should get
5864 * the preferred width first, and then the preferred height for that width.
5866 * For actors implementing width for height, the parent container should get
5867 * the preferred height first, and then the preferred width for that height.
5872 * ClutterRequestMode mode;
5873 * gfloat natural_width, min_width;
5874 * gfloat natural_height, min_height;
5876 * mode = clutter_actor_get_request_mode (child);
5877 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5879 * clutter_actor_get_preferred_width (child, -1,
5881 * &natural_width);
5882 * clutter_actor_get_preferred_height (child, natural_width,
5884 * &natural_height);
5888 * clutter_actor_get_preferred_height (child, -1,
5890 * &natural_height);
5891 * clutter_actor_get_preferred_width (child, natural_height,
5893 * &natural_width);
5897 * will retrieve the minimum and natural width and height depending on the
5898 * preferred request mode of the #ClutterActor "child".
5900 * The clutter_actor_get_preferred_size() function will implement this
5905 obj_props[PROP_REQUEST_MODE] =
5906 g_param_spec_enum ("request-mode",
5908 P_("The actor's request mode"),
5909 CLUTTER_TYPE_REQUEST_MODE,
5910 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5911 CLUTTER_PARAM_READWRITE);
5914 * ClutterActor:depth:
5916 * The position of the actor on the Z axis.
5918 * The #ClutterActor:depth property is relative to the parent's
5921 * The #ClutterActor:depth property is animatable.
5925 obj_props[PROP_DEPTH] =
5926 g_param_spec_float ("depth",
5928 P_("Position on the Z axis"),
5929 -G_MAXFLOAT, G_MAXFLOAT,
5932 G_PARAM_STATIC_STRINGS |
5933 CLUTTER_PARAM_ANIMATABLE);
5936 * ClutterActor:opacity:
5938 * Opacity of an actor, between 0 (fully transparent) and
5939 * 255 (fully opaque)
5941 * The #ClutterActor:opacity property is animatable.
5943 obj_props[PROP_OPACITY] =
5944 g_param_spec_uint ("opacity",
5946 P_("Opacity of an actor"),
5950 G_PARAM_STATIC_STRINGS |
5951 CLUTTER_PARAM_ANIMATABLE);
5954 * ClutterActor:offscreen-redirect:
5956 * Determines the conditions in which the actor will be redirected
5957 * to an offscreen framebuffer while being painted. For example this
5958 * can be used to cache an actor in a framebuffer or for improved
5959 * handling of transparent actors. See
5960 * clutter_actor_set_offscreen_redirect() for details.
5964 obj_props[PROP_OFFSCREEN_REDIRECT] =
5965 g_param_spec_flags ("offscreen-redirect",
5966 P_("Offscreen redirect"),
5967 P_("Flags controlling when to flatten the actor into a single image"),
5968 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5970 CLUTTER_PARAM_READWRITE);
5973 * ClutterActor:visible:
5975 * Whether the actor is set to be visible or not
5977 * See also #ClutterActor:mapped
5979 obj_props[PROP_VISIBLE] =
5980 g_param_spec_boolean ("visible",
5982 P_("Whether the actor is visible or not"),
5984 CLUTTER_PARAM_READWRITE);
5987 * ClutterActor:mapped:
5989 * Whether the actor is mapped (will be painted when the stage
5990 * to which it belongs is mapped)
5994 obj_props[PROP_MAPPED] =
5995 g_param_spec_boolean ("mapped",
5997 P_("Whether the actor will be painted"),
5999 CLUTTER_PARAM_READABLE);
6002 * ClutterActor:realized:
6004 * Whether the actor has been realized
6008 obj_props[PROP_REALIZED] =
6009 g_param_spec_boolean ("realized",
6011 P_("Whether the actor has been realized"),
6013 CLUTTER_PARAM_READABLE);
6016 * ClutterActor:reactive:
6018 * Whether the actor is reactive to events or not
6020 * Only reactive actors will emit event-related signals
6024 obj_props[PROP_REACTIVE] =
6025 g_param_spec_boolean ("reactive",
6027 P_("Whether the actor is reactive to events"),
6029 CLUTTER_PARAM_READWRITE);
6032 * ClutterActor:has-clip:
6034 * Whether the actor has the #ClutterActor:clip property set or not
6036 obj_props[PROP_HAS_CLIP] =
6037 g_param_spec_boolean ("has-clip",
6039 P_("Whether the actor has a clip set"),
6041 CLUTTER_PARAM_READABLE);
6044 * ClutterActor:clip:
6046 * The clip region for the actor, in actor-relative coordinates
6048 * Every part of the actor outside the clip region will not be
6051 obj_props[PROP_CLIP] =
6052 g_param_spec_boxed ("clip",
6054 P_("The clip region for the actor"),
6055 CLUTTER_TYPE_GEOMETRY,
6056 CLUTTER_PARAM_READWRITE);
6059 * ClutterActor:name:
6061 * The name of the actor
6065 obj_props[PROP_NAME] =
6066 g_param_spec_string ("name",
6068 P_("Name of the actor"),
6070 CLUTTER_PARAM_READWRITE);
6073 * ClutterActor:scale-x:
6075 * The horizontal scale of the actor.
6077 * The #ClutterActor:scale-x property is animatable.
6081 obj_props[PROP_SCALE_X] =
6082 g_param_spec_double ("scale-x",
6084 P_("Scale factor on the X axis"),
6088 G_PARAM_STATIC_STRINGS |
6089 CLUTTER_PARAM_ANIMATABLE);
6092 * ClutterActor:scale-y:
6094 * The vertical scale of the actor.
6096 * The #ClutterActor:scale-y property is animatable.
6100 obj_props[PROP_SCALE_Y] =
6101 g_param_spec_double ("scale-y",
6103 P_("Scale factor on the Y axis"),
6107 G_PARAM_STATIC_STRINGS |
6108 CLUTTER_PARAM_ANIMATABLE);
6111 * ClutterActor:scale-center-x:
6113 * The horizontal center point for scaling
6117 obj_props[PROP_SCALE_CENTER_X] =
6118 g_param_spec_float ("scale-center-x",
6119 P_("Scale Center X"),
6120 P_("Horizontal scale center"),
6121 -G_MAXFLOAT, G_MAXFLOAT,
6123 CLUTTER_PARAM_READWRITE);
6126 * ClutterActor:scale-center-y:
6128 * The vertical center point for scaling
6132 obj_props[PROP_SCALE_CENTER_Y] =
6133 g_param_spec_float ("scale-center-y",
6134 P_("Scale Center Y"),
6135 P_("Vertical scale center"),
6136 -G_MAXFLOAT, G_MAXFLOAT,
6138 CLUTTER_PARAM_READWRITE);
6141 * ClutterActor:scale-gravity:
6143 * The center point for scaling expressed as a #ClutterGravity
6147 obj_props[PROP_SCALE_GRAVITY] =
6148 g_param_spec_enum ("scale-gravity",
6149 P_("Scale Gravity"),
6150 P_("The center of scaling"),
6151 CLUTTER_TYPE_GRAVITY,
6152 CLUTTER_GRAVITY_NONE,
6153 CLUTTER_PARAM_READWRITE);
6156 * ClutterActor:rotation-angle-x:
6158 * The rotation angle on the X axis.
6160 * The #ClutterActor:rotation-angle-x property is animatable.
6164 obj_props[PROP_ROTATION_ANGLE_X] =
6165 g_param_spec_double ("rotation-angle-x",
6166 P_("Rotation Angle X"),
6167 P_("The rotation angle on the X axis"),
6168 -G_MAXDOUBLE, G_MAXDOUBLE,
6171 G_PARAM_STATIC_STRINGS |
6172 CLUTTER_PARAM_ANIMATABLE);
6175 * ClutterActor:rotation-angle-y:
6177 * The rotation angle on the Y axis
6179 * The #ClutterActor:rotation-angle-y property is animatable.
6183 obj_props[PROP_ROTATION_ANGLE_Y] =
6184 g_param_spec_double ("rotation-angle-y",
6185 P_("Rotation Angle Y"),
6186 P_("The rotation angle on the Y axis"),
6187 -G_MAXDOUBLE, G_MAXDOUBLE,
6190 G_PARAM_STATIC_STRINGS |
6191 CLUTTER_PARAM_ANIMATABLE);
6194 * ClutterActor:rotation-angle-z:
6196 * The rotation angle on the Z axis
6198 * The #ClutterActor:rotation-angle-z property is animatable.
6202 obj_props[PROP_ROTATION_ANGLE_Z] =
6203 g_param_spec_double ("rotation-angle-z",
6204 P_("Rotation Angle Z"),
6205 P_("The rotation angle on the Z axis"),
6206 -G_MAXDOUBLE, G_MAXDOUBLE,
6209 G_PARAM_STATIC_STRINGS |
6210 CLUTTER_PARAM_ANIMATABLE);
6213 * ClutterActor:rotation-center-x:
6215 * The rotation center on the X axis.
6219 obj_props[PROP_ROTATION_CENTER_X] =
6220 g_param_spec_boxed ("rotation-center-x",
6221 P_("Rotation Center X"),
6222 P_("The rotation center on the X axis"),
6223 CLUTTER_TYPE_VERTEX,
6224 CLUTTER_PARAM_READWRITE);
6227 * ClutterActor:rotation-center-y:
6229 * The rotation center on the Y axis.
6233 obj_props[PROP_ROTATION_CENTER_Y] =
6234 g_param_spec_boxed ("rotation-center-y",
6235 P_("Rotation Center Y"),
6236 P_("The rotation center on the Y axis"),
6237 CLUTTER_TYPE_VERTEX,
6238 CLUTTER_PARAM_READWRITE);
6241 * ClutterActor:rotation-center-z:
6243 * The rotation center on the Z axis.
6247 obj_props[PROP_ROTATION_CENTER_Z] =
6248 g_param_spec_boxed ("rotation-center-z",
6249 P_("Rotation Center Z"),
6250 P_("The rotation center on the Z axis"),
6251 CLUTTER_TYPE_VERTEX,
6252 CLUTTER_PARAM_READWRITE);
6255 * ClutterActor:rotation-center-z-gravity:
6257 * The rotation center on the Z axis expressed as a #ClutterGravity.
6261 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6262 g_param_spec_enum ("rotation-center-z-gravity",
6263 P_("Rotation Center Z Gravity"),
6264 P_("Center point for rotation around the Z axis"),
6265 CLUTTER_TYPE_GRAVITY,
6266 CLUTTER_GRAVITY_NONE,
6267 CLUTTER_PARAM_READWRITE);
6270 * ClutterActor:anchor-x:
6272 * The X coordinate of an actor's anchor point, relative to
6273 * the actor coordinate space, in pixels
6277 obj_props[PROP_ANCHOR_X] =
6278 g_param_spec_float ("anchor-x",
6280 P_("X coordinate of the anchor point"),
6281 -G_MAXFLOAT, G_MAXFLOAT,
6283 CLUTTER_PARAM_READWRITE);
6286 * ClutterActor:anchor-y:
6288 * The Y coordinate of an actor's anchor point, relative to
6289 * the actor coordinate space, in pixels
6293 obj_props[PROP_ANCHOR_Y] =
6294 g_param_spec_float ("anchor-y",
6296 P_("Y coordinate of the anchor point"),
6297 -G_MAXFLOAT, G_MAXFLOAT,
6299 CLUTTER_PARAM_READWRITE);
6302 * ClutterActor:anchor-gravity:
6304 * The anchor point expressed as a #ClutterGravity
6308 obj_props[PROP_ANCHOR_GRAVITY] =
6309 g_param_spec_enum ("anchor-gravity",
6310 P_("Anchor Gravity"),
6311 P_("The anchor point as a ClutterGravity"),
6312 CLUTTER_TYPE_GRAVITY,
6313 CLUTTER_GRAVITY_NONE,
6314 CLUTTER_PARAM_READWRITE);
6317 * ClutterActor:show-on-set-parent:
6319 * If %TRUE, the actor is automatically shown when parented.
6321 * Calling clutter_actor_hide() on an actor which has not been
6322 * parented will set this property to %FALSE as a side effect.
6326 obj_props[PROP_SHOW_ON_SET_PARENT] =
6327 g_param_spec_boolean ("show-on-set-parent",
6328 P_("Show on set parent"),
6329 P_("Whether the actor is shown when parented"),
6331 CLUTTER_PARAM_READWRITE);
6334 * ClutterActor:clip-to-allocation:
6336 * Whether the clip region should track the allocated area
6339 * This property is ignored if a clip area has been explicitly
6340 * set using clutter_actor_set_clip().
6344 obj_props[PROP_CLIP_TO_ALLOCATION] =
6345 g_param_spec_boolean ("clip-to-allocation",
6346 P_("Clip to Allocation"),
6347 P_("Sets the clip region to track the actor's allocation"),
6349 CLUTTER_PARAM_READWRITE);
6352 * ClutterActor:text-direction:
6354 * The direction of the text inside a #ClutterActor.
6358 obj_props[PROP_TEXT_DIRECTION] =
6359 g_param_spec_enum ("text-direction",
6360 P_("Text Direction"),
6361 P_("Direction of the text"),
6362 CLUTTER_TYPE_TEXT_DIRECTION,
6363 CLUTTER_TEXT_DIRECTION_LTR,
6364 CLUTTER_PARAM_READWRITE);
6367 * ClutterActor:has-pointer:
6369 * Whether the actor contains the pointer of a #ClutterInputDevice
6374 obj_props[PROP_HAS_POINTER] =
6375 g_param_spec_boolean ("has-pointer",
6377 P_("Whether the actor contains the pointer of an input device"),
6379 CLUTTER_PARAM_READABLE);
6382 * ClutterActor:actions:
6384 * Adds a #ClutterAction to the actor
6388 obj_props[PROP_ACTIONS] =
6389 g_param_spec_object ("actions",
6391 P_("Adds an action to the actor"),
6392 CLUTTER_TYPE_ACTION,
6393 CLUTTER_PARAM_WRITABLE);
6396 * ClutterActor:constraints:
6398 * Adds a #ClutterConstraint to the actor
6402 obj_props[PROP_CONSTRAINTS] =
6403 g_param_spec_object ("constraints",
6405 P_("Adds a constraint to the actor"),
6406 CLUTTER_TYPE_CONSTRAINT,
6407 CLUTTER_PARAM_WRITABLE);
6410 * ClutterActor:effect:
6412 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6416 obj_props[PROP_EFFECT] =
6417 g_param_spec_object ("effect",
6419 P_("Add an effect to be applied on the actor"),
6420 CLUTTER_TYPE_EFFECT,
6421 CLUTTER_PARAM_WRITABLE);
6424 * ClutterActor:layout-manager:
6426 * A delegate object for controlling the layout of the children of
6431 obj_props[PROP_LAYOUT_MANAGER] =
6432 g_param_spec_object ("layout-manager",
6433 P_("Layout Manager"),
6434 P_("The object controlling the layout of an actor's children"),
6435 CLUTTER_TYPE_LAYOUT_MANAGER,
6436 CLUTTER_PARAM_READWRITE);
6439 * ClutterActor:x-expand:
6441 * Whether a layout manager should assign more space to the actor on
6446 obj_props[PROP_X_EXPAND] =
6447 g_param_spec_boolean ("x-expand",
6449 P_("Whether extra horizontal space should be assigned to the actor"),
6452 G_PARAM_STATIC_STRINGS);
6455 * ClutterActor:y-expand:
6457 * Whether a layout manager should assign more space to the actor on
6462 obj_props[PROP_Y_EXPAND] =
6463 g_param_spec_boolean ("y-expand",
6465 P_("Whether extra vertical space should be assigned to the actor"),
6468 G_PARAM_STATIC_STRINGS);
6471 * ClutterActor:x-align:
6473 * The alignment of an actor on the X axis, if the actor has been given
6474 * extra space for its allocation. See also the #ClutterActor:x-expand
6479 obj_props[PROP_X_ALIGN] =
6480 g_param_spec_enum ("x-align",
6482 P_("The alignment of the actor on the X axis within its allocation"),
6483 CLUTTER_TYPE_ACTOR_ALIGN,
6484 CLUTTER_ACTOR_ALIGN_FILL,
6485 CLUTTER_PARAM_READWRITE);
6488 * ClutterActor:y-align:
6490 * The alignment of an actor on the Y axis, if the actor has been given
6491 * extra space for its allocation.
6495 obj_props[PROP_Y_ALIGN] =
6496 g_param_spec_enum ("y-align",
6498 P_("The alignment of the actor on the Y axis within its allocation"),
6499 CLUTTER_TYPE_ACTOR_ALIGN,
6500 CLUTTER_ACTOR_ALIGN_FILL,
6501 CLUTTER_PARAM_READWRITE);
6504 * ClutterActor:margin-top:
6506 * The margin (in pixels) from the top of the actor.
6508 * This property adds a margin to the actor's preferred size; the margin
6509 * will be automatically taken into account when allocating the actor.
6513 obj_props[PROP_MARGIN_TOP] =
6514 g_param_spec_float ("margin-top",
6516 P_("Extra space at the top"),
6519 CLUTTER_PARAM_READWRITE);
6522 * ClutterActor:margin-bottom:
6524 * The margin (in pixels) from the bottom of the actor.
6526 * This property adds a margin to the actor's preferred size; the margin
6527 * will be automatically taken into account when allocating the actor.
6531 obj_props[PROP_MARGIN_BOTTOM] =
6532 g_param_spec_float ("margin-bottom",
6533 P_("Margin Bottom"),
6534 P_("Extra space at the bottom"),
6537 CLUTTER_PARAM_READWRITE);
6540 * ClutterActor:margin-left:
6542 * The margin (in pixels) from the left of the actor.
6544 * This property adds a margin to the actor's preferred size; the margin
6545 * will be automatically taken into account when allocating the actor.
6549 obj_props[PROP_MARGIN_LEFT] =
6550 g_param_spec_float ("margin-left",
6552 P_("Extra space at the left"),
6555 CLUTTER_PARAM_READWRITE);
6558 * ClutterActor:margin-right:
6560 * The margin (in pixels) from the right of the actor.
6562 * This property adds a margin to the actor's preferred size; the margin
6563 * will be automatically taken into account when allocating the actor.
6567 obj_props[PROP_MARGIN_RIGHT] =
6568 g_param_spec_float ("margin-right",
6570 P_("Extra space at the right"),
6573 CLUTTER_PARAM_READWRITE);
6576 * ClutterActor:background-color-set:
6578 * Whether the #ClutterActor:background-color property has been set.
6582 obj_props[PROP_BACKGROUND_COLOR_SET] =
6583 g_param_spec_boolean ("background-color-set",
6584 P_("Background Color Set"),
6585 P_("Whether the background color is set"),
6587 CLUTTER_PARAM_READABLE);
6590 * ClutterActor:background-color:
6592 * Paints a solid fill of the actor's allocation using the specified
6595 * The #ClutterActor:background-color property is animatable.
6599 obj_props[PROP_BACKGROUND_COLOR] =
6600 clutter_param_spec_color ("background-color",
6601 P_("Background color"),
6602 P_("The actor's background color"),
6603 CLUTTER_COLOR_Transparent,
6605 G_PARAM_STATIC_STRINGS |
6606 CLUTTER_PARAM_ANIMATABLE);
6609 * ClutterActor:first-child:
6611 * The actor's first child.
6615 obj_props[PROP_FIRST_CHILD] =
6616 g_param_spec_object ("first-child",
6618 P_("The actor's first child"),
6620 CLUTTER_PARAM_READABLE);
6623 * ClutterActor:last-child:
6625 * The actor's last child.
6629 obj_props[PROP_LAST_CHILD] =
6630 g_param_spec_object ("last-child",
6632 P_("The actor's last child"),
6634 CLUTTER_PARAM_READABLE);
6637 * ClutterActor:content:
6639 * The #ClutterContent implementation that controls the content
6644 obj_props[PROP_CONTENT] =
6645 g_param_spec_object ("content",
6647 P_("Delegate object for painting the actor's content"),
6648 CLUTTER_TYPE_CONTENT,
6649 CLUTTER_PARAM_READWRITE);
6652 * ClutterActor:content-gravity:
6654 * The alignment that should be honoured by the #ClutterContent
6655 * set with the #ClutterActor:content property.
6657 * Changing the value of this property will change the bounding box of
6658 * the content; you can use the #ClutterActor:content-box property to
6659 * get the position and size of the content within the actor's
6662 * This property is meaningful only for #ClutterContent implementations
6663 * that have a preferred size, and if the preferred size is smaller than
6664 * the actor's allocation.
6666 * The #ClutterActor:content-gravity property is animatable.
6670 obj_props[PROP_CONTENT_GRAVITY] =
6671 g_param_spec_enum ("content-gravity",
6672 P_("Content Gravity"),
6673 P_("Alignment of the actor's content"),
6674 CLUTTER_TYPE_CONTENT_GRAVITY,
6675 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6676 CLUTTER_PARAM_READWRITE);
6679 * ClutterActor:content-box:
6681 * The bounding box for the #ClutterContent used by the actor.
6683 * The value of this property is controlled by the #ClutterActor:allocation
6684 * and #ClutterActor:content-gravity properties of #ClutterActor.
6686 * The bounding box for the content is guaranteed to never exceed the
6687 * allocation's of the actor.
6691 obj_props[PROP_CONTENT_BOX] =
6692 g_param_spec_boxed ("content-box",
6694 P_("The bounding box of the actor's content"),
6695 CLUTTER_TYPE_ACTOR_BOX,
6697 G_PARAM_STATIC_STRINGS |
6698 CLUTTER_PARAM_ANIMATABLE);
6700 obj_props[PROP_MINIFICATION_FILTER] =
6701 g_param_spec_enum ("minification-filter",
6702 P_("Minification Filter"),
6703 P_("The filter used when reducing the size of the content"),
6704 CLUTTER_TYPE_SCALING_FILTER,
6705 CLUTTER_SCALING_FILTER_LINEAR,
6706 CLUTTER_PARAM_READWRITE);
6708 obj_props[PROP_MAGNIFICATION_FILTER] =
6709 g_param_spec_enum ("magnification-filter",
6710 P_("Magnification Filter"),
6711 P_("The filter used when increasing the size of the content"),
6712 CLUTTER_TYPE_SCALING_FILTER,
6713 CLUTTER_SCALING_FILTER_LINEAR,
6714 CLUTTER_PARAM_READWRITE);
6716 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6719 * ClutterActor::destroy:
6720 * @actor: the #ClutterActor which emitted the signal
6722 * The ::destroy signal notifies that all references held on the
6723 * actor which emitted it should be released.
6725 * The ::destroy signal should be used by all holders of a reference
6728 * This signal might result in the finalization of the #ClutterActor
6729 * if all references are released.
6731 * Composite actors and actors implementing the #ClutterContainer
6732 * interface should override the default implementation of the
6733 * class handler of this signal and call clutter_actor_destroy() on
6734 * their children. When overriding the default class handler, it is
6735 * required to chain up to the parent's implementation.
6739 actor_signals[DESTROY] =
6740 g_signal_new (I_("destroy"),
6741 G_TYPE_FROM_CLASS (object_class),
6742 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6743 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6745 _clutter_marshal_VOID__VOID,
6748 * ClutterActor::show:
6749 * @actor: the object which received the signal
6751 * The ::show signal is emitted when an actor is visible and
6752 * rendered on the stage.
6756 actor_signals[SHOW] =
6757 g_signal_new (I_("show"),
6758 G_TYPE_FROM_CLASS (object_class),
6760 G_STRUCT_OFFSET (ClutterActorClass, show),
6762 _clutter_marshal_VOID__VOID,
6765 * ClutterActor::hide:
6766 * @actor: the object which received the signal
6768 * The ::hide signal is emitted when an actor is no longer rendered
6773 actor_signals[HIDE] =
6774 g_signal_new (I_("hide"),
6775 G_TYPE_FROM_CLASS (object_class),
6777 G_STRUCT_OFFSET (ClutterActorClass, hide),
6779 _clutter_marshal_VOID__VOID,
6782 * ClutterActor::parent-set:
6783 * @actor: the object which received the signal
6784 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6786 * This signal is emitted when the parent of the actor changes.
6790 actor_signals[PARENT_SET] =
6791 g_signal_new (I_("parent-set"),
6792 G_TYPE_FROM_CLASS (object_class),
6794 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6796 _clutter_marshal_VOID__OBJECT,
6798 CLUTTER_TYPE_ACTOR);
6801 * ClutterActor::queue-redraw:
6802 * @actor: the actor we're bubbling the redraw request through
6803 * @origin: the actor which initiated the redraw request
6805 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6806 * is called on @origin.
6808 * The default implementation for #ClutterActor chains up to the
6809 * parent actor and queues a redraw on the parent, thus "bubbling"
6810 * the redraw queue up through the actor graph. The default
6811 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6812 * in a main loop idle handler.
6814 * Note that the @origin actor may be the stage, or a container; it
6815 * does not have to be a leaf node in the actor graph.
6817 * Toolkits embedding a #ClutterStage which require a redraw and
6818 * relayout cycle can stop the emission of this signal using the
6819 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6824 * on_redraw_complete (gpointer data)
6826 * ClutterStage *stage = data;
6828 * /* execute the Clutter drawing pipeline */
6829 * clutter_stage_ensure_redraw (stage);
6833 * on_stage_queue_redraw (ClutterStage *stage)
6835 * /* this prevents the default handler to run */
6836 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6838 * /* queue a redraw with the host toolkit and call
6839 * * a function when the redraw has been completed
6841 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6845 * <note><para>This signal is emitted before the Clutter paint
6846 * pipeline is executed. If you want to know when the pipeline has
6847 * been completed you should connect to the ::paint signal on the
6848 * Stage with g_signal_connect_after().</para></note>
6852 actor_signals[QUEUE_REDRAW] =
6853 g_signal_new (I_("queue-redraw"),
6854 G_TYPE_FROM_CLASS (object_class),
6857 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6859 _clutter_marshal_VOID__OBJECT,
6861 CLUTTER_TYPE_ACTOR);
6864 * ClutterActor::queue-relayout
6865 * @actor: the actor being queued for relayout
6867 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6868 * is called on an actor.
6870 * The default implementation for #ClutterActor chains up to the
6871 * parent actor and queues a relayout on the parent, thus "bubbling"
6872 * the relayout queue up through the actor graph.
6874 * The main purpose of this signal is to allow relayout to be propagated
6875 * properly in the procense of #ClutterClone actors. Applications will
6876 * not normally need to connect to this signal.
6880 actor_signals[QUEUE_RELAYOUT] =
6881 g_signal_new (I_("queue-relayout"),
6882 G_TYPE_FROM_CLASS (object_class),
6885 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6887 _clutter_marshal_VOID__VOID,
6891 * ClutterActor::event:
6892 * @actor: the actor which received the event
6893 * @event: a #ClutterEvent
6895 * The ::event signal is emitted each time an event is received
6896 * by the @actor. This signal will be emitted on every actor,
6897 * following the hierarchy chain, until it reaches the top-level
6898 * container (the #ClutterStage).
6900 * Return value: %TRUE if the event has been handled by the actor,
6901 * or %FALSE to continue the emission.
6905 actor_signals[EVENT] =
6906 g_signal_new (I_("event"),
6907 G_TYPE_FROM_CLASS (object_class),
6909 G_STRUCT_OFFSET (ClutterActorClass, event),
6910 _clutter_boolean_handled_accumulator, NULL,
6911 _clutter_marshal_BOOLEAN__BOXED,
6913 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6915 * ClutterActor::button-press-event:
6916 * @actor: the actor which received the event
6917 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6919 * The ::button-press-event signal is emitted each time a mouse button
6920 * is pressed on @actor.
6922 * Return value: %TRUE if the event has been handled by the actor,
6923 * or %FALSE to continue the emission.
6927 actor_signals[BUTTON_PRESS_EVENT] =
6928 g_signal_new (I_("button-press-event"),
6929 G_TYPE_FROM_CLASS (object_class),
6931 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6932 _clutter_boolean_handled_accumulator, NULL,
6933 _clutter_marshal_BOOLEAN__BOXED,
6935 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6937 * ClutterActor::button-release-event:
6938 * @actor: the actor which received the event
6939 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6941 * The ::button-release-event signal is emitted each time a mouse button
6942 * is released on @actor.
6944 * Return value: %TRUE if the event has been handled by the actor,
6945 * or %FALSE to continue the emission.
6949 actor_signals[BUTTON_RELEASE_EVENT] =
6950 g_signal_new (I_("button-release-event"),
6951 G_TYPE_FROM_CLASS (object_class),
6953 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6954 _clutter_boolean_handled_accumulator, NULL,
6955 _clutter_marshal_BOOLEAN__BOXED,
6957 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6959 * ClutterActor::scroll-event:
6960 * @actor: the actor which received the event
6961 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6963 * The ::scroll-event signal is emitted each time the mouse is
6964 * scrolled on @actor
6966 * Return value: %TRUE if the event has been handled by the actor,
6967 * or %FALSE to continue the emission.
6971 actor_signals[SCROLL_EVENT] =
6972 g_signal_new (I_("scroll-event"),
6973 G_TYPE_FROM_CLASS (object_class),
6975 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6976 _clutter_boolean_handled_accumulator, NULL,
6977 _clutter_marshal_BOOLEAN__BOXED,
6979 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6981 * ClutterActor::key-press-event:
6982 * @actor: the actor which received the event
6983 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6985 * The ::key-press-event signal is emitted each time a keyboard button
6986 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6988 * Return value: %TRUE if the event has been handled by the actor,
6989 * or %FALSE to continue the emission.
6993 actor_signals[KEY_PRESS_EVENT] =
6994 g_signal_new (I_("key-press-event"),
6995 G_TYPE_FROM_CLASS (object_class),
6997 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6998 _clutter_boolean_handled_accumulator, NULL,
6999 _clutter_marshal_BOOLEAN__BOXED,
7001 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7003 * ClutterActor::key-release-event:
7004 * @actor: the actor which received the event
7005 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7007 * The ::key-release-event signal is emitted each time a keyboard button
7008 * is released while @actor has key focus (see
7009 * clutter_stage_set_key_focus()).
7011 * Return value: %TRUE if the event has been handled by the actor,
7012 * or %FALSE to continue the emission.
7016 actor_signals[KEY_RELEASE_EVENT] =
7017 g_signal_new (I_("key-release-event"),
7018 G_TYPE_FROM_CLASS (object_class),
7020 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7021 _clutter_boolean_handled_accumulator, NULL,
7022 _clutter_marshal_BOOLEAN__BOXED,
7024 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7026 * ClutterActor::motion-event:
7027 * @actor: the actor which received the event
7028 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7030 * The ::motion-event signal is emitted each time the mouse pointer is
7031 * moved over @actor.
7033 * Return value: %TRUE if the event has been handled by the actor,
7034 * or %FALSE to continue the emission.
7038 actor_signals[MOTION_EVENT] =
7039 g_signal_new (I_("motion-event"),
7040 G_TYPE_FROM_CLASS (object_class),
7042 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7043 _clutter_boolean_handled_accumulator, NULL,
7044 _clutter_marshal_BOOLEAN__BOXED,
7046 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7049 * ClutterActor::key-focus-in:
7050 * @actor: the actor which now has key focus
7052 * The ::key-focus-in signal is emitted when @actor receives key focus.
7056 actor_signals[KEY_FOCUS_IN] =
7057 g_signal_new (I_("key-focus-in"),
7058 G_TYPE_FROM_CLASS (object_class),
7060 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7062 _clutter_marshal_VOID__VOID,
7066 * ClutterActor::key-focus-out:
7067 * @actor: the actor which now has key focus
7069 * The ::key-focus-out signal is emitted when @actor loses key focus.
7073 actor_signals[KEY_FOCUS_OUT] =
7074 g_signal_new (I_("key-focus-out"),
7075 G_TYPE_FROM_CLASS (object_class),
7077 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7079 _clutter_marshal_VOID__VOID,
7083 * ClutterActor::enter-event:
7084 * @actor: the actor which the pointer has entered.
7085 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7087 * The ::enter-event signal is emitted when the pointer enters the @actor
7089 * Return value: %TRUE if the event has been handled by the actor,
7090 * or %FALSE to continue the emission.
7094 actor_signals[ENTER_EVENT] =
7095 g_signal_new (I_("enter-event"),
7096 G_TYPE_FROM_CLASS (object_class),
7098 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7099 _clutter_boolean_handled_accumulator, NULL,
7100 _clutter_marshal_BOOLEAN__BOXED,
7102 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7105 * ClutterActor::leave-event:
7106 * @actor: the actor which the pointer has left
7107 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7109 * The ::leave-event signal is emitted when the pointer leaves the @actor.
7111 * Return value: %TRUE if the event has been handled by the actor,
7112 * or %FALSE to continue the emission.
7116 actor_signals[LEAVE_EVENT] =
7117 g_signal_new (I_("leave-event"),
7118 G_TYPE_FROM_CLASS (object_class),
7120 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7121 _clutter_boolean_handled_accumulator, NULL,
7122 _clutter_marshal_BOOLEAN__BOXED,
7124 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7127 * ClutterActor::captured-event:
7128 * @actor: the actor which received the signal
7129 * @event: a #ClutterEvent
7131 * The ::captured-event signal is emitted when an event is captured
7132 * by Clutter. This signal will be emitted starting from the top-level
7133 * container (the #ClutterStage) to the actor which received the event
7134 * going down the hierarchy. This signal can be used to intercept every
7135 * event before the specialized events (like
7136 * ClutterActor::button-press-event or ::key-released-event) are
7139 * Return value: %TRUE if the event has been handled by the actor,
7140 * or %FALSE to continue the emission.
7144 actor_signals[CAPTURED_EVENT] =
7145 g_signal_new (I_("captured-event"),
7146 G_TYPE_FROM_CLASS (object_class),
7148 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7149 _clutter_boolean_handled_accumulator, NULL,
7150 _clutter_marshal_BOOLEAN__BOXED,
7152 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7155 * ClutterActor::paint:
7156 * @actor: the #ClutterActor that received the signal
7158 * The ::paint signal is emitted each time an actor is being painted.
7160 * Subclasses of #ClutterActor should override the class signal handler
7161 * and paint themselves in that function.
7163 * It is possible to connect a handler to the ::paint signal in order
7164 * to set up some custom aspect of a paint.
7168 actor_signals[PAINT] =
7169 g_signal_new (I_("paint"),
7170 G_TYPE_FROM_CLASS (object_class),
7173 G_STRUCT_OFFSET (ClutterActorClass, paint),
7175 _clutter_marshal_VOID__VOID,
7178 * ClutterActor::realize:
7179 * @actor: the #ClutterActor that received the signal
7181 * The ::realize signal is emitted each time an actor is being
7186 actor_signals[REALIZE] =
7187 g_signal_new (I_("realize"),
7188 G_TYPE_FROM_CLASS (object_class),
7190 G_STRUCT_OFFSET (ClutterActorClass, realize),
7192 _clutter_marshal_VOID__VOID,
7195 * ClutterActor::unrealize:
7196 * @actor: the #ClutterActor that received the signal
7198 * The ::unrealize signal is emitted each time an actor is being
7203 actor_signals[UNREALIZE] =
7204 g_signal_new (I_("unrealize"),
7205 G_TYPE_FROM_CLASS (object_class),
7207 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7209 _clutter_marshal_VOID__VOID,
7213 * ClutterActor::pick:
7214 * @actor: the #ClutterActor that received the signal
7215 * @color: the #ClutterColor to be used when picking
7217 * The ::pick signal is emitted each time an actor is being painted
7218 * in "pick mode". The pick mode is used to identify the actor during
7219 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7220 * The actor should paint its shape using the passed @pick_color.
7222 * Subclasses of #ClutterActor should override the class signal handler
7223 * and paint themselves in that function.
7225 * It is possible to connect a handler to the ::pick signal in order
7226 * to set up some custom aspect of a paint in pick mode.
7230 actor_signals[PICK] =
7231 g_signal_new (I_("pick"),
7232 G_TYPE_FROM_CLASS (object_class),
7234 G_STRUCT_OFFSET (ClutterActorClass, pick),
7236 _clutter_marshal_VOID__BOXED,
7238 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7241 * ClutterActor::allocation-changed:
7242 * @actor: the #ClutterActor that emitted the signal
7243 * @box: a #ClutterActorBox with the new allocation
7244 * @flags: #ClutterAllocationFlags for the allocation
7246 * The ::allocation-changed signal is emitted when the
7247 * #ClutterActor:allocation property changes. Usually, application
7248 * code should just use the notifications for the :allocation property
7249 * but if you want to track the allocation flags as well, for instance
7250 * to know whether the absolute origin of @actor changed, then you might
7251 * want use this signal instead.
7255 actor_signals[ALLOCATION_CHANGED] =
7256 g_signal_new (I_("allocation-changed"),
7257 G_TYPE_FROM_CLASS (object_class),
7261 _clutter_marshal_VOID__BOXED_FLAGS,
7263 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7264 CLUTTER_TYPE_ALLOCATION_FLAGS);
7267 * ClutterActor::transitions-completed:
7268 * @actor: a #ClutterActor
7270 * The ::transitions-completed signal is emitted once all transitions
7271 * involving @actor are complete.
7275 actor_signals[TRANSITIONS_COMPLETED] =
7276 g_signal_new (I_("transitions-completed"),
7277 G_TYPE_FROM_CLASS (object_class),
7281 _clutter_marshal_VOID__VOID,
7286 clutter_actor_init (ClutterActor *self)
7288 ClutterActorPrivate *priv;
7290 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7292 priv->id = _clutter_context_acquire_id (self);
7295 priv->opacity = 0xff;
7296 priv->show_on_set_parent = TRUE;
7298 priv->needs_width_request = TRUE;
7299 priv->needs_height_request = TRUE;
7300 priv->needs_allocation = TRUE;
7302 priv->cached_width_age = 1;
7303 priv->cached_height_age = 1;
7305 priv->opacity_override = -1;
7306 priv->enable_model_view_transform = TRUE;
7308 /* Initialize an empty paint volume to start with */
7309 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7310 priv->last_paint_volume_valid = TRUE;
7312 priv->transform_valid = FALSE;
7314 /* the default is to stretch the content, to match the
7315 * current behaviour of basically all actors. also, it's
7316 * the easiest thing to compute.
7318 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7319 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7320 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7322 /* this flag will be set to TRUE if the actor gets a child
7323 * or if the [xy]-expand flags are explicitly set; until
7324 * then, the actor does not need to expand.
7326 * this also allows us to avoid computing the expand flag
7327 * when building up a scene.
7329 priv->needs_compute_expand = FALSE;
7333 * clutter_actor_new:
7335 * Creates a new #ClutterActor.
7337 * A newly created actor has a floating reference, which will be sunk
7338 * when it is added to another actor.
7340 * Return value: (transfer full): the newly created #ClutterActor
7345 clutter_actor_new (void)
7347 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7351 * clutter_actor_destroy:
7352 * @self: a #ClutterActor
7354 * Destroys an actor. When an actor is destroyed, it will break any
7355 * references it holds to other objects. If the actor is inside a
7356 * container, the actor will be removed.
7358 * When you destroy a container, its children will be destroyed as well.
7360 * Note: you cannot destroy the #ClutterStage returned by
7361 * clutter_stage_get_default().
7364 clutter_actor_destroy (ClutterActor *self)
7366 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7368 g_object_ref (self);
7370 /* avoid recursion while destroying */
7371 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7373 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7375 g_object_run_dispose (G_OBJECT (self));
7377 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7380 g_object_unref (self);
7384 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7385 ClutterPaintVolume *clip)
7387 ClutterActorPrivate *priv = self->priv;
7388 ClutterPaintVolume *pv;
7391 /* Remove queue entry early in the process, otherwise a new
7392 queue_redraw() during signal handling could put back this
7393 object in the stage redraw list (but the entry is freed as
7394 soon as we return from this function, causing a segfault
7397 priv->queue_redraw_entry = NULL;
7399 /* If we've been explicitly passed a clip volume then there's
7400 * nothing more to calculate, but otherwise the only thing we know
7401 * is that the change is constrained to the given actor.
7403 * The idea is that if we know the paint volume for where the actor
7404 * was last drawn (in eye coordinates) and we also have the paint
7405 * volume for where it will be drawn next (in actor coordinates)
7406 * then if we queue a redraw for both these volumes that will cover
7407 * everything that needs to be redrawn to clear the old view and
7408 * show the latest view of the actor.
7410 * Don't clip this redraw if we don't know what position we had for
7411 * the previous redraw since we don't know where to set the clip so
7412 * it will clear the actor as it is currently.
7416 _clutter_actor_set_queue_redraw_clip (self, clip);
7419 else if (G_LIKELY (priv->last_paint_volume_valid))
7421 pv = _clutter_actor_get_paint_volume_mutable (self);
7424 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7426 /* make sure we redraw the actors old position... */
7427 _clutter_actor_set_queue_redraw_clip (stage,
7428 &priv->last_paint_volume);
7429 _clutter_actor_signal_queue_redraw (stage, stage);
7430 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7432 /* XXX: Ideally the redraw signal would take a clip volume
7433 * argument, but that would be an ABI break. Until we can
7434 * break the ABI we pass the argument out-of-band
7437 /* setup the clip for the actors new position... */
7438 _clutter_actor_set_queue_redraw_clip (self, pv);
7447 _clutter_actor_signal_queue_redraw (self, self);
7449 /* Just in case anyone is manually firing redraw signals without
7450 * using the public queue_redraw() API we are careful to ensure that
7451 * our out-of-band clip member is cleared before returning...
7453 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7455 if (G_LIKELY (clipped))
7456 _clutter_actor_set_queue_redraw_clip (self, NULL);
7460 _clutter_actor_get_allocation_clip (ClutterActor *self,
7461 ClutterActorBox *clip)
7463 ClutterActorBox allocation;
7465 /* XXX: we don't care if we get an out of date allocation here
7466 * because clutter_actor_queue_redraw_with_clip knows to ignore
7467 * the clip if the actor's allocation is invalid.
7469 * This is noted because clutter_actor_get_allocation_box does some
7470 * unnecessary work to support buggy code with a comment suggesting
7471 * that it could be changed later which would be good for this use
7474 clutter_actor_get_allocation_box (self, &allocation);
7476 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7477 * actor's own coordinate space but the allocation is in parent
7481 clip->x2 = allocation.x2 - allocation.x1;
7482 clip->y2 = allocation.y2 - allocation.y1;
7486 _clutter_actor_queue_redraw_full (ClutterActor *self,
7487 ClutterRedrawFlags flags,
7488 ClutterPaintVolume *volume,
7489 ClutterEffect *effect)
7491 ClutterActorPrivate *priv = self->priv;
7492 ClutterPaintVolume allocation_pv;
7493 ClutterPaintVolume *pv;
7494 gboolean should_free_pv;
7495 ClutterActor *stage;
7497 /* Here's an outline of the actor queue redraw mechanism:
7499 * The process starts in one of the following two functions which
7500 * are wrappers for this function:
7501 * clutter_actor_queue_redraw
7502 * _clutter_actor_queue_redraw_with_clip
7504 * additionally, an effect can queue a redraw by wrapping this
7505 * function in clutter_effect_queue_rerun
7507 * This functions queues an entry in a list associated with the
7508 * stage which is a list of actors that queued a redraw while
7509 * updating the timelines, performing layouting and processing other
7510 * mainloop sources before the next paint starts.
7512 * We aim to minimize the processing done at this point because
7513 * there is a good chance other events will happen while updating
7514 * the scenegraph that would invalidate any expensive work we might
7515 * otherwise try to do here. For example we don't try and resolve
7516 * the screen space bounding box of an actor at this stage so as to
7517 * minimize how much of the screen redraw because it's possible
7518 * something else will happen which will force a full redraw anyway.
7520 * When all updates are complete and we come to paint the stage then
7521 * we iterate this list and actually emit the "queue-redraw" signals
7522 * for each of the listed actors which will bubble up to the stage
7523 * for each actor and at that point we will transform the actors
7524 * paint volume into screen coordinates to determine the clip region
7525 * for what needs to be redrawn in the next paint.
7527 * Besides minimizing redundant work another reason for this
7528 * deferred design is that it's more likely we will be able to
7529 * determine the paint volume of an actor once we've finished
7530 * updating the scenegraph because its allocation should be up to
7531 * date. NB: If we can't determine an actors paint volume then we
7532 * can't automatically queue a clipped redraw which can make a big
7533 * difference to performance.
7535 * So the control flow goes like this:
7536 * One of clutter_actor_queue_redraw,
7537 * _clutter_actor_queue_redraw_with_clip
7538 * or clutter_effect_queue_rerun
7540 * then control moves to:
7541 * _clutter_stage_queue_actor_redraw
7543 * later during _clutter_stage_do_update, once relayouting is done
7544 * and the scenegraph has been updated we will call:
7545 * _clutter_stage_finish_queue_redraws
7547 * _clutter_stage_finish_queue_redraws will call
7548 * _clutter_actor_finish_queue_redraw for each listed actor.
7549 * Note: actors *are* allowed to queue further redraws during this
7550 * process (considering clone actors or texture_new_from_actor which
7551 * respond to their source queueing a redraw by queuing a redraw
7552 * themselves). We repeat the process until the list is empty.
7554 * This will result in the "queue-redraw" signal being fired for
7555 * each actor which will pass control to the default signal handler:
7556 * clutter_actor_real_queue_redraw
7558 * This will bubble up to the stages handler:
7559 * clutter_stage_real_queue_redraw
7561 * clutter_stage_real_queue_redraw will transform the actors paint
7562 * volume into screen space and add it as a clip region for the next
7566 /* ignore queueing a redraw for actors being destroyed */
7567 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7570 stage = _clutter_actor_get_stage_internal (self);
7572 /* Ignore queueing a redraw for actors not descended from a stage */
7576 /* ignore queueing a redraw on stages that are being destroyed */
7577 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7580 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7582 ClutterActorBox allocation_clip;
7583 ClutterVertex origin;
7585 /* If the actor doesn't have a valid allocation then we will
7586 * queue a full stage redraw. */
7587 if (priv->needs_allocation)
7589 /* NB: NULL denotes an undefined clip which will result in a
7591 _clutter_actor_set_queue_redraw_clip (self, NULL);
7592 _clutter_actor_signal_queue_redraw (self, self);
7596 _clutter_paint_volume_init_static (&allocation_pv, self);
7597 pv = &allocation_pv;
7599 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7601 origin.x = allocation_clip.x1;
7602 origin.y = allocation_clip.y1;
7604 clutter_paint_volume_set_origin (pv, &origin);
7605 clutter_paint_volume_set_width (pv,
7606 allocation_clip.x2 - allocation_clip.x1);
7607 clutter_paint_volume_set_height (pv,
7608 allocation_clip.y2 -
7609 allocation_clip.y1);
7610 should_free_pv = TRUE;
7615 should_free_pv = FALSE;
7618 self->priv->queue_redraw_entry =
7619 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7620 priv->queue_redraw_entry,
7625 clutter_paint_volume_free (pv);
7627 /* If this is the first redraw queued then we can directly use the
7629 if (!priv->is_dirty)
7630 priv->effect_to_redraw = effect;
7631 /* Otherwise we need to merge it with the existing effect parameter */
7632 else if (effect != NULL)
7634 /* If there's already an effect then we need to use whichever is
7635 later in the chain of actors. Otherwise a full redraw has
7636 already been queued on the actor so we need to ignore the
7638 if (priv->effect_to_redraw != NULL)
7640 if (priv->effects == NULL)
7641 g_warning ("Redraw queued with an effect that is "
7642 "not applied to the actor");
7647 for (l = _clutter_meta_group_peek_metas (priv->effects);
7651 if (l->data == priv->effect_to_redraw ||
7653 priv->effect_to_redraw = l->data;
7660 /* If no effect is specified then we need to redraw the whole
7662 priv->effect_to_redraw = NULL;
7665 priv->is_dirty = TRUE;
7669 * clutter_actor_queue_redraw:
7670 * @self: A #ClutterActor
7672 * Queues up a redraw of an actor and any children. The redraw occurs
7673 * once the main loop becomes idle (after the current batch of events
7674 * has been processed, roughly).
7676 * Applications rarely need to call this, as redraws are handled
7677 * automatically by modification functions.
7679 * This function will not do anything if @self is not visible, or
7680 * if the actor is inside an invisible part of the scenegraph.
7682 * Also be aware that painting is a NOP for actors with an opacity of
7685 * When you are implementing a custom actor you must queue a redraw
7686 * whenever some private state changes that will affect painting or
7687 * picking of your actor.
7690 clutter_actor_queue_redraw (ClutterActor *self)
7692 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7694 _clutter_actor_queue_redraw_full (self,
7696 NULL, /* clip volume */
7701 * _clutter_actor_queue_redraw_with_clip:
7702 * @self: A #ClutterActor
7703 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7704 * this queue redraw.
7705 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7706 * redrawn or %NULL if you are just using a @flag to state your
7709 * Queues up a clipped redraw of an actor and any children. The redraw
7710 * occurs once the main loop becomes idle (after the current batch of
7711 * events has been processed, roughly).
7713 * If no flags are given the clip volume is defined by @volume
7714 * specified in actor coordinates and tells Clutter that only content
7715 * within this volume has been changed so Clutter can optionally
7716 * optimize the redraw.
7718 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7719 * should be %NULL and this tells Clutter to use the actor's current
7720 * allocation as a clip box. This flag can only be used for 2D actors,
7721 * because any actor with depth may be projected outside its
7724 * Applications rarely need to call this, as redraws are handled
7725 * automatically by modification functions.
7727 * This function will not do anything if @self is not visible, or if
7728 * the actor is inside an invisible part of the scenegraph.
7730 * Also be aware that painting is a NOP for actors with an opacity of
7733 * When you are implementing a custom actor you must queue a redraw
7734 * whenever some private state changes that will affect painting or
7735 * picking of your actor.
7738 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7739 ClutterRedrawFlags flags,
7740 ClutterPaintVolume *volume)
7742 _clutter_actor_queue_redraw_full (self,
7744 volume, /* clip volume */
7749 _clutter_actor_queue_only_relayout (ClutterActor *self)
7751 ClutterActorPrivate *priv = self->priv;
7753 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7756 if (priv->needs_width_request &&
7757 priv->needs_height_request &&
7758 priv->needs_allocation)
7759 return; /* save some cpu cycles */
7761 #if CLUTTER_ENABLE_DEBUG
7762 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7764 g_warning ("The actor '%s' is currently inside an allocation "
7765 "cycle; calling clutter_actor_queue_relayout() is "
7767 _clutter_actor_get_debug_name (self));
7769 #endif /* CLUTTER_ENABLE_DEBUG */
7771 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7775 * clutter_actor_queue_redraw_with_clip:
7776 * @self: a #ClutterActor
7777 * @clip: (allow-none): a rectangular clip region, or %NULL
7779 * Queues a redraw on @self limited to a specific, actor-relative
7782 * If @clip is %NULL this function is equivalent to
7783 * clutter_actor_queue_redraw().
7788 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7789 const cairo_rectangle_int_t *clip)
7791 ClutterPaintVolume volume;
7792 ClutterVertex origin;
7794 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7798 clutter_actor_queue_redraw (self);
7802 _clutter_paint_volume_init_static (&volume, self);
7808 clutter_paint_volume_set_origin (&volume, &origin);
7809 clutter_paint_volume_set_width (&volume, clip->width);
7810 clutter_paint_volume_set_height (&volume, clip->height);
7812 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7814 clutter_paint_volume_free (&volume);
7818 * clutter_actor_queue_relayout:
7819 * @self: A #ClutterActor
7821 * Indicates that the actor's size request or other layout-affecting
7822 * properties may have changed. This function is used inside #ClutterActor
7823 * subclass implementations, not by applications directly.
7825 * Queueing a new layout automatically queues a redraw as well.
7830 clutter_actor_queue_relayout (ClutterActor *self)
7832 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7834 _clutter_actor_queue_only_relayout (self);
7835 clutter_actor_queue_redraw (self);
7839 * clutter_actor_get_preferred_size:
7840 * @self: a #ClutterActor
7841 * @min_width_p: (out) (allow-none): return location for the minimum
7843 * @min_height_p: (out) (allow-none): return location for the minimum
7845 * @natural_width_p: (out) (allow-none): return location for the natural
7847 * @natural_height_p: (out) (allow-none): return location for the natural
7850 * Computes the preferred minimum and natural size of an actor, taking into
7851 * account the actor's geometry management (either height-for-width
7852 * or width-for-height).
7854 * The width and height used to compute the preferred height and preferred
7855 * width are the actor's natural ones.
7857 * If you need to control the height for the preferred width, or the width for
7858 * the preferred height, you should use clutter_actor_get_preferred_width()
7859 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7860 * geometry management using the #ClutterActor:request-mode property.
7865 clutter_actor_get_preferred_size (ClutterActor *self,
7866 gfloat *min_width_p,
7867 gfloat *min_height_p,
7868 gfloat *natural_width_p,
7869 gfloat *natural_height_p)
7871 ClutterActorPrivate *priv;
7872 gfloat min_width, min_height;
7873 gfloat natural_width, natural_height;
7875 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7879 min_width = min_height = 0;
7880 natural_width = natural_height = 0;
7882 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7884 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7885 clutter_actor_get_preferred_width (self, -1,
7888 clutter_actor_get_preferred_height (self, natural_width,
7894 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7895 clutter_actor_get_preferred_height (self, -1,
7898 clutter_actor_get_preferred_width (self, natural_height,
7904 *min_width_p = min_width;
7907 *min_height_p = min_height;
7909 if (natural_width_p)
7910 *natural_width_p = natural_width;
7912 if (natural_height_p)
7913 *natural_height_p = natural_height;
7918 * @align: a #ClutterActorAlign
7919 * @direction: a #ClutterTextDirection
7921 * Retrieves the correct alignment depending on the text direction
7923 * Return value: the effective alignment
7925 static ClutterActorAlign
7926 effective_align (ClutterActorAlign align,
7927 ClutterTextDirection direction)
7929 ClutterActorAlign res;
7933 case CLUTTER_ACTOR_ALIGN_START:
7934 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7935 ? CLUTTER_ACTOR_ALIGN_END
7936 : CLUTTER_ACTOR_ALIGN_START;
7939 case CLUTTER_ACTOR_ALIGN_END:
7940 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7941 ? CLUTTER_ACTOR_ALIGN_START
7942 : CLUTTER_ACTOR_ALIGN_END;
7954 * _clutter_actor_get_effective_x_align:
7955 * @self: a #ClutterActor
7957 * Retrieves the effective horizontal alignment, taking into
7958 * consideration the text direction of @self.
7960 * Return value: the effective horizontal alignment
7963 _clutter_actor_get_effective_x_align (ClutterActor *self)
7965 return effective_align (clutter_actor_get_x_align (self),
7966 clutter_actor_get_text_direction (self));
7970 adjust_for_margin (float margin_start,
7972 float *minimum_size,
7973 float *natural_size,
7974 float *allocated_start,
7975 float *allocated_end)
7977 *minimum_size -= (margin_start + margin_end);
7978 *natural_size -= (margin_start + margin_end);
7979 *allocated_start += margin_start;
7980 *allocated_end -= margin_end;
7984 adjust_for_alignment (ClutterActorAlign alignment,
7986 float *allocated_start,
7987 float *allocated_end)
7989 float allocated_size = *allocated_end - *allocated_start;
7993 case CLUTTER_ACTOR_ALIGN_FILL:
7997 case CLUTTER_ACTOR_ALIGN_START:
7999 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8002 case CLUTTER_ACTOR_ALIGN_END:
8003 if (allocated_size > natural_size)
8005 *allocated_start += (allocated_size - natural_size);
8006 *allocated_end = *allocated_start + natural_size;
8010 case CLUTTER_ACTOR_ALIGN_CENTER:
8011 if (allocated_size > natural_size)
8013 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8014 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8021 * clutter_actor_adjust_width:
8022 * @self: a #ClutterActor
8023 * @minimum_width: (inout): the actor's preferred minimum width, which
8024 * will be adjusted depending on the margin
8025 * @natural_width: (inout): the actor's preferred natural width, which
8026 * will be adjusted depending on the margin
8027 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8028 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8030 * Adjusts the preferred and allocated position and size of an actor,
8031 * depending on the margin and alignment properties.
8034 clutter_actor_adjust_width (ClutterActor *self,
8035 gfloat *minimum_width,
8036 gfloat *natural_width,
8037 gfloat *adjusted_x1,
8038 gfloat *adjusted_x2)
8040 ClutterTextDirection text_dir;
8041 const ClutterLayoutInfo *info;
8043 info = _clutter_actor_get_layout_info_or_defaults (self);
8044 text_dir = clutter_actor_get_text_direction (self);
8046 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8048 /* this will tweak natural_width to remove the margin, so that
8049 * adjust_for_alignment() will use the correct size
8051 adjust_for_margin (info->margin.left, info->margin.right,
8052 minimum_width, natural_width,
8053 adjusted_x1, adjusted_x2);
8055 adjust_for_alignment (effective_align (info->x_align, text_dir),
8057 adjusted_x1, adjusted_x2);
8061 * clutter_actor_adjust_height:
8062 * @self: a #ClutterActor
8063 * @minimum_height: (inout): the actor's preferred minimum height, which
8064 * will be adjusted depending on the margin
8065 * @natural_height: (inout): the actor's preferred natural height, which
8066 * will be adjusted depending on the margin
8067 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8068 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8070 * Adjusts the preferred and allocated position and size of an actor,
8071 * depending on the margin and alignment properties.
8074 clutter_actor_adjust_height (ClutterActor *self,
8075 gfloat *minimum_height,
8076 gfloat *natural_height,
8077 gfloat *adjusted_y1,
8078 gfloat *adjusted_y2)
8080 const ClutterLayoutInfo *info;
8082 info = _clutter_actor_get_layout_info_or_defaults (self);
8084 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8086 /* this will tweak natural_height to remove the margin, so that
8087 * adjust_for_alignment() will use the correct size
8089 adjust_for_margin (info->margin.top, info->margin.bottom,
8090 minimum_height, natural_height,
8094 /* we don't use effective_align() here, because text direction
8095 * only affects the horizontal axis
8097 adjust_for_alignment (info->y_align,
8104 /* looks for a cached size request for this for_size. If not
8105 * found, returns the oldest entry so it can be overwritten */
8107 _clutter_actor_get_cached_size_request (gfloat for_size,
8108 SizeRequest *cached_size_requests,
8109 SizeRequest **result)
8113 *result = &cached_size_requests[0];
8115 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8119 sr = &cached_size_requests[i];
8122 sr->for_size == for_size)
8124 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8128 else if (sr->age < (*result)->age)
8134 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8140 * clutter_actor_get_preferred_width:
8141 * @self: A #ClutterActor
8142 * @for_height: available height when computing the preferred width,
8143 * or a negative value to indicate that no height is defined
8144 * @min_width_p: (out) (allow-none): return location for minimum width,
8146 * @natural_width_p: (out) (allow-none): return location for the natural
8149 * Computes the requested minimum and natural widths for an actor,
8150 * optionally depending on the specified height, or if they are
8151 * already computed, returns the cached values.
8153 * An actor may not get its request - depending on the layout
8154 * manager that's in effect.
8156 * A request should not incorporate the actor's scale or anchor point;
8157 * those transformations do not affect layout, only rendering.
8162 clutter_actor_get_preferred_width (ClutterActor *self,
8164 gfloat *min_width_p,
8165 gfloat *natural_width_p)
8167 float request_min_width, request_natural_width;
8168 SizeRequest *cached_size_request;
8169 const ClutterLayoutInfo *info;
8170 ClutterActorPrivate *priv;
8171 gboolean found_in_cache;
8173 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8177 info = _clutter_actor_get_layout_info_or_defaults (self);
8179 /* we shortcircuit the case of a fixed size set using set_width() */
8180 if (priv->min_width_set && priv->natural_width_set)
8182 if (min_width_p != NULL)
8183 *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8185 if (natural_width_p != NULL)
8186 *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8191 /* the remaining cases are:
8193 * - either min_width or natural_width have been set
8194 * - neither min_width or natural_width have been set
8196 * in both cases, we go through the cache (and through the actor in case
8197 * of cache misses) and determine the authoritative value depending on
8201 if (!priv->needs_width_request)
8204 _clutter_actor_get_cached_size_request (for_height,
8205 priv->width_requests,
8206 &cached_size_request);
8210 /* if the actor needs a width request we use the first slot */
8211 found_in_cache = FALSE;
8212 cached_size_request = &priv->width_requests[0];
8215 if (!found_in_cache)
8217 gfloat minimum_width, natural_width;
8218 ClutterActorClass *klass;
8220 minimum_width = natural_width = 0;
8222 /* adjust for the margin */
8223 if (for_height >= 0)
8225 for_height -= (info->margin.top + info->margin.bottom);
8230 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8232 klass = CLUTTER_ACTOR_GET_CLASS (self);
8233 klass->get_preferred_width (self, for_height,
8237 /* adjust for the margin */
8238 minimum_width += (info->margin.left + info->margin.right);
8239 natural_width += (info->margin.left + info->margin.right);
8241 /* Due to accumulated float errors, it's better not to warn
8242 * on this, but just fix it.
8244 if (natural_width < minimum_width)
8245 natural_width = minimum_width;
8247 cached_size_request->min_size = minimum_width;
8248 cached_size_request->natural_size = natural_width;
8249 cached_size_request->for_size = for_height;
8250 cached_size_request->age = priv->cached_width_age;
8252 priv->cached_width_age += 1;
8253 priv->needs_width_request = FALSE;
8256 if (!priv->min_width_set)
8257 request_min_width = cached_size_request->min_size;
8259 request_min_width = info->minimum.width;
8261 if (!priv->natural_width_set)
8262 request_natural_width = cached_size_request->natural_size;
8264 request_natural_width = info->natural.width;
8267 *min_width_p = request_min_width;
8269 if (natural_width_p)
8270 *natural_width_p = request_natural_width;
8274 * clutter_actor_get_preferred_height:
8275 * @self: A #ClutterActor
8276 * @for_width: available width to assume in computing desired height,
8277 * or a negative value to indicate that no width is defined
8278 * @min_height_p: (out) (allow-none): return location for minimum height,
8280 * @natural_height_p: (out) (allow-none): return location for natural
8283 * Computes the requested minimum and natural heights for an actor,
8284 * or if they are already computed, returns the cached values.
8286 * An actor may not get its request - depending on the layout
8287 * manager that's in effect.
8289 * A request should not incorporate the actor's scale or anchor point;
8290 * those transformations do not affect layout, only rendering.
8295 clutter_actor_get_preferred_height (ClutterActor *self,
8297 gfloat *min_height_p,
8298 gfloat *natural_height_p)
8300 float request_min_height, request_natural_height;
8301 SizeRequest *cached_size_request;
8302 const ClutterLayoutInfo *info;
8303 ClutterActorPrivate *priv;
8304 gboolean found_in_cache;
8306 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8310 info = _clutter_actor_get_layout_info_or_defaults (self);
8312 /* we shortcircuit the case of a fixed size set using set_height() */
8313 if (priv->min_height_set && priv->natural_height_set)
8315 if (min_height_p != NULL)
8316 *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8318 if (natural_height_p != NULL)
8319 *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8324 /* the remaining cases are:
8326 * - either min_height or natural_height have been set
8327 * - neither min_height or natural_height have been set
8329 * in both cases, we go through the cache (and through the actor in case
8330 * of cache misses) and determine the authoritative value depending on
8334 if (!priv->needs_height_request)
8337 _clutter_actor_get_cached_size_request (for_width,
8338 priv->height_requests,
8339 &cached_size_request);
8343 found_in_cache = FALSE;
8344 cached_size_request = &priv->height_requests[0];
8347 if (!found_in_cache)
8349 gfloat minimum_height, natural_height;
8350 ClutterActorClass *klass;
8352 minimum_height = natural_height = 0;
8354 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8356 /* adjust for margin */
8359 for_width -= (info->margin.left + info->margin.right);
8364 klass = CLUTTER_ACTOR_GET_CLASS (self);
8365 klass->get_preferred_height (self, for_width,
8369 /* adjust for margin */
8370 minimum_height += (info->margin.top + info->margin.bottom);
8371 natural_height += (info->margin.top + info->margin.bottom);
8373 /* Due to accumulated float errors, it's better not to warn
8374 * on this, but just fix it.
8376 if (natural_height < minimum_height)
8377 natural_height = minimum_height;
8379 cached_size_request->min_size = minimum_height;
8380 cached_size_request->natural_size = natural_height;
8381 cached_size_request->for_size = for_width;
8382 cached_size_request->age = priv->cached_height_age;
8384 priv->cached_height_age += 1;
8385 priv->needs_height_request = FALSE;
8388 if (!priv->min_height_set)
8389 request_min_height = cached_size_request->min_size;
8391 request_min_height = info->minimum.height;
8393 if (!priv->natural_height_set)
8394 request_natural_height = cached_size_request->natural_size;
8396 request_natural_height = info->natural.height;
8399 *min_height_p = request_min_height;
8401 if (natural_height_p)
8402 *natural_height_p = request_natural_height;
8406 * clutter_actor_get_allocation_box:
8407 * @self: A #ClutterActor
8408 * @box: (out): the function fills this in with the actor's allocation
8410 * Gets the layout box an actor has been assigned. The allocation can
8411 * only be assumed valid inside a paint() method; anywhere else, it
8412 * may be out-of-date.
8414 * An allocation does not incorporate the actor's scale or anchor point;
8415 * those transformations do not affect layout, only rendering.
8417 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8418 * of functions inside the implementation of the get_preferred_width()
8419 * or get_preferred_height() virtual functions.</note>
8424 clutter_actor_get_allocation_box (ClutterActor *self,
8425 ClutterActorBox *box)
8427 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8429 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8430 * which limits calling get_allocation to inside paint() basically; or
8431 * we can 2) force a layout, which could be expensive if someone calls
8432 * get_allocation somewhere silly; or we can 3) just return the latest
8433 * value, allowing it to be out-of-date, and assume people know what
8436 * The least-surprises approach that keeps existing code working is
8437 * likely to be 2). People can end up doing some inefficient things,
8438 * though, and in general code that requires 2) is probably broken.
8441 /* this implements 2) */
8442 if (G_UNLIKELY (self->priv->needs_allocation))
8444 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8446 /* do not queue a relayout on an unparented actor */
8448 _clutter_stage_maybe_relayout (stage);
8451 /* commenting out the code above and just keeping this assigment
8454 *box = self->priv->allocation;
8458 * clutter_actor_get_allocation_geometry:
8459 * @self: A #ClutterActor
8460 * @geom: (out): allocation geometry in pixels
8462 * Gets the layout box an actor has been assigned. The allocation can
8463 * only be assumed valid inside a paint() method; anywhere else, it
8464 * may be out-of-date.
8466 * An allocation does not incorporate the actor's scale or anchor point;
8467 * those transformations do not affect layout, only rendering.
8469 * The returned rectangle is in pixels.
8474 clutter_actor_get_allocation_geometry (ClutterActor *self,
8475 ClutterGeometry *geom)
8477 ClutterActorBox box;
8479 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8480 g_return_if_fail (geom != NULL);
8482 clutter_actor_get_allocation_box (self, &box);
8484 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8485 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8486 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8487 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8491 clutter_actor_update_constraints (ClutterActor *self,
8492 ClutterActorBox *allocation)
8494 ClutterActorPrivate *priv = self->priv;
8495 const GList *constraints, *l;
8497 if (priv->constraints == NULL)
8500 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8501 for (l = constraints; l != NULL; l = l->next)
8503 ClutterConstraint *constraint = l->data;
8504 ClutterActorMeta *meta = l->data;
8506 if (clutter_actor_meta_get_enabled (meta))
8508 _clutter_constraint_update_allocation (constraint,
8512 CLUTTER_NOTE (LAYOUT,
8513 "Allocation of '%s' after constraint '%s': "
8514 "{ %.2f, %.2f, %.2f, %.2f }",
8515 _clutter_actor_get_debug_name (self),
8516 _clutter_actor_meta_get_debug_name (meta),
8526 * clutter_actor_adjust_allocation:
8527 * @self: a #ClutterActor
8528 * @allocation: (inout): the allocation to adjust
8530 * Adjusts the passed allocation box taking into account the actor's
8531 * layout information, like alignment, expansion, and margin.
8534 clutter_actor_adjust_allocation (ClutterActor *self,
8535 ClutterActorBox *allocation)
8537 ClutterActorBox adj_allocation;
8538 float alloc_width, alloc_height;
8539 float min_width, min_height;
8540 float nat_width, nat_height;
8541 ClutterRequestMode req_mode;
8543 adj_allocation = *allocation;
8545 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8547 /* we want to hit the cache, so we use the public API */
8548 req_mode = clutter_actor_get_request_mode (self);
8550 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8552 clutter_actor_get_preferred_width (self, -1,
8555 clutter_actor_get_preferred_height (self, alloc_width,
8559 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8561 clutter_actor_get_preferred_height (self, -1,
8564 clutter_actor_get_preferred_height (self, alloc_height,
8569 #ifdef CLUTTER_ENABLE_DEBUG
8570 /* warn about underallocations */
8571 if (_clutter_diagnostic_enabled () &&
8572 (floorf (min_width - alloc_width) > 0 ||
8573 floorf (min_height - alloc_height) > 0))
8575 ClutterActor *parent = clutter_actor_get_parent (self);
8577 /* the only actors that are allowed to be underallocated are the Stage,
8578 * as it doesn't have an implicit size, and Actors that specifically
8579 * told us that they want to opt-out from layout control mechanisms
8580 * through the NO_LAYOUT escape hatch.
8582 if (parent != NULL &&
8583 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8585 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8586 "of %.2f x %.2f from its parent actor '%s', but its "
8587 "requested minimum size is of %.2f x %.2f",
8588 _clutter_actor_get_debug_name (self),
8589 alloc_width, alloc_height,
8590 _clutter_actor_get_debug_name (parent),
8591 min_width, min_height);
8596 clutter_actor_adjust_width (self,
8600 &adj_allocation.x2);
8602 clutter_actor_adjust_height (self,
8606 &adj_allocation.y2);
8608 /* we maintain the invariant that an allocation cannot be adjusted
8609 * to be outside the parent-given box
8611 if (adj_allocation.x1 < allocation->x1 ||
8612 adj_allocation.y1 < allocation->y1 ||
8613 adj_allocation.x2 > allocation->x2 ||
8614 adj_allocation.y2 > allocation->y2)
8616 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8617 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8618 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8619 _clutter_actor_get_debug_name (self),
8620 adj_allocation.x1, adj_allocation.y1,
8621 adj_allocation.x2 - adj_allocation.x1,
8622 adj_allocation.y2 - adj_allocation.y1,
8623 allocation->x1, allocation->y1,
8624 allocation->x2 - allocation->x1,
8625 allocation->y2 - allocation->y1);
8629 *allocation = adj_allocation;
8633 * clutter_actor_allocate:
8634 * @self: A #ClutterActor
8635 * @box: new allocation of the actor, in parent-relative coordinates
8636 * @flags: flags that control the allocation
8638 * Called by the parent of an actor to assign the actor its size.
8639 * Should never be called by applications (except when implementing
8640 * a container or layout manager).
8642 * Actors can know from their allocation box whether they have moved
8643 * with respect to their parent actor. The @flags parameter describes
8644 * additional information about the allocation, for instance whether
8645 * the parent has moved with respect to the stage, for example because
8646 * a grandparent's origin has moved.
8651 clutter_actor_allocate (ClutterActor *self,
8652 const ClutterActorBox *box,
8653 ClutterAllocationFlags flags)
8655 ClutterActorPrivate *priv;
8656 ClutterActorClass *klass;
8657 ClutterActorBox old_allocation, real_allocation;
8658 gboolean origin_changed, child_moved, size_changed;
8659 gboolean stage_allocation_changed;
8661 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8662 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8664 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8665 "which isn't a descendent of the stage!\n",
8666 self, _clutter_actor_get_debug_name (self));
8672 old_allocation = priv->allocation;
8673 real_allocation = *box;
8675 /* constraints are allowed to modify the allocation only here; we do
8676 * this prior to all the other checks so that we can bail out if the
8677 * allocation did not change
8679 clutter_actor_update_constraints (self, &real_allocation);
8681 /* adjust the allocation depending on the align/margin properties */
8682 clutter_actor_adjust_allocation (self, &real_allocation);
8684 if (real_allocation.x2 < real_allocation.x1 ||
8685 real_allocation.y2 < real_allocation.y1)
8687 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8688 _clutter_actor_get_debug_name (self),
8689 real_allocation.x2 - real_allocation.x1,
8690 real_allocation.y2 - real_allocation.y1);
8693 /* we allow 0-sized actors, but not negative-sized ones */
8694 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8695 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8697 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8699 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8700 real_allocation.y1 != old_allocation.y1);
8702 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8703 real_allocation.y2 != old_allocation.y2);
8705 if (origin_changed || child_moved || size_changed)
8706 stage_allocation_changed = TRUE;
8708 stage_allocation_changed = FALSE;
8710 /* If we get an allocation "out of the blue"
8711 * (we did not queue relayout), then we want to
8712 * ignore it. But if we have needs_allocation set,
8713 * we want to guarantee that allocate() virtual
8714 * method is always called, i.e. that queue_relayout()
8715 * always results in an allocate() invocation on
8718 * The optimization here is to avoid re-allocating
8719 * actors that did not queue relayout and were
8722 if (!priv->needs_allocation && !stage_allocation_changed)
8724 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8728 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8729 * clutter_actor_allocate(), it indicates whether the parent has its
8730 * absolute origin moved; when passed in to ClutterActor::allocate()
8731 * virtual method though, it indicates whether the child has its
8732 * absolute origin moved. So we set it when child_moved is TRUE
8735 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8737 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8739 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8740 _clutter_actor_get_debug_name (self));
8742 klass = CLUTTER_ACTOR_GET_CLASS (self);
8743 klass->allocate (self, &real_allocation, flags);
8745 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8747 if (stage_allocation_changed)
8748 clutter_actor_queue_redraw (self);
8752 * clutter_actor_set_allocation:
8753 * @self: a #ClutterActor
8754 * @box: a #ClutterActorBox
8755 * @flags: allocation flags
8757 * Stores the allocation of @self as defined by @box.
8759 * This function can only be called from within the implementation of
8760 * the #ClutterActorClass.allocate() virtual function.
8762 * The allocation should have been adjusted to take into account constraints,
8763 * alignment, and margin properties. If you are implementing a #ClutterActor
8764 * subclass that provides its own layout management policy for its children
8765 * instead of using a #ClutterLayoutManager delegate, you should not call
8766 * this function on the children of @self; instead, you should call
8767 * clutter_actor_allocate(), which will adjust the allocation box for
8770 * This function should only be used by subclasses of #ClutterActor
8771 * that wish to store their allocation but cannot chain up to the
8772 * parent's implementation; the default implementation of the
8773 * #ClutterActorClass.allocate() virtual function will call this
8776 * It is important to note that, while chaining up was the recommended
8777 * behaviour for #ClutterActor subclasses prior to the introduction of
8778 * this function, it is recommended to call clutter_actor_set_allocation()
8781 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8782 * to handle the allocation of its children, this function will call
8783 * the clutter_layout_manager_allocate() function only if the
8784 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8785 * expected that the subclass will call clutter_layout_manager_allocate()
8786 * by itself. For instance, the following code:
8790 * my_actor_allocate (ClutterActor *actor,
8791 * const ClutterActorBox *allocation,
8792 * ClutterAllocationFlags flags)
8794 * ClutterActorBox new_alloc;
8795 * ClutterAllocationFlags new_flags;
8797 * adjust_allocation (allocation, &new_alloc);
8799 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8801 * /* this will use the layout manager set on the actor */
8802 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8806 * is equivalent to this:
8810 * my_actor_allocate (ClutterActor *actor,
8811 * const ClutterActorBox *allocation,
8812 * ClutterAllocationFlags flags)
8814 * ClutterLayoutManager *layout;
8815 * ClutterActorBox new_alloc;
8817 * adjust_allocation (allocation, &new_alloc);
8819 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8821 * layout = clutter_actor_get_layout_manager (actor);
8822 * clutter_layout_manager_allocate (layout,
8823 * CLUTTER_CONTAINER (actor),
8832 clutter_actor_set_allocation (ClutterActor *self,
8833 const ClutterActorBox *box,
8834 ClutterAllocationFlags flags)
8836 ClutterActorPrivate *priv;
8839 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8840 g_return_if_fail (box != NULL);
8842 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8844 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8845 "can only be called from within the implementation of "
8846 "the ClutterActor::allocate() virtual function.");
8852 g_object_freeze_notify (G_OBJECT (self));
8854 changed = clutter_actor_set_allocation_internal (self, box, flags);
8856 /* we allocate our children before we notify changes in our geometry,
8857 * so that people connecting to properties will be able to get valid
8858 * data out of the sub-tree of the scene graph that has this actor at
8861 clutter_actor_maybe_layout_children (self, box, flags);
8865 ClutterActorBox signal_box = priv->allocation;
8866 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8868 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8873 g_object_thaw_notify (G_OBJECT (self));
8877 * clutter_actor_set_geometry:
8878 * @self: A #ClutterActor
8879 * @geometry: A #ClutterGeometry
8881 * Sets the actor's fixed position and forces its minimum and natural
8882 * size, in pixels. This means the untransformed actor will have the
8883 * given geometry. This is the same as calling clutter_actor_set_position()
8884 * and clutter_actor_set_size().
8886 * Deprecated: 1.10: Use clutter_actor_set_position() and
8887 * clutter_actor_set_size() instead.
8890 clutter_actor_set_geometry (ClutterActor *self,
8891 const ClutterGeometry *geometry)
8893 g_object_freeze_notify (G_OBJECT (self));
8895 clutter_actor_set_position (self, geometry->x, geometry->y);
8896 clutter_actor_set_size (self, geometry->width, geometry->height);
8898 g_object_thaw_notify (G_OBJECT (self));
8902 * clutter_actor_get_geometry:
8903 * @self: A #ClutterActor
8904 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8906 * Gets the size and position of an actor relative to its parent
8907 * actor. This is the same as calling clutter_actor_get_position() and
8908 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8909 * requested size and position if the actor's allocation is invalid.
8911 * Deprecated: 1.10: Use clutter_actor_get_position() and
8912 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8916 clutter_actor_get_geometry (ClutterActor *self,
8917 ClutterGeometry *geometry)
8919 gfloat x, y, width, height;
8921 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8922 g_return_if_fail (geometry != NULL);
8924 clutter_actor_get_position (self, &x, &y);
8925 clutter_actor_get_size (self, &width, &height);
8927 geometry->x = (int) x;
8928 geometry->y = (int) y;
8929 geometry->width = (int) width;
8930 geometry->height = (int) height;
8934 * clutter_actor_set_position:
8935 * @self: A #ClutterActor
8936 * @x: New left position of actor in pixels.
8937 * @y: New top position of actor in pixels.
8939 * Sets the actor's fixed position in pixels relative to any parent
8942 * If a layout manager is in use, this position will override the
8943 * layout manager and force a fixed position.
8946 clutter_actor_set_position (ClutterActor *self,
8950 ClutterPoint new_position;
8952 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8954 clutter_point_init (&new_position, x, y);
8956 if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
8958 ClutterPoint cur_position;
8960 cur_position.x = clutter_actor_get_x (self);
8961 cur_position.y = clutter_actor_get_y (self);
8963 _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
8968 _clutter_actor_update_transition (self,
8969 obj_props[PROP_POSITION],
8972 clutter_actor_queue_relayout (self);
8976 * clutter_actor_get_fixed_position_set:
8977 * @self: A #ClutterActor
8979 * Checks whether an actor has a fixed position set (and will thus be
8980 * unaffected by any layout manager).
8982 * Return value: %TRUE if the fixed position is set on the actor
8987 clutter_actor_get_fixed_position_set (ClutterActor *self)
8989 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8991 return self->priv->position_set;
8995 * clutter_actor_set_fixed_position_set:
8996 * @self: A #ClutterActor
8997 * @is_set: whether to use fixed position
8999 * Sets whether an actor has a fixed position set (and will thus be
9000 * unaffected by any layout manager).
9005 clutter_actor_set_fixed_position_set (ClutterActor *self,
9008 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9010 if (self->priv->position_set == (is_set != FALSE))
9013 self->priv->position_set = is_set != FALSE;
9014 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9016 clutter_actor_queue_relayout (self);
9020 * clutter_actor_move_by:
9021 * @self: A #ClutterActor
9022 * @dx: Distance to move Actor on X axis.
9023 * @dy: Distance to move Actor on Y axis.
9025 * Moves an actor by the specified distance relative to its current
9026 * position in pixels.
9028 * This function modifies the fixed position of an actor and thus removes
9029 * it from any layout management. Another way to move an actor is with an
9030 * anchor point, see clutter_actor_set_anchor_point().
9035 clutter_actor_move_by (ClutterActor *self,
9039 const ClutterLayoutInfo *info;
9042 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9044 info = _clutter_actor_get_layout_info_or_defaults (self);
9045 x = info->fixed_pos.x;
9046 y = info->fixed_pos.y;
9048 clutter_actor_set_position (self, x + dx, y + dy);
9052 clutter_actor_set_min_width (ClutterActor *self,
9055 ClutterActorPrivate *priv = self->priv;
9056 ClutterActorBox old = { 0, };
9057 ClutterLayoutInfo *info;
9059 /* if we are setting the size on a top-level actor and the
9060 * backend only supports static top-levels (e.g. framebuffers)
9061 * then we ignore the passed value and we override it with
9062 * the stage implementation's preferred size.
9064 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9065 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9068 info = _clutter_actor_get_layout_info (self);
9070 if (priv->min_width_set && min_width == info->minimum.width)
9073 g_object_freeze_notify (G_OBJECT (self));
9075 clutter_actor_store_old_geometry (self, &old);
9077 info->minimum.width = min_width;
9078 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9079 clutter_actor_set_min_width_set (self, TRUE);
9081 clutter_actor_notify_if_geometry_changed (self, &old);
9083 g_object_thaw_notify (G_OBJECT (self));
9085 clutter_actor_queue_relayout (self);
9089 clutter_actor_set_min_height (ClutterActor *self,
9093 ClutterActorPrivate *priv = self->priv;
9094 ClutterActorBox old = { 0, };
9095 ClutterLayoutInfo *info;
9097 /* if we are setting the size on a top-level actor and the
9098 * backend only supports static top-levels (e.g. framebuffers)
9099 * then we ignore the passed value and we override it with
9100 * the stage implementation's preferred size.
9102 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9103 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9106 info = _clutter_actor_get_layout_info (self);
9108 if (priv->min_height_set && min_height == info->minimum.height)
9111 g_object_freeze_notify (G_OBJECT (self));
9113 clutter_actor_store_old_geometry (self, &old);
9115 info->minimum.height = min_height;
9116 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9117 clutter_actor_set_min_height_set (self, TRUE);
9119 clutter_actor_notify_if_geometry_changed (self, &old);
9121 g_object_thaw_notify (G_OBJECT (self));
9123 clutter_actor_queue_relayout (self);
9127 clutter_actor_set_natural_width (ClutterActor *self,
9128 gfloat natural_width)
9130 ClutterActorPrivate *priv = self->priv;
9131 ClutterActorBox old = { 0, };
9132 ClutterLayoutInfo *info;
9134 /* if we are setting the size on a top-level actor and the
9135 * backend only supports static top-levels (e.g. framebuffers)
9136 * then we ignore the passed value and we override it with
9137 * the stage implementation's preferred size.
9139 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9140 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9143 info = _clutter_actor_get_layout_info (self);
9145 if (priv->natural_width_set && natural_width == info->natural.width)
9148 g_object_freeze_notify (G_OBJECT (self));
9150 clutter_actor_store_old_geometry (self, &old);
9152 info->natural.width = natural_width;
9153 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9154 clutter_actor_set_natural_width_set (self, TRUE);
9156 clutter_actor_notify_if_geometry_changed (self, &old);
9158 g_object_thaw_notify (G_OBJECT (self));
9160 clutter_actor_queue_relayout (self);
9164 clutter_actor_set_natural_height (ClutterActor *self,
9165 gfloat natural_height)
9167 ClutterActorPrivate *priv = self->priv;
9168 ClutterActorBox old = { 0, };
9169 ClutterLayoutInfo *info;
9171 /* if we are setting the size on a top-level actor and the
9172 * backend only supports static top-levels (e.g. framebuffers)
9173 * then we ignore the passed value and we override it with
9174 * the stage implementation's preferred size.
9176 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9177 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9180 info = _clutter_actor_get_layout_info (self);
9182 if (priv->natural_height_set && natural_height == info->natural.height)
9185 g_object_freeze_notify (G_OBJECT (self));
9187 clutter_actor_store_old_geometry (self, &old);
9189 info->natural.height = natural_height;
9190 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9191 clutter_actor_set_natural_height_set (self, TRUE);
9193 clutter_actor_notify_if_geometry_changed (self, &old);
9195 g_object_thaw_notify (G_OBJECT (self));
9197 clutter_actor_queue_relayout (self);
9201 clutter_actor_set_min_width_set (ClutterActor *self,
9202 gboolean use_min_width)
9204 ClutterActorPrivate *priv = self->priv;
9205 ClutterActorBox old = { 0, };
9207 if (priv->min_width_set == (use_min_width != FALSE))
9210 clutter_actor_store_old_geometry (self, &old);
9212 priv->min_width_set = use_min_width != FALSE;
9213 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9215 clutter_actor_notify_if_geometry_changed (self, &old);
9217 clutter_actor_queue_relayout (self);
9221 clutter_actor_set_min_height_set (ClutterActor *self,
9222 gboolean use_min_height)
9224 ClutterActorPrivate *priv = self->priv;
9225 ClutterActorBox old = { 0, };
9227 if (priv->min_height_set == (use_min_height != FALSE))
9230 clutter_actor_store_old_geometry (self, &old);
9232 priv->min_height_set = use_min_height != FALSE;
9233 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9235 clutter_actor_notify_if_geometry_changed (self, &old);
9237 clutter_actor_queue_relayout (self);
9241 clutter_actor_set_natural_width_set (ClutterActor *self,
9242 gboolean use_natural_width)
9244 ClutterActorPrivate *priv = self->priv;
9245 ClutterActorBox old = { 0, };
9247 if (priv->natural_width_set == (use_natural_width != FALSE))
9250 clutter_actor_store_old_geometry (self, &old);
9252 priv->natural_width_set = use_natural_width != FALSE;
9253 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9255 clutter_actor_notify_if_geometry_changed (self, &old);
9257 clutter_actor_queue_relayout (self);
9261 clutter_actor_set_natural_height_set (ClutterActor *self,
9262 gboolean use_natural_height)
9264 ClutterActorPrivate *priv = self->priv;
9265 ClutterActorBox old = { 0, };
9267 if (priv->natural_height_set == (use_natural_height != FALSE))
9270 clutter_actor_store_old_geometry (self, &old);
9272 priv->natural_height_set = use_natural_height != FALSE;
9273 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9275 clutter_actor_notify_if_geometry_changed (self, &old);
9277 clutter_actor_queue_relayout (self);
9281 * clutter_actor_set_request_mode:
9282 * @self: a #ClutterActor
9283 * @mode: the request mode
9285 * Sets the geometry request mode of @self.
9287 * The @mode determines the order for invoking
9288 * clutter_actor_get_preferred_width() and
9289 * clutter_actor_get_preferred_height()
9294 clutter_actor_set_request_mode (ClutterActor *self,
9295 ClutterRequestMode mode)
9297 ClutterActorPrivate *priv;
9299 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9303 if (priv->request_mode == mode)
9306 priv->request_mode = mode;
9308 priv->needs_width_request = TRUE;
9309 priv->needs_height_request = TRUE;
9311 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9313 clutter_actor_queue_relayout (self);
9317 * clutter_actor_get_request_mode:
9318 * @self: a #ClutterActor
9320 * Retrieves the geometry request mode of @self
9322 * Return value: the request mode for the actor
9327 clutter_actor_get_request_mode (ClutterActor *self)
9329 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9330 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9332 return self->priv->request_mode;
9335 /* variant of set_width() without checks and without notification
9336 * freeze+thaw, for internal usage only
9339 clutter_actor_set_width_internal (ClutterActor *self,
9344 /* the Stage will use the :min-width to control the minimum
9345 * width to be resized to, so we should not be setting it
9346 * along with the :natural-width
9348 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9349 clutter_actor_set_min_width (self, width);
9351 clutter_actor_set_natural_width (self, width);
9355 /* we only unset the :natural-width for the Stage */
9356 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9357 clutter_actor_set_min_width_set (self, FALSE);
9359 clutter_actor_set_natural_width_set (self, FALSE);
9363 /* variant of set_height() without checks and without notification
9364 * freeze+thaw, for internal usage only
9367 clutter_actor_set_height_internal (ClutterActor *self,
9372 /* see the comment above in set_width_internal() */
9373 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9374 clutter_actor_set_min_height (self, height);
9376 clutter_actor_set_natural_height (self, height);
9380 /* see the comment above in set_width_internal() */
9381 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9382 clutter_actor_set_min_height_set (self, FALSE);
9384 clutter_actor_set_natural_height_set (self, FALSE);
9389 clutter_actor_set_size_internal (ClutterActor *self,
9390 const ClutterSize *size)
9394 clutter_actor_set_width_internal (self, size->width);
9395 clutter_actor_set_height_internal (self, size->height);
9399 clutter_actor_set_width_internal (self, -1);
9400 clutter_actor_set_height_internal (self, -1);
9405 * clutter_actor_set_size:
9406 * @self: A #ClutterActor
9407 * @width: New width of actor in pixels, or -1
9408 * @height: New height of actor in pixels, or -1
9410 * Sets the actor's size request in pixels. This overrides any
9411 * "normal" size request the actor would have. For example
9412 * a text actor might normally request the size of the text;
9413 * this function would force a specific size instead.
9415 * If @width and/or @height are -1 the actor will use its
9416 * "normal" size request instead of overriding it, i.e.
9417 * you can "unset" the size with -1.
9419 * This function sets or unsets both the minimum and natural size.
9422 clutter_actor_set_size (ClutterActor *self,
9426 ClutterSize new_size;
9428 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9430 clutter_size_init (&new_size, width, height);
9432 if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9434 /* minor optimization: if we don't have a duration then we can
9435 * skip the get_size() below, to avoid the chance of going through
9436 * get_preferred_width() and get_preferred_height() just to jump to
9437 * a new desired size
9439 if (clutter_actor_get_easing_duration (self) == 0)
9441 g_object_freeze_notify (G_OBJECT (self));
9443 clutter_actor_set_size_internal (self, &new_size);
9445 g_object_thaw_notify (G_OBJECT (self));
9451 ClutterSize cur_size;
9453 clutter_size_init (&cur_size,
9454 clutter_actor_get_width (self),
9455 clutter_actor_get_height (self));
9457 _clutter_actor_create_transition (self,
9458 obj_props[PROP_SIZE],
9464 _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9466 clutter_actor_queue_relayout (self);
9470 * clutter_actor_get_size:
9471 * @self: A #ClutterActor
9472 * @width: (out) (allow-none): return location for the width, or %NULL.
9473 * @height: (out) (allow-none): return location for the height, or %NULL.
9475 * This function tries to "do what you mean" and return
9476 * the size an actor will have. If the actor has a valid
9477 * allocation, the allocation will be returned; otherwise,
9478 * the actors natural size request will be returned.
9480 * If you care whether you get the request vs. the allocation, you
9481 * should probably call a different function like
9482 * clutter_actor_get_allocation_box() or
9483 * clutter_actor_get_preferred_width().
9488 clutter_actor_get_size (ClutterActor *self,
9492 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9495 *width = clutter_actor_get_width (self);
9498 *height = clutter_actor_get_height (self);
9502 * clutter_actor_get_position:
9503 * @self: a #ClutterActor
9504 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9505 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9507 * This function tries to "do what you mean" and tell you where the
9508 * actor is, prior to any transformations. Retrieves the fixed
9509 * position of an actor in pixels, if one has been set; otherwise, if
9510 * the allocation is valid, returns the actor's allocated position;
9511 * otherwise, returns 0,0.
9513 * The returned position is in pixels.
9518 clutter_actor_get_position (ClutterActor *self,
9522 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9525 *x = clutter_actor_get_x (self);
9528 *y = clutter_actor_get_y (self);
9532 * clutter_actor_get_transformed_position:
9533 * @self: A #ClutterActor
9534 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9535 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9537 * Gets the absolute position of an actor, in pixels relative to the stage.
9542 clutter_actor_get_transformed_position (ClutterActor *self,
9549 v1.x = v1.y = v1.z = 0;
9550 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9560 * clutter_actor_get_transformed_size:
9561 * @self: A #ClutterActor
9562 * @width: (out) (allow-none): return location for the width, or %NULL
9563 * @height: (out) (allow-none): return location for the height, or %NULL
9565 * Gets the absolute size of an actor in pixels, taking into account the
9568 * If the actor has a valid allocation, the allocated size will be used.
9569 * If the actor has not a valid allocation then the preferred size will
9570 * be transformed and returned.
9572 * If you want the transformed allocation, see
9573 * clutter_actor_get_abs_allocation_vertices() instead.
9575 * <note>When the actor (or one of its ancestors) is rotated around the
9576 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9577 * as a generic quadrangle; in that case this function returns the size
9578 * of the smallest rectangle that encapsulates the entire quad. Please
9579 * note that in this case no assumptions can be made about the relative
9580 * position of this envelope to the absolute position of the actor, as
9581 * returned by clutter_actor_get_transformed_position(); if you need this
9582 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9583 * to get the coords of the actual quadrangle.</note>
9588 clutter_actor_get_transformed_size (ClutterActor *self,
9592 ClutterActorPrivate *priv;
9594 gfloat x_min, x_max, y_min, y_max;
9597 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9601 /* if the actor hasn't been allocated yet, get the preferred
9602 * size and transform that
9604 if (priv->needs_allocation)
9606 gfloat natural_width, natural_height;
9607 ClutterActorBox box;
9609 /* Make a fake allocation to transform.
9611 * NB: _clutter_actor_transform_and_project_box expects a box in
9612 * the actor's coordinate space... */
9617 natural_width = natural_height = 0;
9618 clutter_actor_get_preferred_size (self, NULL, NULL,
9622 box.x2 = natural_width;
9623 box.y2 = natural_height;
9625 _clutter_actor_transform_and_project_box (self, &box, v);
9628 clutter_actor_get_abs_allocation_vertices (self, v);
9630 x_min = x_max = v[0].x;
9631 y_min = y_max = v[0].y;
9633 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9649 *width = x_max - x_min;
9652 *height = y_max - y_min;
9656 * clutter_actor_get_width:
9657 * @self: A #ClutterActor
9659 * Retrieves the width of a #ClutterActor.
9661 * If the actor has a valid allocation, this function will return the
9662 * width of the allocated area given to the actor.
9664 * If the actor does not have a valid allocation, this function will
9665 * return the actor's natural width, that is the preferred width of
9668 * If you care whether you get the preferred width or the width that
9669 * has been assigned to the actor, you should probably call a different
9670 * function like clutter_actor_get_allocation_box() to retrieve the
9671 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9674 * If an actor has a fixed width, for instance a width that has been
9675 * assigned using clutter_actor_set_width(), the width returned will
9676 * be the same value.
9678 * Return value: the width of the actor, in pixels
9681 clutter_actor_get_width (ClutterActor *self)
9683 ClutterActorPrivate *priv;
9685 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9689 if (priv->needs_allocation)
9691 gfloat natural_width = 0;
9693 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9694 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9697 gfloat natural_height = 0;
9699 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9700 clutter_actor_get_preferred_width (self, natural_height,
9705 return natural_width;
9708 return priv->allocation.x2 - priv->allocation.x1;
9712 * clutter_actor_get_height:
9713 * @self: A #ClutterActor
9715 * Retrieves the height of a #ClutterActor.
9717 * If the actor has a valid allocation, this function will return the
9718 * height of the allocated area given to the actor.
9720 * If the actor does not have a valid allocation, this function will
9721 * return the actor's natural height, that is the preferred height of
9724 * If you care whether you get the preferred height or the height that
9725 * has been assigned to the actor, you should probably call a different
9726 * function like clutter_actor_get_allocation_box() to retrieve the
9727 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9730 * If an actor has a fixed height, for instance a height that has been
9731 * assigned using clutter_actor_set_height(), the height returned will
9732 * be the same value.
9734 * Return value: the height of the actor, in pixels
9737 clutter_actor_get_height (ClutterActor *self)
9739 ClutterActorPrivate *priv;
9741 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9745 if (priv->needs_allocation)
9747 gfloat natural_height = 0;
9749 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9751 gfloat natural_width = 0;
9753 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9754 clutter_actor_get_preferred_height (self, natural_width,
9755 NULL, &natural_height);
9758 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9760 return natural_height;
9763 return priv->allocation.y2 - priv->allocation.y1;
9767 * clutter_actor_set_width:
9768 * @self: A #ClutterActor
9769 * @width: Requested new width for the actor, in pixels, or -1
9771 * Forces a width on an actor, causing the actor's preferred width
9772 * and height (if any) to be ignored.
9774 * If @width is -1 the actor will use its preferred width request
9775 * instead of overriding it, i.e. you can "unset" the width with -1.
9777 * This function sets both the minimum and natural size of the actor.
9782 clutter_actor_set_width (ClutterActor *self,
9785 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9787 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9791 /* minor optimization: if we don't have a duration
9792 * then we can skip the get_width() below, to avoid
9793 * the chance of going through get_preferred_width()
9794 * just to jump to a new desired width.
9796 if (clutter_actor_get_easing_duration (self) == 0)
9798 g_object_freeze_notify (G_OBJECT (self));
9800 clutter_actor_set_width_internal (self, width);
9802 g_object_thaw_notify (G_OBJECT (self));
9807 cur_size = clutter_actor_get_width (self);
9809 _clutter_actor_create_transition (self,
9810 obj_props[PROP_WIDTH],
9815 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9819 * clutter_actor_set_height:
9820 * @self: A #ClutterActor
9821 * @height: Requested new height for the actor, in pixels, or -1
9823 * Forces a height on an actor, causing the actor's preferred width
9824 * and height (if any) to be ignored.
9826 * If @height is -1 the actor will use its preferred height instead of
9827 * overriding it, i.e. you can "unset" the height with -1.
9829 * This function sets both the minimum and natural size of the actor.
9834 clutter_actor_set_height (ClutterActor *self,
9837 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9839 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9843 /* see the comment in clutter_actor_set_width() above */
9844 if (clutter_actor_get_easing_duration (self) == 0)
9846 g_object_freeze_notify (G_OBJECT (self));
9848 clutter_actor_set_height_internal (self, height);
9850 g_object_thaw_notify (G_OBJECT (self));
9855 cur_size = clutter_actor_get_height (self);
9857 _clutter_actor_create_transition (self,
9858 obj_props[PROP_HEIGHT],
9863 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9867 clutter_actor_set_x_internal (ClutterActor *self,
9870 ClutterActorPrivate *priv = self->priv;
9871 ClutterLayoutInfo *linfo;
9872 ClutterActorBox old = { 0, };
9874 linfo = _clutter_actor_get_layout_info (self);
9876 if (priv->position_set && linfo->fixed_pos.x == x)
9879 clutter_actor_store_old_geometry (self, &old);
9881 linfo->fixed_pos.x = x;
9882 clutter_actor_set_fixed_position_set (self, TRUE);
9884 clutter_actor_notify_if_geometry_changed (self, &old);
9886 clutter_actor_queue_relayout (self);
9890 clutter_actor_set_y_internal (ClutterActor *self,
9893 ClutterActorPrivate *priv = self->priv;
9894 ClutterLayoutInfo *linfo;
9895 ClutterActorBox old = { 0, };
9897 linfo = _clutter_actor_get_layout_info (self);
9899 if (priv->position_set && linfo->fixed_pos.y == y)
9902 clutter_actor_store_old_geometry (self, &old);
9904 linfo->fixed_pos.y = y;
9905 clutter_actor_set_fixed_position_set (self, TRUE);
9907 clutter_actor_notify_if_geometry_changed (self, &old);
9909 clutter_actor_queue_relayout (self);
9913 clutter_actor_set_position_internal (ClutterActor *self,
9914 const ClutterPoint *position)
9916 ClutterActorPrivate *priv = self->priv;
9917 ClutterLayoutInfo *linfo;
9918 ClutterActorBox old = { 0, };
9920 linfo = _clutter_actor_get_layout_info (self);
9922 if (priv->position_set &&
9923 clutter_point_equals (position, &linfo->fixed_pos))
9926 clutter_actor_store_old_geometry (self, &old);
9928 if (position != NULL)
9930 linfo->fixed_pos = *position;
9931 clutter_actor_set_fixed_position_set (self, TRUE);
9934 clutter_actor_set_fixed_position_set (self, FALSE);
9936 clutter_actor_notify_if_geometry_changed (self, &old);
9938 clutter_actor_queue_relayout (self);
9942 * clutter_actor_set_x:
9943 * @self: a #ClutterActor
9944 * @x: the actor's position on the X axis
9946 * Sets the actor's X coordinate, relative to its parent, in pixels.
9948 * Overrides any layout manager and forces a fixed position for
9951 * The #ClutterActor:x property is animatable.
9956 clutter_actor_set_x (ClutterActor *self,
9959 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9961 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9963 float cur_position = clutter_actor_get_x (self);
9965 _clutter_actor_create_transition (self, obj_props[PROP_X],
9970 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9974 * clutter_actor_set_y:
9975 * @self: a #ClutterActor
9976 * @y: the actor's position on the Y axis
9978 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9980 * Overrides any layout manager and forces a fixed position for
9983 * The #ClutterActor:y property is animatable.
9988 clutter_actor_set_y (ClutterActor *self,
9991 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9993 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9995 float cur_position = clutter_actor_get_y (self);
9997 _clutter_actor_create_transition (self, obj_props[PROP_Y],
10002 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10006 * clutter_actor_get_x:
10007 * @self: A #ClutterActor
10009 * Retrieves the X coordinate of a #ClutterActor.
10011 * This function tries to "do what you mean", by returning the
10012 * correct value depending on the actor's state.
10014 * If the actor has a valid allocation, this function will return
10015 * the X coordinate of the origin of the allocation box.
10017 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10018 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10019 * function will return that coordinate.
10021 * If both the allocation and a fixed position are missing, this function
10024 * Return value: the X coordinate, in pixels, ignoring any
10025 * transformation (i.e. scaling, rotation)
10028 clutter_actor_get_x (ClutterActor *self)
10030 ClutterActorPrivate *priv;
10032 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10036 if (priv->needs_allocation)
10038 if (priv->position_set)
10040 const ClutterLayoutInfo *info;
10042 info = _clutter_actor_get_layout_info_or_defaults (self);
10044 return info->fixed_pos.x;
10050 return priv->allocation.x1;
10054 * clutter_actor_get_y:
10055 * @self: A #ClutterActor
10057 * Retrieves the Y coordinate of a #ClutterActor.
10059 * This function tries to "do what you mean", by returning the
10060 * correct value depending on the actor's state.
10062 * If the actor has a valid allocation, this function will return
10063 * the Y coordinate of the origin of the allocation box.
10065 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10066 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10067 * function will return that coordinate.
10069 * If both the allocation and a fixed position are missing, this function
10072 * Return value: the Y coordinate, in pixels, ignoring any
10073 * transformation (i.e. scaling, rotation)
10076 clutter_actor_get_y (ClutterActor *self)
10078 ClutterActorPrivate *priv;
10080 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10084 if (priv->needs_allocation)
10086 if (priv->position_set)
10088 const ClutterLayoutInfo *info;
10090 info = _clutter_actor_get_layout_info_or_defaults (self);
10092 return info->fixed_pos.y;
10098 return priv->allocation.y1;
10102 * clutter_actor_set_scale:
10103 * @self: A #ClutterActor
10104 * @scale_x: double factor to scale actor by horizontally.
10105 * @scale_y: double factor to scale actor by vertically.
10107 * Scales an actor with the given factors. The scaling is relative to
10108 * the scale center and the anchor point. The scale center is
10109 * unchanged by this function and defaults to 0,0.
10111 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10117 clutter_actor_set_scale (ClutterActor *self,
10121 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10123 g_object_freeze_notify (G_OBJECT (self));
10125 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10126 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10128 g_object_thaw_notify (G_OBJECT (self));
10132 * clutter_actor_set_scale_full:
10133 * @self: A #ClutterActor
10134 * @scale_x: double factor to scale actor by horizontally.
10135 * @scale_y: double factor to scale actor by vertically.
10136 * @center_x: X coordinate of the center of the scale.
10137 * @center_y: Y coordinate of the center of the scale
10139 * Scales an actor with the given factors around the given center
10140 * point. The center point is specified in pixels relative to the
10141 * anchor point (usually the top left corner of the actor).
10143 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10149 clutter_actor_set_scale_full (ClutterActor *self,
10155 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10157 g_object_freeze_notify (G_OBJECT (self));
10159 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10160 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10161 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10162 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10164 g_object_thaw_notify (G_OBJECT (self));
10168 * clutter_actor_set_scale_with_gravity:
10169 * @self: A #ClutterActor
10170 * @scale_x: double factor to scale actor by horizontally.
10171 * @scale_y: double factor to scale actor by vertically.
10172 * @gravity: the location of the scale center expressed as a compass
10175 * Scales an actor with the given factors around the given
10176 * center point. The center point is specified as one of the compass
10177 * directions in #ClutterGravity. For example, setting it to north
10178 * will cause the top of the actor to remain unchanged and the rest of
10179 * the actor to expand left, right and downwards.
10181 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10187 clutter_actor_set_scale_with_gravity (ClutterActor *self,
10190 ClutterGravity gravity)
10192 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10194 g_object_freeze_notify (G_OBJECT (self));
10196 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10197 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10198 clutter_actor_set_scale_gravity (self, gravity);
10200 g_object_thaw_notify (G_OBJECT (self));
10204 * clutter_actor_get_scale:
10205 * @self: A #ClutterActor
10206 * @scale_x: (out) (allow-none): Location to store horizonal
10207 * scale factor, or %NULL.
10208 * @scale_y: (out) (allow-none): Location to store vertical
10209 * scale factor, or %NULL.
10211 * Retrieves an actors scale factors.
10216 clutter_actor_get_scale (ClutterActor *self,
10220 const ClutterTransformInfo *info;
10222 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10224 info = _clutter_actor_get_transform_info_or_defaults (self);
10227 *scale_x = info->scale_x;
10230 *scale_y = info->scale_y;
10234 * clutter_actor_get_scale_center:
10235 * @self: A #ClutterActor
10236 * @center_x: (out) (allow-none): Location to store the X position
10237 * of the scale center, or %NULL.
10238 * @center_y: (out) (allow-none): Location to store the Y position
10239 * of the scale center, or %NULL.
10241 * Retrieves the scale center coordinate in pixels relative to the top
10242 * left corner of the actor. If the scale center was specified using a
10243 * #ClutterGravity this will calculate the pixel offset using the
10244 * current size of the actor.
10249 clutter_actor_get_scale_center (ClutterActor *self,
10253 const ClutterTransformInfo *info;
10255 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10257 info = _clutter_actor_get_transform_info_or_defaults (self);
10259 clutter_anchor_coord_get_units (self, &info->scale_center,
10266 * clutter_actor_get_scale_gravity:
10267 * @self: A #ClutterActor
10269 * Retrieves the scale center as a compass direction. If the scale
10270 * center was specified in pixels or units this will return
10271 * %CLUTTER_GRAVITY_NONE.
10273 * Return value: the scale gravity
10278 clutter_actor_get_scale_gravity (ClutterActor *self)
10280 const ClutterTransformInfo *info;
10282 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10284 info = _clutter_actor_get_transform_info_or_defaults (self);
10286 return clutter_anchor_coord_get_gravity (&info->scale_center);
10290 clutter_actor_set_opacity_internal (ClutterActor *self,
10293 ClutterActorPrivate *priv = self->priv;
10295 if (priv->opacity != opacity)
10297 priv->opacity = opacity;
10299 /* Queue a redraw from the flatten effect so that it can use
10300 its cached image if available instead of having to redraw the
10301 actual actor. If it doesn't end up using the FBO then the
10302 effect is still able to continue the paint anyway. If there
10303 is no flatten effect yet then this is equivalent to queueing
10305 _clutter_actor_queue_redraw_full (self,
10308 priv->flatten_effect);
10310 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10315 * clutter_actor_set_opacity:
10316 * @self: A #ClutterActor
10317 * @opacity: New opacity value for the actor.
10319 * Sets the actor's opacity, with zero being completely transparent and
10320 * 255 (0xff) being fully opaque.
10322 * The #ClutterActor:opacity property is animatable.
10325 clutter_actor_set_opacity (ClutterActor *self,
10328 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10330 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10332 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10333 self->priv->opacity,
10337 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10341 * clutter_actor_get_paint_opacity_internal:
10342 * @self: a #ClutterActor
10344 * Retrieves the absolute opacity of the actor, as it appears on the stage
10346 * This function does not do type checks
10348 * Return value: the absolute opacity of the actor
10351 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10353 ClutterActorPrivate *priv = self->priv;
10354 ClutterActor *parent;
10356 /* override the top-level opacity to always be 255; even in
10357 * case of ClutterStage:use-alpha being TRUE we want the rest
10358 * of the scene to be painted
10360 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10363 if (priv->opacity_override >= 0)
10364 return priv->opacity_override;
10366 parent = priv->parent;
10368 /* Factor in the actual actors opacity with parents */
10369 if (parent != NULL)
10371 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10373 if (opacity != 0xff)
10374 return (opacity * priv->opacity) / 0xff;
10377 return priv->opacity;
10382 * clutter_actor_get_paint_opacity:
10383 * @self: A #ClutterActor
10385 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10387 * This function traverses the hierarchy chain and composites the opacity of
10388 * the actor with that of its parents.
10390 * This function is intended for subclasses to use in the paint virtual
10391 * function, to paint themselves with the correct opacity.
10393 * Return value: The actor opacity value.
10398 clutter_actor_get_paint_opacity (ClutterActor *self)
10400 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10402 return clutter_actor_get_paint_opacity_internal (self);
10406 * clutter_actor_get_opacity:
10407 * @self: a #ClutterActor
10409 * Retrieves the opacity value of an actor, as set by
10410 * clutter_actor_set_opacity().
10412 * For retrieving the absolute opacity of the actor inside a paint
10413 * virtual function, see clutter_actor_get_paint_opacity().
10415 * Return value: the opacity of the actor
10418 clutter_actor_get_opacity (ClutterActor *self)
10420 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10422 return self->priv->opacity;
10426 * clutter_actor_set_offscreen_redirect:
10427 * @self: A #ClutterActor
10428 * @redirect: New offscreen redirect flags for the actor.
10430 * Defines the circumstances where the actor should be redirected into
10431 * an offscreen image. The offscreen image is used to flatten the
10432 * actor into a single image while painting for two main reasons.
10433 * Firstly, when the actor is painted a second time without any of its
10434 * contents changing it can simply repaint the cached image without
10435 * descending further down the actor hierarchy. Secondly, it will make
10436 * the opacity look correct even if there are overlapping primitives
10439 * Caching the actor could in some cases be a performance win and in
10440 * some cases be a performance lose so it is important to determine
10441 * which value is right for an actor before modifying this value. For
10442 * example, there is never any reason to flatten an actor that is just
10443 * a single texture (such as a #ClutterTexture) because it is
10444 * effectively already cached in an image so the offscreen would be
10445 * redundant. Also if the actor contains primitives that are far apart
10446 * with a large transparent area in the middle (such as a large
10447 * CluterGroup with a small actor in the top left and a small actor in
10448 * the bottom right) then the cached image will contain the entire
10449 * image of the large area and the paint will waste time blending all
10450 * of the transparent pixels in the middle.
10452 * The default method of implementing opacity on a container simply
10453 * forwards on the opacity to all of the children. If the children are
10454 * overlapping then it will appear as if they are two separate glassy
10455 * objects and there will be a break in the color where they
10456 * overlap. By redirecting to an offscreen buffer it will be as if the
10457 * two opaque objects are combined into one and then made transparent
10458 * which is usually what is expected.
10460 * The image below demonstrates the difference between redirecting and
10461 * not. The image shows two Clutter groups, each containing a red and
10462 * a green rectangle which overlap. The opacity on the group is set to
10463 * 128 (which is 50%). When the offscreen redirect is not used, the
10464 * red rectangle can be seen through the blue rectangle as if the two
10465 * rectangles were separately transparent. When the redirect is used
10466 * the group as a whole is transparent instead so the red rectangle is
10467 * not visible where they overlap.
10469 * <figure id="offscreen-redirect">
10470 * <title>Sample of using an offscreen redirect for transparency</title>
10471 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10474 * The default value for this property is 0, so we effectively will
10475 * never redirect an actor offscreen by default. This means that there
10476 * are times that transparent actors may look glassy as described
10477 * above. The reason this is the default is because there is a
10478 * performance trade off between quality and performance here. In many
10479 * cases the default form of glassy opacity looks good enough, but if
10480 * it's not you will need to set the
10481 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10482 * redirection for opacity.
10484 * Custom actors that don't contain any overlapping primitives are
10485 * recommended to override the has_overlaps() virtual to return %FALSE
10486 * for maximum efficiency.
10491 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10492 ClutterOffscreenRedirect redirect)
10494 ClutterActorPrivate *priv;
10496 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10500 if (priv->offscreen_redirect != redirect)
10502 priv->offscreen_redirect = redirect;
10504 /* Queue a redraw from the effect so that it can use its cached
10505 image if available instead of having to redraw the actual
10506 actor. If it doesn't end up using the FBO then the effect is
10507 still able to continue the paint anyway. If there is no
10508 effect then this is equivalent to queuing a full redraw */
10509 _clutter_actor_queue_redraw_full (self,
10512 priv->flatten_effect);
10514 g_object_notify_by_pspec (G_OBJECT (self),
10515 obj_props[PROP_OFFSCREEN_REDIRECT]);
10520 * clutter_actor_get_offscreen_redirect:
10521 * @self: a #ClutterActor
10523 * Retrieves whether to redirect the actor to an offscreen buffer, as
10524 * set by clutter_actor_set_offscreen_redirect().
10526 * Return value: the value of the offscreen-redirect property of the actor
10530 ClutterOffscreenRedirect
10531 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10533 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10535 return self->priv->offscreen_redirect;
10539 * clutter_actor_set_name:
10540 * @self: A #ClutterActor
10541 * @name: Textual tag to apply to actor
10543 * Sets the given name to @self. The name can be used to identify
10547 clutter_actor_set_name (ClutterActor *self,
10550 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10552 g_free (self->priv->name);
10553 self->priv->name = g_strdup (name);
10555 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10559 * clutter_actor_get_name:
10560 * @self: A #ClutterActor
10562 * Retrieves the name of @self.
10564 * Return value: the name of the actor, or %NULL. The returned string is
10565 * owned by the actor and should not be modified or freed.
10568 clutter_actor_get_name (ClutterActor *self)
10570 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10572 return self->priv->name;
10576 * clutter_actor_get_gid:
10577 * @self: A #ClutterActor
10579 * Retrieves the unique id for @self.
10581 * Return value: Globally unique value for this object instance.
10585 * Deprecated: 1.8: The id is not used any longer.
10588 clutter_actor_get_gid (ClutterActor *self)
10590 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10592 return self->priv->id;
10596 clutter_actor_set_depth_internal (ClutterActor *self,
10599 ClutterTransformInfo *info;
10601 info = _clutter_actor_get_transform_info (self);
10603 if (info->depth != depth)
10605 /* Sets Z value - XXX 2.0: should we invert? */
10606 info->depth = depth;
10608 self->priv->transform_valid = FALSE;
10610 /* FIXME - remove this crap; sadly, there are still containers
10611 * in Clutter that depend on this utter brain damage
10613 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10615 clutter_actor_queue_redraw (self);
10617 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10622 * clutter_actor_set_depth:
10623 * @self: a #ClutterActor
10626 * Sets the Z coordinate of @self to @depth.
10628 * The unit used by @depth is dependant on the perspective setup. See
10629 * also clutter_stage_set_perspective().
10632 clutter_actor_set_depth (ClutterActor *self,
10635 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10637 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10639 const ClutterTransformInfo *info;
10641 info = _clutter_actor_get_transform_info_or_defaults (self);
10643 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10648 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10650 clutter_actor_queue_redraw (self);
10654 * clutter_actor_get_depth:
10655 * @self: a #ClutterActor
10657 * Retrieves the depth of @self.
10659 * Return value: the depth of the actor
10662 clutter_actor_get_depth (ClutterActor *self)
10664 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10666 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10670 * clutter_actor_set_rotation:
10671 * @self: a #ClutterActor
10672 * @axis: the axis of rotation
10673 * @angle: the angle of rotation
10674 * @x: X coordinate of the rotation center
10675 * @y: Y coordinate of the rotation center
10676 * @z: Z coordinate of the rotation center
10678 * Sets the rotation angle of @self around the given axis.
10680 * The rotation center coordinates used depend on the value of @axis:
10682 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10683 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10684 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10687 * The rotation coordinates are relative to the anchor point of the
10688 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10689 * point is set, the upper left corner is assumed as the origin.
10694 clutter_actor_set_rotation (ClutterActor *self,
10695 ClutterRotateAxis axis,
10703 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10709 g_object_freeze_notify (G_OBJECT (self));
10711 clutter_actor_set_rotation_angle (self, axis, angle);
10712 clutter_actor_set_rotation_center_internal (self, axis, &v);
10714 g_object_thaw_notify (G_OBJECT (self));
10718 * clutter_actor_set_z_rotation_from_gravity:
10719 * @self: a #ClutterActor
10720 * @angle: the angle of rotation
10721 * @gravity: the center point of the rotation
10723 * Sets the rotation angle of @self around the Z axis using the center
10724 * point specified as a compass point. For example to rotate such that
10725 * the center of the actor remains static you can use
10726 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10727 * will move accordingly.
10732 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10734 ClutterGravity gravity)
10736 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10738 if (gravity == CLUTTER_GRAVITY_NONE)
10739 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10742 GObject *obj = G_OBJECT (self);
10743 ClutterTransformInfo *info;
10745 info = _clutter_actor_get_transform_info (self);
10747 g_object_freeze_notify (obj);
10749 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10751 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10752 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10753 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10755 g_object_thaw_notify (obj);
10760 * clutter_actor_get_rotation:
10761 * @self: a #ClutterActor
10762 * @axis: the axis of rotation
10763 * @x: (out): return value for the X coordinate of the center of rotation
10764 * @y: (out): return value for the Y coordinate of the center of rotation
10765 * @z: (out): return value for the Z coordinate of the center of rotation
10767 * Retrieves the angle and center of rotation on the given axis,
10768 * set using clutter_actor_set_rotation().
10770 * Return value: the angle of rotation
10775 clutter_actor_get_rotation (ClutterActor *self,
10776 ClutterRotateAxis axis,
10781 const ClutterTransformInfo *info;
10782 const AnchorCoord *anchor_coord;
10783 gdouble retval = 0;
10785 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10787 info = _clutter_actor_get_transform_info_or_defaults (self);
10791 case CLUTTER_X_AXIS:
10792 anchor_coord = &info->rx_center;
10793 retval = info->rx_angle;
10796 case CLUTTER_Y_AXIS:
10797 anchor_coord = &info->ry_center;
10798 retval = info->ry_angle;
10801 case CLUTTER_Z_AXIS:
10802 anchor_coord = &info->rz_center;
10803 retval = info->rz_angle;
10807 anchor_coord = NULL;
10812 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10818 * clutter_actor_get_z_rotation_gravity:
10819 * @self: A #ClutterActor
10821 * Retrieves the center for the rotation around the Z axis as a
10822 * compass direction. If the center was specified in pixels or units
10823 * this will return %CLUTTER_GRAVITY_NONE.
10825 * Return value: the Z rotation center
10830 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10832 const ClutterTransformInfo *info;
10834 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10836 info = _clutter_actor_get_transform_info_or_defaults (self);
10838 return clutter_anchor_coord_get_gravity (&info->rz_center);
10842 * clutter_actor_set_clip:
10843 * @self: A #ClutterActor
10844 * @xoff: X offset of the clip rectangle
10845 * @yoff: Y offset of the clip rectangle
10846 * @width: Width of the clip rectangle
10847 * @height: Height of the clip rectangle
10849 * Sets clip area for @self. The clip area is always computed from the
10850 * upper left corner of the actor, even if the anchor point is set
10856 clutter_actor_set_clip (ClutterActor *self,
10862 ClutterActorPrivate *priv;
10864 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10868 if (priv->has_clip &&
10869 priv->clip.x == xoff &&
10870 priv->clip.y == yoff &&
10871 priv->clip.width == width &&
10872 priv->clip.height == height)
10875 priv->clip.x = xoff;
10876 priv->clip.y = yoff;
10877 priv->clip.width = width;
10878 priv->clip.height = height;
10880 priv->has_clip = TRUE;
10882 clutter_actor_queue_redraw (self);
10884 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10885 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10889 * clutter_actor_remove_clip:
10890 * @self: A #ClutterActor
10892 * Removes clip area from @self.
10895 clutter_actor_remove_clip (ClutterActor *self)
10897 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10899 if (!self->priv->has_clip)
10902 self->priv->has_clip = FALSE;
10904 clutter_actor_queue_redraw (self);
10906 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10910 * clutter_actor_has_clip:
10911 * @self: a #ClutterActor
10913 * Determines whether the actor has a clip area set or not.
10915 * Return value: %TRUE if the actor has a clip area set.
10920 clutter_actor_has_clip (ClutterActor *self)
10922 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10924 return self->priv->has_clip;
10928 * clutter_actor_get_clip:
10929 * @self: a #ClutterActor
10930 * @xoff: (out) (allow-none): return location for the X offset of
10931 * the clip rectangle, or %NULL
10932 * @yoff: (out) (allow-none): return location for the Y offset of
10933 * the clip rectangle, or %NULL
10934 * @width: (out) (allow-none): return location for the width of
10935 * the clip rectangle, or %NULL
10936 * @height: (out) (allow-none): return location for the height of
10937 * the clip rectangle, or %NULL
10939 * Gets the clip area for @self, if any is set
10944 clutter_actor_get_clip (ClutterActor *self,
10950 ClutterActorPrivate *priv;
10952 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10956 if (!priv->has_clip)
10960 *xoff = priv->clip.x;
10963 *yoff = priv->clip.y;
10966 *width = priv->clip.width;
10968 if (height != NULL)
10969 *height = priv->clip.height;
10973 * clutter_actor_get_children:
10974 * @self: a #ClutterActor
10976 * Retrieves the list of children of @self.
10978 * Return value: (transfer container) (element-type ClutterActor): A newly
10979 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10985 clutter_actor_get_children (ClutterActor *self)
10987 ClutterActor *iter;
10990 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10992 /* we walk the list backward so that we can use prepend(),
10995 for (iter = self->priv->last_child, res = NULL;
10997 iter = iter->priv->prev_sibling)
10999 res = g_list_prepend (res, iter);
11006 * insert_child_at_depth:
11007 * @self: a #ClutterActor
11008 * @child: a #ClutterActor
11010 * Inserts @child inside the list of children held by @self, using
11011 * the depth as the insertion criteria.
11013 * This sadly makes the insertion not O(1), but we can keep the
11014 * list sorted so that the painters algorithm we use for painting
11015 * the children will work correctly.
11018 insert_child_at_depth (ClutterActor *self,
11019 ClutterActor *child,
11020 gpointer dummy G_GNUC_UNUSED)
11022 ClutterActor *iter;
11025 child->priv->parent = self;
11028 _clutter_actor_get_transform_info_or_defaults (child)->depth;
11030 /* special-case the first child */
11031 if (self->priv->n_children == 0)
11033 self->priv->first_child = child;
11034 self->priv->last_child = child;
11036 child->priv->next_sibling = NULL;
11037 child->priv->prev_sibling = NULL;
11042 /* Find the right place to insert the child so that it will still be
11043 sorted and the child will be after all of the actors at the same
11045 for (iter = self->priv->first_child;
11047 iter = iter->priv->next_sibling)
11052 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11054 if (iter_depth > child_depth)
11060 ClutterActor *tmp = iter->priv->prev_sibling;
11063 tmp->priv->next_sibling = child;
11065 /* Insert the node before the found one */
11066 child->priv->prev_sibling = iter->priv->prev_sibling;
11067 child->priv->next_sibling = iter;
11068 iter->priv->prev_sibling = child;
11072 ClutterActor *tmp = self->priv->last_child;
11075 tmp->priv->next_sibling = child;
11077 /* insert the node at the end of the list */
11078 child->priv->prev_sibling = self->priv->last_child;
11079 child->priv->next_sibling = NULL;
11082 if (child->priv->prev_sibling == NULL)
11083 self->priv->first_child = child;
11085 if (child->priv->next_sibling == NULL)
11086 self->priv->last_child = child;
11090 insert_child_at_index (ClutterActor *self,
11091 ClutterActor *child,
11094 gint index_ = GPOINTER_TO_INT (data_);
11096 child->priv->parent = self;
11100 ClutterActor *tmp = self->priv->first_child;
11103 tmp->priv->prev_sibling = child;
11105 child->priv->prev_sibling = NULL;
11106 child->priv->next_sibling = tmp;
11108 else if (index_ < 0 || index_ >= self->priv->n_children)
11110 ClutterActor *tmp = self->priv->last_child;
11113 tmp->priv->next_sibling = child;
11115 child->priv->prev_sibling = tmp;
11116 child->priv->next_sibling = NULL;
11120 ClutterActor *iter;
11123 for (iter = self->priv->first_child, i = 0;
11125 iter = iter->priv->next_sibling, i += 1)
11129 ClutterActor *tmp = iter->priv->prev_sibling;
11131 child->priv->prev_sibling = tmp;
11132 child->priv->next_sibling = iter;
11134 iter->priv->prev_sibling = child;
11137 tmp->priv->next_sibling = child;
11144 if (child->priv->prev_sibling == NULL)
11145 self->priv->first_child = child;
11147 if (child->priv->next_sibling == NULL)
11148 self->priv->last_child = child;
11152 insert_child_above (ClutterActor *self,
11153 ClutterActor *child,
11156 ClutterActor *sibling = data;
11158 child->priv->parent = self;
11160 if (sibling == NULL)
11161 sibling = self->priv->last_child;
11163 child->priv->prev_sibling = sibling;
11165 if (sibling != NULL)
11167 ClutterActor *tmp = sibling->priv->next_sibling;
11169 child->priv->next_sibling = tmp;
11172 tmp->priv->prev_sibling = child;
11174 sibling->priv->next_sibling = child;
11177 child->priv->next_sibling = NULL;
11179 if (child->priv->prev_sibling == NULL)
11180 self->priv->first_child = child;
11182 if (child->priv->next_sibling == NULL)
11183 self->priv->last_child = child;
11187 insert_child_below (ClutterActor *self,
11188 ClutterActor *child,
11191 ClutterActor *sibling = data;
11193 child->priv->parent = self;
11195 if (sibling == NULL)
11196 sibling = self->priv->first_child;
11198 child->priv->next_sibling = sibling;
11200 if (sibling != NULL)
11202 ClutterActor *tmp = sibling->priv->prev_sibling;
11204 child->priv->prev_sibling = tmp;
11207 tmp->priv->next_sibling = child;
11209 sibling->priv->prev_sibling = child;
11212 child->priv->prev_sibling = NULL;
11214 if (child->priv->prev_sibling == NULL)
11215 self->priv->first_child = child;
11217 if (child->priv->next_sibling == NULL)
11218 self->priv->last_child = child;
11221 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11222 ClutterActor *child,
11226 ADD_CHILD_CREATE_META = 1 << 0,
11227 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
11228 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
11229 ADD_CHILD_CHECK_STATE = 1 << 3,
11230 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
11231 ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11233 /* default flags for public API */
11234 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
11235 ADD_CHILD_EMIT_PARENT_SET |
11236 ADD_CHILD_EMIT_ACTOR_ADDED |
11237 ADD_CHILD_CHECK_STATE |
11238 ADD_CHILD_NOTIFY_FIRST_LAST |
11239 ADD_CHILD_SHOW_ON_SET_PARENT,
11241 /* flags for legacy/deprecated API */
11242 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
11243 ADD_CHILD_CHECK_STATE |
11244 ADD_CHILD_NOTIFY_FIRST_LAST |
11245 ADD_CHILD_SHOW_ON_SET_PARENT
11246 } ClutterActorAddChildFlags;
11249 * clutter_actor_add_child_internal:
11250 * @self: a #ClutterActor
11251 * @child: a #ClutterActor
11252 * @flags: control flags for actions
11253 * @add_func: delegate function
11254 * @data: (closure): data to pass to @add_func
11256 * Adds @child to the list of children of @self.
11258 * The actual insertion inside the list is delegated to @add_func: this
11259 * function will just set up the state, perform basic checks, and emit
11262 * The @flags argument is used to perform additional operations.
11265 clutter_actor_add_child_internal (ClutterActor *self,
11266 ClutterActor *child,
11267 ClutterActorAddChildFlags flags,
11268 ClutterActorAddChildFunc add_func,
11271 ClutterTextDirection text_dir;
11272 gboolean create_meta;
11273 gboolean emit_parent_set, emit_actor_added;
11274 gboolean check_state;
11275 gboolean notify_first_last;
11276 gboolean show_on_set_parent;
11277 ClutterActor *old_first_child, *old_last_child;
11279 if (child->priv->parent != NULL)
11281 g_warning ("The actor '%s' already has a parent, '%s'. You must "
11282 "use clutter_actor_remove_child() first.",
11283 _clutter_actor_get_debug_name (child),
11284 _clutter_actor_get_debug_name (child->priv->parent));
11288 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11290 g_warning ("The actor '%s' is a top-level actor, and cannot be "
11291 "a child of another actor.",
11292 _clutter_actor_get_debug_name (child));
11297 /* XXX - this check disallows calling methods that change the stacking
11298 * order within the destruction sequence, by triggering a critical
11299 * warning first, and leaving the actor in an undefined state, which
11300 * then ends up being caught by an assertion.
11302 * the reproducible sequence is:
11304 * - actor gets destroyed;
11305 * - another actor, linked to the first, will try to change the
11306 * stacking order of the first actor;
11307 * - changing the stacking order is a composite operation composed
11308 * by the following steps:
11309 * 1. ref() the child;
11310 * 2. remove_child_internal(), which removes the reference;
11311 * 3. add_child_internal(), which adds a reference;
11312 * - the state of the actor is not changed between (2) and (3), as
11313 * it could be an expensive recomputation;
11314 * - if (3) bails out, then the actor is in an undefined state, but
11316 * - the destruction sequence terminates, but the actor is unparented
11317 * while its state indicates being parented instead.
11318 * - assertion failure.
11320 * the obvious fix would be to decompose each set_child_*_sibling()
11321 * method into proper remove_child()/add_child(), with state validation;
11322 * this may cause excessive work, though, and trigger a cascade of other
11323 * bugs in code that assumes that a change in the stacking order is an
11324 * atomic operation.
11326 * another potential fix is to just remove this check here, and let
11327 * code doing stacking order changes inside the destruction sequence
11328 * of an actor continue doing the work.
11330 * the third fix is to silently bail out early from every
11331 * set_child_*_sibling() and set_child_at_index() method, and avoid
11334 * I have a preference for the second solution, since it involves the
11335 * least amount of work, and the least amount of code duplication.
11337 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11339 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11341 g_warning ("The actor '%s' is currently being destroyed, and "
11342 "cannot be added as a child of another actor.",
11343 _clutter_actor_get_debug_name (child));
11348 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11349 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11350 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11351 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11352 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11353 show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11355 old_first_child = self->priv->first_child;
11356 old_last_child = self->priv->last_child;
11358 g_object_freeze_notify (G_OBJECT (self));
11361 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11363 g_object_ref_sink (child);
11364 child->priv->parent = NULL;
11365 child->priv->next_sibling = NULL;
11366 child->priv->prev_sibling = NULL;
11368 /* delegate the actual insertion */
11369 add_func (self, child, data);
11371 g_assert (child->priv->parent == self);
11373 self->priv->n_children += 1;
11375 self->priv->age += 1;
11377 /* if push_internal() has been called then we automatically set
11378 * the flag on the actor
11380 if (self->priv->internal_child)
11381 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11383 /* children may cause their parent to expand, if they are set
11384 * to expand; if a child is not expanded then it cannot change
11385 * its parent's state. any further change later on will queue
11386 * an expand state check.
11388 * this check, with the initial state of the needs_compute_expand
11389 * flag set to FALSE, should avoid recomputing the expand flags
11390 * state while building the actor tree.
11392 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11393 (child->priv->needs_compute_expand ||
11394 child->priv->needs_x_expand ||
11395 child->priv->needs_y_expand))
11397 clutter_actor_queue_compute_expand (self);
11400 /* clutter_actor_reparent() will emit ::parent-set for us */
11401 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11402 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11406 /* If parent is mapped or realized, we need to also be mapped or
11407 * realized once we're inside the parent.
11409 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11411 /* propagate the parent's text direction to the child */
11412 text_dir = clutter_actor_get_text_direction (self);
11413 clutter_actor_set_text_direction (child, text_dir);
11416 if (show_on_set_parent && child->priv->show_on_set_parent)
11417 clutter_actor_show (child);
11419 if (CLUTTER_ACTOR_IS_MAPPED (child))
11420 clutter_actor_queue_redraw (child);
11422 /* maintain the invariant that if an actor needs layout,
11423 * its parents do as well
11425 if (child->priv->needs_width_request ||
11426 child->priv->needs_height_request ||
11427 child->priv->needs_allocation)
11429 /* we work around the short-circuiting we do
11430 * in clutter_actor_queue_relayout() since we
11431 * want to force a relayout
11433 child->priv->needs_width_request = TRUE;
11434 child->priv->needs_height_request = TRUE;
11435 child->priv->needs_allocation = TRUE;
11437 clutter_actor_queue_relayout (child->priv->parent);
11440 if (emit_actor_added)
11441 g_signal_emit_by_name (self, "actor-added", child);
11443 if (notify_first_last)
11445 if (old_first_child != self->priv->first_child)
11446 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11448 if (old_last_child != self->priv->last_child)
11449 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11452 g_object_thaw_notify (G_OBJECT (self));
11456 * clutter_actor_add_child:
11457 * @self: a #ClutterActor
11458 * @child: a #ClutterActor
11460 * Adds @child to the children of @self.
11462 * This function will acquire a reference on @child that will only
11463 * be released when calling clutter_actor_remove_child().
11465 * This function will take into consideration the #ClutterActor:depth
11466 * of @child, and will keep the list of children sorted.
11468 * This function will emit the #ClutterContainer::actor-added signal
11474 clutter_actor_add_child (ClutterActor *self,
11475 ClutterActor *child)
11477 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11478 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11479 g_return_if_fail (self != child);
11480 g_return_if_fail (child->priv->parent == NULL);
11482 clutter_actor_add_child_internal (self, child,
11483 ADD_CHILD_DEFAULT_FLAGS,
11484 insert_child_at_depth,
11489 * clutter_actor_insert_child_at_index:
11490 * @self: a #ClutterActor
11491 * @child: a #ClutterActor
11492 * @index_: the index
11494 * Inserts @child into the list of children of @self, using the
11495 * given @index_. If @index_ is greater than the number of children
11496 * in @self, or is less than 0, then the new child is added at the end.
11498 * This function will acquire a reference on @child that will only
11499 * be released when calling clutter_actor_remove_child().
11501 * This function will not take into consideration the #ClutterActor:depth
11504 * This function will emit the #ClutterContainer::actor-added signal
11510 clutter_actor_insert_child_at_index (ClutterActor *self,
11511 ClutterActor *child,
11514 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11515 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11516 g_return_if_fail (self != child);
11517 g_return_if_fail (child->priv->parent == NULL);
11519 clutter_actor_add_child_internal (self, child,
11520 ADD_CHILD_DEFAULT_FLAGS,
11521 insert_child_at_index,
11522 GINT_TO_POINTER (index_));
11526 * clutter_actor_insert_child_above:
11527 * @self: a #ClutterActor
11528 * @child: a #ClutterActor
11529 * @sibling: (allow-none): a child of @self, or %NULL
11531 * Inserts @child into the list of children of @self, above another
11532 * child of @self or, if @sibling is %NULL, above all the children
11535 * This function will acquire a reference on @child that will only
11536 * be released when calling clutter_actor_remove_child().
11538 * This function will not take into consideration the #ClutterActor:depth
11541 * This function will emit the #ClutterContainer::actor-added signal
11547 clutter_actor_insert_child_above (ClutterActor *self,
11548 ClutterActor *child,
11549 ClutterActor *sibling)
11551 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11552 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11553 g_return_if_fail (self != child);
11554 g_return_if_fail (child != sibling);
11555 g_return_if_fail (child->priv->parent == NULL);
11556 g_return_if_fail (sibling == NULL ||
11557 (CLUTTER_IS_ACTOR (sibling) &&
11558 sibling->priv->parent == self));
11560 clutter_actor_add_child_internal (self, child,
11561 ADD_CHILD_DEFAULT_FLAGS,
11562 insert_child_above,
11567 * clutter_actor_insert_child_below:
11568 * @self: a #ClutterActor
11569 * @child: a #ClutterActor
11570 * @sibling: (allow-none): a child of @self, or %NULL
11572 * Inserts @child into the list of children of @self, below another
11573 * child of @self or, if @sibling is %NULL, below all the children
11576 * This function will acquire a reference on @child that will only
11577 * be released when calling clutter_actor_remove_child().
11579 * This function will not take into consideration the #ClutterActor:depth
11582 * This function will emit the #ClutterContainer::actor-added signal
11588 clutter_actor_insert_child_below (ClutterActor *self,
11589 ClutterActor *child,
11590 ClutterActor *sibling)
11592 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11593 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11594 g_return_if_fail (self != child);
11595 g_return_if_fail (child != sibling);
11596 g_return_if_fail (child->priv->parent == NULL);
11597 g_return_if_fail (sibling == NULL ||
11598 (CLUTTER_IS_ACTOR (sibling) &&
11599 sibling->priv->parent == self));
11601 clutter_actor_add_child_internal (self, child,
11602 ADD_CHILD_DEFAULT_FLAGS,
11603 insert_child_below,
11608 * clutter_actor_set_parent:
11609 * @self: A #ClutterActor
11610 * @parent: A new #ClutterActor parent
11612 * Sets the parent of @self to @parent.
11614 * This function will result in @parent acquiring a reference on @self,
11615 * eventually by sinking its floating reference first. The reference
11616 * will be released by clutter_actor_unparent().
11618 * This function should only be called by legacy #ClutterActor<!-- -->s
11619 * implementing the #ClutterContainer interface.
11621 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11624 clutter_actor_set_parent (ClutterActor *self,
11625 ClutterActor *parent)
11627 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11628 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11629 g_return_if_fail (self != parent);
11630 g_return_if_fail (self->priv->parent == NULL);
11632 /* as this function will be called inside ClutterContainer::add
11633 * implementations or when building up a composite actor, we have
11634 * to preserve the old behaviour, and not create child meta or
11635 * emit the ::actor-added signal, to avoid recursion or double
11638 clutter_actor_add_child_internal (parent, self,
11639 ADD_CHILD_LEGACY_FLAGS,
11640 insert_child_at_depth,
11645 * clutter_actor_get_parent:
11646 * @self: A #ClutterActor
11648 * Retrieves the parent of @self.
11650 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11651 * if no parent is set
11654 clutter_actor_get_parent (ClutterActor *self)
11656 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11658 return self->priv->parent;
11662 * clutter_actor_get_paint_visibility:
11663 * @self: A #ClutterActor
11665 * Retrieves the 'paint' visibility of an actor recursively checking for non
11668 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11670 * Return Value: %TRUE if the actor is visibile and will be painted.
11675 clutter_actor_get_paint_visibility (ClutterActor *actor)
11677 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11679 return CLUTTER_ACTOR_IS_MAPPED (actor);
11683 * clutter_actor_remove_child:
11684 * @self: a #ClutterActor
11685 * @child: a #ClutterActor
11687 * Removes @child from the children of @self.
11689 * This function will release the reference added by
11690 * clutter_actor_add_child(), so if you want to keep using @child
11691 * you will have to acquire a referenced on it before calling this
11694 * This function will emit the #ClutterContainer::actor-removed
11700 clutter_actor_remove_child (ClutterActor *self,
11701 ClutterActor *child)
11703 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11704 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11705 g_return_if_fail (self != child);
11706 g_return_if_fail (child->priv->parent != NULL);
11707 g_return_if_fail (child->priv->parent == self);
11709 clutter_actor_remove_child_internal (self, child,
11710 REMOVE_CHILD_DEFAULT_FLAGS);
11714 * clutter_actor_remove_all_children:
11715 * @self: a #ClutterActor
11717 * Removes all children of @self.
11719 * This function releases the reference added by inserting a child actor
11720 * in the list of children of @self.
11722 * If the reference count of a child drops to zero, the child will be
11723 * destroyed. If you want to ensure the destruction of all the children
11724 * of @self, use clutter_actor_destroy_all_children().
11729 clutter_actor_remove_all_children (ClutterActor *self)
11731 ClutterActorIter iter;
11733 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11735 if (self->priv->n_children == 0)
11738 g_object_freeze_notify (G_OBJECT (self));
11740 clutter_actor_iter_init (&iter, self);
11741 while (clutter_actor_iter_next (&iter, NULL))
11742 clutter_actor_iter_remove (&iter);
11744 g_object_thaw_notify (G_OBJECT (self));
11747 g_assert (self->priv->first_child == NULL);
11748 g_assert (self->priv->last_child == NULL);
11749 g_assert (self->priv->n_children == 0);
11753 * clutter_actor_destroy_all_children:
11754 * @self: a #ClutterActor
11756 * Destroys all children of @self.
11758 * This function releases the reference added by inserting a child
11759 * actor in the list of children of @self, and ensures that the
11760 * #ClutterActor::destroy signal is emitted on each child of the
11763 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11764 * when its reference count drops to 0; the default handler of the
11765 * #ClutterActor::destroy signal will destroy all the children of an
11766 * actor. This function ensures that all children are destroyed, instead
11767 * of just removed from @self, unlike clutter_actor_remove_all_children()
11768 * which will merely release the reference and remove each child.
11770 * Unless you acquired an additional reference on each child of @self
11771 * prior to calling clutter_actor_remove_all_children() and want to reuse
11772 * the actors, you should use clutter_actor_destroy_all_children() in
11773 * order to make sure that children are destroyed and signal handlers
11774 * are disconnected even in cases where circular references prevent this
11775 * from automatically happening through reference counting alone.
11780 clutter_actor_destroy_all_children (ClutterActor *self)
11782 ClutterActorIter iter;
11784 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11786 if (self->priv->n_children == 0)
11789 g_object_freeze_notify (G_OBJECT (self));
11791 clutter_actor_iter_init (&iter, self);
11792 while (clutter_actor_iter_next (&iter, NULL))
11793 clutter_actor_iter_destroy (&iter);
11795 g_object_thaw_notify (G_OBJECT (self));
11798 g_assert (self->priv->first_child == NULL);
11799 g_assert (self->priv->last_child == NULL);
11800 g_assert (self->priv->n_children == 0);
11803 typedef struct _InsertBetweenData {
11804 ClutterActor *prev_sibling;
11805 ClutterActor *next_sibling;
11806 } InsertBetweenData;
11809 insert_child_between (ClutterActor *self,
11810 ClutterActor *child,
11813 InsertBetweenData *data = data_;
11814 ClutterActor *prev_sibling = data->prev_sibling;
11815 ClutterActor *next_sibling = data->next_sibling;
11817 child->priv->parent = self;
11818 child->priv->prev_sibling = prev_sibling;
11819 child->priv->next_sibling = next_sibling;
11821 if (prev_sibling != NULL)
11822 prev_sibling->priv->next_sibling = child;
11824 if (next_sibling != NULL)
11825 next_sibling->priv->prev_sibling = child;
11827 if (child->priv->prev_sibling == NULL)
11828 self->priv->first_child = child;
11830 if (child->priv->next_sibling == NULL)
11831 self->priv->last_child = child;
11835 * clutter_actor_replace_child:
11836 * @self: a #ClutterActor
11837 * @old_child: the child of @self to replace
11838 * @new_child: the #ClutterActor to replace @old_child
11840 * Replaces @old_child with @new_child in the list of children of @self.
11845 clutter_actor_replace_child (ClutterActor *self,
11846 ClutterActor *old_child,
11847 ClutterActor *new_child)
11849 ClutterActor *prev_sibling, *next_sibling;
11850 InsertBetweenData clos;
11852 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11853 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11854 g_return_if_fail (old_child->priv->parent == self);
11855 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11856 g_return_if_fail (old_child != new_child);
11857 g_return_if_fail (new_child != self);
11858 g_return_if_fail (new_child->priv->parent == NULL);
11860 prev_sibling = old_child->priv->prev_sibling;
11861 next_sibling = old_child->priv->next_sibling;
11862 clutter_actor_remove_child_internal (self, old_child,
11863 REMOVE_CHILD_DEFAULT_FLAGS);
11865 clos.prev_sibling = prev_sibling;
11866 clos.next_sibling = next_sibling;
11867 clutter_actor_add_child_internal (self, new_child,
11868 ADD_CHILD_DEFAULT_FLAGS,
11869 insert_child_between,
11874 * clutter_actor_unparent:
11875 * @self: a #ClutterActor
11877 * Removes the parent of @self.
11879 * This will cause the parent of @self to release the reference
11880 * acquired when calling clutter_actor_set_parent(), so if you
11881 * want to keep @self you will have to acquire a reference of
11882 * your own, through g_object_ref().
11884 * This function should only be called by legacy #ClutterActor<!-- -->s
11885 * implementing the #ClutterContainer interface.
11889 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11892 clutter_actor_unparent (ClutterActor *self)
11894 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11896 if (self->priv->parent == NULL)
11899 clutter_actor_remove_child_internal (self->priv->parent, self,
11900 REMOVE_CHILD_LEGACY_FLAGS);
11904 * clutter_actor_reparent:
11905 * @self: a #ClutterActor
11906 * @new_parent: the new #ClutterActor parent
11908 * Resets the parent actor of @self.
11910 * This function is logically equivalent to calling clutter_actor_unparent()
11911 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11912 * ensures the child is not finalized when unparented, and emits the
11913 * #ClutterActor::parent-set signal only once.
11915 * In reality, calling this function is less useful than it sounds, as some
11916 * application code may rely on changes in the intermediate state between
11917 * removal and addition of the actor from its old parent to the @new_parent.
11918 * Thus, it is strongly encouraged to avoid using this function in application
11923 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11924 * clutter_actor_add_child() instead; remember to take a reference on
11925 * the actor being removed before calling clutter_actor_remove_child()
11926 * to avoid the reference count dropping to zero and the actor being
11930 clutter_actor_reparent (ClutterActor *self,
11931 ClutterActor *new_parent)
11933 ClutterActorPrivate *priv;
11935 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11936 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11937 g_return_if_fail (self != new_parent);
11939 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11941 g_warning ("Cannot set a parent on a toplevel actor");
11945 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11947 g_warning ("Cannot set a parent currently being destroyed");
11953 if (priv->parent != new_parent)
11955 ClutterActor *old_parent;
11957 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11959 old_parent = priv->parent;
11961 g_object_ref (self);
11963 if (old_parent != NULL)
11965 /* go through the Container implementation if this is a regular
11966 * child and not an internal one
11968 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11970 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11972 /* this will have to call unparent() */
11973 clutter_container_remove_actor (parent, self);
11976 clutter_actor_remove_child_internal (old_parent, self,
11977 REMOVE_CHILD_LEGACY_FLAGS);
11980 /* Note, will call set_parent() */
11981 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11982 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11984 clutter_actor_add_child_internal (new_parent, self,
11985 ADD_CHILD_LEGACY_FLAGS,
11986 insert_child_at_depth,
11989 /* we emit the ::parent-set signal once */
11990 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11992 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11994 /* the IN_REPARENT flag suspends state updates */
11995 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11997 g_object_unref (self);
12002 * clutter_actor_contains:
12003 * @self: A #ClutterActor
12004 * @descendant: A #ClutterActor, possibly contained in @self
12006 * Determines if @descendant is contained inside @self (either as an
12007 * immediate child, or as a deeper descendant). If @self and
12008 * @descendant point to the same actor then it will also return %TRUE.
12010 * Return value: whether @descendent is contained within @self
12015 clutter_actor_contains (ClutterActor *self,
12016 ClutterActor *descendant)
12018 ClutterActor *actor;
12020 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12021 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12023 for (actor = descendant; actor; actor = actor->priv->parent)
12031 * clutter_actor_set_child_above_sibling:
12032 * @self: a #ClutterActor
12033 * @child: a #ClutterActor child of @self
12034 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12036 * Sets @child to be above @sibling in the list of children of @self.
12038 * If @sibling is %NULL, @child will be the new last child of @self.
12040 * This function is logically equivalent to removing @child and using
12041 * clutter_actor_insert_child_above(), but it will not emit signals
12042 * or change state on @child.
12047 clutter_actor_set_child_above_sibling (ClutterActor *self,
12048 ClutterActor *child,
12049 ClutterActor *sibling)
12051 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12052 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12053 g_return_if_fail (child->priv->parent == self);
12054 g_return_if_fail (child != sibling);
12055 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12057 if (sibling != NULL)
12058 g_return_if_fail (sibling->priv->parent == self);
12060 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12061 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12062 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12065 /* we don't want to change the state of child, or emit signals, or
12066 * regenerate ChildMeta instances here, but we still want to follow
12067 * the correct sequence of steps encoded in remove_child() and
12068 * add_child(), so that correctness is ensured, and we only go
12069 * through one known code path.
12071 g_object_ref (child);
12072 clutter_actor_remove_child_internal (self, child, 0);
12073 clutter_actor_add_child_internal (self, child,
12074 ADD_CHILD_NOTIFY_FIRST_LAST,
12075 insert_child_above,
12078 clutter_actor_queue_relayout (self);
12082 * clutter_actor_set_child_below_sibling:
12083 * @self: a #ClutterActor
12084 * @child: a #ClutterActor child of @self
12085 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12087 * Sets @child to be below @sibling in the list of children of @self.
12089 * If @sibling is %NULL, @child will be the new first child of @self.
12091 * This function is logically equivalent to removing @self and using
12092 * clutter_actor_insert_child_below(), but it will not emit signals
12093 * or change state on @child.
12098 clutter_actor_set_child_below_sibling (ClutterActor *self,
12099 ClutterActor *child,
12100 ClutterActor *sibling)
12102 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12103 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12104 g_return_if_fail (child->priv->parent == self);
12105 g_return_if_fail (child != sibling);
12106 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12108 if (sibling != NULL)
12109 g_return_if_fail (sibling->priv->parent == self);
12111 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12112 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12113 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12116 /* see the comment in set_child_above_sibling() */
12117 g_object_ref (child);
12118 clutter_actor_remove_child_internal (self, child, 0);
12119 clutter_actor_add_child_internal (self, child,
12120 ADD_CHILD_NOTIFY_FIRST_LAST,
12121 insert_child_below,
12124 clutter_actor_queue_relayout (self);
12128 * clutter_actor_set_child_at_index:
12129 * @self: a #ClutterActor
12130 * @child: a #ClutterActor child of @self
12131 * @index_: the new index for @child
12133 * Changes the index of @child in the list of children of @self.
12135 * This function is logically equivalent to removing @child and
12136 * calling clutter_actor_insert_child_at_index(), but it will not
12137 * emit signals or change state on @child.
12142 clutter_actor_set_child_at_index (ClutterActor *self,
12143 ClutterActor *child,
12146 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12147 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12148 g_return_if_fail (child->priv->parent == self);
12149 g_return_if_fail (index_ <= self->priv->n_children);
12151 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12152 CLUTTER_ACTOR_IN_DESTRUCTION (child))
12155 g_object_ref (child);
12156 clutter_actor_remove_child_internal (self, child, 0);
12157 clutter_actor_add_child_internal (self, child,
12158 ADD_CHILD_NOTIFY_FIRST_LAST,
12159 insert_child_at_index,
12160 GINT_TO_POINTER (index_));
12162 clutter_actor_queue_relayout (self);
12166 * clutter_actor_raise:
12167 * @self: A #ClutterActor
12168 * @below: (allow-none): A #ClutterActor to raise above.
12170 * Puts @self above @below.
12172 * Both actors must have the same parent, and the parent must implement
12173 * the #ClutterContainer interface
12175 * This function calls clutter_container_raise_child() internally.
12177 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12180 clutter_actor_raise (ClutterActor *self,
12181 ClutterActor *below)
12183 ClutterActor *parent;
12185 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12187 parent = clutter_actor_get_parent (self);
12188 if (parent == NULL)
12190 g_warning ("%s: Actor '%s' is not inside a container",
12192 _clutter_actor_get_debug_name (self));
12198 if (parent != clutter_actor_get_parent (below))
12200 g_warning ("%s Actor '%s' is not in the same container as "
12203 _clutter_actor_get_debug_name (self),
12204 _clutter_actor_get_debug_name (below));
12209 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12213 * clutter_actor_lower:
12214 * @self: A #ClutterActor
12215 * @above: (allow-none): A #ClutterActor to lower below
12217 * Puts @self below @above.
12219 * Both actors must have the same parent, and the parent must implement
12220 * the #ClutterContainer interface.
12222 * This function calls clutter_container_lower_child() internally.
12224 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12227 clutter_actor_lower (ClutterActor *self,
12228 ClutterActor *above)
12230 ClutterActor *parent;
12232 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12234 parent = clutter_actor_get_parent (self);
12235 if (parent == NULL)
12237 g_warning ("%s: Actor of type %s is not inside a container",
12239 _clutter_actor_get_debug_name (self));
12245 if (parent != clutter_actor_get_parent (above))
12247 g_warning ("%s: Actor '%s' is not in the same container as "
12250 _clutter_actor_get_debug_name (self),
12251 _clutter_actor_get_debug_name (above));
12256 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12260 * clutter_actor_raise_top:
12261 * @self: A #ClutterActor
12263 * Raises @self to the top.
12265 * This function calls clutter_actor_raise() internally.
12267 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12268 * a %NULL sibling, instead.
12271 clutter_actor_raise_top (ClutterActor *self)
12273 clutter_actor_raise (self, NULL);
12277 * clutter_actor_lower_bottom:
12278 * @self: A #ClutterActor
12280 * Lowers @self to the bottom.
12282 * This function calls clutter_actor_lower() internally.
12284 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12285 * a %NULL sibling, instead.
12288 clutter_actor_lower_bottom (ClutterActor *self)
12290 clutter_actor_lower (self, NULL);
12298 * clutter_actor_event:
12299 * @actor: a #ClutterActor
12300 * @event: a #ClutterEvent
12301 * @capture: TRUE if event in in capture phase, FALSE otherwise.
12303 * This function is used to emit an event on the main stage.
12304 * You should rarely need to use this function, except for
12305 * synthetising events.
12307 * Return value: the return value from the signal emission: %TRUE
12308 * if the actor handled the event, or %FALSE if the event was
12314 clutter_actor_event (ClutterActor *actor,
12315 ClutterEvent *event,
12318 gboolean retval = FALSE;
12319 gint signal_num = -1;
12321 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12322 g_return_val_if_fail (event != NULL, FALSE);
12324 g_object_ref (actor);
12328 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12334 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12338 switch (event->type)
12340 case CLUTTER_NOTHING:
12342 case CLUTTER_BUTTON_PRESS:
12343 signal_num = BUTTON_PRESS_EVENT;
12345 case CLUTTER_BUTTON_RELEASE:
12346 signal_num = BUTTON_RELEASE_EVENT;
12348 case CLUTTER_SCROLL:
12349 signal_num = SCROLL_EVENT;
12351 case CLUTTER_KEY_PRESS:
12352 signal_num = KEY_PRESS_EVENT;
12354 case CLUTTER_KEY_RELEASE:
12355 signal_num = KEY_RELEASE_EVENT;
12357 case CLUTTER_MOTION:
12358 signal_num = MOTION_EVENT;
12360 case CLUTTER_ENTER:
12361 signal_num = ENTER_EVENT;
12363 case CLUTTER_LEAVE:
12364 signal_num = LEAVE_EVENT;
12366 case CLUTTER_DELETE:
12367 case CLUTTER_DESTROY_NOTIFY:
12368 case CLUTTER_CLIENT_MESSAGE:
12374 if (signal_num != -1)
12375 g_signal_emit (actor, actor_signals[signal_num], 0,
12380 g_object_unref (actor);
12386 * clutter_actor_set_reactive:
12387 * @actor: a #ClutterActor
12388 * @reactive: whether the actor should be reactive to events
12390 * Sets @actor as reactive. Reactive actors will receive events.
12395 clutter_actor_set_reactive (ClutterActor *actor,
12398 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12400 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12404 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12406 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12408 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12412 * clutter_actor_get_reactive:
12413 * @actor: a #ClutterActor
12415 * Checks whether @actor is marked as reactive.
12417 * Return value: %TRUE if the actor is reactive
12422 clutter_actor_get_reactive (ClutterActor *actor)
12424 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12426 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12430 * clutter_actor_get_anchor_point:
12431 * @self: a #ClutterActor
12432 * @anchor_x: (out): return location for the X coordinate of the anchor point
12433 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12435 * Gets the current anchor point of the @actor in pixels.
12440 clutter_actor_get_anchor_point (ClutterActor *self,
12444 const ClutterTransformInfo *info;
12446 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12448 info = _clutter_actor_get_transform_info_or_defaults (self);
12449 clutter_anchor_coord_get_units (self, &info->anchor,
12456 * clutter_actor_set_anchor_point:
12457 * @self: a #ClutterActor
12458 * @anchor_x: X coordinate of the anchor point
12459 * @anchor_y: Y coordinate of the anchor point
12461 * Sets an anchor point for @self. The anchor point is a point in the
12462 * coordinate space of an actor to which the actor position within its
12463 * parent is relative; the default is (0, 0), i.e. the top-left corner
12469 clutter_actor_set_anchor_point (ClutterActor *self,
12473 ClutterTransformInfo *info;
12474 ClutterActorPrivate *priv;
12475 gboolean changed = FALSE;
12476 gfloat old_anchor_x, old_anchor_y;
12479 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12481 obj = G_OBJECT (self);
12483 info = _clutter_actor_get_transform_info (self);
12485 g_object_freeze_notify (obj);
12487 clutter_anchor_coord_get_units (self, &info->anchor,
12492 if (info->anchor.is_fractional)
12493 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12495 if (old_anchor_x != anchor_x)
12497 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12501 if (old_anchor_y != anchor_y)
12503 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12507 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12511 priv->transform_valid = FALSE;
12512 clutter_actor_queue_redraw (self);
12515 g_object_thaw_notify (obj);
12519 * clutter_actor_get_anchor_point_gravity:
12520 * @self: a #ClutterActor
12522 * Retrieves the anchor position expressed as a #ClutterGravity. If
12523 * the anchor point was specified using pixels or units this will
12524 * return %CLUTTER_GRAVITY_NONE.
12526 * Return value: the #ClutterGravity used by the anchor point
12531 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12533 const ClutterTransformInfo *info;
12535 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12537 info = _clutter_actor_get_transform_info_or_defaults (self);
12539 return clutter_anchor_coord_get_gravity (&info->anchor);
12543 * clutter_actor_move_anchor_point:
12544 * @self: a #ClutterActor
12545 * @anchor_x: X coordinate of the anchor point
12546 * @anchor_y: Y coordinate of the anchor point
12548 * Sets an anchor point for the actor, and adjusts the actor postion so that
12549 * the relative position of the actor toward its parent remains the same.
12554 clutter_actor_move_anchor_point (ClutterActor *self,
12558 gfloat old_anchor_x, old_anchor_y;
12559 const ClutterTransformInfo *info;
12561 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12563 info = _clutter_actor_get_transform_info (self);
12564 clutter_anchor_coord_get_units (self, &info->anchor,
12569 g_object_freeze_notify (G_OBJECT (self));
12571 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12573 if (self->priv->position_set)
12574 clutter_actor_move_by (self,
12575 anchor_x - old_anchor_x,
12576 anchor_y - old_anchor_y);
12578 g_object_thaw_notify (G_OBJECT (self));
12582 * clutter_actor_move_anchor_point_from_gravity:
12583 * @self: a #ClutterActor
12584 * @gravity: #ClutterGravity.
12586 * Sets an anchor point on the actor based on the given gravity, adjusting the
12587 * actor postion so that its relative position within its parent remains
12590 * Since version 1.0 the anchor point will be stored as a gravity so
12591 * that if the actor changes size then the anchor point will move. For
12592 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12593 * and later double the size of the actor, the anchor point will move
12594 * to the bottom right.
12599 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12600 ClutterGravity gravity)
12602 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12603 const ClutterTransformInfo *info;
12604 ClutterActorPrivate *priv;
12606 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12609 info = _clutter_actor_get_transform_info (self);
12611 g_object_freeze_notify (G_OBJECT (self));
12613 clutter_anchor_coord_get_units (self, &info->anchor,
12617 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12618 clutter_anchor_coord_get_units (self, &info->anchor,
12623 if (priv->position_set)
12624 clutter_actor_move_by (self,
12625 new_anchor_x - old_anchor_x,
12626 new_anchor_y - old_anchor_y);
12628 g_object_thaw_notify (G_OBJECT (self));
12632 * clutter_actor_set_anchor_point_from_gravity:
12633 * @self: a #ClutterActor
12634 * @gravity: #ClutterGravity.
12636 * Sets an anchor point on the actor, based on the given gravity (this is a
12637 * convenience function wrapping clutter_actor_set_anchor_point()).
12639 * Since version 1.0 the anchor point will be stored as a gravity so
12640 * that if the actor changes size then the anchor point will move. For
12641 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12642 * and later double the size of the actor, the anchor point will move
12643 * to the bottom right.
12648 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12649 ClutterGravity gravity)
12651 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12653 if (gravity == CLUTTER_GRAVITY_NONE)
12654 clutter_actor_set_anchor_point (self, 0, 0);
12657 GObject *obj = G_OBJECT (self);
12658 ClutterTransformInfo *info;
12660 g_object_freeze_notify (obj);
12662 info = _clutter_actor_get_transform_info (self);
12663 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12665 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12666 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12667 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12669 self->priv->transform_valid = FALSE;
12671 clutter_actor_queue_redraw (self);
12673 g_object_thaw_notify (obj);
12678 clutter_actor_store_content_box (ClutterActor *self,
12679 const ClutterActorBox *box)
12683 self->priv->content_box = *box;
12684 self->priv->content_box_valid = TRUE;
12687 self->priv->content_box_valid = FALSE;
12689 clutter_actor_queue_redraw (self);
12691 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12695 clutter_container_iface_init (ClutterContainerIface *iface)
12697 /* we don't override anything, as ClutterContainer already has a default
12698 * implementation that we can use, and which calls into our own API.
12713 parse_units (ClutterActor *self,
12714 ParseDimension dimension,
12717 GValue value = G_VALUE_INIT;
12720 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12723 json_node_get_value (node, &value);
12725 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12727 retval = (gfloat) g_value_get_int64 (&value);
12729 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12731 retval = g_value_get_double (&value);
12733 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12735 ClutterUnits units;
12738 res = clutter_units_from_string (&units, g_value_get_string (&value));
12740 retval = clutter_units_to_pixels (&units);
12743 g_warning ("Invalid value '%s': integers, strings or floating point "
12744 "values can be used for the x, y, width and height "
12745 "properties. Valid modifiers for strings are 'px', 'mm', "
12747 g_value_get_string (&value));
12753 g_warning ("Invalid value of type '%s': integers, strings of floating "
12754 "point values can be used for the x, y, width, height "
12755 "anchor-x and anchor-y properties.",
12756 g_type_name (G_VALUE_TYPE (&value)));
12759 g_value_unset (&value);
12765 ClutterRotateAxis axis;
12774 static inline gboolean
12775 parse_rotation_array (ClutterActor *actor,
12777 RotationInfo *info)
12781 if (json_array_get_length (array) != 2)
12785 element = json_array_get_element (array, 0);
12786 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12787 info->angle = json_node_get_double (element);
12792 element = json_array_get_element (array, 1);
12793 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12795 JsonArray *center = json_node_get_array (element);
12797 if (json_array_get_length (center) != 2)
12800 switch (info->axis)
12802 case CLUTTER_X_AXIS:
12803 info->center_y = parse_units (actor, PARSE_Y,
12804 json_array_get_element (center, 0));
12805 info->center_z = parse_units (actor, PARSE_Y,
12806 json_array_get_element (center, 1));
12809 case CLUTTER_Y_AXIS:
12810 info->center_x = parse_units (actor, PARSE_X,
12811 json_array_get_element (center, 0));
12812 info->center_z = parse_units (actor, PARSE_X,
12813 json_array_get_element (center, 1));
12816 case CLUTTER_Z_AXIS:
12817 info->center_x = parse_units (actor, PARSE_X,
12818 json_array_get_element (center, 0));
12819 info->center_y = parse_units (actor, PARSE_Y,
12820 json_array_get_element (center, 1));
12829 parse_rotation (ClutterActor *actor,
12831 RotationInfo *info)
12835 gboolean retval = FALSE;
12837 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12839 g_warning ("Invalid node of type '%s' found, expecting an array",
12840 json_node_type_name (node));
12844 array = json_node_get_array (node);
12845 len = json_array_get_length (array);
12847 for (i = 0; i < len; i++)
12849 JsonNode *element = json_array_get_element (array, i);
12850 JsonObject *object;
12853 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12855 g_warning ("Invalid node of type '%s' found, expecting an object",
12856 json_node_type_name (element));
12860 object = json_node_get_object (element);
12862 if (json_object_has_member (object, "x-axis"))
12864 member = json_object_get_member (object, "x-axis");
12866 info->axis = CLUTTER_X_AXIS;
12868 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12870 info->angle = json_node_get_double (member);
12873 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12874 retval = parse_rotation_array (actor,
12875 json_node_get_array (member),
12880 else if (json_object_has_member (object, "y-axis"))
12882 member = json_object_get_member (object, "y-axis");
12884 info->axis = CLUTTER_Y_AXIS;
12886 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12888 info->angle = json_node_get_double (member);
12891 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12892 retval = parse_rotation_array (actor,
12893 json_node_get_array (member),
12898 else if (json_object_has_member (object, "z-axis"))
12900 member = json_object_get_member (object, "z-axis");
12902 info->axis = CLUTTER_Z_AXIS;
12904 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12906 info->angle = json_node_get_double (member);
12909 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12910 retval = parse_rotation_array (actor,
12911 json_node_get_array (member),
12922 parse_actor_metas (ClutterScript *script,
12923 ClutterActor *actor,
12926 GList *elements, *l;
12927 GSList *retval = NULL;
12929 if (!JSON_NODE_HOLDS_ARRAY (node))
12932 elements = json_array_get_elements (json_node_get_array (node));
12934 for (l = elements; l != NULL; l = l->next)
12936 JsonNode *element = l->data;
12937 const gchar *id_ = _clutter_script_get_id_from_node (element);
12940 if (id_ == NULL || *id_ == '\0')
12943 meta = clutter_script_get_object (script, id_);
12947 retval = g_slist_prepend (retval, meta);
12950 g_list_free (elements);
12952 return g_slist_reverse (retval);
12956 parse_behaviours (ClutterScript *script,
12957 ClutterActor *actor,
12960 GList *elements, *l;
12961 GSList *retval = NULL;
12963 if (!JSON_NODE_HOLDS_ARRAY (node))
12966 elements = json_array_get_elements (json_node_get_array (node));
12968 for (l = elements; l != NULL; l = l->next)
12970 JsonNode *element = l->data;
12971 const gchar *id_ = _clutter_script_get_id_from_node (element);
12972 GObject *behaviour;
12974 if (id_ == NULL || *id_ == '\0')
12977 behaviour = clutter_script_get_object (script, id_);
12978 if (behaviour == NULL)
12981 retval = g_slist_prepend (retval, behaviour);
12984 g_list_free (elements);
12986 return g_slist_reverse (retval);
12990 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12991 ClutterScript *script,
12996 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12997 gboolean retval = FALSE;
12999 if ((name[0] == 'x' && name[1] == '\0') ||
13000 (name[0] == 'y' && name[1] == '\0') ||
13001 (strcmp (name, "width") == 0) ||
13002 (strcmp (name, "height") == 0) ||
13003 (strcmp (name, "anchor_x") == 0) ||
13004 (strcmp (name, "anchor_y") == 0))
13006 ParseDimension dimension;
13009 if (name[0] == 'x')
13010 dimension = PARSE_X;
13011 else if (name[0] == 'y')
13012 dimension = PARSE_Y;
13013 else if (name[0] == 'w')
13014 dimension = PARSE_WIDTH;
13015 else if (name[0] == 'h')
13016 dimension = PARSE_HEIGHT;
13017 else if (name[0] == 'a' && name[7] == 'x')
13018 dimension = PARSE_ANCHOR_X;
13019 else if (name[0] == 'a' && name[7] == 'y')
13020 dimension = PARSE_ANCHOR_Y;
13024 units = parse_units (actor, dimension, node);
13026 /* convert back to pixels: all properties are pixel-based */
13027 g_value_init (value, G_TYPE_FLOAT);
13028 g_value_set_float (value, units);
13032 else if (strcmp (name, "rotation") == 0)
13034 RotationInfo *info;
13036 info = g_slice_new0 (RotationInfo);
13037 retval = parse_rotation (actor, node, info);
13041 g_value_init (value, G_TYPE_POINTER);
13042 g_value_set_pointer (value, info);
13045 g_slice_free (RotationInfo, info);
13047 else if (strcmp (name, "behaviours") == 0)
13051 #ifdef CLUTTER_ENABLE_DEBUG
13052 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13053 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13054 "and it should not be used in newly "
13055 "written ClutterScript definitions.");
13058 l = parse_behaviours (script, actor, node);
13060 g_value_init (value, G_TYPE_POINTER);
13061 g_value_set_pointer (value, l);
13065 else if (strcmp (name, "actions") == 0 ||
13066 strcmp (name, "constraints") == 0 ||
13067 strcmp (name, "effects") == 0)
13071 l = parse_actor_metas (script, actor, node);
13073 g_value_init (value, G_TYPE_POINTER);
13074 g_value_set_pointer (value, l);
13083 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13084 ClutterScript *script,
13086 const GValue *value)
13088 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13090 #ifdef CLUTTER_ENABLE_DEBUG
13091 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13093 gchar *tmp = g_strdup_value_contents (value);
13095 CLUTTER_NOTE (SCRIPT,
13096 "in ClutterActor::set_custom_property('%s') = %s",
13102 #endif /* CLUTTER_ENABLE_DEBUG */
13104 if (strcmp (name, "rotation") == 0)
13106 RotationInfo *info;
13108 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13111 info = g_value_get_pointer (value);
13113 clutter_actor_set_rotation (actor,
13114 info->axis, info->angle,
13119 g_slice_free (RotationInfo, info);
13124 if (strcmp (name, "behaviours") == 0)
13126 GSList *behaviours, *l;
13128 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13131 behaviours = g_value_get_pointer (value);
13132 for (l = behaviours; l != NULL; l = l->next)
13134 ClutterBehaviour *behaviour = l->data;
13136 clutter_behaviour_apply (behaviour, actor);
13139 g_slist_free (behaviours);
13144 if (strcmp (name, "actions") == 0 ||
13145 strcmp (name, "constraints") == 0 ||
13146 strcmp (name, "effects") == 0)
13150 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13153 metas = g_value_get_pointer (value);
13154 for (l = metas; l != NULL; l = l->next)
13156 if (name[0] == 'a')
13157 clutter_actor_add_action (actor, l->data);
13159 if (name[0] == 'c')
13160 clutter_actor_add_constraint (actor, l->data);
13162 if (name[0] == 'e')
13163 clutter_actor_add_effect (actor, l->data);
13166 g_slist_free (metas);
13171 g_object_set_property (G_OBJECT (scriptable), name, value);
13175 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13177 iface->parse_custom_node = clutter_actor_parse_custom_node;
13178 iface->set_custom_property = clutter_actor_set_custom_property;
13181 static ClutterActorMeta *
13182 get_meta_from_animation_property (ClutterActor *actor,
13186 ClutterActorPrivate *priv = actor->priv;
13187 ClutterActorMeta *meta = NULL;
13190 /* if this is not a special property, fall through */
13191 if (name[0] != '@')
13194 /* detect the properties named using the following spec:
13196 * @<section>.<meta-name>.<property-name>
13198 * where <section> can be one of the following:
13204 * and <meta-name> is the name set on a specific ActorMeta
13207 tokens = g_strsplit (name + 1, ".", -1);
13208 if (tokens == NULL || g_strv_length (tokens) != 3)
13210 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13212 g_strfreev (tokens);
13216 if (strcmp (tokens[0], "actions") == 0)
13217 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13219 if (strcmp (tokens[0], "constraints") == 0)
13220 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13222 if (strcmp (tokens[0], "effects") == 0)
13223 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13225 if (name_p != NULL)
13226 *name_p = g_strdup (tokens[2]);
13228 CLUTTER_NOTE (ANIMATION,
13229 "Looking for property '%s' of object '%s' in section '%s'",
13234 g_strfreev (tokens);
13239 static GParamSpec *
13240 clutter_actor_find_property (ClutterAnimatable *animatable,
13241 const gchar *property_name)
13243 ClutterActorMeta *meta = NULL;
13244 GObjectClass *klass = NULL;
13245 GParamSpec *pspec = NULL;
13246 gchar *p_name = NULL;
13248 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13254 klass = G_OBJECT_GET_CLASS (meta);
13256 pspec = g_object_class_find_property (klass, p_name);
13260 klass = G_OBJECT_GET_CLASS (animatable);
13262 pspec = g_object_class_find_property (klass, property_name);
13271 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13272 const gchar *property_name,
13275 ClutterActorMeta *meta = NULL;
13276 gchar *p_name = NULL;
13278 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13283 g_object_get_property (G_OBJECT (meta), p_name, initial);
13285 g_object_get_property (G_OBJECT (animatable), property_name, initial);
13291 * clutter_actor_set_animatable_property:
13292 * @actor: a #ClutterActor
13293 * @prop_id: the paramspec id
13294 * @value: the value to set
13295 * @pspec: the paramspec
13297 * Sets values of animatable properties.
13299 * This is a variant of clutter_actor_set_property() that gets called
13300 * by the #ClutterAnimatable implementation of #ClutterActor for the
13301 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13304 * Unlike the implementation of #GObjectClass.set_property(), this
13305 * function will not update the interval if a transition involving an
13306 * animatable property is in progress - this avoids cycles with the
13307 * transition API calling the public API.
13310 clutter_actor_set_animatable_property (ClutterActor *actor,
13312 const GValue *value,
13315 GObject *obj = G_OBJECT (actor);
13317 g_object_freeze_notify (obj);
13322 clutter_actor_set_x_internal (actor, g_value_get_float (value));
13326 clutter_actor_set_y_internal (actor, g_value_get_float (value));
13329 case PROP_POSITION:
13330 clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13334 clutter_actor_set_width_internal (actor, g_value_get_float (value));
13338 clutter_actor_set_height_internal (actor, g_value_get_float (value));
13342 clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13346 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13350 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13353 case PROP_BACKGROUND_COLOR:
13354 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13358 clutter_actor_set_scale_factor_internal (actor,
13359 g_value_get_double (value),
13364 clutter_actor_set_scale_factor_internal (actor,
13365 g_value_get_double (value),
13369 case PROP_ROTATION_ANGLE_X:
13370 clutter_actor_set_rotation_angle_internal (actor,
13372 g_value_get_double (value));
13375 case PROP_ROTATION_ANGLE_Y:
13376 clutter_actor_set_rotation_angle_internal (actor,
13378 g_value_get_double (value));
13381 case PROP_ROTATION_ANGLE_Z:
13382 clutter_actor_set_rotation_angle_internal (actor,
13384 g_value_get_double (value));
13387 case PROP_CONTENT_BOX:
13388 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13392 g_object_set_property (obj, pspec->name, value);
13396 g_object_thaw_notify (obj);
13400 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13401 const gchar *property_name,
13402 const GValue *final)
13404 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13405 ClutterActorMeta *meta = NULL;
13406 gchar *p_name = NULL;
13408 meta = get_meta_from_animation_property (actor,
13412 g_object_set_property (G_OBJECT (meta), p_name, final);
13415 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13418 pspec = g_object_class_find_property (obj_class, property_name);
13420 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13422 /* XXX - I'm going to the special hell for this */
13423 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13426 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13433 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13435 iface->find_property = clutter_actor_find_property;
13436 iface->get_initial_state = clutter_actor_get_initial_state;
13437 iface->set_final_state = clutter_actor_set_final_state;
13441 * clutter_actor_transform_stage_point:
13442 * @self: A #ClutterActor
13443 * @x: (in): x screen coordinate of the point to unproject
13444 * @y: (in): y screen coordinate of the point to unproject
13445 * @x_out: (out): return location for the unprojected x coordinance
13446 * @y_out: (out): return location for the unprojected y coordinance
13448 * This function translates screen coordinates (@x, @y) to
13449 * coordinates relative to the actor. For example, it can be used to translate
13450 * screen events from global screen coordinates into actor-local coordinates.
13452 * The conversion can fail, notably if the transform stack results in the
13453 * actor being projected on the screen as a mere line.
13455 * The conversion should not be expected to be pixel-perfect due to the
13456 * nature of the operation. In general the error grows when the skewing
13457 * of the actor rectangle on screen increases.
13459 * <note><para>This function can be computationally intensive.</para></note>
13461 * <note><para>This function only works when the allocation is up-to-date,
13462 * i.e. inside of paint().</para></note>
13464 * Return value: %TRUE if conversion was successful.
13469 clutter_actor_transform_stage_point (ClutterActor *self,
13475 ClutterVertex v[4];
13478 int du, dv, xi, yi;
13480 float xf, yf, wf, det;
13481 ClutterActorPrivate *priv;
13483 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13487 /* This implementation is based on the quad -> quad projection algorithm
13488 * described by Paul Heckbert in:
13490 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13492 * and the sample implementation at:
13494 * http://www.cs.cmu.edu/~ph/src/texfund/
13496 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13497 * quad to rectangle only, which significantly simplifies things; the
13498 * function calls have been unrolled, and most of the math is done in fixed
13502 clutter_actor_get_abs_allocation_vertices (self, v);
13504 /* Keeping these as ints simplifies the multiplication (no significant
13505 * loss of precision here).
13507 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13508 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13513 #define UX2FP(x) (x)
13514 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13516 /* First, find mapping from unit uv square to xy quadrilateral; this
13517 * equivalent to the pmap_square_quad() functions in the sample
13518 * implementation, which we can simplify, since our target is always
13521 px = v[0].x - v[1].x + v[3].x - v[2].x;
13522 py = v[0].y - v[1].y + v[3].y - v[2].y;
13526 /* affine transform */
13527 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13528 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13529 RQ[2][0] = UX2FP (v[0].x);
13530 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13531 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13532 RQ[2][1] = UX2FP (v[0].y);
13539 /* projective transform */
13540 double dx1, dx2, dy1, dy2, del;
13542 dx1 = UX2FP (v[1].x - v[3].x);
13543 dx2 = UX2FP (v[2].x - v[3].x);
13544 dy1 = UX2FP (v[1].y - v[3].y);
13545 dy2 = UX2FP (v[2].y - v[3].y);
13547 del = DET2FP (dx1, dx2, dy1, dy2);
13552 * The division here needs to be done in floating point for
13553 * precisions reasons.
13555 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13556 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13557 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13559 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13560 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13561 RQ[2][0] = UX2FP (v[0].x);
13562 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13563 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13564 RQ[2][1] = UX2FP (v[0].y);
13568 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13569 * square. Since our rectangle is based at 0,0 we only need to scale.
13579 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13582 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13583 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13584 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13585 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13586 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13587 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13588 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13589 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13590 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13593 * Check the resulting matrix is OK.
13595 det = (RQ[0][0] * ST[0][0])
13596 + (RQ[0][1] * ST[0][1])
13597 + (RQ[0][2] * ST[0][2]);
13602 * Now transform our point with the ST matrix; the notional w
13603 * coordinate is 1, hence the last part is simply added.
13608 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13609 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13610 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13625 * clutter_actor_is_rotated:
13626 * @self: a #ClutterActor
13628 * Checks whether any rotation is applied to the actor.
13630 * Return value: %TRUE if the actor is rotated.
13635 clutter_actor_is_rotated (ClutterActor *self)
13637 const ClutterTransformInfo *info;
13639 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13641 info = _clutter_actor_get_transform_info_or_defaults (self);
13643 if (info->rx_angle || info->ry_angle || info->rz_angle)
13650 * clutter_actor_is_scaled:
13651 * @self: a #ClutterActor
13653 * Checks whether the actor is scaled in either dimension.
13655 * Return value: %TRUE if the actor is scaled.
13660 clutter_actor_is_scaled (ClutterActor *self)
13662 const ClutterTransformInfo *info;
13664 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13666 info = _clutter_actor_get_transform_info_or_defaults (self);
13668 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13675 _clutter_actor_get_stage_internal (ClutterActor *actor)
13677 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13678 actor = actor->priv->parent;
13684 * clutter_actor_get_stage:
13685 * @actor: a #ClutterActor
13687 * Retrieves the #ClutterStage where @actor is contained.
13689 * Return value: (transfer none) (type Clutter.Stage): the stage
13690 * containing the actor, or %NULL
13695 clutter_actor_get_stage (ClutterActor *actor)
13697 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13699 return _clutter_actor_get_stage_internal (actor);
13703 * clutter_actor_allocate_available_size:
13704 * @self: a #ClutterActor
13705 * @x: the actor's X coordinate
13706 * @y: the actor's Y coordinate
13707 * @available_width: the maximum available width, or -1 to use the
13708 * actor's natural width
13709 * @available_height: the maximum available height, or -1 to use the
13710 * actor's natural height
13711 * @flags: flags controlling the allocation
13713 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13714 * preferred size, but limiting it to the maximum available width
13715 * and height provided.
13717 * This function will do the right thing when dealing with the
13718 * actor's request mode.
13720 * The implementation of this function is equivalent to:
13723 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13725 * clutter_actor_get_preferred_width (self, available_height,
13727 * &natural_width);
13728 * width = CLAMP (natural_width, min_width, available_width);
13730 * clutter_actor_get_preferred_height (self, width,
13732 * &natural_height);
13733 * height = CLAMP (natural_height, min_height, available_height);
13737 * clutter_actor_get_preferred_height (self, available_width,
13739 * &natural_height);
13740 * height = CLAMP (natural_height, min_height, available_height);
13742 * clutter_actor_get_preferred_width (self, height,
13744 * &natural_width);
13745 * width = CLAMP (natural_width, min_width, available_width);
13748 * box.x1 = x; box.y1 = y;
13749 * box.x2 = box.x1 + available_width;
13750 * box.y2 = box.y1 + available_height;
13751 * clutter_actor_allocate (self, &box, flags);
13754 * This function can be used by fluid layout managers to allocate
13755 * an actor's preferred size without making it bigger than the area
13756 * available for the container.
13761 clutter_actor_allocate_available_size (ClutterActor *self,
13764 gfloat available_width,
13765 gfloat available_height,
13766 ClutterAllocationFlags flags)
13768 ClutterActorPrivate *priv;
13769 gfloat width, height;
13770 gfloat min_width, min_height;
13771 gfloat natural_width, natural_height;
13772 ClutterActorBox box;
13774 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13778 width = height = 0.0;
13780 switch (priv->request_mode)
13782 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13783 clutter_actor_get_preferred_width (self, available_height,
13786 width = CLAMP (natural_width, min_width, available_width);
13788 clutter_actor_get_preferred_height (self, width,
13791 height = CLAMP (natural_height, min_height, available_height);
13794 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13795 clutter_actor_get_preferred_height (self, available_width,
13798 height = CLAMP (natural_height, min_height, available_height);
13800 clutter_actor_get_preferred_width (self, height,
13803 width = CLAMP (natural_width, min_width, available_width);
13810 box.x2 = box.x1 + width;
13811 box.y2 = box.y1 + height;
13812 clutter_actor_allocate (self, &box, flags);
13816 * clutter_actor_allocate_preferred_size:
13817 * @self: a #ClutterActor
13818 * @flags: flags controlling the allocation
13820 * Allocates the natural size of @self.
13822 * This function is a utility call for #ClutterActor implementations
13823 * that allocates the actor's preferred natural size. It can be used
13824 * by fixed layout managers (like #ClutterGroup or so called
13825 * 'composite actors') inside the ClutterActor::allocate
13826 * implementation to give each child exactly how much space it
13829 * This function is not meant to be used by applications. It is also
13830 * not meant to be used outside the implementation of the
13831 * ClutterActor::allocate virtual function.
13836 clutter_actor_allocate_preferred_size (ClutterActor *self,
13837 ClutterAllocationFlags flags)
13839 gfloat actor_x, actor_y;
13840 gfloat natural_width, natural_height;
13841 ClutterActorBox actor_box;
13843 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13845 actor_x = clutter_actor_get_x (self);
13846 actor_y = clutter_actor_get_y (self);
13848 clutter_actor_get_preferred_size (self,
13853 actor_box.x1 = actor_x;
13854 actor_box.y1 = actor_y;
13855 actor_box.x2 = actor_box.x1 + natural_width;
13856 actor_box.y2 = actor_box.y1 + natural_height;
13858 clutter_actor_allocate (self, &actor_box, flags);
13862 * clutter_actor_allocate_align_fill:
13863 * @self: a #ClutterActor
13864 * @box: a #ClutterActorBox, containing the available width and height
13865 * @x_align: the horizontal alignment, between 0 and 1
13866 * @y_align: the vertical alignment, between 0 and 1
13867 * @x_fill: whether the actor should fill horizontally
13868 * @y_fill: whether the actor should fill vertically
13869 * @flags: allocation flags to be passed to clutter_actor_allocate()
13871 * Allocates @self by taking into consideration the available allocation
13872 * area; an alignment factor on either axis; and whether the actor should
13873 * fill the allocation on either axis.
13875 * The @box should contain the available allocation width and height;
13876 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13877 * allocation will be offset by their value.
13879 * This function takes into consideration the geometry request specified by
13880 * the #ClutterActor:request-mode property, and the text direction.
13882 * This function is useful for fluid layout managers, like #ClutterBinLayout
13883 * or #ClutterTableLayout
13888 clutter_actor_allocate_align_fill (ClutterActor *self,
13889 const ClutterActorBox *box,
13894 ClutterAllocationFlags flags)
13896 ClutterActorPrivate *priv;
13897 ClutterActorBox allocation = { 0, };
13898 gfloat x_offset, y_offset;
13899 gfloat available_width, available_height;
13900 gfloat child_width, child_height;
13902 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13903 g_return_if_fail (box != NULL);
13904 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13905 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13909 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13910 clutter_actor_box_get_size (box, &available_width, &available_height);
13912 if (available_width < 0)
13913 available_width = 0;
13915 if (available_height < 0)
13916 available_height = 0;
13920 allocation.x1 = x_offset;
13921 allocation.x2 = allocation.x1 + available_width;
13926 allocation.y1 = y_offset;
13927 allocation.y2 = allocation.y1 + available_height;
13930 /* if we are filling horizontally and vertically then we're done */
13931 if (x_fill && y_fill)
13934 child_width = child_height = 0.0f;
13936 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13938 gfloat min_width, natural_width;
13939 gfloat min_height, natural_height;
13941 clutter_actor_get_preferred_width (self, available_height,
13945 child_width = CLAMP (natural_width, min_width, available_width);
13949 clutter_actor_get_preferred_height (self, child_width,
13953 child_height = CLAMP (natural_height, min_height, available_height);
13958 gfloat min_width, natural_width;
13959 gfloat min_height, natural_height;
13961 clutter_actor_get_preferred_height (self, available_width,
13965 child_height = CLAMP (natural_height, min_height, available_height);
13969 clutter_actor_get_preferred_width (self, child_height,
13973 child_width = CLAMP (natural_width, min_width, available_width);
13977 /* invert the horizontal alignment for RTL languages */
13978 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13979 x_align = 1.0 - x_align;
13983 allocation.x1 = x_offset
13984 + ((available_width - child_width) * x_align);
13985 allocation.x2 = allocation.x1 + child_width;
13990 allocation.y1 = y_offset
13991 + ((available_height - child_height) * y_align);
13992 allocation.y2 = allocation.y1 + child_height;
13996 clutter_actor_box_clamp_to_pixel (&allocation);
13997 clutter_actor_allocate (self, &allocation, flags);
14001 * clutter_actor_grab_key_focus:
14002 * @self: a #ClutterActor
14004 * Sets the key focus of the #ClutterStage including @self
14005 * to this #ClutterActor.
14010 clutter_actor_grab_key_focus (ClutterActor *self)
14012 ClutterActor *stage;
14014 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14016 stage = _clutter_actor_get_stage_internal (self);
14018 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14022 * clutter_actor_get_pango_context:
14023 * @self: a #ClutterActor
14025 * Retrieves the #PangoContext for @self. The actor's #PangoContext
14026 * is already configured using the appropriate font map, resolution
14027 * and font options.
14029 * Unlike clutter_actor_create_pango_context(), this context is owend
14030 * by the #ClutterActor and it will be updated each time the options
14031 * stored by the #ClutterBackend change.
14033 * You can use the returned #PangoContext to create a #PangoLayout
14034 * and render text using cogl_pango_render_layout() to reuse the
14035 * glyphs cache also used by Clutter.
14037 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14038 * The returned #PangoContext is owned by the actor and should not be
14039 * unreferenced by the application code
14044 clutter_actor_get_pango_context (ClutterActor *self)
14046 ClutterActorPrivate *priv;
14048 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14052 if (priv->pango_context != NULL)
14053 return priv->pango_context;
14055 priv->pango_context = _clutter_context_get_pango_context ();
14056 g_object_ref (priv->pango_context);
14058 return priv->pango_context;
14062 * clutter_actor_create_pango_context:
14063 * @self: a #ClutterActor
14065 * Creates a #PangoContext for the given actor. The #PangoContext
14066 * is already configured using the appropriate font map, resolution
14067 * and font options.
14069 * See also clutter_actor_get_pango_context().
14071 * Return value: (transfer full): the newly created #PangoContext.
14072 * Use g_object_unref() on the returned value to deallocate its
14078 clutter_actor_create_pango_context (ClutterActor *self)
14080 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14082 return _clutter_context_create_pango_context ();
14086 * clutter_actor_create_pango_layout:
14087 * @self: a #ClutterActor
14088 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14090 * Creates a new #PangoLayout from the same #PangoContext used
14091 * by the #ClutterActor. The #PangoLayout is already configured
14092 * with the font map, resolution and font options, and the
14095 * If you want to keep around a #PangoLayout created by this
14096 * function you will have to connect to the #ClutterBackend::font-changed
14097 * and #ClutterBackend::resolution-changed signals, and call
14098 * pango_layout_context_changed() in response to them.
14100 * Return value: (transfer full): the newly created #PangoLayout.
14101 * Use g_object_unref() when done
14106 clutter_actor_create_pango_layout (ClutterActor *self,
14109 PangoContext *context;
14110 PangoLayout *layout;
14112 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14114 context = clutter_actor_get_pango_context (self);
14115 layout = pango_layout_new (context);
14118 pango_layout_set_text (layout, text, -1);
14123 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14124 * ClutterOffscreenEffect.
14127 _clutter_actor_set_opacity_override (ClutterActor *self,
14130 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14132 self->priv->opacity_override = opacity;
14136 _clutter_actor_get_opacity_override (ClutterActor *self)
14138 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14140 return self->priv->opacity_override;
14143 /* Allows you to disable applying the actors model view transform during
14144 * a paint. Used by ClutterClone. */
14146 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14149 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14151 self->priv->enable_model_view_transform = enable;
14155 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14158 ClutterActorPrivate *priv;
14160 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14164 priv->enable_paint_unmapped = enable;
14166 if (priv->enable_paint_unmapped)
14168 /* Make sure that the parents of the widget are realized first;
14169 * otherwise checks in clutter_actor_update_map_state() will
14172 clutter_actor_realize (self);
14174 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14178 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14183 clutter_anchor_coord_get_units (ClutterActor *self,
14184 const AnchorCoord *coord,
14189 if (coord->is_fractional)
14191 gfloat actor_width, actor_height;
14193 clutter_actor_get_size (self, &actor_width, &actor_height);
14196 *x = actor_width * coord->v.fraction.x;
14199 *y = actor_height * coord->v.fraction.y;
14207 *x = coord->v.units.x;
14210 *y = coord->v.units.y;
14213 *z = coord->v.units.z;
14218 clutter_anchor_coord_set_units (AnchorCoord *coord,
14223 coord->is_fractional = FALSE;
14224 coord->v.units.x = x;
14225 coord->v.units.y = y;
14226 coord->v.units.z = z;
14229 static ClutterGravity
14230 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14232 if (coord->is_fractional)
14234 if (coord->v.fraction.x == 0.0)
14236 if (coord->v.fraction.y == 0.0)
14237 return CLUTTER_GRAVITY_NORTH_WEST;
14238 else if (coord->v.fraction.y == 0.5)
14239 return CLUTTER_GRAVITY_WEST;
14240 else if (coord->v.fraction.y == 1.0)
14241 return CLUTTER_GRAVITY_SOUTH_WEST;
14243 return CLUTTER_GRAVITY_NONE;
14245 else if (coord->v.fraction.x == 0.5)
14247 if (coord->v.fraction.y == 0.0)
14248 return CLUTTER_GRAVITY_NORTH;
14249 else if (coord->v.fraction.y == 0.5)
14250 return CLUTTER_GRAVITY_CENTER;
14251 else if (coord->v.fraction.y == 1.0)
14252 return CLUTTER_GRAVITY_SOUTH;
14254 return CLUTTER_GRAVITY_NONE;
14256 else if (coord->v.fraction.x == 1.0)
14258 if (coord->v.fraction.y == 0.0)
14259 return CLUTTER_GRAVITY_NORTH_EAST;
14260 else if (coord->v.fraction.y == 0.5)
14261 return CLUTTER_GRAVITY_EAST;
14262 else if (coord->v.fraction.y == 1.0)
14263 return CLUTTER_GRAVITY_SOUTH_EAST;
14265 return CLUTTER_GRAVITY_NONE;
14268 return CLUTTER_GRAVITY_NONE;
14271 return CLUTTER_GRAVITY_NONE;
14275 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14276 ClutterGravity gravity)
14280 case CLUTTER_GRAVITY_NORTH:
14281 coord->v.fraction.x = 0.5;
14282 coord->v.fraction.y = 0.0;
14285 case CLUTTER_GRAVITY_NORTH_EAST:
14286 coord->v.fraction.x = 1.0;
14287 coord->v.fraction.y = 0.0;
14290 case CLUTTER_GRAVITY_EAST:
14291 coord->v.fraction.x = 1.0;
14292 coord->v.fraction.y = 0.5;
14295 case CLUTTER_GRAVITY_SOUTH_EAST:
14296 coord->v.fraction.x = 1.0;
14297 coord->v.fraction.y = 1.0;
14300 case CLUTTER_GRAVITY_SOUTH:
14301 coord->v.fraction.x = 0.5;
14302 coord->v.fraction.y = 1.0;
14305 case CLUTTER_GRAVITY_SOUTH_WEST:
14306 coord->v.fraction.x = 0.0;
14307 coord->v.fraction.y = 1.0;
14310 case CLUTTER_GRAVITY_WEST:
14311 coord->v.fraction.x = 0.0;
14312 coord->v.fraction.y = 0.5;
14315 case CLUTTER_GRAVITY_NORTH_WEST:
14316 coord->v.fraction.x = 0.0;
14317 coord->v.fraction.y = 0.0;
14320 case CLUTTER_GRAVITY_CENTER:
14321 coord->v.fraction.x = 0.5;
14322 coord->v.fraction.y = 0.5;
14326 coord->v.fraction.x = 0.0;
14327 coord->v.fraction.y = 0.0;
14331 coord->is_fractional = TRUE;
14335 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14337 if (coord->is_fractional)
14338 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14340 return (coord->v.units.x == 0.0
14341 && coord->v.units.y == 0.0
14342 && coord->v.units.z == 0.0);
14346 * clutter_actor_get_flags:
14347 * @self: a #ClutterActor
14349 * Retrieves the flags set on @self
14351 * Return value: a bitwise or of #ClutterActorFlags or 0
14356 clutter_actor_get_flags (ClutterActor *self)
14358 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14360 return self->flags;
14364 * clutter_actor_set_flags:
14365 * @self: a #ClutterActor
14366 * @flags: the flags to set
14368 * Sets @flags on @self
14370 * This function will emit notifications for the changed properties
14375 clutter_actor_set_flags (ClutterActor *self,
14376 ClutterActorFlags flags)
14378 ClutterActorFlags old_flags;
14380 gboolean was_reactive_set, reactive_set;
14381 gboolean was_realized_set, realized_set;
14382 gboolean was_mapped_set, mapped_set;
14383 gboolean was_visible_set, visible_set;
14385 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14387 if (self->flags == flags)
14390 obj = G_OBJECT (self);
14391 g_object_ref (obj);
14392 g_object_freeze_notify (obj);
14394 old_flags = self->flags;
14396 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14397 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14398 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14399 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14401 self->flags |= flags;
14403 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14404 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14405 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14406 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14408 if (reactive_set != was_reactive_set)
14409 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14411 if (realized_set != was_realized_set)
14412 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14414 if (mapped_set != was_mapped_set)
14415 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14417 if (visible_set != was_visible_set)
14418 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14420 g_object_thaw_notify (obj);
14421 g_object_unref (obj);
14425 * clutter_actor_unset_flags:
14426 * @self: a #ClutterActor
14427 * @flags: the flags to unset
14429 * Unsets @flags on @self
14431 * This function will emit notifications for the changed properties
14436 clutter_actor_unset_flags (ClutterActor *self,
14437 ClutterActorFlags flags)
14439 ClutterActorFlags old_flags;
14441 gboolean was_reactive_set, reactive_set;
14442 gboolean was_realized_set, realized_set;
14443 gboolean was_mapped_set, mapped_set;
14444 gboolean was_visible_set, visible_set;
14446 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14448 obj = G_OBJECT (self);
14449 g_object_freeze_notify (obj);
14451 old_flags = self->flags;
14453 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14454 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14455 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14456 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14458 self->flags &= ~flags;
14460 if (self->flags == old_flags)
14463 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14464 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14465 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14466 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14468 if (reactive_set != was_reactive_set)
14469 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14471 if (realized_set != was_realized_set)
14472 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14474 if (mapped_set != was_mapped_set)
14475 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14477 if (visible_set != was_visible_set)
14478 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14480 g_object_thaw_notify (obj);
14484 * clutter_actor_get_transformation_matrix:
14485 * @self: a #ClutterActor
14486 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14488 * Retrieves the transformations applied to @self relative to its
14494 clutter_actor_get_transformation_matrix (ClutterActor *self,
14495 CoglMatrix *matrix)
14497 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14499 cogl_matrix_init_identity (matrix);
14501 _clutter_actor_apply_modelview_transform (self, matrix);
14505 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14506 gboolean is_in_clone_paint)
14508 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14509 self->priv->in_clone_paint = is_in_clone_paint;
14513 * clutter_actor_is_in_clone_paint:
14514 * @self: a #ClutterActor
14516 * Checks whether @self is being currently painted by a #ClutterClone
14518 * This function is useful only inside the ::paint virtual function
14519 * implementations or within handlers for the #ClutterActor::paint
14522 * This function should not be used by applications
14524 * Return value: %TRUE if the #ClutterActor is currently being painted
14525 * by a #ClutterClone, and %FALSE otherwise
14530 clutter_actor_is_in_clone_paint (ClutterActor *self)
14532 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14534 return self->priv->in_clone_paint;
14538 set_direction_recursive (ClutterActor *actor,
14539 gpointer user_data)
14541 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14543 clutter_actor_set_text_direction (actor, text_dir);
14549 * clutter_actor_set_text_direction:
14550 * @self: a #ClutterActor
14551 * @text_dir: the text direction for @self
14553 * Sets the #ClutterTextDirection for an actor
14555 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14557 * If @self implements #ClutterContainer then this function will recurse
14558 * inside all the children of @self (including the internal ones).
14560 * Composite actors not implementing #ClutterContainer, or actors requiring
14561 * special handling when the text direction changes, should connect to
14562 * the #GObject::notify signal for the #ClutterActor:text-direction property
14567 clutter_actor_set_text_direction (ClutterActor *self,
14568 ClutterTextDirection text_dir)
14570 ClutterActorPrivate *priv;
14572 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14573 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14577 if (priv->text_direction != text_dir)
14579 priv->text_direction = text_dir;
14581 /* we need to emit the notify::text-direction first, so that
14582 * the sub-classes can catch that and do specific handling of
14583 * the text direction; see clutter_text_direction_changed_cb()
14584 * inside clutter-text.c
14586 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14588 _clutter_actor_foreach_child (self, set_direction_recursive,
14589 GINT_TO_POINTER (text_dir));
14591 clutter_actor_queue_relayout (self);
14596 _clutter_actor_set_has_pointer (ClutterActor *self,
14597 gboolean has_pointer)
14599 ClutterActorPrivate *priv = self->priv;
14601 if (priv->has_pointer != has_pointer)
14603 priv->has_pointer = has_pointer;
14605 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14610 * clutter_actor_get_text_direction:
14611 * @self: a #ClutterActor
14613 * Retrieves the value set using clutter_actor_set_text_direction()
14615 * If no text direction has been previously set, the default text
14616 * direction, as returned by clutter_get_default_text_direction(), will
14617 * be returned instead
14619 * Return value: the #ClutterTextDirection for the actor
14623 ClutterTextDirection
14624 clutter_actor_get_text_direction (ClutterActor *self)
14626 ClutterActorPrivate *priv;
14628 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14629 CLUTTER_TEXT_DIRECTION_LTR);
14633 /* if no direction has been set yet use the default */
14634 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14635 priv->text_direction = clutter_get_default_text_direction ();
14637 return priv->text_direction;
14641 * clutter_actor_push_internal:
14642 * @self: a #ClutterActor
14644 * Should be used by actors implementing the #ClutterContainer and with
14645 * internal children added through clutter_actor_set_parent(), for instance:
14649 * my_actor_init (MyActor *self)
14651 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14653 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14655 * /* calling clutter_actor_set_parent() now will result in
14656 * * the internal flag being set on a child of MyActor
14659 * /* internal child - a background texture */
14660 * self->priv->background_tex = clutter_texture_new ();
14661 * clutter_actor_set_parent (self->priv->background_tex,
14662 * CLUTTER_ACTOR (self));
14664 * /* internal child - a label */
14665 * self->priv->label = clutter_text_new ();
14666 * clutter_actor_set_parent (self->priv->label,
14667 * CLUTTER_ACTOR (self));
14669 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14671 * /* calling clutter_actor_set_parent() now will not result in
14672 * * the internal flag being set on a child of MyActor
14677 * This function will be used by Clutter to toggle an "internal child"
14678 * flag whenever clutter_actor_set_parent() is called; internal children
14679 * are handled differently by Clutter, specifically when destroying their
14682 * Call clutter_actor_pop_internal() when you finished adding internal
14685 * Nested calls to clutter_actor_push_internal() are allowed, but each
14686 * one must by followed by a clutter_actor_pop_internal() call.
14690 * Deprecated: 1.10: All children of an actor are accessible through
14691 * the #ClutterActor API, and #ClutterActor implements the
14692 * #ClutterContainer interface, so this function is only useful
14693 * for legacy containers overriding the default implementation.
14696 clutter_actor_push_internal (ClutterActor *self)
14698 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14700 self->priv->internal_child += 1;
14704 * clutter_actor_pop_internal:
14705 * @self: a #ClutterActor
14707 * Disables the effects of clutter_actor_push_internal().
14711 * Deprecated: 1.10: All children of an actor are accessible through
14712 * the #ClutterActor API. This function is only useful for legacy
14713 * containers overriding the default implementation of the
14714 * #ClutterContainer interface.
14717 clutter_actor_pop_internal (ClutterActor *self)
14719 ClutterActorPrivate *priv;
14721 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14725 if (priv->internal_child == 0)
14727 g_warning ("Mismatched %s: you need to call "
14728 "clutter_actor_push_composite() at least once before "
14729 "calling this function", G_STRFUNC);
14733 priv->internal_child -= 1;
14737 * clutter_actor_has_pointer:
14738 * @self: a #ClutterActor
14740 * Checks whether an actor contains the pointer of a
14741 * #ClutterInputDevice
14743 * Return value: %TRUE if the actor contains the pointer, and
14749 clutter_actor_has_pointer (ClutterActor *self)
14751 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14753 return self->priv->has_pointer;
14756 /* XXX: This is a workaround for not being able to break the ABI of
14757 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14758 * clutter_actor_queue_clipped_redraw() for details.
14760 ClutterPaintVolume *
14761 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14763 return g_object_get_data (G_OBJECT (self),
14764 "-clutter-actor-queue-redraw-clip");
14768 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14769 ClutterPaintVolume *clip)
14771 g_object_set_data (G_OBJECT (self),
14772 "-clutter-actor-queue-redraw-clip",
14777 * clutter_actor_has_allocation:
14778 * @self: a #ClutterActor
14780 * Checks if the actor has an up-to-date allocation assigned to
14781 * it. This means that the actor should have an allocation: it's
14782 * visible and has a parent. It also means that there is no
14783 * outstanding relayout request in progress for the actor or its
14784 * children (There might be other outstanding layout requests in
14785 * progress that will cause the actor to get a new allocation
14786 * when the stage is laid out, however).
14788 * If this function returns %FALSE, then the actor will normally
14789 * be allocated before it is next drawn on the screen.
14791 * Return value: %TRUE if the actor has an up-to-date allocation
14796 clutter_actor_has_allocation (ClutterActor *self)
14798 ClutterActorPrivate *priv;
14800 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14804 return priv->parent != NULL &&
14805 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14806 !priv->needs_allocation;
14810 * clutter_actor_add_action:
14811 * @self: a #ClutterActor
14812 * @action: a #ClutterAction
14814 * Adds @action to the list of actions applied to @self
14816 * A #ClutterAction can only belong to one actor at a time
14818 * The #ClutterActor will hold a reference on @action until either
14819 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14825 clutter_actor_add_action (ClutterActor *self,
14826 ClutterAction *action)
14828 ClutterActorPrivate *priv;
14830 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14831 g_return_if_fail (CLUTTER_IS_ACTION (action));
14835 if (priv->actions == NULL)
14837 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14838 priv->actions->actor = self;
14841 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14843 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14847 * clutter_actor_add_action_with_name:
14848 * @self: a #ClutterActor
14849 * @name: the name to set on the action
14850 * @action: a #ClutterAction
14852 * A convenience function for setting the name of a #ClutterAction
14853 * while adding it to the list of actions applied to @self
14855 * This function is the logical equivalent of:
14858 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14859 * clutter_actor_add_action (self, action);
14865 clutter_actor_add_action_with_name (ClutterActor *self,
14867 ClutterAction *action)
14869 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14870 g_return_if_fail (name != NULL);
14871 g_return_if_fail (CLUTTER_IS_ACTION (action));
14873 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14874 clutter_actor_add_action (self, action);
14878 * clutter_actor_remove_action:
14879 * @self: a #ClutterActor
14880 * @action: a #ClutterAction
14882 * Removes @action from the list of actions applied to @self
14884 * The reference held by @self on the #ClutterAction will be released
14889 clutter_actor_remove_action (ClutterActor *self,
14890 ClutterAction *action)
14892 ClutterActorPrivate *priv;
14894 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14895 g_return_if_fail (CLUTTER_IS_ACTION (action));
14899 if (priv->actions == NULL)
14902 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14904 if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14905 g_clear_object (&priv->actions);
14907 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14911 * clutter_actor_remove_action_by_name:
14912 * @self: a #ClutterActor
14913 * @name: the name of the action to remove
14915 * Removes the #ClutterAction with the given name from the list
14916 * of actions applied to @self
14921 clutter_actor_remove_action_by_name (ClutterActor *self,
14924 ClutterActorPrivate *priv;
14925 ClutterActorMeta *meta;
14927 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14928 g_return_if_fail (name != NULL);
14932 if (priv->actions == NULL)
14935 meta = _clutter_meta_group_get_meta (priv->actions, name);
14939 _clutter_meta_group_remove_meta (priv->actions, meta);
14941 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14945 * clutter_actor_get_actions:
14946 * @self: a #ClutterActor
14948 * Retrieves the list of actions applied to @self
14950 * Return value: (transfer container) (element-type Clutter.Action): a copy
14951 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14952 * owned by the #ClutterActor. Use g_list_free() to free the resources
14953 * allocated by the returned #GList
14958 clutter_actor_get_actions (ClutterActor *self)
14960 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14962 if (self->priv->actions == NULL)
14965 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14969 * clutter_actor_get_action:
14970 * @self: a #ClutterActor
14971 * @name: the name of the action to retrieve
14973 * Retrieves the #ClutterAction with the given name in the list
14974 * of actions applied to @self
14976 * Return value: (transfer none): a #ClutterAction for the given
14977 * name, or %NULL. The returned #ClutterAction is owned by the
14978 * actor and it should not be unreferenced directly
14983 clutter_actor_get_action (ClutterActor *self,
14986 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14987 g_return_val_if_fail (name != NULL, NULL);
14989 if (self->priv->actions == NULL)
14992 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14996 * clutter_actor_clear_actions:
14997 * @self: a #ClutterActor
14999 * Clears the list of actions applied to @self
15004 clutter_actor_clear_actions (ClutterActor *self)
15006 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15008 if (self->priv->actions == NULL)
15011 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15015 * clutter_actor_add_constraint:
15016 * @self: a #ClutterActor
15017 * @constraint: a #ClutterConstraint
15019 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15022 * The #ClutterActor will hold a reference on the @constraint until
15023 * either clutter_actor_remove_constraint() or
15024 * clutter_actor_clear_constraints() is called.
15029 clutter_actor_add_constraint (ClutterActor *self,
15030 ClutterConstraint *constraint)
15032 ClutterActorPrivate *priv;
15034 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15035 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15039 if (priv->constraints == NULL)
15041 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15042 priv->constraints->actor = self;
15045 _clutter_meta_group_add_meta (priv->constraints,
15046 CLUTTER_ACTOR_META (constraint));
15047 clutter_actor_queue_relayout (self);
15049 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15053 * clutter_actor_add_constraint_with_name:
15054 * @self: a #ClutterActor
15055 * @name: the name to set on the constraint
15056 * @constraint: a #ClutterConstraint
15058 * A convenience function for setting the name of a #ClutterConstraint
15059 * while adding it to the list of constraints applied to @self
15061 * This function is the logical equivalent of:
15064 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15065 * clutter_actor_add_constraint (self, constraint);
15071 clutter_actor_add_constraint_with_name (ClutterActor *self,
15073 ClutterConstraint *constraint)
15075 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15076 g_return_if_fail (name != NULL);
15077 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15079 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15080 clutter_actor_add_constraint (self, constraint);
15084 * clutter_actor_remove_constraint:
15085 * @self: a #ClutterActor
15086 * @constraint: a #ClutterConstraint
15088 * Removes @constraint from the list of constraints applied to @self
15090 * The reference held by @self on the #ClutterConstraint will be released
15095 clutter_actor_remove_constraint (ClutterActor *self,
15096 ClutterConstraint *constraint)
15098 ClutterActorPrivate *priv;
15100 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15101 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15105 if (priv->constraints == NULL)
15108 _clutter_meta_group_remove_meta (priv->constraints,
15109 CLUTTER_ACTOR_META (constraint));
15111 if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15112 g_clear_object (&priv->constraints);
15114 clutter_actor_queue_relayout (self);
15116 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15120 * clutter_actor_remove_constraint_by_name:
15121 * @self: a #ClutterActor
15122 * @name: the name of the constraint to remove
15124 * Removes the #ClutterConstraint with the given name from the list
15125 * of constraints applied to @self
15130 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15133 ClutterActorPrivate *priv;
15134 ClutterActorMeta *meta;
15136 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15137 g_return_if_fail (name != NULL);
15141 if (priv->constraints == NULL)
15144 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15148 _clutter_meta_group_remove_meta (priv->constraints, meta);
15149 clutter_actor_queue_relayout (self);
15153 * clutter_actor_get_constraints:
15154 * @self: a #ClutterActor
15156 * Retrieves the list of constraints applied to @self
15158 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15159 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15160 * owned by the #ClutterActor. Use g_list_free() to free the resources
15161 * allocated by the returned #GList
15166 clutter_actor_get_constraints (ClutterActor *self)
15168 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15170 if (self->priv->constraints == NULL)
15173 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15177 * clutter_actor_get_constraint:
15178 * @self: a #ClutterActor
15179 * @name: the name of the constraint to retrieve
15181 * Retrieves the #ClutterConstraint with the given name in the list
15182 * of constraints applied to @self
15184 * Return value: (transfer none): a #ClutterConstraint for the given
15185 * name, or %NULL. The returned #ClutterConstraint is owned by the
15186 * actor and it should not be unreferenced directly
15190 ClutterConstraint *
15191 clutter_actor_get_constraint (ClutterActor *self,
15194 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15195 g_return_val_if_fail (name != NULL, NULL);
15197 if (self->priv->constraints == NULL)
15200 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15204 * clutter_actor_clear_constraints:
15205 * @self: a #ClutterActor
15207 * Clears the list of constraints applied to @self
15212 clutter_actor_clear_constraints (ClutterActor *self)
15214 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15216 if (self->priv->constraints == NULL)
15219 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15221 clutter_actor_queue_relayout (self);
15225 * clutter_actor_set_clip_to_allocation:
15226 * @self: a #ClutterActor
15227 * @clip_set: %TRUE to apply a clip tracking the allocation
15229 * Sets whether @self should be clipped to the same size as its
15235 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15238 ClutterActorPrivate *priv;
15240 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15242 clip_set = !!clip_set;
15246 if (priv->clip_to_allocation != clip_set)
15248 priv->clip_to_allocation = clip_set;
15250 clutter_actor_queue_redraw (self);
15252 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15257 * clutter_actor_get_clip_to_allocation:
15258 * @self: a #ClutterActor
15260 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15262 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15267 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15269 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15271 return self->priv->clip_to_allocation;
15275 * clutter_actor_add_effect:
15276 * @self: a #ClutterActor
15277 * @effect: a #ClutterEffect
15279 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15281 * The #ClutterActor will hold a reference on the @effect until either
15282 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15288 clutter_actor_add_effect (ClutterActor *self,
15289 ClutterEffect *effect)
15291 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15292 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15294 _clutter_actor_add_effect_internal (self, effect);
15296 clutter_actor_queue_redraw (self);
15298 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15302 * clutter_actor_add_effect_with_name:
15303 * @self: a #ClutterActor
15304 * @name: the name to set on the effect
15305 * @effect: a #ClutterEffect
15307 * A convenience function for setting the name of a #ClutterEffect
15308 * while adding it to the list of effectss applied to @self
15310 * This function is the logical equivalent of:
15313 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15314 * clutter_actor_add_effect (self, effect);
15320 clutter_actor_add_effect_with_name (ClutterActor *self,
15322 ClutterEffect *effect)
15324 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15325 g_return_if_fail (name != NULL);
15326 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15328 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15329 clutter_actor_add_effect (self, effect);
15333 * clutter_actor_remove_effect:
15334 * @self: a #ClutterActor
15335 * @effect: a #ClutterEffect
15337 * Removes @effect from the list of effects applied to @self
15339 * The reference held by @self on the #ClutterEffect will be released
15344 clutter_actor_remove_effect (ClutterActor *self,
15345 ClutterEffect *effect)
15347 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15348 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15350 _clutter_actor_remove_effect_internal (self, effect);
15352 clutter_actor_queue_redraw (self);
15354 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15358 * clutter_actor_remove_effect_by_name:
15359 * @self: a #ClutterActor
15360 * @name: the name of the effect to remove
15362 * Removes the #ClutterEffect with the given name from the list
15363 * of effects applied to @self
15368 clutter_actor_remove_effect_by_name (ClutterActor *self,
15371 ClutterActorPrivate *priv;
15372 ClutterActorMeta *meta;
15374 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15375 g_return_if_fail (name != NULL);
15379 if (priv->effects == NULL)
15382 meta = _clutter_meta_group_get_meta (priv->effects, name);
15386 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15390 * clutter_actor_get_effects:
15391 * @self: a #ClutterActor
15393 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15395 * Return value: (transfer container) (element-type Clutter.Effect): a list
15396 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15397 * list are owned by Clutter and they should not be freed. You should
15398 * free the returned list using g_list_free() when done
15403 clutter_actor_get_effects (ClutterActor *self)
15405 ClutterActorPrivate *priv;
15407 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15411 if (priv->effects == NULL)
15414 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15418 * clutter_actor_get_effect:
15419 * @self: a #ClutterActor
15420 * @name: the name of the effect to retrieve
15422 * Retrieves the #ClutterEffect with the given name in the list
15423 * of effects applied to @self
15425 * Return value: (transfer none): a #ClutterEffect for the given
15426 * name, or %NULL. The returned #ClutterEffect is owned by the
15427 * actor and it should not be unreferenced directly
15432 clutter_actor_get_effect (ClutterActor *self,
15435 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15436 g_return_val_if_fail (name != NULL, NULL);
15438 if (self->priv->effects == NULL)
15441 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15445 * clutter_actor_clear_effects:
15446 * @self: a #ClutterActor
15448 * Clears the list of effects applied to @self
15453 clutter_actor_clear_effects (ClutterActor *self)
15455 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15457 if (self->priv->effects == NULL)
15460 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15462 clutter_actor_queue_redraw (self);
15466 * clutter_actor_has_key_focus:
15467 * @self: a #ClutterActor
15469 * Checks whether @self is the #ClutterActor that has key focus
15471 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15476 clutter_actor_has_key_focus (ClutterActor *self)
15478 ClutterActor *stage;
15480 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15482 stage = _clutter_actor_get_stage_internal (self);
15486 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15490 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15491 ClutterPaintVolume *pv)
15493 ClutterActorPrivate *priv = self->priv;
15495 /* Actors are only expected to report a valid paint volume
15496 * while they have a valid allocation. */
15497 if (G_UNLIKELY (priv->needs_allocation))
15499 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15500 "Actor needs allocation",
15501 _clutter_actor_get_debug_name (self));
15505 /* Check if there are any handlers connected to the paint
15506 * signal. If there are then all bets are off for what the paint
15507 * volume for this actor might possibly be!
15509 * XXX: It's expected that this is going to end up being quite a
15510 * costly check to have to do here, but we haven't come up with
15511 * another solution that can reliably catch paint signal handlers at
15512 * the right time to either avoid artefacts due to invalid stage
15513 * clipping or due to incorrect culling.
15515 * Previously we checked in clutter_actor_paint(), but at that time
15516 * we may already be using a stage clip that could be derived from
15517 * an invalid paint-volume. We used to try and handle that by
15518 * queuing a follow up, unclipped, redraw but still the previous
15519 * checking wasn't enough to catch invalid volumes involved in
15520 * culling (considering that containers may derive their volume from
15521 * children that haven't yet been painted)
15523 * Longer term, improved solutions could be:
15524 * - Disallow painting in the paint signal, only allow using it
15525 * for tracking when paints happen. We can add another API that
15526 * allows monkey patching the paint of arbitrary actors but in a
15527 * more controlled way and that also supports modifying the
15529 * - If we could be notified somehow when signal handlers are
15530 * connected we wouldn't have to poll for handlers like this.
15532 if (g_signal_has_handler_pending (self,
15533 actor_signals[PAINT],
15537 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15538 "Actor has \"paint\" signal handlers",
15539 _clutter_actor_get_debug_name (self));
15543 _clutter_paint_volume_init_static (pv, self);
15545 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15547 clutter_paint_volume_free (pv);
15548 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15549 "Actor failed to report a volume",
15550 _clutter_actor_get_debug_name (self));
15554 /* since effects can modify the paint volume, we allow them to actually
15555 * do this by making get_paint_volume() "context sensitive"
15557 if (priv->effects != NULL)
15559 if (priv->current_effect != NULL)
15561 const GList *effects, *l;
15563 /* if we are being called from within the paint sequence of
15564 * an actor, get the paint volume up to the current effect
15566 effects = _clutter_meta_group_peek_metas (priv->effects);
15568 l != NULL || (l != NULL && l->data != priv->current_effect);
15571 if (!_clutter_effect_get_paint_volume (l->data, pv))
15573 clutter_paint_volume_free (pv);
15574 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15575 "Effect (%s) failed to report a volume",
15576 _clutter_actor_get_debug_name (self),
15577 _clutter_actor_meta_get_debug_name (l->data));
15584 const GList *effects, *l;
15586 /* otherwise, get the cumulative volume */
15587 effects = _clutter_meta_group_peek_metas (priv->effects);
15588 for (l = effects; l != NULL; l = l->next)
15589 if (!_clutter_effect_get_paint_volume (l->data, pv))
15591 clutter_paint_volume_free (pv);
15592 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15593 "Effect (%s) failed to report a volume",
15594 _clutter_actor_get_debug_name (self),
15595 _clutter_actor_meta_get_debug_name (l->data));
15604 /* The public clutter_actor_get_paint_volume API returns a const
15605 * pointer since we return a pointer directly to the cached
15606 * PaintVolume associated with the actor and don't want the user to
15607 * inadvertently modify it, but for internal uses we sometimes need
15608 * access to the same PaintVolume but need to apply some book-keeping
15609 * modifications to it so we don't want a const pointer.
15611 static ClutterPaintVolume *
15612 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15614 ClutterActorPrivate *priv;
15618 if (priv->paint_volume_valid)
15619 clutter_paint_volume_free (&priv->paint_volume);
15621 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15623 priv->paint_volume_valid = TRUE;
15624 return &priv->paint_volume;
15628 priv->paint_volume_valid = FALSE;
15634 * clutter_actor_get_paint_volume:
15635 * @self: a #ClutterActor
15637 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15638 * when a paint volume can't be determined.
15640 * The paint volume is defined as the 3D space occupied by an actor
15641 * when being painted.
15643 * This function will call the <function>get_paint_volume()</function>
15644 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15645 * should not usually care about overriding the default implementation,
15646 * unless they are, for instance: painting outside their allocation, or
15647 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15650 * <note>2D actors overriding <function>get_paint_volume()</function>
15651 * ensure their volume has a depth of 0. (This will be true so long as
15652 * you don't call clutter_paint_volume_set_depth().)</note>
15654 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15655 * or %NULL if no volume could be determined. The returned pointer
15656 * is not guaranteed to be valid across multiple frames; if you want
15657 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15661 const ClutterPaintVolume *
15662 clutter_actor_get_paint_volume (ClutterActor *self)
15664 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15666 return _clutter_actor_get_paint_volume_mutable (self);
15670 * clutter_actor_get_transformed_paint_volume:
15671 * @self: a #ClutterActor
15672 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15673 * (or %NULL for the stage)
15675 * Retrieves the 3D paint volume of an actor like
15676 * clutter_actor_get_paint_volume() does (Please refer to the
15677 * documentation of clutter_actor_get_paint_volume() for more
15678 * details.) and it additionally transforms the paint volume into the
15679 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15680 * is passed for @relative_to_ancestor)
15682 * This can be used by containers that base their paint volume on
15683 * the volume of their children. Such containers can query the
15684 * transformed paint volume of all of its children and union them
15685 * together using clutter_paint_volume_union().
15687 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15688 * or %NULL if no volume could be determined. The returned pointer is
15689 * not guaranteed to be valid across multiple frames; if you wish to
15690 * keep it, you will have to copy it using clutter_paint_volume_copy().
15694 const ClutterPaintVolume *
15695 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15696 ClutterActor *relative_to_ancestor)
15698 const ClutterPaintVolume *volume;
15699 ClutterActor *stage;
15700 ClutterPaintVolume *transformed_volume;
15702 stage = _clutter_actor_get_stage_internal (self);
15703 if (G_UNLIKELY (stage == NULL))
15706 if (relative_to_ancestor == NULL)
15707 relative_to_ancestor = stage;
15709 volume = clutter_actor_get_paint_volume (self);
15710 if (volume == NULL)
15713 transformed_volume =
15714 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15716 _clutter_paint_volume_copy_static (volume, transformed_volume);
15718 _clutter_paint_volume_transform_relative (transformed_volume,
15719 relative_to_ancestor);
15721 return transformed_volume;
15725 * clutter_actor_get_paint_box:
15726 * @self: a #ClutterActor
15727 * @box: (out): return location for a #ClutterActorBox
15729 * Retrieves the paint volume of the passed #ClutterActor, and
15730 * transforms it into a 2D bounding box in stage coordinates.
15732 * This function is useful to determine the on screen area occupied by
15733 * the actor. The box is only an approximation and may often be
15734 * considerably larger due to the optimizations used to calculate the
15735 * box. The box is never smaller though, so it can reliably be used
15738 * There are times when a 2D paint box can't be determined, e.g.
15739 * because the actor isn't yet parented under a stage or because
15740 * the actor is unable to determine a paint volume.
15742 * Return value: %TRUE if a 2D paint box could be determined, else
15748 clutter_actor_get_paint_box (ClutterActor *self,
15749 ClutterActorBox *box)
15751 ClutterActor *stage;
15752 ClutterPaintVolume *pv;
15754 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15755 g_return_val_if_fail (box != NULL, FALSE);
15757 stage = _clutter_actor_get_stage_internal (self);
15758 if (G_UNLIKELY (!stage))
15761 pv = _clutter_actor_get_paint_volume_mutable (self);
15762 if (G_UNLIKELY (!pv))
15765 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15771 * clutter_actor_has_overlaps:
15772 * @self: A #ClutterActor
15774 * Asks the actor's implementation whether it may contain overlapping
15777 * For example; Clutter may use this to determine whether the painting
15778 * should be redirected to an offscreen buffer to correctly implement
15779 * the opacity property.
15781 * Custom actors can override the default response by implementing the
15782 * #ClutterActor <function>has_overlaps</function> virtual function. See
15783 * clutter_actor_set_offscreen_redirect() for more information.
15785 * Return value: %TRUE if the actor may have overlapping primitives, and
15791 clutter_actor_has_overlaps (ClutterActor *self)
15793 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15795 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15799 * clutter_actor_has_effects:
15800 * @self: A #ClutterActor
15802 * Returns whether the actor has any effects applied.
15804 * Return value: %TRUE if the actor has any effects,
15810 clutter_actor_has_effects (ClutterActor *self)
15812 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15814 if (self->priv->effects == NULL)
15817 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15821 * clutter_actor_has_constraints:
15822 * @self: A #ClutterActor
15824 * Returns whether the actor has any constraints applied.
15826 * Return value: %TRUE if the actor has any constraints,
15832 clutter_actor_has_constraints (ClutterActor *self)
15834 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15836 return self->priv->constraints != NULL;
15840 * clutter_actor_has_actions:
15841 * @self: A #ClutterActor
15843 * Returns whether the actor has any actions applied.
15845 * Return value: %TRUE if the actor has any actions,
15851 clutter_actor_has_actions (ClutterActor *self)
15853 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15855 return self->priv->actions != NULL;
15859 * clutter_actor_get_n_children:
15860 * @self: a #ClutterActor
15862 * Retrieves the number of children of @self.
15864 * Return value: the number of children of an actor
15869 clutter_actor_get_n_children (ClutterActor *self)
15871 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15873 return self->priv->n_children;
15877 * clutter_actor_get_child_at_index:
15878 * @self: a #ClutterActor
15879 * @index_: the position in the list of children
15881 * Retrieves the actor at the given @index_ inside the list of
15882 * children of @self.
15884 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15889 clutter_actor_get_child_at_index (ClutterActor *self,
15892 ClutterActor *iter;
15895 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15896 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15898 for (iter = self->priv->first_child, i = 0;
15899 iter != NULL && i < index_;
15900 iter = iter->priv->next_sibling, i += 1)
15907 * _clutter_actor_foreach_child:
15908 * @actor: The actor whos children you want to iterate
15909 * @callback: The function to call for each child
15910 * @user_data: Private data to pass to @callback
15912 * Calls a given @callback once for each child of the specified @actor and
15913 * passing the @user_data pointer each time.
15915 * Return value: returns %TRUE if all children were iterated, else
15916 * %FALSE if a callback broke out of iteration early.
15919 _clutter_actor_foreach_child (ClutterActor *self,
15920 ClutterForeachCallback callback,
15921 gpointer user_data)
15923 ClutterActor *iter;
15926 if (self->priv->first_child == NULL)
15930 iter = self->priv->first_child;
15932 /* we use this form so that it's safe to change the children
15933 * list while iterating it
15935 while (cont && iter != NULL)
15937 ClutterActor *next = iter->priv->next_sibling;
15939 cont = callback (iter, user_data);
15948 /* For debugging purposes this gives us a simple way to print out
15949 * the scenegraph e.g in gdb using:
15951 * _clutter_actor_traverse (stage,
15953 * clutter_debug_print_actor_cb,
15958 static ClutterActorTraverseVisitFlags
15959 clutter_debug_print_actor_cb (ClutterActor *actor,
15963 g_print ("%*s%s:%p\n",
15965 _clutter_actor_get_debug_name (actor),
15968 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15973 _clutter_actor_traverse_breadth (ClutterActor *actor,
15974 ClutterTraverseCallback callback,
15975 gpointer user_data)
15977 GQueue *queue = g_queue_new ();
15978 ClutterActor dummy;
15979 int current_depth = 0;
15981 g_queue_push_tail (queue, actor);
15982 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15984 while ((actor = g_queue_pop_head (queue)))
15986 ClutterActorTraverseVisitFlags flags;
15988 if (actor == &dummy)
15991 g_queue_push_tail (queue, &dummy);
15995 flags = callback (actor, current_depth, user_data);
15996 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15998 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16000 ClutterActor *iter;
16002 for (iter = actor->priv->first_child;
16004 iter = iter->priv->next_sibling)
16006 g_queue_push_tail (queue, iter);
16011 g_queue_free (queue);
16014 static ClutterActorTraverseVisitFlags
16015 _clutter_actor_traverse_depth (ClutterActor *actor,
16016 ClutterTraverseCallback before_children_callback,
16017 ClutterTraverseCallback after_children_callback,
16019 gpointer user_data)
16021 ClutterActorTraverseVisitFlags flags;
16023 flags = before_children_callback (actor, current_depth, user_data);
16024 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16025 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16027 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16029 ClutterActor *iter;
16031 for (iter = actor->priv->first_child;
16033 iter = iter->priv->next_sibling)
16035 flags = _clutter_actor_traverse_depth (iter,
16036 before_children_callback,
16037 after_children_callback,
16041 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16042 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16046 if (after_children_callback)
16047 return after_children_callback (actor, current_depth, user_data);
16049 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16052 /* _clutter_actor_traverse:
16053 * @actor: The actor to start traversing the graph from
16054 * @flags: These flags may affect how the traversal is done
16055 * @before_children_callback: A function to call before visiting the
16056 * children of the current actor.
16057 * @after_children_callback: A function to call after visiting the
16058 * children of the current actor. (Ignored if
16059 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16060 * @user_data: The private data to pass to the callbacks
16062 * Traverses the scenegraph starting at the specified @actor and
16063 * descending through all its children and its children's children.
16064 * For each actor traversed @before_children_callback and
16065 * @after_children_callback are called with the specified
16066 * @user_data, before and after visiting that actor's children.
16068 * The callbacks can return flags that affect the ongoing traversal
16069 * such as by skipping over an actors children or bailing out of
16070 * any further traversing.
16073 _clutter_actor_traverse (ClutterActor *actor,
16074 ClutterActorTraverseFlags flags,
16075 ClutterTraverseCallback before_children_callback,
16076 ClutterTraverseCallback after_children_callback,
16077 gpointer user_data)
16079 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16080 _clutter_actor_traverse_breadth (actor,
16081 before_children_callback,
16083 else /* DEPTH_FIRST */
16084 _clutter_actor_traverse_depth (actor,
16085 before_children_callback,
16086 after_children_callback,
16087 0, /* start depth */
16092 on_layout_manager_changed (ClutterLayoutManager *manager,
16093 ClutterActor *self)
16095 clutter_actor_queue_relayout (self);
16099 * clutter_actor_set_layout_manager:
16100 * @self: a #ClutterActor
16101 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16103 * Sets the #ClutterLayoutManager delegate object that will be used to
16104 * lay out the children of @self.
16106 * The #ClutterActor will take a reference on the passed @manager which
16107 * will be released either when the layout manager is removed, or when
16108 * the actor is destroyed.
16113 clutter_actor_set_layout_manager (ClutterActor *self,
16114 ClutterLayoutManager *manager)
16116 ClutterActorPrivate *priv;
16118 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16119 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16123 if (priv->layout_manager != NULL)
16125 g_signal_handlers_disconnect_by_func (priv->layout_manager,
16126 G_CALLBACK (on_layout_manager_changed),
16128 clutter_layout_manager_set_container (priv->layout_manager, NULL);
16129 g_clear_object (&priv->layout_manager);
16132 priv->layout_manager = manager;
16134 if (priv->layout_manager != NULL)
16136 g_object_ref_sink (priv->layout_manager);
16137 clutter_layout_manager_set_container (priv->layout_manager,
16138 CLUTTER_CONTAINER (self));
16139 g_signal_connect (priv->layout_manager, "layout-changed",
16140 G_CALLBACK (on_layout_manager_changed),
16144 clutter_actor_queue_relayout (self);
16146 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16150 * clutter_actor_get_layout_manager:
16151 * @self: a #ClutterActor
16153 * Retrieves the #ClutterLayoutManager used by @self.
16155 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16160 ClutterLayoutManager *
16161 clutter_actor_get_layout_manager (ClutterActor *self)
16163 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16165 return self->priv->layout_manager;
16168 static const ClutterLayoutInfo default_layout_info = {
16169 CLUTTER_POINT_INIT_ZERO, /* fixed-pos */
16170 { 0, 0, 0, 0 }, /* margin */
16171 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16172 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16173 FALSE, FALSE, /* expand */
16174 CLUTTER_SIZE_INIT_ZERO, /* minimum */
16175 CLUTTER_SIZE_INIT_ZERO, /* natural */
16179 layout_info_free (gpointer data)
16181 if (G_LIKELY (data != NULL))
16182 g_slice_free (ClutterLayoutInfo, data);
16186 * _clutter_actor_get_layout_info:
16187 * @self: a #ClutterActor
16189 * Retrieves a pointer to the ClutterLayoutInfo structure.
16191 * If the actor does not have a ClutterLayoutInfo associated to it, one
16192 * will be created and initialized to the default values.
16194 * This function should be used for setters.
16196 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16199 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16201 ClutterLayoutInfo *
16202 _clutter_actor_get_layout_info (ClutterActor *self)
16204 ClutterLayoutInfo *retval;
16206 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16207 if (retval == NULL)
16209 retval = g_slice_new (ClutterLayoutInfo);
16211 *retval = default_layout_info;
16213 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16222 * _clutter_actor_get_layout_info_or_defaults:
16223 * @self: a #ClutterActor
16225 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16227 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16228 * then the default structure will be returned.
16230 * This function should only be used for getters.
16232 * Return value: a const pointer to the ClutterLayoutInfo structure
16234 const ClutterLayoutInfo *
16235 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16237 const ClutterLayoutInfo *info;
16239 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16241 return &default_layout_info;
16247 * clutter_actor_set_x_align:
16248 * @self: a #ClutterActor
16249 * @x_align: the horizontal alignment policy
16251 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16252 * actor received extra horizontal space.
16254 * See also the #ClutterActor:x-align property.
16259 clutter_actor_set_x_align (ClutterActor *self,
16260 ClutterActorAlign x_align)
16262 ClutterLayoutInfo *info;
16264 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16266 info = _clutter_actor_get_layout_info (self);
16268 if (info->x_align != x_align)
16270 info->x_align = x_align;
16272 clutter_actor_queue_relayout (self);
16274 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16279 * clutter_actor_get_x_align:
16280 * @self: a #ClutterActor
16282 * Retrieves the horizontal alignment policy set using
16283 * clutter_actor_set_x_align().
16285 * Return value: the horizontal alignment policy.
16290 clutter_actor_get_x_align (ClutterActor *self)
16292 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16294 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16298 * clutter_actor_set_y_align:
16299 * @self: a #ClutterActor
16300 * @y_align: the vertical alignment policy
16302 * Sets the vertical alignment policy of a #ClutterActor, in case the
16303 * actor received extra vertical space.
16305 * See also the #ClutterActor:y-align property.
16310 clutter_actor_set_y_align (ClutterActor *self,
16311 ClutterActorAlign y_align)
16313 ClutterLayoutInfo *info;
16315 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16317 info = _clutter_actor_get_layout_info (self);
16319 if (info->y_align != y_align)
16321 info->y_align = y_align;
16323 clutter_actor_queue_relayout (self);
16325 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16330 * clutter_actor_get_y_align:
16331 * @self: a #ClutterActor
16333 * Retrieves the vertical alignment policy set using
16334 * clutter_actor_set_y_align().
16336 * Return value: the vertical alignment policy.
16341 clutter_actor_get_y_align (ClutterActor *self)
16343 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16345 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16349 * clutter_actor_set_margin:
16350 * @self: a #ClutterActor
16351 * @margin: a #ClutterMargin
16353 * Sets all the components of the margin of a #ClutterActor.
16358 clutter_actor_set_margin (ClutterActor *self,
16359 const ClutterMargin *margin)
16361 ClutterLayoutInfo *info;
16365 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16366 g_return_if_fail (margin != NULL);
16368 obj = G_OBJECT (self);
16371 g_object_freeze_notify (obj);
16373 info = _clutter_actor_get_layout_info (self);
16375 if (info->margin.top != margin->top)
16377 info->margin.top = margin->top;
16378 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16382 if (info->margin.right != margin->right)
16384 info->margin.right = margin->right;
16385 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16389 if (info->margin.bottom != margin->bottom)
16391 info->margin.bottom = margin->bottom;
16392 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16396 if (info->margin.left != margin->left)
16398 info->margin.left = margin->left;
16399 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16404 clutter_actor_queue_relayout (self);
16406 g_object_thaw_notify (obj);
16410 * clutter_actor_get_margin:
16411 * @self: a #ClutterActor
16412 * @margin: (out caller-allocates): return location for a #ClutterMargin
16414 * Retrieves all the components of the margin of a #ClutterActor.
16419 clutter_actor_get_margin (ClutterActor *self,
16420 ClutterMargin *margin)
16422 const ClutterLayoutInfo *info;
16424 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16425 g_return_if_fail (margin != NULL);
16427 info = _clutter_actor_get_layout_info_or_defaults (self);
16429 *margin = info->margin;
16433 * clutter_actor_set_margin_top:
16434 * @self: a #ClutterActor
16435 * @margin: the top margin
16437 * Sets the margin from the top of a #ClutterActor.
16442 clutter_actor_set_margin_top (ClutterActor *self,
16445 ClutterLayoutInfo *info;
16447 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16448 g_return_if_fail (margin >= 0.f);
16450 info = _clutter_actor_get_layout_info (self);
16452 if (info->margin.top == margin)
16455 info->margin.top = margin;
16457 clutter_actor_queue_relayout (self);
16459 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16463 * clutter_actor_get_margin_top:
16464 * @self: a #ClutterActor
16466 * Retrieves the top margin of a #ClutterActor.
16468 * Return value: the top margin
16473 clutter_actor_get_margin_top (ClutterActor *self)
16475 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16477 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16481 * clutter_actor_set_margin_bottom:
16482 * @self: a #ClutterActor
16483 * @margin: the bottom margin
16485 * Sets the margin from the bottom of a #ClutterActor.
16490 clutter_actor_set_margin_bottom (ClutterActor *self,
16493 ClutterLayoutInfo *info;
16495 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16496 g_return_if_fail (margin >= 0.f);
16498 info = _clutter_actor_get_layout_info (self);
16500 if (info->margin.bottom == margin)
16503 info->margin.bottom = margin;
16505 clutter_actor_queue_relayout (self);
16507 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16511 * clutter_actor_get_margin_bottom:
16512 * @self: a #ClutterActor
16514 * Retrieves the bottom margin of a #ClutterActor.
16516 * Return value: the bottom margin
16521 clutter_actor_get_margin_bottom (ClutterActor *self)
16523 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16525 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16529 * clutter_actor_set_margin_left:
16530 * @self: a #ClutterActor
16531 * @margin: the left margin
16533 * Sets the margin from the left of a #ClutterActor.
16538 clutter_actor_set_margin_left (ClutterActor *self,
16541 ClutterLayoutInfo *info;
16543 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16544 g_return_if_fail (margin >= 0.f);
16546 info = _clutter_actor_get_layout_info (self);
16548 if (info->margin.left == margin)
16551 info->margin.left = margin;
16553 clutter_actor_queue_relayout (self);
16555 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16559 * clutter_actor_get_margin_left:
16560 * @self: a #ClutterActor
16562 * Retrieves the left margin of a #ClutterActor.
16564 * Return value: the left margin
16569 clutter_actor_get_margin_left (ClutterActor *self)
16571 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16573 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16577 * clutter_actor_set_margin_right:
16578 * @self: a #ClutterActor
16579 * @margin: the right margin
16581 * Sets the margin from the right of a #ClutterActor.
16586 clutter_actor_set_margin_right (ClutterActor *self,
16589 ClutterLayoutInfo *info;
16591 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16592 g_return_if_fail (margin >= 0.f);
16594 info = _clutter_actor_get_layout_info (self);
16596 if (info->margin.right == margin)
16599 info->margin.right = margin;
16601 clutter_actor_queue_relayout (self);
16603 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16607 * clutter_actor_get_margin_right:
16608 * @self: a #ClutterActor
16610 * Retrieves the right margin of a #ClutterActor.
16612 * Return value: the right margin
16617 clutter_actor_get_margin_right (ClutterActor *self)
16619 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16621 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16625 clutter_actor_set_background_color_internal (ClutterActor *self,
16626 const ClutterColor *color)
16628 ClutterActorPrivate *priv = self->priv;
16631 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16634 obj = G_OBJECT (self);
16636 priv->bg_color = *color;
16637 priv->bg_color_set = TRUE;
16639 clutter_actor_queue_redraw (self);
16641 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16642 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16646 * clutter_actor_set_background_color:
16647 * @self: a #ClutterActor
16648 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16651 * Sets the background color of a #ClutterActor.
16653 * The background color will be used to cover the whole allocation of the
16654 * actor. The default background color of an actor is transparent.
16656 * To check whether an actor has a background color, you can use the
16657 * #ClutterActor:background-color-set actor property.
16659 * The #ClutterActor:background-color property is animatable.
16664 clutter_actor_set_background_color (ClutterActor *self,
16665 const ClutterColor *color)
16667 ClutterActorPrivate *priv;
16669 GParamSpec *bg_color_pspec;
16671 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16673 obj = G_OBJECT (self);
16679 priv->bg_color_set = FALSE;
16680 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16681 clutter_actor_queue_redraw (self);
16685 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16686 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16688 _clutter_actor_create_transition (self, bg_color_pspec,
16693 _clutter_actor_update_transition (self, bg_color_pspec, color);
16695 clutter_actor_queue_redraw (self);
16699 * clutter_actor_get_background_color:
16700 * @self: a #ClutterActor
16701 * @color: (out caller-allocates): return location for a #ClutterColor
16703 * Retrieves the color set using clutter_actor_set_background_color().
16708 clutter_actor_get_background_color (ClutterActor *self,
16709 ClutterColor *color)
16711 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16712 g_return_if_fail (color != NULL);
16714 *color = self->priv->bg_color;
16718 * clutter_actor_get_previous_sibling:
16719 * @self: a #ClutterActor
16721 * Retrieves the sibling of @self that comes before it in the list
16722 * of children of @self's parent.
16724 * The returned pointer is only valid until the scene graph changes; it
16725 * is not safe to modify the list of children of @self while iterating
16728 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16733 clutter_actor_get_previous_sibling (ClutterActor *self)
16735 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16737 return self->priv->prev_sibling;
16741 * clutter_actor_get_next_sibling:
16742 * @self: a #ClutterActor
16744 * Retrieves the sibling of @self that comes after it in the list
16745 * of children of @self's parent.
16747 * The returned pointer is only valid until the scene graph changes; it
16748 * is not safe to modify the list of children of @self while iterating
16751 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16756 clutter_actor_get_next_sibling (ClutterActor *self)
16758 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16760 return self->priv->next_sibling;
16764 * clutter_actor_get_first_child:
16765 * @self: a #ClutterActor
16767 * Retrieves the first child of @self.
16769 * The returned pointer is only valid until the scene graph changes; it
16770 * is not safe to modify the list of children of @self while iterating
16773 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16778 clutter_actor_get_first_child (ClutterActor *self)
16780 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16782 return self->priv->first_child;
16786 * clutter_actor_get_last_child:
16787 * @self: a #ClutterActor
16789 * Retrieves the last child of @self.
16791 * The returned pointer is only valid until the scene graph changes; it
16792 * is not safe to modify the list of children of @self while iterating
16795 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16800 clutter_actor_get_last_child (ClutterActor *self)
16802 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16804 return self->priv->last_child;
16807 /* easy way to have properly named fields instead of the dummy ones
16808 * we use in the public structure
16810 typedef struct _RealActorIter
16812 ClutterActor *root; /* dummy1 */
16813 ClutterActor *current; /* dummy2 */
16814 gpointer padding_1; /* dummy3 */
16815 gint age; /* dummy4 */
16816 gpointer padding_2; /* dummy5 */
16820 * clutter_actor_iter_init:
16821 * @iter: a #ClutterActorIter
16822 * @root: a #ClutterActor
16824 * Initializes a #ClutterActorIter, which can then be used to iterate
16825 * efficiently over a section of the scene graph, and associates it
16828 * Modifying the scene graph section that contains @root will invalidate
16832 * ClutterActorIter iter;
16833 * ClutterActor *child;
16835 * clutter_actor_iter_init (&iter, container);
16836 * while (clutter_actor_iter_next (&iter, &child))
16838 * /* do something with child */
16845 clutter_actor_iter_init (ClutterActorIter *iter,
16846 ClutterActor *root)
16848 RealActorIter *ri = (RealActorIter *) iter;
16850 g_return_if_fail (iter != NULL);
16851 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16854 ri->current = NULL;
16855 ri->age = root->priv->age;
16859 * clutter_actor_iter_next:
16860 * @iter: a #ClutterActorIter
16861 * @child: (out): return location for a #ClutterActor
16863 * Advances the @iter and retrieves the next child of the root #ClutterActor
16864 * that was used to initialize the #ClutterActorIterator.
16866 * If the iterator can advance, this function returns %TRUE and sets the
16869 * If the iterator cannot advance, this function returns %FALSE, and
16870 * the contents of @child are undefined.
16872 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16877 clutter_actor_iter_next (ClutterActorIter *iter,
16878 ClutterActor **child)
16880 RealActorIter *ri = (RealActorIter *) iter;
16882 g_return_val_if_fail (iter != NULL, FALSE);
16883 g_return_val_if_fail (ri->root != NULL, FALSE);
16884 #ifndef G_DISABLE_ASSERT
16885 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16888 if (ri->current == NULL)
16889 ri->current = ri->root->priv->first_child;
16891 ri->current = ri->current->priv->next_sibling;
16894 *child = ri->current;
16896 return ri->current != NULL;
16900 * clutter_actor_iter_prev:
16901 * @iter: a #ClutterActorIter
16902 * @child: (out): return location for a #ClutterActor
16904 * Advances the @iter and retrieves the previous child of the root
16905 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16907 * If the iterator can advance, this function returns %TRUE and sets the
16910 * If the iterator cannot advance, this function returns %FALSE, and
16911 * the contents of @child are undefined.
16913 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16918 clutter_actor_iter_prev (ClutterActorIter *iter,
16919 ClutterActor **child)
16921 RealActorIter *ri = (RealActorIter *) iter;
16923 g_return_val_if_fail (iter != NULL, FALSE);
16924 g_return_val_if_fail (ri->root != NULL, FALSE);
16925 #ifndef G_DISABLE_ASSERT
16926 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16929 if (ri->current == NULL)
16930 ri->current = ri->root->priv->last_child;
16932 ri->current = ri->current->priv->prev_sibling;
16935 *child = ri->current;
16937 return ri->current != NULL;
16941 * clutter_actor_iter_remove:
16942 * @iter: a #ClutterActorIter
16944 * Safely removes the #ClutterActor currently pointer to by the iterator
16947 * This function can only be called after clutter_actor_iter_next() or
16948 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16949 * than once for the same actor.
16951 * This function will call clutter_actor_remove_child() internally.
16956 clutter_actor_iter_remove (ClutterActorIter *iter)
16958 RealActorIter *ri = (RealActorIter *) iter;
16961 g_return_if_fail (iter != NULL);
16962 g_return_if_fail (ri->root != NULL);
16963 #ifndef G_DISABLE_ASSERT
16964 g_return_if_fail (ri->age == ri->root->priv->age);
16966 g_return_if_fail (ri->current != NULL);
16972 ri->current = cur->priv->prev_sibling;
16974 clutter_actor_remove_child_internal (ri->root, cur,
16975 REMOVE_CHILD_DEFAULT_FLAGS);
16982 * clutter_actor_iter_destroy:
16983 * @iter: a #ClutterActorIter
16985 * Safely destroys the #ClutterActor currently pointer to by the iterator
16988 * This function can only be called after clutter_actor_iter_next() or
16989 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16990 * than once for the same actor.
16992 * This function will call clutter_actor_destroy() internally.
16997 clutter_actor_iter_destroy (ClutterActorIter *iter)
16999 RealActorIter *ri = (RealActorIter *) iter;
17002 g_return_if_fail (iter != NULL);
17003 g_return_if_fail (ri->root != NULL);
17004 #ifndef G_DISABLE_ASSERT
17005 g_return_if_fail (ri->age == ri->root->priv->age);
17007 g_return_if_fail (ri->current != NULL);
17013 ri->current = cur->priv->prev_sibling;
17015 clutter_actor_destroy (cur);
17021 static const ClutterAnimationInfo default_animation_info = {
17022 NULL, /* transitions */
17024 NULL, /* cur_state */
17028 clutter_animation_info_free (gpointer data)
17032 ClutterAnimationInfo *info = data;
17034 if (info->transitions != NULL)
17035 g_hash_table_unref (info->transitions);
17037 if (info->states != NULL)
17038 g_array_unref (info->states);
17040 g_slice_free (ClutterAnimationInfo, info);
17044 const ClutterAnimationInfo *
17045 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17047 const ClutterAnimationInfo *res;
17048 GObject *obj = G_OBJECT (self);
17050 res = g_object_get_qdata (obj, quark_actor_animation_info);
17054 return &default_animation_info;
17057 ClutterAnimationInfo *
17058 _clutter_actor_get_animation_info (ClutterActor *self)
17060 GObject *obj = G_OBJECT (self);
17061 ClutterAnimationInfo *res;
17063 res = g_object_get_qdata (obj, quark_actor_animation_info);
17066 res = g_slice_new (ClutterAnimationInfo);
17068 *res = default_animation_info;
17070 g_object_set_qdata_full (obj, quark_actor_animation_info,
17072 clutter_animation_info_free);
17078 ClutterTransition *
17079 _clutter_actor_get_transition (ClutterActor *actor,
17082 const ClutterAnimationInfo *info;
17084 info = _clutter_actor_get_animation_info_or_defaults (actor);
17086 if (info->transitions == NULL)
17089 return g_hash_table_lookup (info->transitions, pspec->name);
17092 typedef struct _TransitionClosure
17094 ClutterActor *actor;
17095 ClutterTransition *transition;
17097 gulong completed_id;
17098 } TransitionClosure;
17101 transition_closure_free (gpointer data)
17103 if (G_LIKELY (data != NULL))
17105 TransitionClosure *clos = data;
17106 ClutterTimeline *timeline;
17108 timeline = CLUTTER_TIMELINE (clos->transition);
17110 if (clutter_timeline_is_playing (timeline))
17111 clutter_timeline_stop (timeline);
17113 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17115 g_object_unref (clos->transition);
17116 g_free (clos->name);
17118 g_slice_free (TransitionClosure, clos);
17123 on_transition_completed (ClutterTransition *transition,
17124 TransitionClosure *clos)
17126 ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17127 ClutterActor *actor = clos->actor;
17128 ClutterAnimationInfo *info;
17129 gint n_repeats, cur_repeat;
17131 info = _clutter_actor_get_animation_info (actor);
17133 /* reset the caches used by animations */
17134 clutter_actor_store_content_box (actor, NULL);
17136 /* ensure that we remove the transition only at the end
17137 * of its run; we emit ::completed for every repeat
17139 n_repeats = clutter_timeline_get_repeat_count (timeline);
17140 cur_repeat = clutter_timeline_get_current_repeat (timeline);
17142 if (cur_repeat == n_repeats)
17144 if (clutter_transition_get_remove_on_complete (transition))
17146 /* we take a reference here because removing the closure
17147 * will release the reference on the transition, and we
17148 * want the transition to survive the signal emission;
17149 * the master clock will release the last reference at
17150 * the end of the frame processing.
17152 g_object_ref (transition);
17153 g_hash_table_remove (info->transitions, clos->name);
17157 /* if it's the last transition then we clean up */
17158 if (g_hash_table_size (info->transitions) == 0)
17160 g_hash_table_unref (info->transitions);
17161 info->transitions = NULL;
17163 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17164 _clutter_actor_get_debug_name (actor));
17166 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17171 _clutter_actor_update_transition (ClutterActor *actor,
17175 TransitionClosure *clos;
17176 ClutterTimeline *timeline;
17177 ClutterInterval *interval;
17178 const ClutterAnimationInfo *info;
17181 GValue initial = G_VALUE_INIT;
17182 GValue final = G_VALUE_INIT;
17183 char *error = NULL;
17185 info = _clutter_actor_get_animation_info_or_defaults (actor);
17187 if (info->transitions == NULL)
17190 clos = g_hash_table_lookup (info->transitions, pspec->name);
17194 timeline = CLUTTER_TIMELINE (clos->transition);
17196 va_start (var_args, pspec);
17198 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17200 g_value_init (&initial, ptype);
17201 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17205 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17208 g_critical ("%s: %s", G_STRLOC, error);
17213 interval = clutter_transition_get_interval (clos->transition);
17214 clutter_interval_set_initial_value (interval, &initial);
17215 clutter_interval_set_final_value (interval, &final);
17217 /* if we're updating with an easing duration of zero milliseconds,
17218 * we just jump the timeline to the end and let it run its course
17220 if (info->cur_state != NULL &&
17221 info->cur_state->easing_duration != 0)
17223 guint cur_duration = clutter_timeline_get_duration (timeline);
17224 ClutterAnimationMode cur_mode =
17225 clutter_timeline_get_progress_mode (timeline);
17227 if (cur_duration != info->cur_state->easing_duration)
17228 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17230 if (cur_mode != info->cur_state->easing_mode)
17231 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17233 clutter_timeline_rewind (timeline);
17237 guint duration = clutter_timeline_get_duration (timeline);
17239 clutter_timeline_advance (timeline, duration);
17243 g_value_unset (&initial);
17244 g_value_unset (&final);
17250 * _clutter_actor_create_transition:
17251 * @actor: a #ClutterActor
17252 * @pspec: the property used for the transition
17253 * @...: initial and final state
17255 * Creates a #ClutterTransition for the property represented by @pspec.
17257 * Return value: a #ClutterTransition
17259 ClutterTransition *
17260 _clutter_actor_create_transition (ClutterActor *actor,
17264 ClutterAnimationInfo *info;
17265 ClutterTransition *res = NULL;
17266 gboolean call_restore = FALSE;
17267 TransitionClosure *clos;
17270 info = _clutter_actor_get_animation_info (actor);
17272 /* XXX - this will go away in 2.0
17274 * if no state has been pushed, we assume that the easing state is
17275 * in "compatibility mode": all transitions have a duration of 0
17276 * msecs, which means that they happen immediately. in Clutter 2.0
17277 * this will turn into a g_assert(info->states != NULL), as every
17278 * actor will start with a predefined easing state
17280 if (info->states == NULL)
17282 clutter_actor_save_easing_state (actor);
17283 clutter_actor_set_easing_duration (actor, 0);
17284 call_restore = TRUE;
17287 if (info->transitions == NULL)
17288 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17290 transition_closure_free);
17292 va_start (var_args, pspec);
17294 clos = g_hash_table_lookup (info->transitions, pspec->name);
17297 ClutterTimeline *timeline;
17298 ClutterInterval *interval;
17299 GValue initial = G_VALUE_INIT;
17300 GValue final = G_VALUE_INIT;
17304 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17306 G_VALUE_COLLECT_INIT (&initial, ptype,
17311 g_critical ("%s: %s", G_STRLOC, error);
17316 G_VALUE_COLLECT_INIT (&final, ptype,
17322 g_critical ("%s: %s", G_STRLOC, error);
17323 g_value_unset (&initial);
17328 /* if the current easing state has a duration of 0, then we don't
17329 * bother to create the transition, and we just set the final value
17330 * directly on the actor; we don't go through the Animatable
17331 * interface because we know we got here through an animatable
17334 if (info->cur_state->easing_duration == 0)
17336 clutter_actor_set_animatable_property (actor,
17340 g_value_unset (&initial);
17341 g_value_unset (&final);
17346 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17348 g_value_unset (&initial);
17349 g_value_unset (&final);
17351 res = clutter_property_transition_new (pspec->name);
17353 clutter_transition_set_interval (res, interval);
17354 clutter_transition_set_remove_on_complete (res, TRUE);
17356 timeline = CLUTTER_TIMELINE (res);
17357 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17358 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17359 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17361 /* this will start the transition as well */
17362 clutter_actor_add_transition (actor, pspec->name, res);
17364 /* the actor now owns the transition */
17365 g_object_unref (res);
17368 res = clos->transition;
17372 clutter_actor_restore_easing_state (actor);
17380 * clutter_actor_add_transition:
17381 * @self: a #ClutterActor
17382 * @name: the name of the transition to add
17383 * @transition: the #ClutterTransition to add
17385 * Adds a @transition to the #ClutterActor's list of animations.
17387 * The @name string is a per-actor unique identifier of the @transition: only
17388 * one #ClutterTransition can be associated to the specified @name.
17390 * The @transition will be started once added.
17392 * This function will take a reference on the @transition.
17394 * This function is usually called implicitly when modifying an animatable
17400 clutter_actor_add_transition (ClutterActor *self,
17402 ClutterTransition *transition)
17404 ClutterTimeline *timeline;
17405 TransitionClosure *clos;
17406 ClutterAnimationInfo *info;
17408 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17409 g_return_if_fail (name != NULL);
17410 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17412 info = _clutter_actor_get_animation_info (self);
17414 if (info->transitions == NULL)
17415 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17417 transition_closure_free);
17419 if (g_hash_table_lookup (info->transitions, name) != NULL)
17421 g_warning ("A transition with name '%s' already exists for "
17424 _clutter_actor_get_debug_name (self));
17428 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17430 timeline = CLUTTER_TIMELINE (transition);
17432 clos = g_slice_new (TransitionClosure);
17433 clos->actor = self;
17434 clos->transition = g_object_ref (transition);
17435 clos->name = g_strdup (name);
17436 clos->completed_id = g_signal_connect (timeline, "completed",
17437 G_CALLBACK (on_transition_completed),
17440 CLUTTER_NOTE (ANIMATION,
17441 "Adding transition '%s' [%p] to actor '%s'",
17444 _clutter_actor_get_debug_name (self));
17446 g_hash_table_insert (info->transitions, clos->name, clos);
17447 clutter_timeline_start (timeline);
17451 * clutter_actor_remove_transition:
17452 * @self: a #ClutterActor
17453 * @name: the name of the transition to remove
17455 * Removes the transition stored inside a #ClutterActor using @name
17458 * If the transition is currently in progress, it will be stopped.
17460 * This function releases the reference acquired when the transition
17461 * was added to the #ClutterActor.
17466 clutter_actor_remove_transition (ClutterActor *self,
17469 const ClutterAnimationInfo *info;
17471 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17472 g_return_if_fail (name != NULL);
17474 info = _clutter_actor_get_animation_info_or_defaults (self);
17476 if (info->transitions == NULL)
17479 g_hash_table_remove (info->transitions, name);
17483 * clutter_actor_remove_all_transitions:
17484 * @self: a #ClutterActor
17486 * Removes all transitions associated to @self.
17491 clutter_actor_remove_all_transitions (ClutterActor *self)
17493 const ClutterAnimationInfo *info;
17495 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17497 info = _clutter_actor_get_animation_info_or_defaults (self);
17498 if (info->transitions == NULL)
17501 g_hash_table_remove_all (info->transitions);
17505 * clutter_actor_set_easing_duration:
17506 * @self: a #ClutterActor
17507 * @msecs: the duration of the easing, or %NULL
17509 * Sets the duration of the tweening for animatable properties
17510 * of @self for the current easing state.
17515 clutter_actor_set_easing_duration (ClutterActor *self,
17518 ClutterAnimationInfo *info;
17520 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17522 info = _clutter_actor_get_animation_info (self);
17524 if (info->cur_state == NULL)
17526 g_warning ("You must call clutter_actor_save_easing_state() prior "
17527 "to calling clutter_actor_set_easing_duration().");
17531 if (info->cur_state->easing_duration != msecs)
17532 info->cur_state->easing_duration = msecs;
17536 * clutter_actor_get_easing_duration:
17537 * @self: a #ClutterActor
17539 * Retrieves the duration of the tweening for animatable
17540 * properties of @self for the current easing state.
17542 * Return value: the duration of the tweening, in milliseconds
17547 clutter_actor_get_easing_duration (ClutterActor *self)
17549 const ClutterAnimationInfo *info;
17551 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17553 info = _clutter_actor_get_animation_info_or_defaults (self);
17555 if (info->cur_state != NULL)
17556 return info->cur_state->easing_duration;
17562 * clutter_actor_set_easing_mode:
17563 * @self: a #ClutterActor
17564 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17566 * Sets the easing mode for the tweening of animatable properties
17572 clutter_actor_set_easing_mode (ClutterActor *self,
17573 ClutterAnimationMode mode)
17575 ClutterAnimationInfo *info;
17577 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17578 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17579 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17581 info = _clutter_actor_get_animation_info (self);
17583 if (info->cur_state == NULL)
17585 g_warning ("You must call clutter_actor_save_easing_state() prior "
17586 "to calling clutter_actor_set_easing_mode().");
17590 if (info->cur_state->easing_mode != mode)
17591 info->cur_state->easing_mode = mode;
17595 * clutter_actor_get_easing_mode:
17596 * @self: a #ClutterActor
17598 * Retrieves the easing mode for the tweening of animatable properties
17599 * of @self for the current easing state.
17601 * Return value: an easing mode
17605 ClutterAnimationMode
17606 clutter_actor_get_easing_mode (ClutterActor *self)
17608 const ClutterAnimationInfo *info;
17610 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17612 info = _clutter_actor_get_animation_info_or_defaults (self);
17614 if (info->cur_state != NULL)
17615 return info->cur_state->easing_mode;
17617 return CLUTTER_EASE_OUT_CUBIC;
17621 * clutter_actor_set_easing_delay:
17622 * @self: a #ClutterActor
17623 * @msecs: the delay before the start of the tweening, in milliseconds
17625 * Sets the delay that should be applied before tweening animatable
17631 clutter_actor_set_easing_delay (ClutterActor *self,
17634 ClutterAnimationInfo *info;
17636 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17638 info = _clutter_actor_get_animation_info (self);
17640 if (info->cur_state == NULL)
17642 g_warning ("You must call clutter_actor_save_easing_state() prior "
17643 "to calling clutter_actor_set_easing_delay().");
17647 if (info->cur_state->easing_delay != msecs)
17648 info->cur_state->easing_delay = msecs;
17652 * clutter_actor_get_easing_delay:
17653 * @self: a #ClutterActor
17655 * Retrieves the delay that should be applied when tweening animatable
17658 * Return value: a delay, in milliseconds
17663 clutter_actor_get_easing_delay (ClutterActor *self)
17665 const ClutterAnimationInfo *info;
17667 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17669 info = _clutter_actor_get_animation_info_or_defaults (self);
17671 if (info->cur_state != NULL)
17672 return info->cur_state->easing_delay;
17678 * clutter_actor_get_transition:
17679 * @self: a #ClutterActor
17680 * @name: the name of the transition
17682 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17683 * transition @name.
17685 * Transitions created for animatable properties use the name of the
17686 * property itself, for instance the code below:
17689 * clutter_actor_set_easing_duration (actor, 1000);
17690 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17692 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17693 * g_signal_connect (transition, "completed",
17694 * G_CALLBACK (on_transition_complete),
17698 * will call the <function>on_transition_complete</function> callback when
17699 * the transition is complete.
17701 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17702 * was found to match the passed name; the returned instance is owned
17703 * by Clutter and it should not be freed
17707 ClutterTransition *
17708 clutter_actor_get_transition (ClutterActor *self,
17711 TransitionClosure *clos;
17712 const ClutterAnimationInfo *info;
17714 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17715 g_return_val_if_fail (name != NULL, NULL);
17717 info = _clutter_actor_get_animation_info_or_defaults (self);
17718 if (info->transitions == NULL)
17721 clos = g_hash_table_lookup (info->transitions, name);
17725 return clos->transition;
17729 * clutter_actor_save_easing_state:
17730 * @self: a #ClutterActor
17732 * Saves the current easing state for animatable properties, and creates
17733 * a new state with the default values for easing mode and duration.
17738 clutter_actor_save_easing_state (ClutterActor *self)
17740 ClutterAnimationInfo *info;
17743 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17745 info = _clutter_actor_get_animation_info (self);
17747 if (info->states == NULL)
17748 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17750 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17751 new_state.easing_duration = 250;
17752 new_state.easing_delay = 0;
17754 g_array_append_val (info->states, new_state);
17756 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17760 * clutter_actor_restore_easing_state:
17761 * @self: a #ClutterActor
17763 * Restores the easing state as it was prior to a call to
17764 * clutter_actor_save_easing_state().
17769 clutter_actor_restore_easing_state (ClutterActor *self)
17771 ClutterAnimationInfo *info;
17773 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17775 info = _clutter_actor_get_animation_info (self);
17777 if (info->states == NULL)
17779 g_critical ("The function clutter_actor_restore_easing_state() has "
17780 "called without a previous call to "
17781 "clutter_actor_save_easing_state().");
17785 g_array_remove_index (info->states, info->states->len - 1);
17787 if (info->states->len > 0)
17788 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17791 g_array_unref (info->states);
17792 info->states = NULL;
17793 info->cur_state = NULL;
17798 * clutter_actor_set_content:
17799 * @self: a #ClutterActor
17800 * @content: (allow-none): a #ClutterContent, or %NULL
17802 * Sets the contents of a #ClutterActor.
17807 clutter_actor_set_content (ClutterActor *self,
17808 ClutterContent *content)
17810 ClutterActorPrivate *priv;
17812 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17813 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17817 if (priv->content != NULL)
17819 _clutter_content_detached (priv->content, self);
17820 g_clear_object (&priv->content);
17823 priv->content = content;
17825 if (priv->content != NULL)
17827 g_object_ref (priv->content);
17828 _clutter_content_attached (priv->content, self);
17831 /* given that the content is always painted within the allocation,
17832 * we only need to queue a redraw here
17834 clutter_actor_queue_redraw (self);
17836 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17838 /* if the content gravity is not resize-fill, and the new content has a
17839 * different preferred size than the previous one, then the content box
17840 * may have been changed. since we compute that lazily, we just notify
17841 * here, and let whomever watches :content-box do whatever they need to
17844 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17845 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17849 * clutter_actor_get_content:
17850 * @self: a #ClutterActor
17852 * Retrieves the contents of @self.
17854 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17855 * or %NULL if none was set
17860 clutter_actor_get_content (ClutterActor *self)
17862 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17864 return self->priv->content;
17868 * clutter_actor_set_content_gravity:
17869 * @self: a #ClutterActor
17870 * @gravity: the #ClutterContentGravity
17872 * Sets the gravity of the #ClutterContent used by @self.
17874 * See the description of the #ClutterActor:content-gravity property for
17875 * more information.
17877 * The #ClutterActor:content-gravity property is animatable.
17882 clutter_actor_set_content_gravity (ClutterActor *self,
17883 ClutterContentGravity gravity)
17885 ClutterActorPrivate *priv;
17887 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17891 if (priv->content_gravity == gravity)
17894 priv->content_box_valid = FALSE;
17896 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17898 ClutterActorBox from_box, to_box;
17900 clutter_actor_get_content_box (self, &from_box);
17902 priv->content_gravity = gravity;
17904 clutter_actor_get_content_box (self, &to_box);
17906 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17912 ClutterActorBox to_box;
17914 priv->content_gravity = gravity;
17916 clutter_actor_get_content_box (self, &to_box);
17918 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17922 clutter_actor_queue_redraw (self);
17924 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17928 * clutter_actor_get_content_gravity:
17929 * @self: a #ClutterActor
17931 * Retrieves the content gravity as set using
17932 * clutter_actor_get_content_gravity().
17934 * Return value: the content gravity
17938 ClutterContentGravity
17939 clutter_actor_get_content_gravity (ClutterActor *self)
17941 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17942 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17944 return self->priv->content_gravity;
17948 * clutter_actor_get_content_box:
17949 * @self: a #ClutterActor
17950 * @box: (out caller-allocates): the return location for the bounding
17951 * box for the #ClutterContent
17953 * Retrieves the bounding box for the #ClutterContent of @self.
17955 * The bounding box is relative to the actor's allocation.
17957 * If no #ClutterContent is set for @self, or if @self has not been
17958 * allocated yet, then the result is undefined.
17960 * The content box is guaranteed to be, at most, as big as the allocation
17961 * of the #ClutterActor.
17963 * If the #ClutterContent used by the actor has a preferred size, then
17964 * it is possible to modify the content box by using the
17965 * #ClutterActor:content-gravity property.
17970 clutter_actor_get_content_box (ClutterActor *self,
17971 ClutterActorBox *box)
17973 ClutterActorPrivate *priv;
17974 gfloat content_w, content_h;
17975 gfloat alloc_w, alloc_h;
17977 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17978 g_return_if_fail (box != NULL);
17984 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17985 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17987 if (priv->content_box_valid)
17989 *box = priv->content_box;
17993 /* no need to do any more work */
17994 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17997 if (priv->content == NULL)
18000 /* if the content does not have a preferred size then there is
18001 * no point in computing the content box
18003 if (!clutter_content_get_preferred_size (priv->content,
18011 switch (priv->content_gravity)
18013 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18014 box->x2 = box->x1 + MIN (content_w, alloc_w);
18015 box->y2 = box->y1 + MIN (content_h, alloc_h);
18018 case CLUTTER_CONTENT_GRAVITY_TOP:
18019 if (alloc_w > content_w)
18021 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18022 box->x2 = box->x1 + content_w;
18024 box->y2 = box->y1 + MIN (content_h, alloc_h);
18027 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18028 if (alloc_w > content_w)
18030 box->x1 += (alloc_w - content_w);
18031 box->x2 = box->x1 + content_w;
18033 box->y2 = box->y1 + MIN (content_h, alloc_h);
18036 case CLUTTER_CONTENT_GRAVITY_LEFT:
18037 box->x2 = box->x1 + MIN (content_w, alloc_w);
18038 if (alloc_h > content_h)
18040 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18041 box->y2 = box->y1 + content_h;
18045 case CLUTTER_CONTENT_GRAVITY_CENTER:
18046 if (alloc_w > content_w)
18048 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18049 box->x2 = box->x1 + content_w;
18051 if (alloc_h > content_h)
18053 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18054 box->y2 = box->y1 + content_h;
18058 case CLUTTER_CONTENT_GRAVITY_RIGHT:
18059 if (alloc_w > content_w)
18061 box->x1 += (alloc_w - content_w);
18062 box->x2 = box->x1 + content_w;
18064 if (alloc_h > content_h)
18066 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18067 box->y2 = box->y1 + content_h;
18071 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18072 box->x2 = box->x1 + MIN (content_w, alloc_w);
18073 if (alloc_h > content_h)
18075 box->y1 += (alloc_h - content_h);
18076 box->y2 = box->y1 + content_h;
18080 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18081 if (alloc_w > content_w)
18083 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18084 box->x2 = box->x1 + content_w;
18086 if (alloc_h > content_h)
18088 box->y1 += (alloc_h - content_h);
18089 box->y2 = box->y1 + content_h;
18093 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18094 if (alloc_w > content_w)
18096 box->x1 += (alloc_w - content_w);
18097 box->x2 = box->x1 + content_w;
18099 if (alloc_h > content_h)
18101 box->y1 += (alloc_h - content_h);
18102 box->y2 = box->y1 + content_h;
18106 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18107 g_assert_not_reached ();
18110 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18112 double r_c = content_w / content_h;
18113 double r_a = alloc_w / alloc_h;
18122 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18123 box->y2 = box->y1 + (alloc_w * r_c);
18130 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18131 box->x2 = box->x1 + (alloc_h * r_c);
18141 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18142 box->x2 = box->x1 + (alloc_h * r_c);
18149 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18150 box->y2 = box->y1 + (alloc_w * r_c);
18159 * clutter_actor_set_content_scaling_filters:
18160 * @self: a #ClutterActor
18161 * @min_filter: the minification filter for the content
18162 * @mag_filter: the magnification filter for the content
18164 * Sets the minification and magnification filter to be applied when
18165 * scaling the #ClutterActor:content of a #ClutterActor.
18167 * The #ClutterActor:minification-filter will be used when reducing
18168 * the size of the content; the #ClutterActor:magnification-filter
18169 * will be used when increasing the size of the content.
18174 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18175 ClutterScalingFilter min_filter,
18176 ClutterScalingFilter mag_filter)
18178 ClutterActorPrivate *priv;
18182 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18185 obj = G_OBJECT (self);
18187 g_object_freeze_notify (obj);
18191 if (priv->min_filter != min_filter)
18193 priv->min_filter = min_filter;
18196 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18199 if (priv->mag_filter != mag_filter)
18201 priv->mag_filter = mag_filter;
18204 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18208 clutter_actor_queue_redraw (self);
18210 g_object_thaw_notify (obj);
18214 * clutter_actor_get_content_scaling_filters:
18215 * @self: a #ClutterActor
18216 * @min_filter: (out) (allow-none): return location for the minification
18218 * @mag_filter: (out) (allow-none): return location for the magnification
18221 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18226 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18227 ClutterScalingFilter *min_filter,
18228 ClutterScalingFilter *mag_filter)
18230 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18232 if (min_filter != NULL)
18233 *min_filter = self->priv->min_filter;
18235 if (mag_filter != NULL)
18236 *mag_filter = self->priv->mag_filter;
18240 * clutter_actor_queue_compute_expand:
18241 * @self: a #ClutterActor
18243 * Invalidates the needs_x_expand and needs_y_expand flags on @self
18244 * and its parents up to the top-level actor.
18246 * This function also queues a relayout if anything changed.
18249 clutter_actor_queue_compute_expand (ClutterActor *self)
18251 ClutterActor *parent;
18254 if (self->priv->needs_compute_expand)
18259 while (parent != NULL)
18261 if (!parent->priv->needs_compute_expand)
18263 parent->priv->needs_compute_expand = TRUE;
18267 parent = parent->priv->parent;
18271 clutter_actor_queue_relayout (self);
18275 * clutter_actor_set_x_expand:
18276 * @self: a #ClutterActor
18277 * @expand: whether the actor should expand horizontally
18279 * Sets whether a #ClutterActor should expand horizontally; this means
18280 * that layout manager should allocate extra space for the actor, if
18283 * Setting an actor to expand will also make all its parent expand, so
18284 * that it's possible to build an actor tree and only set this flag on
18285 * its leaves and not on every single actor.
18290 clutter_actor_set_x_expand (ClutterActor *self,
18293 ClutterLayoutInfo *info;
18295 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18299 info = _clutter_actor_get_layout_info (self);
18300 if (info->x_expand != expand)
18302 info->x_expand = expand;
18304 self->priv->x_expand_set = TRUE;
18306 clutter_actor_queue_compute_expand (self);
18308 g_object_notify_by_pspec (G_OBJECT (self),
18309 obj_props[PROP_X_EXPAND]);
18314 * clutter_actor_get_x_expand:
18315 * @self: a #ClutterActor
18317 * Retrieves the value set with clutter_actor_set_x_expand().
18319 * See also: clutter_actor_needs_expand()
18321 * Return value: %TRUE if the actor has been set to expand
18326 clutter_actor_get_x_expand (ClutterActor *self)
18328 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18330 return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18334 * clutter_actor_set_y_expand:
18335 * @self: a #ClutterActor
18336 * @expand: whether the actor should expand vertically
18338 * Sets whether a #ClutterActor should expand horizontally; this means
18339 * that layout manager should allocate extra space for the actor, if
18342 * Setting an actor to expand will also make all its parent expand, so
18343 * that it's possible to build an actor tree and only set this flag on
18344 * its leaves and not on every single actor.
18349 clutter_actor_set_y_expand (ClutterActor *self,
18352 ClutterLayoutInfo *info;
18354 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18358 info = _clutter_actor_get_layout_info (self);
18359 if (info->y_expand != expand)
18361 info->y_expand = expand;
18363 self->priv->y_expand_set = TRUE;
18365 clutter_actor_queue_compute_expand (self);
18367 g_object_notify_by_pspec (G_OBJECT (self),
18368 obj_props[PROP_Y_EXPAND]);
18373 * clutter_actor_get_y_expand:
18374 * @self: a #ClutterActor
18376 * Retrieves the value set with clutter_actor_set_y_expand().
18378 * See also: clutter_actor_needs_expand()
18380 * Return value: %TRUE if the actor has been set to expand
18385 clutter_actor_get_y_expand (ClutterActor *self)
18387 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18389 return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18393 clutter_actor_compute_expand_recursive (ClutterActor *self,
18394 gboolean *x_expand_p,
18395 gboolean *y_expand_p)
18397 ClutterActorIter iter;
18398 ClutterActor *child;
18399 gboolean x_expand, y_expand;
18401 x_expand = y_expand = FALSE;
18403 /* note that we don't recurse into children if we're already set to expand;
18404 * this avoids traversing the whole actor tree, even if it may lead to some
18405 * child left with the needs_compute_expand flag set.
18407 clutter_actor_iter_init (&iter, self);
18408 while (clutter_actor_iter_next (&iter, &child))
18410 x_expand = x_expand ||
18411 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18413 y_expand = y_expand ||
18414 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18417 *x_expand_p = x_expand;
18418 *y_expand_p = y_expand;
18422 clutter_actor_compute_expand (ClutterActor *self)
18424 if (self->priv->needs_compute_expand)
18426 const ClutterLayoutInfo *info;
18427 gboolean x_expand, y_expand;
18429 info = _clutter_actor_get_layout_info_or_defaults (self);
18431 if (self->priv->x_expand_set)
18432 x_expand = info->x_expand;
18436 if (self->priv->y_expand_set)
18437 y_expand = info->y_expand;
18441 /* we don't need to recurse down to the children if the
18442 * actor has been forcibly set to expand
18444 if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18446 if (self->priv->n_children != 0)
18448 gboolean *x_expand_p, *y_expand_p;
18449 gboolean ignored = FALSE;
18451 x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18452 y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18454 clutter_actor_compute_expand_recursive (self,
18460 self->priv->needs_compute_expand = FALSE;
18461 self->priv->needs_x_expand = (x_expand != FALSE);
18462 self->priv->needs_y_expand = (y_expand != FALSE);
18467 * clutter_actor_needs_expand:
18468 * @self: a #ClutterActor
18469 * @orientation: the direction of expansion
18471 * Checks whether an actor, or any of its children, is set to expand
18472 * horizontally or vertically.
18474 * This function should only be called by layout managers that can
18475 * assign extra space to their children.
18477 * If you want to know whether the actor was explicitly set to expand,
18478 * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18480 * Return value: %TRUE if the actor should expand
18485 clutter_actor_needs_expand (ClutterActor *self,
18486 ClutterOrientation orientation)
18488 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18490 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18493 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18496 clutter_actor_compute_expand (self);
18498 switch (orientation)
18500 case CLUTTER_ORIENTATION_HORIZONTAL:
18501 return self->priv->needs_x_expand;
18503 case CLUTTER_ORIENTATION_VERTICAL:
18504 return self->priv->needs_y_expand;