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_interval (transition, clutter_interval_new (G_TYPE_UINT, 255, 0));
298 * clutter_actor_add_transition (actor, "animate-opacity", transition);
299 * </programlisting></informalexample>
300 * <para>The example above will animate the #ClutterActor:opacity property
301 * of an actor between fully opaque and fully transparent, and back, over
302 * a span of 3 seconds. The animation does not begin until it is added to
304 * <para>The explicit animation API should also be used when using custom
305 * animatable properties for #ClutterAction, #ClutterConstraint, and
306 * #ClutterEffect instances associated to an actor; see the section on
307 * <ulink linkend="ClutterActor-custom-animatable-properties">custom
308 * animatable properties below</ulink> for an example.</para>
309 * <para>Finally, explicit animations are useful for creating animations
310 * that run continuously, for instance:</para>
311 * <informalexample><programlisting>
312 * /* this animation will pulse the actor's opacity continuously */
313 * ClutterTransition *transition;
314 * ClutterInterval *interval;
316 * transition = clutter_property_transition_new ("opacity");
318 * /* we want to animate the opacity between 0 and 255 */
319 * internal = clutter_interval_new (G_TYPE_UINT, 0, 255);
320 * clutter_transition_set_interval (transition, interval);
322 * /* over a one second duration, running an infinite amount of times */
323 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
324 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
326 * /* we want to fade in and out, so we need to auto-reverse the transition */
327 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
329 * /* and we want to use an easing function that eases both in and out */
330 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
331 * CLUTTER_EASE_IN_OUT_CUBIC);
333 * /* add the transition to the desired actor; this will
334 * * start the animation.
336 * clutter_actor_add_transition (actor, "opacityAnimation", transition);
337 * </programlisting></informalexample>
341 * <refsect2 id="ClutterActor-subclassing">
342 * <title>Implementing an actor</title>
343 * <para>Careful consideration should be given when deciding to implement
344 * a #ClutterActor sub-class. It is generally recommended to implement a
345 * sub-class of #ClutterActor only for actors that should be used as leaf
346 * nodes of a scene graph.</para>
347 * <para>If your actor should be painted in a custom way, you should
348 * override the #ClutterActor::paint signal class handler. You can either
349 * opt to chain up to the parent class implementation or decide to fully
350 * override the default paint implementation; Clutter will set up the
351 * transformations and clip regions prior to emitting the #ClutterActor::paint
353 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
354 * #ClutterActorClass.get_preferred_height() virtual functions it is
355 * possible to change or provide the preferred size of an actor; similarly,
356 * by overriding the #ClutterActorClass.allocate() virtual function it is
357 * possible to control the layout of the children of an actor. Make sure to
358 * always chain up to the parent implementation of the
359 * #ClutterActorClass.allocate() virtual function.</para>
360 * <para>In general, it is strongly encouraged to use delegation and
361 * composition instead of direct subclassing.</para>
364 * <refsect2 id="ClutterActor-script">
365 * <title>ClutterActor custom properties for #ClutterScript</title>
366 * <para>#ClutterActor defines a custom "rotation" property which
367 * allows a short-hand description of the rotations to be applied
368 * to an actor.</para>
369 * <para>The syntax of the "rotation" property is the following:</para>
373 * { "<axis>" : [ <angle>, [ <center> ] ] }
377 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
378 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
379 * floating point value representing the rotation angle on the given axis,
381 * <para>The <emphasis>center</emphasis> array is optional, and if present
382 * it must contain the center of rotation as described by two coordinates:
383 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
385 * <para>#ClutterActor will also parse every positional and dimensional
386 * property defined as a string through clutter_units_from_string(); you
387 * should read the documentation for the #ClutterUnits parser format for
388 * the valid units and syntax.</para>
391 * <refsect2 id="ClutterActor-custom-animatable-properties">
392 * <title>Custom animatable properties</title>
393 * <para>#ClutterActor allows accessing properties of #ClutterAction,
394 * #ClutterEffect, and #ClutterConstraint instances associated to an actor
395 * instance for animation purposes.</para>
396 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
397 * property it is necessary to set the #ClutterActorMeta:name property on the
398 * given action or constraint.</para>
399 * <para>The property can be accessed using the following syntax:</para>
402 * @<section>.<meta-name>.<property-name>
405 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
406 * <para>The <emphasis>section</emphasis> fragment can be one between
407 * "actions", "constraints" and "effects".</para>
408 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
409 * action or constraint, as specified by the #ClutterActorMeta:name
411 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
412 * action or constraint property to be animated.</para>
413 * <para>The example below animates a #ClutterBindConstraint applied to an
414 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
415 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
416 * its initial state is overlapping the actor to which is bound to.</para>
417 * <informalexample><programlisting>
418 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
419 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
420 * clutter_actor_add_constraint (rect, constraint);
422 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
423 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
424 * clutter_actor_add_constraint (rect, constraint);
426 * clutter_actor_set_reactive (origin, TRUE);
428 * g_signal_connect (origin, "button-press-event",
429 * G_CALLBACK (on_button_press),
431 * </programlisting></informalexample>
432 * <para>On button press, the rectangle "slides" from behind the actor to
433 * which is bound to, using the #ClutterBindConstraint:offset property to
434 * achieve the effect:</para>
435 * <informalexample><programlisting>
437 * on_button_press (ClutterActor *origin,
438 * ClutterEvent *event,
439 * ClutterActor *rect)
441 * ClutterTransition *transition;
442 * ClutterInterval *interval;
444 * /* the offset that we want to apply; this will make the actor
445 * * slide in from behind the origin and rest at the right of
446 * * the origin, plus a padding value.
448 * float new_offset = clutter_actor_get_width (origin) + h_padding;
450 * /* the property we wish to animate; the "@constraints" section
451 * * tells Clutter to check inside the constraints associated
452 * * with the actor; the "bind-x" section is the name of the
453 * * constraint; and the "offset" is the name of the property
454 * * on the constraint.
456 * const char *prop = "@constraints.bind-x.offset";
458 * /* create a new transition for the given property */
459 * transition = clutter_property_transition_new (prop);
461 * /* set the easing mode and duration */
462 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
463 * CLUTTER_EASE_OUT_CUBIC);
464 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
466 * /* create the interval with the initial and final values */
467 * interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
468 * clutter_transition_set_interval (transition, interval);
470 * /* add the transition to the actor; this causes the animation
471 * * to start. the name "offsetAnimation" can be used to retrieve
472 * * the transition later.
474 * clutter_actor_add_transition (rect, "offsetAnimation", transition);
476 * /* we handled the event */
477 * return CLUTTER_EVENT_STOP;
479 * </programlisting></informalexample>
484 * CLUTTER_ACTOR_IS_MAPPED:
485 * @a: a #ClutterActor
487 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
489 * The mapped state is set when the actor is visible and all its parents up
490 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
492 * This check can be used to see if an actor is going to be painted, as only
493 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
495 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
496 * not be checked directly; instead, the recommended usage is to connect a
497 * handler on the #GObject::notify signal for the #ClutterActor:mapped
498 * property of #ClutterActor, and check the presence of
499 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
501 * It is also important to note that Clutter may delay the changes of
502 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
503 * limitations, or during the reparenting of an actor, to optimize
504 * unnecessary (and potentially expensive) state changes.
510 * CLUTTER_ACTOR_IS_REALIZED:
511 * @a: a #ClutterActor
513 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
515 * The realized state has an actor-dependant interpretation. If an
516 * actor wants to delay allocating resources until it is attached to a
517 * stage, it may use the realize state to do so. However it is
518 * perfectly acceptable for an actor to allocate Cogl resources before
519 * being realized because there is only one drawing context used by Clutter
520 * so any resources will work on any stage. If an actor is mapped it
521 * must also be realized, but an actor can be realized and unmapped
522 * (this is so hiding an actor temporarily doesn't do an expensive
523 * unrealize/realize).
525 * To be realized an actor must be inside a stage, and all its parents
532 * CLUTTER_ACTOR_IS_VISIBLE:
533 * @a: a #ClutterActor
535 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
536 * Equivalent to the ClutterActor::visible object property.
538 * Note that an actor is only painted onscreen if it's mapped, which
539 * means it's visible, and all its parents are visible, and one of the
540 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
546 * CLUTTER_ACTOR_IS_REACTIVE:
547 * @a: a #ClutterActor
549 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
551 * Only reactive actors will receive event-related signals.
562 #include <gobject/gvaluecollector.h>
564 #include <cogl/cogl.h>
566 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
567 #define CLUTTER_ENABLE_EXPERIMENTAL_API
569 #include "clutter-actor-private.h"
571 #include "clutter-action.h"
572 #include "clutter-actor-meta-private.h"
573 #include "clutter-animatable.h"
574 #include "clutter-color-static.h"
575 #include "clutter-color.h"
576 #include "clutter-constraint.h"
577 #include "clutter-container.h"
578 #include "clutter-content-private.h"
579 #include "clutter-debug.h"
580 #include "clutter-effect-private.h"
581 #include "clutter-enum-types.h"
582 #include "clutter-fixed-layout.h"
583 #include "clutter-flatten-effect.h"
584 #include "clutter-interval.h"
585 #include "clutter-main.h"
586 #include "clutter-marshal.h"
587 #include "clutter-paint-nodes.h"
588 #include "clutter-paint-node-private.h"
589 #include "clutter-paint-volume-private.h"
590 #include "clutter-private.h"
591 #include "clutter-profile.h"
592 #include "clutter-property-transition.h"
593 #include "clutter-scriptable.h"
594 #include "clutter-script-private.h"
595 #include "clutter-stage-private.h"
596 #include "clutter-timeline.h"
597 #include "clutter-transition.h"
598 #include "clutter-units.h"
600 #include "deprecated/clutter-actor.h"
601 #include "deprecated/clutter-behaviour.h"
602 #include "deprecated/clutter-container.h"
604 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
605 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
607 /* Internal enum used to control mapped state update. This is a hint
608 * which indicates when to do something other than just enforce
612 MAP_STATE_CHECK, /* just enforce invariants. */
613 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
614 * used when about to unparent.
616 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
617 * used to set mapped on toplevels.
619 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
620 * used just before unmapping parent.
624 /* 3 entries should be a good compromise, few layout managers
625 * will ask for 3 different preferred size in each allocation cycle */
626 #define N_CACHED_SIZE_REQUESTS 3
628 struct _ClutterActorPrivate
631 ClutterRequestMode request_mode;
633 /* our cached size requests for different width / height */
634 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
635 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
637 /* An age of 0 means the entry is not set */
638 guint cached_height_age;
639 guint cached_width_age;
641 /* the bounding box of the actor, relative to the parent's
644 ClutterActorBox allocation;
645 ClutterAllocationFlags allocation_flags;
647 /* clip, in actor coordinates */
648 cairo_rectangle_t clip;
650 /* the cached transformation matrix; see apply_transform() */
651 CoglMatrix transform;
654 gint opacity_override;
656 ClutterOffscreenRedirect offscreen_redirect;
658 /* This is an internal effect used to implement the
659 offscreen-redirect property */
660 ClutterEffect *flatten_effect;
663 ClutterActor *parent;
664 ClutterActor *prev_sibling;
665 ClutterActor *next_sibling;
666 ClutterActor *first_child;
667 ClutterActor *last_child;
671 /* tracks whenever the children of an actor are changed; the
672 * age is incremented by 1 whenever an actor is added or
673 * removed. the age is not incremented when the first or the
674 * last child pointers are changed, or when grandchildren of
675 * an actor are changed.
679 gchar *name; /* a non-unique name, used for debugging */
680 guint32 id; /* unique id, used for backward compatibility */
682 gint32 pick_id; /* per-stage unique id, used for picking */
684 /* a back-pointer to the Pango context that we can use
685 * to create pre-configured PangoLayout
687 PangoContext *pango_context;
689 /* the text direction configured for this child - either by
690 * application code, or by the actor's parent
692 ClutterTextDirection text_direction;
694 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
698 ClutterMetaGroup *actions;
699 ClutterMetaGroup *constraints;
700 ClutterMetaGroup *effects;
702 /* delegate object used to allocate the children of this actor */
703 ClutterLayoutManager *layout_manager;
705 /* delegate object used to paint the contents of this actor */
706 ClutterContent *content;
708 ClutterContentGravity content_gravity;
709 ClutterScalingFilter min_filter;
710 ClutterScalingFilter mag_filter;
712 /* used when painting, to update the paint volume */
713 ClutterEffect *current_effect;
715 /* This is used to store an effect which needs to be redrawn. A
716 redraw can be queued to start from a particular effect. This is
717 used by parametrised effects that can cache an image of the
718 actor. If a parameter of the effect changes then it only needs to
719 redraw the cached image, not the actual actor. The pointer is
720 only valid if is_dirty == TRUE. If the pointer is NULL then the
721 whole actor is dirty. */
722 ClutterEffect *effect_to_redraw;
724 /* This is used when painting effects to implement the
725 clutter_actor_continue_paint() function. It points to the node in
726 the list of effects that is next in the chain */
727 const GList *next_effect_to_paint;
729 ClutterPaintVolume paint_volume;
731 /* NB: This volume isn't relative to this actor, it is in eye
732 * coordinates so that it can remain valid after the actor changes.
734 ClutterPaintVolume last_paint_volume;
736 ClutterStageQueueRedrawEntry *queue_redraw_entry;
738 ClutterColor bg_color;
742 /* fixed position and sizes */
743 guint position_set : 1;
744 guint min_width_set : 1;
745 guint min_height_set : 1;
746 guint natural_width_set : 1;
747 guint natural_height_set : 1;
748 /* cached request is invalid (implies allocation is too) */
749 guint needs_width_request : 1;
750 /* cached request is invalid (implies allocation is too) */
751 guint needs_height_request : 1;
752 /* cached allocation is invalid (request has changed, probably) */
753 guint needs_allocation : 1;
754 guint show_on_set_parent : 1;
756 guint clip_to_allocation : 1;
757 guint enable_model_view_transform : 1;
758 guint enable_paint_unmapped : 1;
759 guint has_pointer : 1;
760 guint propagated_one_redraw : 1;
761 guint paint_volume_valid : 1;
762 guint last_paint_volume_valid : 1;
763 guint in_clone_paint : 1;
764 guint transform_valid : 1;
765 /* This is TRUE if anything has queued a redraw since we were last
766 painted. In this case effect_to_redraw will point to an effect
767 the redraw was queued from or it will be NULL if the redraw was
768 queued without an effect. */
770 guint bg_color_set : 1;
779 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
780 * when set they force a size request, when gotten they
781 * get the allocation if the allocation is valid, and the
789 /* Then the rest of these size-related properties are the "actual"
790 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
795 PROP_FIXED_POSITION_SET,
804 PROP_NATURAL_WIDTH_SET,
807 PROP_NATURAL_HEIGHT_SET,
811 /* Allocation properties are read-only */
818 PROP_CLIP_TO_ALLOCATION,
822 PROP_OFFSCREEN_REDIRECT,
835 PROP_ROTATION_ANGLE_X,
836 PROP_ROTATION_ANGLE_Y,
837 PROP_ROTATION_ANGLE_Z,
838 PROP_ROTATION_CENTER_X,
839 PROP_ROTATION_CENTER_Y,
840 PROP_ROTATION_CENTER_Z,
841 /* This property only makes sense for the z rotation because the
842 others would depend on the actor having a size along the
844 PROP_ROTATION_CENTER_Z_GRAVITY,
850 PROP_SHOW_ON_SET_PARENT,
868 PROP_BACKGROUND_COLOR,
869 PROP_BACKGROUND_COLOR_SET,
875 PROP_CONTENT_GRAVITY,
877 PROP_MINIFICATION_FILTER,
878 PROP_MAGNIFICATION_FILTER,
883 static GParamSpec *obj_props[PROP_LAST];
902 BUTTON_RELEASE_EVENT,
910 TRANSITIONS_COMPLETED,
915 static guint actor_signals[LAST_SIGNAL] = { 0, };
917 static void clutter_container_iface_init (ClutterContainerIface *iface);
918 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
919 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
920 static void atk_implementor_iface_init (AtkImplementorIface *iface);
922 /* These setters are all static for now, maybe they should be in the
923 * public API, but they are perhaps obscure enough to leave only as
926 static void clutter_actor_set_min_width (ClutterActor *self,
928 static void clutter_actor_set_min_height (ClutterActor *self,
930 static void clutter_actor_set_natural_width (ClutterActor *self,
931 gfloat natural_width);
932 static void clutter_actor_set_natural_height (ClutterActor *self,
933 gfloat natural_height);
934 static void clutter_actor_set_min_width_set (ClutterActor *self,
935 gboolean use_min_width);
936 static void clutter_actor_set_min_height_set (ClutterActor *self,
937 gboolean use_min_height);
938 static void clutter_actor_set_natural_width_set (ClutterActor *self,
939 gboolean use_natural_width);
940 static void clutter_actor_set_natural_height_set (ClutterActor *self,
941 gboolean use_natural_height);
942 static void clutter_actor_update_map_state (ClutterActor *self,
943 MapStateChange change);
944 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
946 /* Helper routines for managing anchor coords */
947 static void clutter_anchor_coord_get_units (ClutterActor *self,
948 const AnchorCoord *coord,
952 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
957 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
958 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
959 ClutterGravity gravity);
961 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
963 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
965 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
966 ClutterActor *ancestor,
969 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
971 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
973 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
974 const ClutterColor *color);
976 static void on_layout_manager_changed (ClutterLayoutManager *manager,
979 /* Helper macro which translates by the anchor coord, applies the
980 given transformation and then translates back */
981 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
982 gfloat _tx, _ty, _tz; \
983 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
984 cogl_matrix_translate ((m), _tx, _ty, _tz); \
986 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
988 static GQuark quark_shader_data = 0;
989 static GQuark quark_actor_layout_info = 0;
990 static GQuark quark_actor_transform_info = 0;
991 static GQuark quark_actor_animation_info = 0;
993 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
995 G_TYPE_INITIALLY_UNOWNED,
996 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
997 clutter_container_iface_init)
998 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
999 clutter_scriptable_iface_init)
1000 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1001 clutter_animatable_iface_init)
1002 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1003 atk_implementor_iface_init));
1006 * clutter_actor_get_debug_name:
1007 * @actor: a #ClutterActor
1009 * Retrieves a printable name of @actor for debugging messages
1011 * Return value: a string with a printable name
1014 _clutter_actor_get_debug_name (ClutterActor *actor)
1016 return actor->priv->name != NULL ? actor->priv->name
1017 : G_OBJECT_TYPE_NAME (actor);
1020 #ifdef CLUTTER_ENABLE_DEBUG
1021 /* XXX - this is for debugging only, remove once working (or leave
1022 * in only in some debug mode). Should leave it for a little while
1023 * until we're confident in the new map/realize/visible handling.
1026 clutter_actor_verify_map_state (ClutterActor *self)
1028 ClutterActorPrivate *priv = self->priv;
1030 if (CLUTTER_ACTOR_IS_REALIZED (self))
1032 /* all bets are off during reparent when we're potentially realized,
1033 * but should not be according to invariants
1035 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1037 if (priv->parent == NULL)
1039 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1043 g_warning ("Realized non-toplevel actor '%s' should "
1045 _clutter_actor_get_debug_name (self));
1047 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1049 g_warning ("Realized actor %s has an unrealized parent %s",
1050 _clutter_actor_get_debug_name (self),
1051 _clutter_actor_get_debug_name (priv->parent));
1056 if (CLUTTER_ACTOR_IS_MAPPED (self))
1058 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1059 g_warning ("Actor '%s' is mapped but not realized",
1060 _clutter_actor_get_debug_name (self));
1062 /* remaining bets are off during reparent when we're potentially
1063 * mapped, but should not be according to invariants
1065 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1067 if (priv->parent == NULL)
1069 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1071 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1072 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1074 g_warning ("Toplevel actor '%s' is mapped "
1076 _clutter_actor_get_debug_name (self));
1081 g_warning ("Mapped actor '%s' should have a parent",
1082 _clutter_actor_get_debug_name (self));
1087 ClutterActor *iter = self;
1089 /* check for the enable_paint_unmapped flag on the actor
1090 * and parents; if the flag is enabled at any point of this
1091 * branch of the scene graph then all the later checks
1094 while (iter != NULL)
1096 if (iter->priv->enable_paint_unmapped)
1099 iter = iter->priv->parent;
1102 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1104 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1106 _clutter_actor_get_debug_name (self),
1107 _clutter_actor_get_debug_name (priv->parent));
1110 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1112 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1114 _clutter_actor_get_debug_name (self),
1115 _clutter_actor_get_debug_name (priv->parent));
1118 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1120 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1121 g_warning ("Actor '%s' is mapped but its non-toplevel "
1122 "parent '%s' is not mapped",
1123 _clutter_actor_get_debug_name (self),
1124 _clutter_actor_get_debug_name (priv->parent));
1131 #endif /* CLUTTER_ENABLE_DEBUG */
1134 clutter_actor_set_mapped (ClutterActor *self,
1137 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1142 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1143 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1147 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1148 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1152 /* this function updates the mapped and realized states according to
1153 * invariants, in the appropriate order.
1156 clutter_actor_update_map_state (ClutterActor *self,
1157 MapStateChange change)
1159 gboolean was_mapped;
1161 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1163 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1165 /* the mapped flag on top-level actors must be set by the
1166 * per-backend implementation because it might be asynchronous.
1168 * That is, the MAPPED flag on toplevels currently tracks the X
1169 * server mapped-ness of the window, while the expected behavior
1170 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1171 * This creates some weird complexity by breaking the invariant
1172 * that if we're visible and all ancestors shown then we are
1173 * also mapped - instead, we are mapped if all ancestors
1174 * _possibly excepting_ the stage are mapped. The stage
1175 * will map/unmap for example when it is minimized or
1176 * moved to another workspace.
1178 * So, the only invariant on the stage is that if visible it
1179 * should be realized, and that it has to be visible to be
1182 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1183 clutter_actor_realize (self);
1187 case MAP_STATE_CHECK:
1190 case MAP_STATE_MAKE_MAPPED:
1191 g_assert (!was_mapped);
1192 clutter_actor_set_mapped (self, TRUE);
1195 case MAP_STATE_MAKE_UNMAPPED:
1196 g_assert (was_mapped);
1197 clutter_actor_set_mapped (self, FALSE);
1200 case MAP_STATE_MAKE_UNREALIZED:
1201 /* we only use MAKE_UNREALIZED in unparent,
1202 * and unparenting a stage isn't possible.
1203 * If someone wants to just unrealize a stage
1204 * then clutter_actor_unrealize() doesn't
1205 * go through this codepath.
1207 g_warning ("Trying to force unrealize stage is not allowed");
1211 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1212 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1213 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1215 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1216 "it is somehow still mapped",
1217 _clutter_actor_get_debug_name (self));
1222 ClutterActorPrivate *priv = self->priv;
1223 ClutterActor *parent = priv->parent;
1224 gboolean should_be_mapped;
1225 gboolean may_be_realized;
1226 gboolean must_be_realized;
1228 should_be_mapped = FALSE;
1229 may_be_realized = TRUE;
1230 must_be_realized = FALSE;
1232 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1234 may_be_realized = FALSE;
1238 /* Maintain invariant that if parent is mapped, and we are
1239 * visible, then we are mapped ... unless parent is a
1240 * stage, in which case we map regardless of parent's map
1241 * state but do require stage to be visible and realized.
1243 * If parent is realized, that does not force us to be
1244 * realized; but if parent is unrealized, that does force
1245 * us to be unrealized.
1247 * The reason we don't force children to realize with
1248 * parents is _clutter_actor_rerealize(); if we require that
1249 * a realized parent means children are realized, then to
1250 * unrealize an actor we would have to unrealize its
1251 * parents, which would end up meaning unrealizing and
1252 * hiding the entire stage. So we allow unrealizing a
1253 * child (as long as that child is not mapped) while that
1254 * child still has a realized parent.
1256 * Also, if we unrealize from leaf nodes to root, and
1257 * realize from root to leaf, the invariants are never
1258 * violated if we allow children to be unrealized
1259 * while parents are realized.
1261 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1262 * to force us to unmap, even though parent is still
1263 * mapped. This is because we're unmapping from leaf nodes
1266 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1267 change != MAP_STATE_MAKE_UNMAPPED)
1269 gboolean parent_is_visible_realized_toplevel;
1271 parent_is_visible_realized_toplevel =
1272 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1273 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1274 CLUTTER_ACTOR_IS_REALIZED (parent));
1276 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1277 parent_is_visible_realized_toplevel)
1279 must_be_realized = TRUE;
1280 should_be_mapped = TRUE;
1284 /* if the actor has been set to be painted even if unmapped
1285 * then we should map it and check for realization as well;
1286 * this is an override for the branch of the scene graph
1287 * which begins with this node
1289 if (priv->enable_paint_unmapped)
1291 if (priv->parent == NULL)
1292 g_warning ("Attempting to map an unparented actor '%s'",
1293 _clutter_actor_get_debug_name (self));
1295 should_be_mapped = TRUE;
1296 must_be_realized = TRUE;
1299 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1300 may_be_realized = FALSE;
1303 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1306 g_warning ("Attempting to map a child that does not "
1307 "meet the necessary invariants: the actor '%s' "
1309 _clutter_actor_get_debug_name (self));
1311 g_warning ("Attempting to map a child that does not "
1312 "meet the necessary invariants: the actor '%s' "
1313 "is parented to an unmapped actor '%s'",
1314 _clutter_actor_get_debug_name (self),
1315 _clutter_actor_get_debug_name (priv->parent));
1318 /* If in reparent, we temporarily suspend unmap and unrealize.
1320 * We want to go in the order "realize, map" and "unmap, unrealize"
1324 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1325 clutter_actor_set_mapped (self, FALSE);
1328 if (must_be_realized)
1329 clutter_actor_realize (self);
1331 /* if we must be realized then we may be, presumably */
1332 g_assert (!(must_be_realized && !may_be_realized));
1335 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1336 clutter_actor_unrealize_not_hiding (self);
1339 if (should_be_mapped)
1341 if (!must_be_realized)
1342 g_warning ("Somehow we think actor '%s' should be mapped but "
1343 "not realized, which isn't allowed",
1344 _clutter_actor_get_debug_name (self));
1346 /* realization is allowed to fail (though I don't know what
1347 * an app is supposed to do about that - shouldn't it just
1348 * be a g_error? anyway, we have to avoid mapping if this
1351 if (CLUTTER_ACTOR_IS_REALIZED (self))
1352 clutter_actor_set_mapped (self, TRUE);
1356 #ifdef CLUTTER_ENABLE_DEBUG
1357 /* check all invariants were kept */
1358 clutter_actor_verify_map_state (self);
1363 clutter_actor_real_map (ClutterActor *self)
1365 ClutterActorPrivate *priv = self->priv;
1366 ClutterActor *stage, *iter;
1368 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1370 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1371 _clutter_actor_get_debug_name (self));
1373 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1375 stage = _clutter_actor_get_stage_internal (self);
1376 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1378 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1380 _clutter_actor_get_debug_name (self));
1382 /* notify on parent mapped before potentially mapping
1383 * children, so apps see a top-down notification.
1385 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1387 for (iter = self->priv->first_child;
1389 iter = iter->priv->next_sibling)
1391 clutter_actor_map (iter);
1396 * clutter_actor_map:
1397 * @self: A #ClutterActor
1399 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1400 * and realizes its children if they are visible. Does nothing if the
1401 * actor is not visible.
1403 * Calling this function is strongly disencouraged: the default
1404 * implementation of #ClutterActorClass.map() will map all the children
1405 * of an actor when mapping its parent.
1407 * When overriding map, it is mandatory to chain up to the parent
1413 clutter_actor_map (ClutterActor *self)
1415 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1417 if (CLUTTER_ACTOR_IS_MAPPED (self))
1420 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1423 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1427 clutter_actor_real_unmap (ClutterActor *self)
1429 ClutterActorPrivate *priv = self->priv;
1432 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1434 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1435 _clutter_actor_get_debug_name (self));
1437 for (iter = self->priv->first_child;
1439 iter = iter->priv->next_sibling)
1441 clutter_actor_unmap (iter);
1444 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1446 /* clear the contents of the last paint volume, so that hiding + moving +
1447 * showing will not result in the wrong area being repainted
1449 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1450 priv->last_paint_volume_valid = TRUE;
1452 /* notify on parent mapped after potentially unmapping
1453 * children, so apps see a bottom-up notification.
1455 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1457 /* relinquish keyboard focus if we were unmapped while owning it */
1458 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1460 ClutterStage *stage;
1462 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1465 _clutter_stage_release_pick_id (stage, priv->pick_id);
1469 if (stage != NULL &&
1470 clutter_stage_get_key_focus (stage) == self)
1472 clutter_stage_set_key_focus (stage, NULL);
1478 * clutter_actor_unmap:
1479 * @self: A #ClutterActor
1481 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1482 * unmaps its children if they were mapped.
1484 * Calling this function is not encouraged: the default #ClutterActor
1485 * implementation of #ClutterActorClass.unmap() will also unmap any
1486 * eventual children by default when their parent is unmapped.
1488 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1489 * chain up to the parent implementation.
1491 * <note>It is important to note that the implementation of the
1492 * #ClutterActorClass.unmap() virtual function may be called after
1493 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1494 * implementation, but it is guaranteed to be called before the
1495 * #GObjectClass.finalize() implementation.</note>
1500 clutter_actor_unmap (ClutterActor *self)
1502 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1504 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1507 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1511 clutter_actor_real_show (ClutterActor *self)
1513 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1515 ClutterActorPrivate *priv = self->priv;
1517 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1519 /* we notify on the "visible" flag in the clutter_actor_show()
1520 * wrapper so the entire show signal emission completes first
1523 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1525 /* we queue a relayout unless the actor is inside a
1526 * container that explicitly told us not to
1528 if (priv->parent != NULL &&
1529 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1531 /* While an actor is hidden the parent may not have
1532 * allocated/requested so we need to start from scratch
1533 * and avoid the short-circuiting in
1534 * clutter_actor_queue_relayout().
1536 priv->needs_width_request = FALSE;
1537 priv->needs_height_request = FALSE;
1538 priv->needs_allocation = FALSE;
1539 clutter_actor_queue_relayout (self);
1545 set_show_on_set_parent (ClutterActor *self,
1548 ClutterActorPrivate *priv = self->priv;
1550 set_show = !!set_show;
1552 if (priv->show_on_set_parent == set_show)
1555 if (priv->parent == NULL)
1557 priv->show_on_set_parent = set_show;
1558 g_object_notify_by_pspec (G_OBJECT (self),
1559 obj_props[PROP_SHOW_ON_SET_PARENT]);
1564 * clutter_actor_show:
1565 * @self: A #ClutterActor
1567 * Flags an actor to be displayed. An actor that isn't shown will not
1568 * be rendered on the stage.
1570 * Actors are visible by default.
1572 * If this function is called on an actor without a parent, the
1573 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1577 clutter_actor_show (ClutterActor *self)
1579 ClutterActorPrivate *priv;
1581 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1583 /* simple optimization */
1584 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1586 /* we still need to set the :show-on-set-parent property, in
1587 * case show() is called on an unparented actor
1589 set_show_on_set_parent (self, TRUE);
1593 #ifdef CLUTTER_ENABLE_DEBUG
1594 clutter_actor_verify_map_state (self);
1599 g_object_freeze_notify (G_OBJECT (self));
1601 set_show_on_set_parent (self, TRUE);
1603 g_signal_emit (self, actor_signals[SHOW], 0);
1604 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1606 if (priv->parent != NULL)
1607 clutter_actor_queue_redraw (priv->parent);
1609 g_object_thaw_notify (G_OBJECT (self));
1613 * clutter_actor_show_all:
1614 * @self: a #ClutterActor
1616 * Calls clutter_actor_show() on all children of an actor (if any).
1620 * Deprecated: 1.10: Actors are visible by default
1623 clutter_actor_show_all (ClutterActor *self)
1625 ClutterActorClass *klass;
1627 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1629 klass = CLUTTER_ACTOR_GET_CLASS (self);
1630 if (klass->show_all)
1631 klass->show_all (self);
1635 clutter_actor_real_hide (ClutterActor *self)
1637 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1639 ClutterActorPrivate *priv = self->priv;
1641 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1643 /* we notify on the "visible" flag in the clutter_actor_hide()
1644 * wrapper so the entire hide signal emission completes first
1647 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1649 /* we queue a relayout unless the actor is inside a
1650 * container that explicitly told us not to
1652 if (priv->parent != NULL &&
1653 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1654 clutter_actor_queue_relayout (priv->parent);
1659 * clutter_actor_hide:
1660 * @self: A #ClutterActor
1662 * Flags an actor to be hidden. A hidden actor will not be
1663 * rendered on the stage.
1665 * Actors are visible by default.
1667 * If this function is called on an actor without a parent, the
1668 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1672 clutter_actor_hide (ClutterActor *self)
1674 ClutterActorPrivate *priv;
1676 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1678 /* simple optimization */
1679 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1681 /* we still need to set the :show-on-set-parent property, in
1682 * case hide() is called on an unparented actor
1684 set_show_on_set_parent (self, FALSE);
1688 #ifdef CLUTTER_ENABLE_DEBUG
1689 clutter_actor_verify_map_state (self);
1694 g_object_freeze_notify (G_OBJECT (self));
1696 set_show_on_set_parent (self, FALSE);
1698 g_signal_emit (self, actor_signals[HIDE], 0);
1699 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1701 if (priv->parent != NULL)
1702 clutter_actor_queue_redraw (priv->parent);
1704 g_object_thaw_notify (G_OBJECT (self));
1708 * clutter_actor_hide_all:
1709 * @self: a #ClutterActor
1711 * Calls clutter_actor_hide() on all child actors (if any).
1715 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1716 * prevent its children from being painted as well.
1719 clutter_actor_hide_all (ClutterActor *self)
1721 ClutterActorClass *klass;
1723 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1725 klass = CLUTTER_ACTOR_GET_CLASS (self);
1726 if (klass->hide_all)
1727 klass->hide_all (self);
1731 * clutter_actor_realize:
1732 * @self: A #ClutterActor
1734 * Realization informs the actor that it is attached to a stage. It
1735 * can use this to allocate resources if it wanted to delay allocation
1736 * until it would be rendered. However it is perfectly acceptable for
1737 * an actor to create resources before being realized because Clutter
1738 * only ever has a single rendering context so that actor is free to
1739 * be moved from one stage to another.
1741 * This function does nothing if the actor is already realized.
1743 * Because a realized actor must have realized parent actors, calling
1744 * clutter_actor_realize() will also realize all parents of the actor.
1746 * This function does not realize child actors, except in the special
1747 * case that realizing the stage, when the stage is visible, will
1748 * suddenly map (and thus realize) the children of the stage.
1751 clutter_actor_realize (ClutterActor *self)
1753 ClutterActorPrivate *priv;
1755 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1759 #ifdef CLUTTER_ENABLE_DEBUG
1760 clutter_actor_verify_map_state (self);
1763 if (CLUTTER_ACTOR_IS_REALIZED (self))
1766 /* To be realized, our parent actors must be realized first.
1767 * This will only succeed if we're inside a toplevel.
1769 if (priv->parent != NULL)
1770 clutter_actor_realize (priv->parent);
1772 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1774 /* toplevels can be realized at any time */
1778 /* "Fail" the realization if parent is missing or unrealized;
1779 * this should really be a g_warning() not some kind of runtime
1780 * failure; how can an app possibly recover? Instead it's a bug
1781 * in the app and the app should get an explanatory warning so
1782 * someone can fix it. But for now it's too hard to fix this
1783 * because e.g. ClutterTexture needs reworking.
1785 if (priv->parent == NULL ||
1786 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1790 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1792 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1793 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1795 g_signal_emit (self, actor_signals[REALIZE], 0);
1797 /* Stage actor is allowed to unset the realized flag again in its
1798 * default signal handler, though that is a pathological situation.
1801 /* If realization "failed" we'll have to update child state. */
1802 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1806 clutter_actor_real_unrealize (ClutterActor *self)
1808 /* we must be unmapped (implying our children are also unmapped) */
1809 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1813 * clutter_actor_unrealize:
1814 * @self: A #ClutterActor
1816 * Unrealization informs the actor that it may be being destroyed or
1817 * moved to another stage. The actor may want to destroy any
1818 * underlying graphics resources at this point. However it is
1819 * perfectly acceptable for it to retain the resources until the actor
1820 * is destroyed because Clutter only ever uses a single rendering
1821 * context and all of the graphics resources are valid on any stage.
1823 * Because mapped actors must be realized, actors may not be
1824 * unrealized if they are mapped. This function hides the actor to be
1825 * sure it isn't mapped, an application-visible side effect that you
1826 * may not be expecting.
1828 * This function should not be called by application code.
1831 clutter_actor_unrealize (ClutterActor *self)
1833 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1834 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1836 /* This function should not really be in the public API, because
1837 * there isn't a good reason to call it. ClutterActor will already
1838 * unrealize things for you when it's important to do so.
1840 * If you were using clutter_actor_unrealize() in a dispose
1841 * implementation, then don't, just chain up to ClutterActor's
1844 * If you were using clutter_actor_unrealize() to implement
1845 * unrealizing children of your container, then don't, ClutterActor
1846 * will already take care of that.
1848 * If you were using clutter_actor_unrealize() to re-realize to
1849 * create your resources in a different way, then use
1850 * _clutter_actor_rerealize() (inside Clutter) or just call your
1851 * code that recreates your resources directly (outside Clutter).
1854 #ifdef CLUTTER_ENABLE_DEBUG
1855 clutter_actor_verify_map_state (self);
1858 clutter_actor_hide (self);
1860 clutter_actor_unrealize_not_hiding (self);
1863 static ClutterActorTraverseVisitFlags
1864 unrealize_actor_before_children_cb (ClutterActor *self,
1868 /* If an actor is already unrealized we know its children have also
1869 * already been unrealized... */
1870 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1871 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1873 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1875 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1878 static ClutterActorTraverseVisitFlags
1879 unrealize_actor_after_children_cb (ClutterActor *self,
1883 /* We want to unset the realized flag only _after_
1884 * child actors are unrealized, to maintain invariants.
1886 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1887 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1888 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1892 * clutter_actor_unrealize_not_hiding:
1893 * @self: A #ClutterActor
1895 * Unrealization informs the actor that it may be being destroyed or
1896 * moved to another stage. The actor may want to destroy any
1897 * underlying graphics resources at this point. However it is
1898 * perfectly acceptable for it to retain the resources until the actor
1899 * is destroyed because Clutter only ever uses a single rendering
1900 * context and all of the graphics resources are valid on any stage.
1902 * Because mapped actors must be realized, actors may not be
1903 * unrealized if they are mapped. You must hide the actor or one of
1904 * its parents before attempting to unrealize.
1906 * This function is separate from clutter_actor_unrealize() because it
1907 * does not automatically hide the actor.
1908 * Actors need not be hidden to be unrealized, they just need to
1909 * be unmapped. In fact we don't want to mess up the application's
1910 * setting of the "visible" flag, so hiding is very undesirable.
1912 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1913 * backward compatibility.
1916 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1918 _clutter_actor_traverse (self,
1919 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1920 unrealize_actor_before_children_cb,
1921 unrealize_actor_after_children_cb,
1926 * _clutter_actor_rerealize:
1927 * @self: A #ClutterActor
1928 * @callback: Function to call while unrealized
1929 * @data: data for callback
1931 * If an actor is already unrealized, this just calls the callback.
1933 * If it is realized, it unrealizes temporarily, calls the callback,
1934 * and then re-realizes the actor.
1936 * As a side effect, leaves all children of the actor unrealized if
1937 * the actor was realized but not showing. This is because when we
1938 * unrealize the actor temporarily we must unrealize its children
1939 * (e.g. children of a stage can't be realized if stage window is
1940 * gone). And we aren't clever enough to save the realization state of
1941 * all children. In most cases this should not matter, because
1942 * the children will automatically realize when they next become mapped.
1945 _clutter_actor_rerealize (ClutterActor *self,
1946 ClutterCallback callback,
1949 gboolean was_mapped;
1950 gboolean was_showing;
1951 gboolean was_realized;
1953 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1955 #ifdef CLUTTER_ENABLE_DEBUG
1956 clutter_actor_verify_map_state (self);
1959 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1960 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1961 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1963 /* Must be unmapped to unrealize. Note we only have to hide this
1964 * actor if it was mapped (if all parents were showing). If actor
1965 * is merely visible (but not mapped), then that's fine, we can
1969 clutter_actor_hide (self);
1971 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1973 /* unrealize self and all children */
1974 clutter_actor_unrealize_not_hiding (self);
1976 if (callback != NULL)
1978 (* callback) (self, data);
1982 clutter_actor_show (self); /* will realize only if mapping implies it */
1983 else if (was_realized)
1984 clutter_actor_realize (self); /* realize self and all parents */
1988 clutter_actor_real_pick (ClutterActor *self,
1989 const ClutterColor *color)
1991 /* the default implementation is just to paint a rectangle
1992 * with the same size of the actor using the passed color
1994 if (clutter_actor_should_pick_paint (self))
1996 ClutterActorBox box = { 0, };
1997 float width, height;
1999 clutter_actor_get_allocation_box (self, &box);
2001 width = box.x2 - box.x1;
2002 height = box.y2 - box.y1;
2004 cogl_set_source_color4ub (color->red,
2009 cogl_rectangle (0, 0, width, height);
2012 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2013 * with existing container classes that override the pick() virtual
2014 * and chain up to the default implementation - otherwise we'll end up
2015 * painting our children twice.
2017 * this has to go away for 2.0; hopefully along the pick() itself.
2019 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2023 for (iter = self->priv->first_child;
2025 iter = iter->priv->next_sibling)
2026 clutter_actor_paint (iter);
2031 * clutter_actor_should_pick_paint:
2032 * @self: A #ClutterActor
2034 * Should be called inside the implementation of the
2035 * #ClutterActor::pick virtual function in order to check whether
2036 * the actor should paint itself in pick mode or not.
2038 * This function should never be called directly by applications.
2040 * Return value: %TRUE if the actor should paint its silhouette,
2044 clutter_actor_should_pick_paint (ClutterActor *self)
2046 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2048 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2049 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2050 CLUTTER_ACTOR_IS_REACTIVE (self)))
2057 clutter_actor_real_get_preferred_width (ClutterActor *self,
2059 gfloat *min_width_p,
2060 gfloat *natural_width_p)
2062 ClutterActorPrivate *priv = self->priv;
2064 if (priv->n_children != 0 &&
2065 priv->layout_manager != NULL)
2067 ClutterContainer *container = CLUTTER_CONTAINER (self);
2069 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2070 "for the preferred width",
2071 G_OBJECT_TYPE_NAME (priv->layout_manager),
2072 priv->layout_manager);
2074 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2083 /* Default implementation is always 0x0, usually an actor
2084 * using this default is relying on someone to set the
2087 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2092 if (natural_width_p)
2093 *natural_width_p = 0;
2097 clutter_actor_real_get_preferred_height (ClutterActor *self,
2099 gfloat *min_height_p,
2100 gfloat *natural_height_p)
2102 ClutterActorPrivate *priv = self->priv;
2104 if (priv->n_children != 0 &&
2105 priv->layout_manager != NULL)
2107 ClutterContainer *container = CLUTTER_CONTAINER (self);
2109 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2110 "for the preferred height",
2111 G_OBJECT_TYPE_NAME (priv->layout_manager),
2112 priv->layout_manager);
2114 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2122 /* Default implementation is always 0x0, usually an actor
2123 * using this default is relying on someone to set the
2126 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2131 if (natural_height_p)
2132 *natural_height_p = 0;
2136 clutter_actor_store_old_geometry (ClutterActor *self,
2137 ClutterActorBox *box)
2139 *box = self->priv->allocation;
2143 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2144 const ClutterActorBox *old)
2146 ClutterActorPrivate *priv = self->priv;
2147 GObject *obj = G_OBJECT (self);
2149 g_object_freeze_notify (obj);
2151 /* to avoid excessive requisition or allocation cycles we
2152 * use the cached values.
2154 * - if we don't have an allocation we assume that we need
2156 * - if we don't have a width or a height request we notify
2158 * - if we have a valid allocation then we check the old
2159 * bounding box with the current allocation and we notify
2162 if (priv->needs_allocation)
2164 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2165 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2166 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2167 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2169 else if (priv->needs_width_request || priv->needs_height_request)
2171 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2172 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2177 gfloat width, height;
2179 x = priv->allocation.x1;
2180 y = priv->allocation.y1;
2181 width = priv->allocation.x2 - priv->allocation.x1;
2182 height = priv->allocation.y2 - priv->allocation.y1;
2185 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2188 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2190 if (width != (old->x2 - old->x1))
2191 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2193 if (height != (old->y2 - old->y1))
2194 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2197 g_object_thaw_notify (obj);
2201 * clutter_actor_set_allocation_internal:
2202 * @self: a #ClutterActor
2203 * @box: a #ClutterActorBox
2204 * @flags: allocation flags
2206 * Stores the allocation of @self.
2208 * This function only performs basic storage and property notification.
2210 * This function should be called by clutter_actor_set_allocation()
2211 * and by the default implementation of #ClutterActorClass.allocate().
2213 * Return value: %TRUE if the allocation of the #ClutterActor has been
2214 * changed, and %FALSE otherwise
2216 static inline gboolean
2217 clutter_actor_set_allocation_internal (ClutterActor *self,
2218 const ClutterActorBox *box,
2219 ClutterAllocationFlags flags)
2221 ClutterActorPrivate *priv = self->priv;
2223 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2224 gboolean flags_changed;
2226 ClutterActorBox old_alloc = { 0, };
2228 obj = G_OBJECT (self);
2230 g_object_freeze_notify (obj);
2232 clutter_actor_store_old_geometry (self, &old_alloc);
2234 x1_changed = priv->allocation.x1 != box->x1;
2235 y1_changed = priv->allocation.y1 != box->y1;
2236 x2_changed = priv->allocation.x2 != box->x2;
2237 y2_changed = priv->allocation.y2 != box->y2;
2239 flags_changed = priv->allocation_flags != flags;
2241 priv->allocation = *box;
2242 priv->allocation_flags = flags;
2244 /* allocation is authoritative */
2245 priv->needs_width_request = FALSE;
2246 priv->needs_height_request = FALSE;
2247 priv->needs_allocation = FALSE;
2249 if (x1_changed || y1_changed ||
2250 x2_changed || y2_changed ||
2253 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2254 _clutter_actor_get_debug_name (self));
2256 priv->transform_valid = FALSE;
2258 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2260 /* if the allocation changes, so does the content box */
2261 if (priv->content != NULL)
2262 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2269 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2271 g_object_thaw_notify (obj);
2276 static void clutter_actor_real_allocate (ClutterActor *self,
2277 const ClutterActorBox *box,
2278 ClutterAllocationFlags flags);
2281 clutter_actor_maybe_layout_children (ClutterActor *self,
2282 const ClutterActorBox *allocation,
2283 ClutterAllocationFlags flags)
2285 ClutterActorPrivate *priv = self->priv;
2287 /* this is going to be a bit hard to follow, so let's put an explanation
2290 * we want ClutterActor to have a default layout manager if the actor was
2291 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2293 * we also want any subclass of ClutterActor that does not override the
2294 * ::allocate() virtual function to delegate to a layout manager.
2296 * finally, we want to allow people subclassing ClutterActor and overriding
2297 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2299 * on the other hand, we want existing actor subclasses overriding the
2300 * ::allocate() virtual function and chaining up to the parent's
2301 * implementation to continue working without allocating their children
2302 * twice, or without entering an allocation loop.
2304 * for the first two points, we check if the class of the actor is
2305 * overridding the ::allocate() virtual function; if it isn't, then we
2306 * follow through with checking whether we have children and a layout
2307 * manager, and eventually calling clutter_layout_manager_allocate().
2309 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2310 * allocation flags that we got passed, and if it is present, we continue
2311 * with the check above.
2313 * if neither of these two checks yields a positive result, we just
2314 * assume that the ::allocate() virtual function that resulted in this
2315 * function being called will also allocate the children of the actor.
2318 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2321 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2327 if (priv->n_children != 0 &&
2328 priv->layout_manager != NULL)
2330 ClutterContainer *container = CLUTTER_CONTAINER (self);
2331 ClutterAllocationFlags children_flags;
2332 ClutterActorBox children_box;
2334 /* normalize the box passed to the layout manager */
2335 children_box.x1 = children_box.y1 = 0.f;
2336 children_box.x2 = (allocation->x2 - allocation->x1);
2337 children_box.y2 = (allocation->y2 - allocation->y1);
2339 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2340 * the actor's children, since it refers only to the current
2341 * actor's allocation.
2343 children_flags = flags;
2344 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2346 CLUTTER_NOTE (LAYOUT,
2347 "Allocating %d children of %s "
2348 "at { %.2f, %.2f - %.2f x %.2f } "
2351 _clutter_actor_get_debug_name (self),
2354 (allocation->x2 - allocation->x1),
2355 (allocation->y2 - allocation->y1),
2356 G_OBJECT_TYPE_NAME (priv->layout_manager));
2358 clutter_layout_manager_allocate (priv->layout_manager,
2366 clutter_actor_real_allocate (ClutterActor *self,
2367 const ClutterActorBox *box,
2368 ClutterAllocationFlags flags)
2370 ClutterActorPrivate *priv = self->priv;
2373 g_object_freeze_notify (G_OBJECT (self));
2375 changed = clutter_actor_set_allocation_internal (self, box, flags);
2377 /* we allocate our children before we notify changes in our geometry,
2378 * so that people connecting to properties will be able to get valid
2379 * data out of the sub-tree of the scene graph that has this actor at
2382 clutter_actor_maybe_layout_children (self, box, flags);
2386 ClutterActorBox signal_box = priv->allocation;
2387 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2389 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2394 g_object_thaw_notify (G_OBJECT (self));
2398 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2399 ClutterActor *origin)
2401 /* no point in queuing a redraw on a destroyed actor */
2402 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2405 /* NB: We can't bail out early here if the actor is hidden in case
2406 * the actor bas been cloned. In this case the clone will need to
2407 * receive the signal so it can queue its own redraw.
2410 /* calls klass->queue_redraw in default handler */
2411 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2415 clutter_actor_real_queue_redraw (ClutterActor *self,
2416 ClutterActor *origin)
2418 ClutterActor *parent;
2420 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2421 _clutter_actor_get_debug_name (self),
2422 origin != NULL ? _clutter_actor_get_debug_name (origin)
2425 /* no point in queuing a redraw on a destroyed actor */
2426 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2429 /* If the queue redraw is coming from a child then the actor has
2430 become dirty and any queued effect is no longer valid */
2433 self->priv->is_dirty = TRUE;
2434 self->priv->effect_to_redraw = NULL;
2437 /* If the actor isn't visible, we still had to emit the signal
2438 * to allow for a ClutterClone, but the appearance of the parent
2439 * won't change so we don't have to propagate up the hierarchy.
2441 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2444 /* Although we could determine here that a full stage redraw
2445 * has already been queued and immediately bail out, we actually
2446 * guarantee that we will propagate a queue-redraw signal to our
2447 * parent at least once so that it's possible to implement a
2448 * container that tracks which of its children have queued a
2451 if (self->priv->propagated_one_redraw)
2453 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2454 if (stage != NULL &&
2455 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2459 self->priv->propagated_one_redraw = TRUE;
2461 /* notify parents, if they are all visible eventually we'll
2462 * queue redraw on the stage, which queues the redraw idle.
2464 parent = clutter_actor_get_parent (self);
2467 /* this will go up recursively */
2468 _clutter_actor_signal_queue_redraw (parent, origin);
2473 clutter_actor_real_queue_relayout (ClutterActor *self)
2475 ClutterActorPrivate *priv = self->priv;
2477 /* no point in queueing a redraw on a destroyed actor */
2478 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2481 priv->needs_width_request = TRUE;
2482 priv->needs_height_request = TRUE;
2483 priv->needs_allocation = TRUE;
2485 /* reset the cached size requests */
2486 memset (priv->width_requests, 0,
2487 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2488 memset (priv->height_requests, 0,
2489 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2491 /* We need to go all the way up the hierarchy */
2492 if (priv->parent != NULL)
2493 _clutter_actor_queue_only_relayout (priv->parent);
2497 * clutter_actor_apply_relative_transform_to_point:
2498 * @self: A #ClutterActor
2499 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2500 * default #ClutterStage
2501 * @point: A point as #ClutterVertex
2502 * @vertex: (out caller-allocates): The translated #ClutterVertex
2504 * Transforms @point in coordinates relative to the actor into
2505 * ancestor-relative coordinates using the relevant transform
2506 * stack (i.e. scale, rotation, etc).
2508 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2509 * this case, the coordinates returned will be the coordinates on
2510 * the stage before the projection is applied. This is different from
2511 * the behaviour of clutter_actor_apply_transform_to_point().
2516 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2517 ClutterActor *ancestor,
2518 const ClutterVertex *point,
2519 ClutterVertex *vertex)
2524 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2525 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2526 g_return_if_fail (point != NULL);
2527 g_return_if_fail (vertex != NULL);
2532 if (ancestor == NULL)
2533 ancestor = _clutter_actor_get_stage_internal (self);
2535 if (ancestor == NULL)
2541 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2542 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2546 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2547 const ClutterVertex *vertices_in,
2548 ClutterVertex *vertices_out,
2551 ClutterActor *stage;
2552 CoglMatrix modelview;
2553 CoglMatrix projection;
2556 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2558 stage = _clutter_actor_get_stage_internal (self);
2560 /* We really can't do anything meaningful in this case so don't try
2561 * to do any transform */
2565 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2566 * that gets us to stage coordinates, we want to go all the way to eye
2568 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2570 /* Fetch the projection and viewport */
2571 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2572 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2578 _clutter_util_fully_transform_vertices (&modelview,
2589 * clutter_actor_apply_transform_to_point:
2590 * @self: A #ClutterActor
2591 * @point: A point as #ClutterVertex
2592 * @vertex: (out caller-allocates): The translated #ClutterVertex
2594 * Transforms @point in coordinates relative to the actor
2595 * into screen-relative coordinates with the current actor
2596 * transformation (i.e. scale, rotation, etc)
2601 clutter_actor_apply_transform_to_point (ClutterActor *self,
2602 const ClutterVertex *point,
2603 ClutterVertex *vertex)
2605 g_return_if_fail (point != NULL);
2606 g_return_if_fail (vertex != NULL);
2607 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2611 * _clutter_actor_get_relative_transformation_matrix:
2612 * @self: The actor whose coordinate space you want to transform from.
2613 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2614 * or %NULL if you want to transform all the way to eye coordinates.
2615 * @matrix: A #CoglMatrix to store the transformation
2617 * This gets a transformation @matrix that will transform coordinates from the
2618 * coordinate space of @self into the coordinate space of @ancestor.
2620 * For example if you need a matrix that can transform the local actor
2621 * coordinates of @self into stage coordinates you would pass the actor's stage
2622 * pointer as the @ancestor.
2624 * If you pass %NULL then the transformation will take you all the way through
2625 * to eye coordinates. This can be useful if you want to extract the entire
2626 * modelview transform that Clutter applies before applying the projection
2627 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2628 * using cogl_set_modelview_matrix() for example then you would want a matrix
2629 * that transforms into eye coordinates.
2631 * <note><para>This function explicitly initializes the given @matrix. If you just
2632 * want clutter to multiply a relative transformation with an existing matrix
2633 * you can use clutter_actor_apply_relative_transformation_matrix()
2634 * instead.</para></note>
2637 /* XXX: We should consider caching the stage relative modelview along with
2638 * the actor itself */
2640 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2641 ClutterActor *ancestor,
2644 cogl_matrix_init_identity (matrix);
2646 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2649 /* Project the given @box into stage window coordinates, writing the
2650 * transformed vertices to @verts[]. */
2652 _clutter_actor_transform_and_project_box (ClutterActor *self,
2653 const ClutterActorBox *box,
2654 ClutterVertex verts[])
2656 ClutterVertex box_vertices[4];
2658 box_vertices[0].x = box->x1;
2659 box_vertices[0].y = box->y1;
2660 box_vertices[0].z = 0;
2661 box_vertices[1].x = box->x2;
2662 box_vertices[1].y = box->y1;
2663 box_vertices[1].z = 0;
2664 box_vertices[2].x = box->x1;
2665 box_vertices[2].y = box->y2;
2666 box_vertices[2].z = 0;
2667 box_vertices[3].x = box->x2;
2668 box_vertices[3].y = box->y2;
2669 box_vertices[3].z = 0;
2672 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2676 * clutter_actor_get_allocation_vertices:
2677 * @self: A #ClutterActor
2678 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2679 * against, or %NULL to use the #ClutterStage
2680 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2681 * location for an array of 4 #ClutterVertex in which to store the result
2683 * Calculates the transformed coordinates of the four corners of the
2684 * actor in the plane of @ancestor. The returned vertices relate to
2685 * the #ClutterActorBox coordinates as follows:
2687 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2688 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2689 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2690 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2693 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2694 * this case, the coordinates returned will be the coordinates on
2695 * the stage before the projection is applied. This is different from
2696 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2701 clutter_actor_get_allocation_vertices (ClutterActor *self,
2702 ClutterActor *ancestor,
2703 ClutterVertex verts[])
2705 ClutterActorPrivate *priv;
2706 ClutterActorBox box;
2707 ClutterVertex vertices[4];
2708 CoglMatrix modelview;
2710 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2711 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2713 if (ancestor == NULL)
2714 ancestor = _clutter_actor_get_stage_internal (self);
2716 /* Fallback to a NOP transform if the actor isn't parented under a
2718 if (ancestor == NULL)
2723 /* if the actor needs to be allocated we force a relayout, so that
2724 * we will have valid values to use in the transformations */
2725 if (priv->needs_allocation)
2727 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2729 _clutter_stage_maybe_relayout (stage);
2732 box.x1 = box.y1 = 0;
2733 /* The result isn't really meaningful in this case but at
2734 * least try to do something *vaguely* reasonable... */
2735 clutter_actor_get_size (self, &box.x2, &box.y2);
2739 clutter_actor_get_allocation_box (self, &box);
2741 vertices[0].x = box.x1;
2742 vertices[0].y = box.y1;
2744 vertices[1].x = box.x2;
2745 vertices[1].y = box.y1;
2747 vertices[2].x = box.x1;
2748 vertices[2].y = box.y2;
2750 vertices[3].x = box.x2;
2751 vertices[3].y = box.y2;
2754 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2757 cogl_matrix_transform_points (&modelview,
2759 sizeof (ClutterVertex),
2761 sizeof (ClutterVertex),
2767 * clutter_actor_get_abs_allocation_vertices:
2768 * @self: A #ClutterActor
2769 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2770 * of 4 #ClutterVertex where to store the result.
2772 * Calculates the transformed screen coordinates of the four corners of
2773 * the actor; the returned vertices relate to the #ClutterActorBox
2774 * coordinates as follows:
2776 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2777 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2778 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2779 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2785 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2786 ClutterVertex verts[])
2788 ClutterActorPrivate *priv;
2789 ClutterActorBox actor_space_allocation;
2791 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2795 /* if the actor needs to be allocated we force a relayout, so that
2796 * the actor allocation box will be valid for
2797 * _clutter_actor_transform_and_project_box()
2799 if (priv->needs_allocation)
2801 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2802 /* There's nothing meaningful we can do now */
2806 _clutter_stage_maybe_relayout (stage);
2809 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2810 * own coordinate space... */
2811 actor_space_allocation.x1 = 0;
2812 actor_space_allocation.y1 = 0;
2813 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2814 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2815 _clutter_actor_transform_and_project_box (self,
2816 &actor_space_allocation,
2821 clutter_actor_real_apply_transform (ClutterActor *self,
2824 ClutterActorPrivate *priv = self->priv;
2826 if (!priv->transform_valid)
2828 CoglMatrix *transform = &priv->transform;
2829 const ClutterTransformInfo *info;
2831 info = _clutter_actor_get_transform_info_or_defaults (self);
2833 cogl_matrix_init_identity (transform);
2835 cogl_matrix_translate (transform,
2836 priv->allocation.x1,
2837 priv->allocation.y1,
2841 cogl_matrix_translate (transform, 0, 0, info->depth);
2844 * because the rotation involves translations, we must scale
2845 * before applying the rotations (if we apply the scale after
2846 * the rotations, the translations included in the rotation are
2847 * not scaled and so the entire object will move on the screen
2848 * as a result of rotating it).
2850 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2852 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2853 &info->scale_center,
2854 cogl_matrix_scale (transform,
2861 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2863 cogl_matrix_rotate (transform,
2868 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2870 cogl_matrix_rotate (transform,
2875 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2877 cogl_matrix_rotate (transform,
2881 if (!clutter_anchor_coord_is_zero (&info->anchor))
2885 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2886 cogl_matrix_translate (transform, -x, -y, -z);
2889 priv->transform_valid = TRUE;
2892 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2895 /* Applies the transforms associated with this actor to the given
2898 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2901 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2905 * clutter_actor_apply_relative_transformation_matrix:
2906 * @self: The actor whose coordinate space you want to transform from.
2907 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2908 * or %NULL if you want to transform all the way to eye coordinates.
2909 * @matrix: A #CoglMatrix to apply the transformation too.
2911 * This multiplies a transform with @matrix that will transform coordinates
2912 * from the coordinate space of @self into the coordinate space of @ancestor.
2914 * For example if you need a matrix that can transform the local actor
2915 * coordinates of @self into stage coordinates you would pass the actor's stage
2916 * pointer as the @ancestor.
2918 * If you pass %NULL then the transformation will take you all the way through
2919 * to eye coordinates. This can be useful if you want to extract the entire
2920 * modelview transform that Clutter applies before applying the projection
2921 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2922 * using cogl_set_modelview_matrix() for example then you would want a matrix
2923 * that transforms into eye coordinates.
2925 * <note>This function doesn't initialize the given @matrix, it simply
2926 * multiplies the requested transformation matrix with the existing contents of
2927 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2928 * before calling this function, or you can use
2929 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2932 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2933 ClutterActor *ancestor,
2936 ClutterActor *parent;
2938 /* Note we terminate before ever calling stage->apply_transform()
2939 * since that would conceptually be relative to the underlying
2940 * window OpenGL coordinates so we'd need a special @ancestor
2941 * value to represent the fake parent of the stage. */
2942 if (self == ancestor)
2945 parent = clutter_actor_get_parent (self);
2948 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2951 _clutter_actor_apply_modelview_transform (self, matrix);
2955 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2956 ClutterPaintVolume *pv,
2958 const CoglColor *color)
2960 static CoglPipeline *outline = NULL;
2961 CoglPrimitive *prim;
2962 ClutterVertex line_ends[12 * 2];
2965 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2966 /* XXX: at some point we'll query this from the stage but we can't
2967 * do that until the osx backend uses Cogl natively. */
2968 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2970 if (outline == NULL)
2971 outline = cogl_pipeline_new (ctx);
2973 _clutter_paint_volume_complete (pv);
2975 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2978 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2979 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2980 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2981 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2986 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2987 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2988 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2989 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2991 /* Lines connecting front face to back face */
2992 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2993 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2994 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2995 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2998 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3000 (CoglVertexP3 *)line_ends);
3002 cogl_pipeline_set_color (outline, color);
3003 cogl_framebuffer_draw_primitive (fb, outline, prim);
3004 cogl_object_unref (prim);
3008 PangoLayout *layout;
3009 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3010 pango_layout_set_text (layout, label, -1);
3011 cogl_pango_render_layout (layout,
3016 g_object_unref (layout);
3021 _clutter_actor_draw_paint_volume (ClutterActor *self)
3023 ClutterPaintVolume *pv;
3026 pv = _clutter_actor_get_paint_volume_mutable (self);
3029 gfloat width, height;
3030 ClutterPaintVolume fake_pv;
3032 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3033 _clutter_paint_volume_init_static (&fake_pv, stage);
3035 clutter_actor_get_size (self, &width, &height);
3036 clutter_paint_volume_set_width (&fake_pv, width);
3037 clutter_paint_volume_set_height (&fake_pv, height);
3039 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3040 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3041 _clutter_actor_get_debug_name (self),
3044 clutter_paint_volume_free (&fake_pv);
3048 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3049 _clutter_actor_draw_paint_volume_full (self, pv,
3050 _clutter_actor_get_debug_name (self),
3056 _clutter_actor_paint_cull_result (ClutterActor *self,
3058 ClutterCullResult result)
3060 ClutterPaintVolume *pv;
3065 if (result == CLUTTER_CULL_RESULT_IN)
3066 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3067 else if (result == CLUTTER_CULL_RESULT_OUT)
3068 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3070 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3073 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3075 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3076 _clutter_actor_draw_paint_volume_full (self, pv,
3077 _clutter_actor_get_debug_name (self),
3081 PangoLayout *layout;
3083 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3084 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3085 cogl_set_source_color (&color);
3087 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3088 pango_layout_set_text (layout, label, -1);
3089 cogl_pango_render_layout (layout,
3095 g_object_unref (layout);
3099 static int clone_paint_level = 0;
3102 _clutter_actor_push_clone_paint (void)
3104 clone_paint_level++;
3108 _clutter_actor_pop_clone_paint (void)
3110 clone_paint_level--;
3114 in_clone_paint (void)
3116 return clone_paint_level > 0;
3119 /* Returns TRUE if the actor can be ignored */
3120 /* FIXME: we should return a ClutterCullResult, and
3121 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3122 * means there's no point in trying to cull descendants of the current
3125 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3127 ClutterActorPrivate *priv = self->priv;
3128 ClutterActor *stage;
3129 const ClutterPlane *stage_clip;
3131 if (!priv->last_paint_volume_valid)
3133 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3134 "->last_paint_volume_valid == FALSE",
3135 _clutter_actor_get_debug_name (self));
3139 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3142 stage = _clutter_actor_get_stage_internal (self);
3143 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3144 if (G_UNLIKELY (!stage_clip))
3146 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3147 "No stage clip set",
3148 _clutter_actor_get_debug_name (self));
3152 if (cogl_get_draw_framebuffer () !=
3153 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3155 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3156 "Current framebuffer doesn't correspond to stage",
3157 _clutter_actor_get_debug_name (self));
3162 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3167 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3169 ClutterActorPrivate *priv = self->priv;
3170 const ClutterPaintVolume *pv;
3172 if (priv->last_paint_volume_valid)
3174 clutter_paint_volume_free (&priv->last_paint_volume);
3175 priv->last_paint_volume_valid = FALSE;
3178 pv = clutter_actor_get_paint_volume (self);
3181 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3182 "Actor failed to report a paint volume",
3183 _clutter_actor_get_debug_name (self));
3187 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3189 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3190 NULL); /* eye coordinates */
3192 priv->last_paint_volume_valid = TRUE;
3195 static inline gboolean
3196 actor_has_shader_data (ClutterActor *self)
3198 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3202 _clutter_actor_get_pick_id (ClutterActor *self)
3204 if (self->priv->pick_id < 0)
3207 return self->priv->pick_id;
3210 /* This is the same as clutter_actor_add_effect except that it doesn't
3211 queue a redraw and it doesn't notify on the effect property */
3213 _clutter_actor_add_effect_internal (ClutterActor *self,
3214 ClutterEffect *effect)
3216 ClutterActorPrivate *priv = self->priv;
3218 if (priv->effects == NULL)
3220 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3221 priv->effects->actor = self;
3224 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3227 /* This is the same as clutter_actor_remove_effect except that it doesn't
3228 queue a redraw and it doesn't notify on the effect property */
3230 _clutter_actor_remove_effect_internal (ClutterActor *self,
3231 ClutterEffect *effect)
3233 ClutterActorPrivate *priv = self->priv;
3235 if (priv->effects == NULL)
3238 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3242 needs_flatten_effect (ClutterActor *self)
3244 ClutterActorPrivate *priv = self->priv;
3246 if (G_UNLIKELY (clutter_paint_debug_flags &
3247 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3250 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3252 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3254 if (clutter_actor_get_paint_opacity (self) < 255 &&
3255 clutter_actor_has_overlaps (self))
3263 add_or_remove_flatten_effect (ClutterActor *self)
3265 ClutterActorPrivate *priv = self->priv;
3267 /* Add or remove the flatten effect depending on the
3268 offscreen-redirect property. */
3269 if (needs_flatten_effect (self))
3271 if (priv->flatten_effect == NULL)
3273 ClutterActorMeta *actor_meta;
3276 priv->flatten_effect = _clutter_flatten_effect_new ();
3277 /* Keep a reference to the effect so that we can queue
3279 g_object_ref_sink (priv->flatten_effect);
3281 /* Set the priority of the effect to high so that it will
3282 always be applied to the actor first. It uses an internal
3283 priority so that it won't be visible to applications */
3284 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3285 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3286 _clutter_actor_meta_set_priority (actor_meta, priority);
3288 /* This will add the effect without queueing a redraw */
3289 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3294 if (priv->flatten_effect != NULL)
3296 /* Destroy the effect so that it will lose its fbo cache of
3298 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3299 g_clear_object (&priv->flatten_effect);
3305 clutter_actor_real_paint (ClutterActor *actor)
3307 ClutterActorPrivate *priv = actor->priv;
3310 for (iter = priv->first_child;
3312 iter = iter->priv->next_sibling)
3314 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3315 _clutter_actor_get_debug_name (iter),
3316 _clutter_actor_get_debug_name (actor),
3317 iter->priv->allocation.x1,
3318 iter->priv->allocation.y1,
3319 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3320 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3322 clutter_actor_paint (iter);
3327 clutter_actor_paint_node (ClutterActor *actor,
3328 ClutterPaintNode *root)
3330 ClutterActorPrivate *priv = actor->priv;
3335 if (priv->bg_color_set &&
3336 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3338 ClutterPaintNode *node;
3339 ClutterColor bg_color;
3340 ClutterActorBox box;
3344 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3345 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3347 bg_color = priv->bg_color;
3348 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3349 * priv->bg_color.alpha
3352 node = clutter_color_node_new (&bg_color);
3353 clutter_paint_node_set_name (node, "backgroundColor");
3354 clutter_paint_node_add_rectangle (node, &box);
3355 clutter_paint_node_add_child (root, node);
3356 clutter_paint_node_unref (node);
3359 if (priv->content != NULL)
3360 _clutter_content_paint_content (priv->content, actor, root);
3362 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3363 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3365 if (clutter_paint_node_get_n_children (root) == 0)
3368 #ifdef CLUTTER_ENABLE_DEBUG
3369 if (CLUTTER_HAS_DEBUG (PAINT))
3371 /* dump the tree only if we have one */
3372 _clutter_paint_node_dump_tree (root);
3374 #endif /* CLUTTER_ENABLE_DEBUG */
3376 _clutter_paint_node_paint (root);
3379 /* XXX: Uncomment this when we disable emitting the paint signal */
3380 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3387 * clutter_actor_paint:
3388 * @self: A #ClutterActor
3390 * Renders the actor to display.
3392 * This function should not be called directly by applications.
3393 * Call clutter_actor_queue_redraw() to queue paints, instead.
3395 * This function is context-aware, and will either cause a
3396 * regular paint or a pick paint.
3398 * This function will emit the #ClutterActor::paint signal or
3399 * the #ClutterActor::pick signal, depending on the context.
3401 * This function does not paint the actor if the actor is set to 0,
3402 * unless it is performing a pick paint.
3405 clutter_actor_paint (ClutterActor *self)
3407 ClutterActorPrivate *priv;
3408 ClutterPickMode pick_mode;
3409 gboolean clip_set = FALSE;
3410 gboolean shader_applied = FALSE;
3412 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3413 "Actor real-paint counter",
3414 "Increments each time any actor is painted",
3415 0 /* no application private data */);
3416 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3417 "Actor pick-paint counter",
3418 "Increments each time any actor is painted "
3420 0 /* no application private data */);
3422 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3424 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3429 pick_mode = _clutter_context_get_pick_mode ();
3431 if (pick_mode == CLUTTER_PICK_NONE)
3432 priv->propagated_one_redraw = FALSE;
3434 /* It's an important optimization that we consider painting of
3435 * actors with 0 opacity to be a NOP... */
3436 if (pick_mode == CLUTTER_PICK_NONE &&
3437 /* ignore top-levels, since they might be transparent */
3438 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3439 /* Use the override opacity if its been set */
3440 ((priv->opacity_override >= 0) ?
3441 priv->opacity_override : priv->opacity) == 0)
3444 /* if we aren't paintable (not in a toplevel with all
3445 * parents paintable) then do nothing.
3447 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3450 /* mark that we are in the paint process */
3451 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3455 if (priv->enable_model_view_transform)
3459 /* XXX: It could be better to cache the modelview with the actor
3460 * instead of progressively building up the transformations on
3461 * the matrix stack every time we paint. */
3462 cogl_get_modelview_matrix (&matrix);
3463 _clutter_actor_apply_modelview_transform (self, &matrix);
3465 #ifdef CLUTTER_ENABLE_DEBUG
3466 /* Catch when out-of-band transforms have been made by actors not as part
3467 * of an apply_transform vfunc... */
3468 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3470 CoglMatrix expected_matrix;
3472 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3475 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3477 GString *buf = g_string_sized_new (1024);
3478 ClutterActor *parent;
3481 while (parent != NULL)
3483 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3485 if (parent->priv->parent != NULL)
3486 g_string_append (buf, "->");
3488 parent = parent->priv->parent;
3491 g_warning ("Unexpected transform found when painting actor "
3492 "\"%s\". This will be caused by one of the actor's "
3493 "ancestors (%s) using the Cogl API directly to transform "
3494 "children instead of using ::apply_transform().",
3495 _clutter_actor_get_debug_name (self),
3498 g_string_free (buf, TRUE);
3501 #endif /* CLUTTER_ENABLE_DEBUG */
3503 cogl_set_modelview_matrix (&matrix);
3508 cogl_clip_push_rectangle (priv->clip.x,
3510 priv->clip.x + priv->clip.width,
3511 priv->clip.y + priv->clip.height);
3514 else if (priv->clip_to_allocation)
3516 gfloat width, height;
3518 width = priv->allocation.x2 - priv->allocation.x1;
3519 height = priv->allocation.y2 - priv->allocation.y1;
3521 cogl_clip_push_rectangle (0, 0, width, height);
3525 if (pick_mode == CLUTTER_PICK_NONE)
3527 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3529 /* We check whether we need to add the flatten effect before
3530 each paint so that we can avoid having a mechanism for
3531 applications to notify when the value of the
3532 has_overlaps virtual changes. */
3533 add_or_remove_flatten_effect (self);
3536 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3538 /* We save the current paint volume so that the next time the
3539 * actor queues a redraw we can constrain the redraw to just
3540 * cover the union of the new bounding box and the old.
3542 * We also fetch the current paint volume to perform culling so
3543 * we can avoid painting actors outside the current clip region.
3545 * If we are painting inside a clone, we should neither update
3546 * the paint volume or use it to cull painting, since the paint
3547 * box represents the location of the source actor on the
3550 * XXX: We are starting to do a lot of vertex transforms on
3551 * the CPU in a typical paint, so at some point we should
3552 * audit these and consider caching some things.
3554 * NB: We don't perform culling while picking at this point because
3555 * clutter-stage.c doesn't setup the clipping planes appropriately.
3557 * NB: We don't want to update the last-paint-volume during picking
3558 * because the last-paint-volume is used to determine the old screen
3559 * space location of an actor that has moved so we can know the
3560 * minimal region to redraw to clear an old view of the actor. If we
3561 * update this during picking then by the time we come around to
3562 * paint then the last-paint-volume would likely represent the new
3563 * actor position not the old.
3565 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3568 /* annoyingly gcc warns if uninitialized even though
3569 * the initialization is redundant :-( */
3570 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3572 if (G_LIKELY ((clutter_paint_debug_flags &
3573 (CLUTTER_DEBUG_DISABLE_CULLING |
3574 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3575 (CLUTTER_DEBUG_DISABLE_CULLING |
3576 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3577 _clutter_actor_update_last_paint_volume (self);
3579 success = cull_actor (self, &result);
3581 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3582 _clutter_actor_paint_cull_result (self, success, result);
3583 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3587 if (priv->effects == NULL)
3589 if (pick_mode == CLUTTER_PICK_NONE &&
3590 actor_has_shader_data (self))
3592 _clutter_actor_shader_pre_paint (self, FALSE);
3593 shader_applied = TRUE;
3596 priv->next_effect_to_paint = NULL;
3599 priv->next_effect_to_paint =
3600 _clutter_meta_group_peek_metas (priv->effects);
3602 clutter_actor_continue_paint (self);
3605 _clutter_actor_shader_post_paint (self);
3607 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3608 pick_mode == CLUTTER_PICK_NONE))
3609 _clutter_actor_draw_paint_volume (self);
3612 /* If we make it here then the actor has run through a complete
3613 paint run including all the effects so it's no longer dirty */
3614 if (pick_mode == CLUTTER_PICK_NONE)
3615 priv->is_dirty = FALSE;
3622 /* paint sequence complete */
3623 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3627 * clutter_actor_continue_paint:
3628 * @self: A #ClutterActor
3630 * Run the next stage of the paint sequence. This function should only
3631 * be called within the implementation of the ‘run’ virtual of a
3632 * #ClutterEffect. It will cause the run method of the next effect to
3633 * be applied, or it will paint the actual actor if the current effect
3634 * is the last effect in the chain.
3639 clutter_actor_continue_paint (ClutterActor *self)
3641 ClutterActorPrivate *priv;
3643 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3644 /* This should only be called from with in the ‘run’ implementation
3645 of a ClutterEffect */
3646 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3650 /* Skip any effects that are disabled */
3651 while (priv->next_effect_to_paint &&
3652 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3653 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3655 /* If this has come from the last effect then we'll just paint the
3657 if (priv->next_effect_to_paint == NULL)
3659 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3661 ClutterPaintNode *dummy;
3663 /* XXX - this will go away in 2.0, when we can get rid of this
3664 * stuff and switch to a pure retained render tree of PaintNodes
3665 * for the entire frame, starting from the Stage; the paint()
3666 * virtual function can then be called directly.
3668 dummy = _clutter_dummy_node_new (self);
3669 clutter_paint_node_set_name (dummy, "Root");
3671 /* XXX - for 1.12, we use the return value of paint_node() to
3672 * decide whether we should emit the ::paint signal.
3674 clutter_actor_paint_node (self, dummy);
3675 clutter_paint_node_unref (dummy);
3677 g_signal_emit (self, actor_signals[PAINT], 0);
3681 ClutterColor col = { 0, };
3683 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3685 /* Actor will then paint silhouette of itself in supplied
3686 * color. See clutter_stage_get_actor_at_pos() for where
3687 * picking is enabled.
3689 g_signal_emit (self, actor_signals[PICK], 0, &col);
3694 ClutterEffect *old_current_effect;
3695 ClutterEffectPaintFlags run_flags = 0;
3697 /* Cache the current effect so that we can put it back before
3699 old_current_effect = priv->current_effect;
3701 priv->current_effect = priv->next_effect_to_paint->data;
3702 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3704 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3708 /* If there's an effect queued with this redraw then all
3709 effects up to that one will be considered dirty. It
3710 is expected the queued effect will paint the cached
3711 image and not call clutter_actor_continue_paint again
3712 (although it should work ok if it does) */
3713 if (priv->effect_to_redraw == NULL ||
3714 priv->current_effect != priv->effect_to_redraw)
3715 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3718 _clutter_effect_paint (priv->current_effect, run_flags);
3722 /* We can't determine when an actor has been modified since
3723 its last pick so lets just assume it has always been
3725 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3727 _clutter_effect_pick (priv->current_effect, run_flags);
3730 priv->current_effect = old_current_effect;
3734 static ClutterActorTraverseVisitFlags
3735 invalidate_queue_redraw_entry (ClutterActor *self,
3739 ClutterActorPrivate *priv = self->priv;
3741 if (priv->queue_redraw_entry != NULL)
3743 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3744 priv->queue_redraw_entry = NULL;
3747 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3751 remove_child (ClutterActor *self,
3752 ClutterActor *child)
3754 ClutterActor *prev_sibling, *next_sibling;
3756 prev_sibling = child->priv->prev_sibling;
3757 next_sibling = child->priv->next_sibling;
3759 if (prev_sibling != NULL)
3760 prev_sibling->priv->next_sibling = next_sibling;
3762 if (next_sibling != NULL)
3763 next_sibling->priv->prev_sibling = prev_sibling;
3765 if (self->priv->first_child == child)
3766 self->priv->first_child = next_sibling;
3768 if (self->priv->last_child == child)
3769 self->priv->last_child = prev_sibling;
3771 child->priv->parent = NULL;
3772 child->priv->prev_sibling = NULL;
3773 child->priv->next_sibling = NULL;
3777 REMOVE_CHILD_DESTROY_META = 1 << 0,
3778 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3779 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3780 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3781 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3782 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3784 /* default flags for public API */
3785 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3786 REMOVE_CHILD_EMIT_PARENT_SET |
3787 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3788 REMOVE_CHILD_CHECK_STATE |
3789 REMOVE_CHILD_FLUSH_QUEUE |
3790 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3792 /* flags for legacy/deprecated API */
3793 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3794 REMOVE_CHILD_FLUSH_QUEUE |
3795 REMOVE_CHILD_EMIT_PARENT_SET |
3796 REMOVE_CHILD_NOTIFY_FIRST_LAST
3797 } ClutterActorRemoveChildFlags;
3800 * clutter_actor_remove_child_internal:
3801 * @self: a #ClutterActor
3802 * @child: the child of @self that has to be removed
3803 * @flags: control the removal operations
3805 * Removes @child from the list of children of @self.
3808 clutter_actor_remove_child_internal (ClutterActor *self,
3809 ClutterActor *child,
3810 ClutterActorRemoveChildFlags flags)
3812 ClutterActor *old_first, *old_last;
3813 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3814 gboolean flush_queue;
3815 gboolean notify_first_last;
3816 gboolean was_mapped;
3818 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3819 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3820 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3821 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3822 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3823 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3825 g_object_freeze_notify (G_OBJECT (self));
3828 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3832 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3834 /* we need to unrealize *before* we set parent_actor to NULL,
3835 * because in an unrealize method actors are dissociating from the
3836 * stage, which means they need to be able to
3837 * clutter_actor_get_stage().
3839 * yhis should unmap and unrealize, unless we're reparenting.
3841 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3848 /* We take this opportunity to invalidate any queue redraw entry
3849 * associated with the actor and descendants since we won't be able to
3850 * determine the appropriate stage after this.
3852 * we do this after we updated the mapped state because actors might
3853 * end up queueing redraws inside their mapped/unmapped virtual
3854 * functions, and if we invalidate the redraw entry we could end up
3855 * with an inconsistent state and weird memory corruption. see
3858 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3859 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3861 _clutter_actor_traverse (child,
3863 invalidate_queue_redraw_entry,
3868 old_first = self->priv->first_child;
3869 old_last = self->priv->last_child;
3871 remove_child (self, child);
3873 self->priv->n_children -= 1;
3875 self->priv->age += 1;
3877 /* clutter_actor_reparent() will emit ::parent-set for us */
3878 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3879 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3881 /* if the child was mapped then we need to relayout ourselves to account
3882 * for the removed child
3885 clutter_actor_queue_relayout (self);
3887 /* we need to emit the signal before dropping the reference */
3888 if (emit_actor_removed)
3889 g_signal_emit_by_name (self, "actor-removed", child);
3891 if (notify_first_last)
3893 if (old_first != self->priv->first_child)
3894 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3896 if (old_last != self->priv->last_child)
3897 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3900 g_object_thaw_notify (G_OBJECT (self));
3902 /* remove the reference we acquired in clutter_actor_add_child() */
3903 g_object_unref (child);
3906 static const ClutterTransformInfo default_transform_info = {
3907 0.0, { 0, }, /* rotation-x */
3908 0.0, { 0, }, /* rotation-y */
3909 0.0, { 0, }, /* rotation-z */
3911 1.0, 1.0, { 0, }, /* scale */
3913 { 0, }, /* anchor */
3919 * _clutter_actor_get_transform_info_or_defaults:
3920 * @self: a #ClutterActor
3922 * Retrieves the ClutterTransformInfo structure associated to an actor.
3924 * If the actor does not have a ClutterTransformInfo structure associated
3925 * to it, then the default structure will be returned.
3927 * This function should only be used for getters.
3929 * Return value: a const pointer to the ClutterTransformInfo structure
3931 const ClutterTransformInfo *
3932 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3934 ClutterTransformInfo *info;
3936 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3940 return &default_transform_info;
3944 clutter_transform_info_free (gpointer data)
3947 g_slice_free (ClutterTransformInfo, data);
3951 * _clutter_actor_get_transform_info:
3952 * @self: a #ClutterActor
3954 * Retrieves a pointer to the ClutterTransformInfo structure.
3956 * If the actor does not have a ClutterTransformInfo associated to it, one
3957 * will be created and initialized to the default values.
3959 * This function should be used for setters.
3961 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3964 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3967 ClutterTransformInfo *
3968 _clutter_actor_get_transform_info (ClutterActor *self)
3970 ClutterTransformInfo *info;
3972 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3975 info = g_slice_new (ClutterTransformInfo);
3977 *info = default_transform_info;
3979 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3981 clutter_transform_info_free);
3988 * clutter_actor_set_rotation_angle_internal:
3989 * @self: a #ClutterActor
3990 * @axis: the axis of the angle to change
3991 * @angle: the angle of rotation
3993 * Sets the rotation angle on the given axis without affecting the
3994 * rotation center point.
3997 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3998 ClutterRotateAxis axis,
4001 GObject *obj = G_OBJECT (self);
4002 ClutterTransformInfo *info;
4004 info = _clutter_actor_get_transform_info (self);
4006 g_object_freeze_notify (obj);
4010 case CLUTTER_X_AXIS:
4011 info->rx_angle = angle;
4012 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4015 case CLUTTER_Y_AXIS:
4016 info->ry_angle = angle;
4017 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4020 case CLUTTER_Z_AXIS:
4021 info->rz_angle = angle;
4022 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4026 self->priv->transform_valid = FALSE;
4028 g_object_thaw_notify (obj);
4030 clutter_actor_queue_redraw (self);
4034 clutter_actor_set_rotation_angle (ClutterActor *self,
4035 ClutterRotateAxis axis,
4038 const ClutterTransformInfo *info;
4039 const double *cur_angle_p = NULL;
4040 GParamSpec *pspec = NULL;
4042 info = _clutter_actor_get_transform_info_or_defaults (self);
4046 case CLUTTER_X_AXIS:
4047 cur_angle_p = &info->rx_angle;
4048 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4051 case CLUTTER_Y_AXIS:
4052 cur_angle_p = &info->ry_angle;
4053 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4056 case CLUTTER_Z_AXIS:
4057 cur_angle_p = &info->rz_angle;
4058 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4062 g_assert (pspec != NULL);
4063 g_assert (cur_angle_p != NULL);
4065 if (_clutter_actor_get_transition (self, pspec) == NULL)
4066 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4068 _clutter_actor_update_transition (self, pspec, angle);
4070 clutter_actor_queue_redraw (self);
4074 * clutter_actor_set_rotation_center_internal:
4075 * @self: a #ClutterActor
4076 * @axis: the axis of the center to change
4077 * @center: the coordinates of the rotation center
4079 * Sets the rotation center on the given axis without affecting the
4083 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4084 ClutterRotateAxis axis,
4085 const ClutterVertex *center)
4087 GObject *obj = G_OBJECT (self);
4088 ClutterTransformInfo *info;
4089 ClutterVertex v = { 0, 0, 0 };
4091 info = _clutter_actor_get_transform_info (self);
4096 g_object_freeze_notify (obj);
4100 case CLUTTER_X_AXIS:
4101 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4102 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4105 case CLUTTER_Y_AXIS:
4106 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4107 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4110 case CLUTTER_Z_AXIS:
4111 /* if the previously set rotation center was fractional, then
4112 * setting explicit coordinates will have to notify the
4113 * :rotation-center-z-gravity property as well
4115 if (info->rz_center.is_fractional)
4116 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4118 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4119 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4123 self->priv->transform_valid = FALSE;
4125 g_object_thaw_notify (obj);
4127 clutter_actor_queue_redraw (self);
4131 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4135 GObject *obj = G_OBJECT (self);
4136 ClutterTransformInfo *info;
4138 info = _clutter_actor_get_transform_info (self);
4140 if (pspec == obj_props[PROP_SCALE_X])
4141 info->scale_x = factor;
4143 info->scale_y = factor;
4145 self->priv->transform_valid = FALSE;
4146 clutter_actor_queue_redraw (self);
4147 g_object_notify_by_pspec (obj, pspec);
4151 clutter_actor_set_scale_factor (ClutterActor *self,
4152 ClutterRotateAxis axis,
4155 const ClutterTransformInfo *info;
4156 const double *scale_p = NULL;
4157 GParamSpec *pspec = NULL;
4159 info = _clutter_actor_get_transform_info_or_defaults (self);
4163 case CLUTTER_X_AXIS:
4164 pspec = obj_props[PROP_SCALE_X];
4165 scale_p = &info->scale_x;
4168 case CLUTTER_Y_AXIS:
4169 pspec = obj_props[PROP_SCALE_Y];
4170 scale_p = &info->scale_y;
4173 case CLUTTER_Z_AXIS:
4177 g_assert (pspec != NULL);
4178 g_assert (scale_p != NULL);
4180 if (_clutter_actor_get_transition (self, pspec) == NULL)
4181 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4183 _clutter_actor_update_transition (self, pspec, factor);
4185 clutter_actor_queue_redraw (self);
4189 clutter_actor_set_scale_center (ClutterActor *self,
4190 ClutterRotateAxis axis,
4193 GObject *obj = G_OBJECT (self);
4194 ClutterTransformInfo *info;
4195 gfloat center_x, center_y;
4197 info = _clutter_actor_get_transform_info (self);
4199 g_object_freeze_notify (obj);
4201 /* get the current scale center coordinates */
4202 clutter_anchor_coord_get_units (self, &info->scale_center,
4207 /* we need to notify this too, because setting explicit coordinates will
4208 * change the gravity as a side effect
4210 if (info->scale_center.is_fractional)
4211 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4215 case CLUTTER_X_AXIS:
4216 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4217 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4220 case CLUTTER_Y_AXIS:
4221 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4222 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4226 g_assert_not_reached ();
4229 self->priv->transform_valid = FALSE;
4231 clutter_actor_queue_redraw (self);
4233 g_object_thaw_notify (obj);
4237 clutter_actor_set_scale_gravity (ClutterActor *self,
4238 ClutterGravity gravity)
4240 ClutterTransformInfo *info;
4243 info = _clutter_actor_get_transform_info (self);
4244 obj = G_OBJECT (self);
4246 if (gravity == CLUTTER_GRAVITY_NONE)
4247 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4249 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4251 self->priv->transform_valid = FALSE;
4253 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4254 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4255 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4257 clutter_actor_queue_redraw (self);
4261 clutter_actor_set_anchor_coord (ClutterActor *self,
4262 ClutterRotateAxis axis,
4265 GObject *obj = G_OBJECT (self);
4266 ClutterTransformInfo *info;
4267 gfloat anchor_x, anchor_y;
4269 info = _clutter_actor_get_transform_info (self);
4271 g_object_freeze_notify (obj);
4273 clutter_anchor_coord_get_units (self, &info->anchor,
4278 if (info->anchor.is_fractional)
4279 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4283 case CLUTTER_X_AXIS:
4284 clutter_anchor_coord_set_units (&info->anchor,
4288 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4291 case CLUTTER_Y_AXIS:
4292 clutter_anchor_coord_set_units (&info->anchor,
4296 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4300 g_assert_not_reached ();
4303 self->priv->transform_valid = FALSE;
4305 clutter_actor_queue_redraw (self);
4307 g_object_thaw_notify (obj);
4311 clutter_actor_set_property (GObject *object,
4313 const GValue *value,
4316 ClutterActor *actor = CLUTTER_ACTOR (object);
4317 ClutterActorPrivate *priv = actor->priv;
4322 clutter_actor_set_x (actor, g_value_get_float (value));
4326 clutter_actor_set_y (actor, g_value_get_float (value));
4330 clutter_actor_set_width (actor, g_value_get_float (value));
4334 clutter_actor_set_height (actor, g_value_get_float (value));
4338 clutter_actor_set_x (actor, g_value_get_float (value));
4342 clutter_actor_set_y (actor, g_value_get_float (value));
4345 case PROP_FIXED_POSITION_SET:
4346 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4349 case PROP_MIN_WIDTH:
4350 clutter_actor_set_min_width (actor, g_value_get_float (value));
4353 case PROP_MIN_HEIGHT:
4354 clutter_actor_set_min_height (actor, g_value_get_float (value));
4357 case PROP_NATURAL_WIDTH:
4358 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4361 case PROP_NATURAL_HEIGHT:
4362 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4365 case PROP_MIN_WIDTH_SET:
4366 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4369 case PROP_MIN_HEIGHT_SET:
4370 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4373 case PROP_NATURAL_WIDTH_SET:
4374 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4377 case PROP_NATURAL_HEIGHT_SET:
4378 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4381 case PROP_REQUEST_MODE:
4382 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4386 clutter_actor_set_depth (actor, g_value_get_float (value));
4390 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4393 case PROP_OFFSCREEN_REDIRECT:
4394 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4398 clutter_actor_set_name (actor, g_value_get_string (value));
4402 if (g_value_get_boolean (value) == TRUE)
4403 clutter_actor_show (actor);
4405 clutter_actor_hide (actor);
4409 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4410 g_value_get_double (value));
4414 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4415 g_value_get_double (value));
4418 case PROP_SCALE_CENTER_X:
4419 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4420 g_value_get_float (value));
4423 case PROP_SCALE_CENTER_Y:
4424 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4425 g_value_get_float (value));
4428 case PROP_SCALE_GRAVITY:
4429 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4434 const ClutterGeometry *geom = g_value_get_boxed (value);
4436 clutter_actor_set_clip (actor,
4438 geom->width, geom->height);
4442 case PROP_CLIP_TO_ALLOCATION:
4443 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4447 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4450 case PROP_ROTATION_ANGLE_X:
4451 clutter_actor_set_rotation_angle (actor,
4453 g_value_get_double (value));
4456 case PROP_ROTATION_ANGLE_Y:
4457 clutter_actor_set_rotation_angle (actor,
4459 g_value_get_double (value));
4462 case PROP_ROTATION_ANGLE_Z:
4463 clutter_actor_set_rotation_angle (actor,
4465 g_value_get_double (value));
4468 case PROP_ROTATION_CENTER_X:
4469 clutter_actor_set_rotation_center_internal (actor,
4471 g_value_get_boxed (value));
4474 case PROP_ROTATION_CENTER_Y:
4475 clutter_actor_set_rotation_center_internal (actor,
4477 g_value_get_boxed (value));
4480 case PROP_ROTATION_CENTER_Z:
4481 clutter_actor_set_rotation_center_internal (actor,
4483 g_value_get_boxed (value));
4486 case PROP_ROTATION_CENTER_Z_GRAVITY:
4488 const ClutterTransformInfo *info;
4490 info = _clutter_actor_get_transform_info_or_defaults (actor);
4491 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4492 g_value_get_enum (value));
4497 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4498 g_value_get_float (value));
4502 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4503 g_value_get_float (value));
4506 case PROP_ANCHOR_GRAVITY:
4507 clutter_actor_set_anchor_point_from_gravity (actor,
4508 g_value_get_enum (value));
4511 case PROP_SHOW_ON_SET_PARENT:
4512 priv->show_on_set_parent = g_value_get_boolean (value);
4515 case PROP_TEXT_DIRECTION:
4516 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4520 clutter_actor_add_action (actor, g_value_get_object (value));
4523 case PROP_CONSTRAINTS:
4524 clutter_actor_add_constraint (actor, g_value_get_object (value));
4528 clutter_actor_add_effect (actor, g_value_get_object (value));
4531 case PROP_LAYOUT_MANAGER:
4532 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4536 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4540 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4543 case PROP_MARGIN_TOP:
4544 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4547 case PROP_MARGIN_BOTTOM:
4548 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4551 case PROP_MARGIN_LEFT:
4552 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4555 case PROP_MARGIN_RIGHT:
4556 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4559 case PROP_BACKGROUND_COLOR:
4560 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4564 clutter_actor_set_content (actor, g_value_get_object (value));
4567 case PROP_CONTENT_GRAVITY:
4568 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4571 case PROP_MINIFICATION_FILTER:
4572 clutter_actor_set_content_scaling_filters (actor,
4573 g_value_get_enum (value),
4574 actor->priv->mag_filter);
4577 case PROP_MAGNIFICATION_FILTER:
4578 clutter_actor_set_content_scaling_filters (actor,
4579 actor->priv->min_filter,
4580 g_value_get_enum (value));
4584 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4590 clutter_actor_get_property (GObject *object,
4595 ClutterActor *actor = CLUTTER_ACTOR (object);
4596 ClutterActorPrivate *priv = actor->priv;
4601 g_value_set_float (value, clutter_actor_get_x (actor));
4605 g_value_set_float (value, clutter_actor_get_y (actor));
4609 g_value_set_float (value, clutter_actor_get_width (actor));
4613 g_value_set_float (value, clutter_actor_get_height (actor));
4618 const ClutterLayoutInfo *info;
4620 info = _clutter_actor_get_layout_info_or_defaults (actor);
4621 g_value_set_float (value, info->fixed_x);
4627 const ClutterLayoutInfo *info;
4629 info = _clutter_actor_get_layout_info_or_defaults (actor);
4630 g_value_set_float (value, info->fixed_y);
4634 case PROP_FIXED_POSITION_SET:
4635 g_value_set_boolean (value, priv->position_set);
4638 case PROP_MIN_WIDTH:
4640 const ClutterLayoutInfo *info;
4642 info = _clutter_actor_get_layout_info_or_defaults (actor);
4643 g_value_set_float (value, info->min_width);
4647 case PROP_MIN_HEIGHT:
4649 const ClutterLayoutInfo *info;
4651 info = _clutter_actor_get_layout_info_or_defaults (actor);
4652 g_value_set_float (value, info->min_height);
4656 case PROP_NATURAL_WIDTH:
4658 const ClutterLayoutInfo *info;
4660 info = _clutter_actor_get_layout_info_or_defaults (actor);
4661 g_value_set_float (value, info->natural_width);
4665 case PROP_NATURAL_HEIGHT:
4667 const ClutterLayoutInfo *info;
4669 info = _clutter_actor_get_layout_info_or_defaults (actor);
4670 g_value_set_float (value, info->natural_height);
4674 case PROP_MIN_WIDTH_SET:
4675 g_value_set_boolean (value, priv->min_width_set);
4678 case PROP_MIN_HEIGHT_SET:
4679 g_value_set_boolean (value, priv->min_height_set);
4682 case PROP_NATURAL_WIDTH_SET:
4683 g_value_set_boolean (value, priv->natural_width_set);
4686 case PROP_NATURAL_HEIGHT_SET:
4687 g_value_set_boolean (value, priv->natural_height_set);
4690 case PROP_REQUEST_MODE:
4691 g_value_set_enum (value, priv->request_mode);
4694 case PROP_ALLOCATION:
4695 g_value_set_boxed (value, &priv->allocation);
4699 g_value_set_float (value, clutter_actor_get_depth (actor));
4703 g_value_set_uint (value, priv->opacity);
4706 case PROP_OFFSCREEN_REDIRECT:
4707 g_value_set_enum (value, priv->offscreen_redirect);
4711 g_value_set_string (value, priv->name);
4715 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4719 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4723 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4727 g_value_set_boolean (value, priv->has_clip);
4732 ClutterGeometry clip;
4734 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4735 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4736 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4737 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4739 g_value_set_boxed (value, &clip);
4743 case PROP_CLIP_TO_ALLOCATION:
4744 g_value_set_boolean (value, priv->clip_to_allocation);
4749 const ClutterTransformInfo *info;
4751 info = _clutter_actor_get_transform_info_or_defaults (actor);
4752 g_value_set_double (value, info->scale_x);
4758 const ClutterTransformInfo *info;
4760 info = _clutter_actor_get_transform_info_or_defaults (actor);
4761 g_value_set_double (value, info->scale_y);
4765 case PROP_SCALE_CENTER_X:
4769 clutter_actor_get_scale_center (actor, ¢er, NULL);
4771 g_value_set_float (value, center);
4775 case PROP_SCALE_CENTER_Y:
4779 clutter_actor_get_scale_center (actor, NULL, ¢er);
4781 g_value_set_float (value, center);
4785 case PROP_SCALE_GRAVITY:
4786 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4790 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4793 case PROP_ROTATION_ANGLE_X:
4795 const ClutterTransformInfo *info;
4797 info = _clutter_actor_get_transform_info_or_defaults (actor);
4798 g_value_set_double (value, info->rx_angle);
4802 case PROP_ROTATION_ANGLE_Y:
4804 const ClutterTransformInfo *info;
4806 info = _clutter_actor_get_transform_info_or_defaults (actor);
4807 g_value_set_double (value, info->ry_angle);
4811 case PROP_ROTATION_ANGLE_Z:
4813 const ClutterTransformInfo *info;
4815 info = _clutter_actor_get_transform_info_or_defaults (actor);
4816 g_value_set_double (value, info->rz_angle);
4820 case PROP_ROTATION_CENTER_X:
4822 ClutterVertex center;
4824 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4829 g_value_set_boxed (value, ¢er);
4833 case PROP_ROTATION_CENTER_Y:
4835 ClutterVertex center;
4837 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4842 g_value_set_boxed (value, ¢er);
4846 case PROP_ROTATION_CENTER_Z:
4848 ClutterVertex center;
4850 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4855 g_value_set_boxed (value, ¢er);
4859 case PROP_ROTATION_CENTER_Z_GRAVITY:
4860 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4865 const ClutterTransformInfo *info;
4868 info = _clutter_actor_get_transform_info_or_defaults (actor);
4869 clutter_anchor_coord_get_units (actor, &info->anchor,
4873 g_value_set_float (value, anchor_x);
4879 const ClutterTransformInfo *info;
4882 info = _clutter_actor_get_transform_info_or_defaults (actor);
4883 clutter_anchor_coord_get_units (actor, &info->anchor,
4887 g_value_set_float (value, anchor_y);
4891 case PROP_ANCHOR_GRAVITY:
4892 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4895 case PROP_SHOW_ON_SET_PARENT:
4896 g_value_set_boolean (value, priv->show_on_set_parent);
4899 case PROP_TEXT_DIRECTION:
4900 g_value_set_enum (value, priv->text_direction);
4903 case PROP_HAS_POINTER:
4904 g_value_set_boolean (value, priv->has_pointer);
4907 case PROP_LAYOUT_MANAGER:
4908 g_value_set_object (value, priv->layout_manager);
4913 const ClutterLayoutInfo *info;
4915 info = _clutter_actor_get_layout_info_or_defaults (actor);
4916 g_value_set_enum (value, info->x_align);
4922 const ClutterLayoutInfo *info;
4924 info = _clutter_actor_get_layout_info_or_defaults (actor);
4925 g_value_set_enum (value, info->y_align);
4929 case PROP_MARGIN_TOP:
4931 const ClutterLayoutInfo *info;
4933 info = _clutter_actor_get_layout_info_or_defaults (actor);
4934 g_value_set_float (value, info->margin.top);
4938 case PROP_MARGIN_BOTTOM:
4940 const ClutterLayoutInfo *info;
4942 info = _clutter_actor_get_layout_info_or_defaults (actor);
4943 g_value_set_float (value, info->margin.bottom);
4947 case PROP_MARGIN_LEFT:
4949 const ClutterLayoutInfo *info;
4951 info = _clutter_actor_get_layout_info_or_defaults (actor);
4952 g_value_set_float (value, info->margin.left);
4956 case PROP_MARGIN_RIGHT:
4958 const ClutterLayoutInfo *info;
4960 info = _clutter_actor_get_layout_info_or_defaults (actor);
4961 g_value_set_float (value, info->margin.right);
4965 case PROP_BACKGROUND_COLOR_SET:
4966 g_value_set_boolean (value, priv->bg_color_set);
4969 case PROP_BACKGROUND_COLOR:
4970 g_value_set_boxed (value, &priv->bg_color);
4973 case PROP_FIRST_CHILD:
4974 g_value_set_object (value, priv->first_child);
4977 case PROP_LAST_CHILD:
4978 g_value_set_object (value, priv->last_child);
4982 g_value_set_object (value, priv->content);
4985 case PROP_CONTENT_GRAVITY:
4986 g_value_set_enum (value, priv->content_gravity);
4989 case PROP_CONTENT_BOX:
4991 ClutterActorBox box = { 0, };
4993 clutter_actor_get_content_box (actor, &box);
4994 g_value_set_boxed (value, &box);
4998 case PROP_MINIFICATION_FILTER:
4999 g_value_set_enum (value, priv->min_filter);
5002 case PROP_MAGNIFICATION_FILTER:
5003 g_value_set_enum (value, priv->mag_filter);
5007 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5013 clutter_actor_dispose (GObject *object)
5015 ClutterActor *self = CLUTTER_ACTOR (object);
5016 ClutterActorPrivate *priv = self->priv;
5018 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5020 g_type_name (G_OBJECT_TYPE (self)),
5023 g_signal_emit (self, actor_signals[DESTROY], 0);
5025 /* avoid recursing when called from clutter_actor_destroy() */
5026 if (priv->parent != NULL)
5028 ClutterActor *parent = priv->parent;
5030 /* go through the Container implementation unless this
5031 * is an internal child and has been marked as such.
5033 * removing the actor from its parent will reset the
5034 * realized and mapped states.
5036 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5037 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5039 clutter_actor_remove_child_internal (parent, self,
5040 REMOVE_CHILD_LEGACY_FLAGS);
5043 /* parent must be gone at this point */
5044 g_assert (priv->parent == NULL);
5046 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5048 /* can't be mapped or realized with no parent */
5049 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5050 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5053 g_clear_object (&priv->pango_context);
5054 g_clear_object (&priv->actions);
5055 g_clear_object (&priv->constraints);
5056 g_clear_object (&priv->effects);
5057 g_clear_object (&priv->flatten_effect);
5059 if (priv->layout_manager != NULL)
5061 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5062 g_clear_object (&priv->layout_manager);
5065 if (priv->content != NULL)
5067 _clutter_content_detached (priv->content, self);
5068 g_clear_object (&priv->content);
5071 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5075 clutter_actor_finalize (GObject *object)
5077 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5079 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5080 priv->name != NULL ? priv->name : "<none>",
5082 g_type_name (G_OBJECT_TYPE (object)));
5084 _clutter_context_release_id (priv->id);
5086 g_free (priv->name);
5088 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5093 * clutter_actor_get_accessible:
5094 * @self: a #ClutterActor
5096 * Returns the accessible object that describes the actor to an
5097 * assistive technology.
5099 * If no class-specific #AtkObject implementation is available for the
5100 * actor instance in question, it will inherit an #AtkObject
5101 * implementation from the first ancestor class for which such an
5102 * implementation is defined.
5104 * The documentation of the <ulink
5105 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5106 * library contains more information about accessible objects and
5109 * Returns: (transfer none): the #AtkObject associated with @actor
5112 clutter_actor_get_accessible (ClutterActor *self)
5114 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5116 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5120 clutter_actor_real_get_accessible (ClutterActor *actor)
5122 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5126 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5128 AtkObject *accessible;
5130 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5131 if (accessible != NULL)
5132 g_object_ref (accessible);
5138 atk_implementor_iface_init (AtkImplementorIface *iface)
5140 iface->ref_accessible = _clutter_actor_ref_accessible;
5144 clutter_actor_update_default_paint_volume (ClutterActor *self,
5145 ClutterPaintVolume *volume)
5147 ClutterActorPrivate *priv = self->priv;
5148 gboolean res = FALSE;
5150 /* we start from the allocation */
5151 clutter_paint_volume_set_width (volume,
5152 priv->allocation.x2 - priv->allocation.x1);
5153 clutter_paint_volume_set_height (volume,
5154 priv->allocation.y2 - priv->allocation.y1);
5156 /* if the actor has a clip set then we have a pretty definite
5157 * size for the paint volume: the actor cannot possibly paint
5158 * outside the clip region.
5160 if (priv->clip_to_allocation)
5162 /* the allocation has already been set, so we just flip the
5169 ClutterActor *child;
5171 if (priv->has_clip &&
5172 priv->clip.width >= 0 &&
5173 priv->clip.height >= 0)
5175 ClutterVertex origin;
5177 origin.x = priv->clip.x;
5178 origin.y = priv->clip.y;
5181 clutter_paint_volume_set_origin (volume, &origin);
5182 clutter_paint_volume_set_width (volume, priv->clip.width);
5183 clutter_paint_volume_set_height (volume, priv->clip.height);
5188 /* if we don't have children we just bail out here... */
5189 if (priv->n_children == 0)
5192 /* ...but if we have children then we ask for their paint volume in
5193 * our coordinates. if any of our children replies that it doesn't
5194 * have a paint volume, we bail out
5196 for (child = priv->first_child;
5198 child = child->priv->next_sibling)
5200 const ClutterPaintVolume *child_volume;
5202 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5203 if (child_volume == NULL)
5209 clutter_paint_volume_union (volume, child_volume);
5219 clutter_actor_real_get_paint_volume (ClutterActor *self,
5220 ClutterPaintVolume *volume)
5222 ClutterActorClass *klass;
5225 klass = CLUTTER_ACTOR_GET_CLASS (self);
5227 /* XXX - this thoroughly sucks, but we don't want to penalize users
5228 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5229 * redraw. This should go away in 2.0.
5231 if (klass->paint == clutter_actor_real_paint &&
5232 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5238 /* this is the default return value: we cannot know if a class
5239 * is going to paint outside its allocation, so we take the
5240 * conservative approach.
5245 if (clutter_actor_update_default_paint_volume (self, volume))
5252 * clutter_actor_get_default_paint_volume:
5253 * @self: a #ClutterActor
5255 * Retrieves the default paint volume for @self.
5257 * This function provides the same #ClutterPaintVolume that would be
5258 * computed by the default implementation inside #ClutterActor of the
5259 * #ClutterActorClass.get_paint_volume() virtual function.
5261 * This function should only be used by #ClutterActor subclasses that
5262 * cannot chain up to the parent implementation when computing their
5265 * Return value: (transfer none): a pointer to the default
5266 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5267 * the actor could not compute a valid paint volume. The returned value
5268 * is not guaranteed to be stable across multiple frames, so if you
5269 * want to retain it, you will need to copy it using
5270 * clutter_paint_volume_copy().
5274 const ClutterPaintVolume *
5275 clutter_actor_get_default_paint_volume (ClutterActor *self)
5277 ClutterPaintVolume volume;
5278 ClutterPaintVolume *res;
5280 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5283 _clutter_paint_volume_init_static (&volume, self);
5284 if (clutter_actor_update_default_paint_volume (self, &volume))
5286 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5290 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5291 _clutter_paint_volume_copy_static (&volume, res);
5295 clutter_paint_volume_free (&volume);
5301 clutter_actor_real_has_overlaps (ClutterActor *self)
5303 /* By default we'll assume that all actors need an offscreen redirect to get
5304 * the correct opacity. Actors such as ClutterTexture that would never need
5305 * an offscreen redirect can override this to return FALSE. */
5310 clutter_actor_real_destroy (ClutterActor *actor)
5312 ClutterActorIter iter;
5314 g_object_freeze_notify (G_OBJECT (actor));
5316 clutter_actor_iter_init (&iter, actor);
5317 while (clutter_actor_iter_next (&iter, NULL))
5318 clutter_actor_iter_destroy (&iter);
5320 g_object_thaw_notify (G_OBJECT (actor));
5324 clutter_actor_constructor (GType gtype,
5326 GObjectConstructParam *props)
5328 GObjectClass *gobject_class;
5332 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5333 retval = gobject_class->constructor (gtype, n_props, props);
5334 self = CLUTTER_ACTOR (retval);
5336 if (self->priv->layout_manager == NULL)
5338 ClutterLayoutManager *default_layout;
5340 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5342 default_layout = clutter_fixed_layout_new ();
5343 clutter_actor_set_layout_manager (self, default_layout);
5350 clutter_actor_class_init (ClutterActorClass *klass)
5352 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5354 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5355 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5356 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5357 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5359 object_class->constructor = clutter_actor_constructor;
5360 object_class->set_property = clutter_actor_set_property;
5361 object_class->get_property = clutter_actor_get_property;
5362 object_class->dispose = clutter_actor_dispose;
5363 object_class->finalize = clutter_actor_finalize;
5365 klass->show = clutter_actor_real_show;
5366 klass->show_all = clutter_actor_show;
5367 klass->hide = clutter_actor_real_hide;
5368 klass->hide_all = clutter_actor_hide;
5369 klass->map = clutter_actor_real_map;
5370 klass->unmap = clutter_actor_real_unmap;
5371 klass->unrealize = clutter_actor_real_unrealize;
5372 klass->pick = clutter_actor_real_pick;
5373 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5374 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5375 klass->allocate = clutter_actor_real_allocate;
5376 klass->queue_redraw = clutter_actor_real_queue_redraw;
5377 klass->queue_relayout = clutter_actor_real_queue_relayout;
5378 klass->apply_transform = clutter_actor_real_apply_transform;
5379 klass->get_accessible = clutter_actor_real_get_accessible;
5380 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5381 klass->has_overlaps = clutter_actor_real_has_overlaps;
5382 klass->paint = clutter_actor_real_paint;
5383 klass->destroy = clutter_actor_real_destroy;
5385 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5390 * X coordinate of the actor in pixels. If written, forces a fixed
5391 * position for the actor. If read, returns the fixed position if any,
5392 * otherwise the allocation if available, otherwise 0.
5394 * The #ClutterActor:x property is animatable.
5397 g_param_spec_float ("x",
5399 P_("X coordinate of the actor"),
5400 -G_MAXFLOAT, G_MAXFLOAT,
5403 G_PARAM_STATIC_STRINGS |
5404 CLUTTER_PARAM_ANIMATABLE);
5409 * Y coordinate of the actor in pixels. If written, forces a fixed
5410 * position for the actor. If read, returns the fixed position if
5411 * any, otherwise the allocation if available, otherwise 0.
5413 * The #ClutterActor:y property is animatable.
5416 g_param_spec_float ("y",
5418 P_("Y coordinate of the actor"),
5419 -G_MAXFLOAT, G_MAXFLOAT,
5422 G_PARAM_STATIC_STRINGS |
5423 CLUTTER_PARAM_ANIMATABLE);
5426 * ClutterActor:width:
5428 * Width of the actor (in pixels). If written, forces the minimum and
5429 * natural size request of the actor to the given width. If read, returns
5430 * the allocated width if available, otherwise the width request.
5432 * The #ClutterActor:width property is animatable.
5434 obj_props[PROP_WIDTH] =
5435 g_param_spec_float ("width",
5437 P_("Width of the actor"),
5441 G_PARAM_STATIC_STRINGS |
5442 CLUTTER_PARAM_ANIMATABLE);
5445 * ClutterActor:height:
5447 * Height of the actor (in pixels). If written, forces the minimum and
5448 * natural size request of the actor to the given height. If read, returns
5449 * the allocated height if available, otherwise the height request.
5451 * The #ClutterActor:height property is animatable.
5453 obj_props[PROP_HEIGHT] =
5454 g_param_spec_float ("height",
5456 P_("Height of the actor"),
5460 G_PARAM_STATIC_STRINGS |
5461 CLUTTER_PARAM_ANIMATABLE);
5464 * ClutterActor:fixed-x:
5466 * The fixed X position of the actor in pixels.
5468 * Writing this property sets #ClutterActor:fixed-position-set
5469 * property as well, as a side effect
5473 obj_props[PROP_FIXED_X] =
5474 g_param_spec_float ("fixed-x",
5476 P_("Forced X position of the actor"),
5477 -G_MAXFLOAT, G_MAXFLOAT,
5479 CLUTTER_PARAM_READWRITE);
5482 * ClutterActor:fixed-y:
5484 * The fixed Y position of the actor in pixels.
5486 * Writing this property sets the #ClutterActor:fixed-position-set
5487 * property as well, as a side effect
5491 obj_props[PROP_FIXED_Y] =
5492 g_param_spec_float ("fixed-y",
5494 P_("Forced Y position of the actor"),
5495 -G_MAXFLOAT, G_MAXFLOAT,
5497 CLUTTER_PARAM_READWRITE);
5500 * ClutterActor:fixed-position-set:
5502 * This flag controls whether the #ClutterActor:fixed-x and
5503 * #ClutterActor:fixed-y properties are used
5507 obj_props[PROP_FIXED_POSITION_SET] =
5508 g_param_spec_boolean ("fixed-position-set",
5509 P_("Fixed position set"),
5510 P_("Whether to use fixed positioning for the actor"),
5512 CLUTTER_PARAM_READWRITE);
5515 * ClutterActor:min-width:
5517 * A forced minimum width request for the actor, in pixels
5519 * Writing this property sets the #ClutterActor:min-width-set property
5520 * as well, as a side effect.
5522 *This property overrides the usual width request of the actor.
5526 obj_props[PROP_MIN_WIDTH] =
5527 g_param_spec_float ("min-width",
5529 P_("Forced minimum width request for the actor"),
5532 CLUTTER_PARAM_READWRITE);
5535 * ClutterActor:min-height:
5537 * A forced minimum height request for the actor, in pixels
5539 * Writing this property sets the #ClutterActor:min-height-set property
5540 * as well, as a side effect. This property overrides the usual height
5541 * request of the actor.
5545 obj_props[PROP_MIN_HEIGHT] =
5546 g_param_spec_float ("min-height",
5548 P_("Forced minimum height request for the actor"),
5551 CLUTTER_PARAM_READWRITE);
5554 * ClutterActor:natural-width:
5556 * A forced natural width request for the actor, in pixels
5558 * Writing this property sets the #ClutterActor:natural-width-set
5559 * property as well, as a side effect. This property overrides the
5560 * usual width request of the actor
5564 obj_props[PROP_NATURAL_WIDTH] =
5565 g_param_spec_float ("natural-width",
5566 P_("Natural Width"),
5567 P_("Forced natural width request for the actor"),
5570 CLUTTER_PARAM_READWRITE);
5573 * ClutterActor:natural-height:
5575 * A forced natural height request for the actor, in pixels
5577 * Writing this property sets the #ClutterActor:natural-height-set
5578 * property as well, as a side effect. This property overrides the
5579 * usual height request of the actor
5583 obj_props[PROP_NATURAL_HEIGHT] =
5584 g_param_spec_float ("natural-height",
5585 P_("Natural Height"),
5586 P_("Forced natural height request for the actor"),
5589 CLUTTER_PARAM_READWRITE);
5592 * ClutterActor:min-width-set:
5594 * This flag controls whether the #ClutterActor:min-width property
5599 obj_props[PROP_MIN_WIDTH_SET] =
5600 g_param_spec_boolean ("min-width-set",
5601 P_("Minimum width set"),
5602 P_("Whether to use the min-width property"),
5604 CLUTTER_PARAM_READWRITE);
5607 * ClutterActor:min-height-set:
5609 * This flag controls whether the #ClutterActor:min-height property
5614 obj_props[PROP_MIN_HEIGHT_SET] =
5615 g_param_spec_boolean ("min-height-set",
5616 P_("Minimum height set"),
5617 P_("Whether to use the min-height property"),
5619 CLUTTER_PARAM_READWRITE);
5622 * ClutterActor:natural-width-set:
5624 * This flag controls whether the #ClutterActor:natural-width property
5629 obj_props[PROP_NATURAL_WIDTH_SET] =
5630 g_param_spec_boolean ("natural-width-set",
5631 P_("Natural width set"),
5632 P_("Whether to use the natural-width property"),
5634 CLUTTER_PARAM_READWRITE);
5637 * ClutterActor:natural-height-set:
5639 * This flag controls whether the #ClutterActor:natural-height property
5644 obj_props[PROP_NATURAL_HEIGHT_SET] =
5645 g_param_spec_boolean ("natural-height-set",
5646 P_("Natural height set"),
5647 P_("Whether to use the natural-height property"),
5649 CLUTTER_PARAM_READWRITE);
5652 * ClutterActor:allocation:
5654 * The allocation for the actor, in pixels
5656 * This is property is read-only, but you might monitor it to know when an
5657 * actor moves or resizes
5661 obj_props[PROP_ALLOCATION] =
5662 g_param_spec_boxed ("allocation",
5664 P_("The actor's allocation"),
5665 CLUTTER_TYPE_ACTOR_BOX,
5666 CLUTTER_PARAM_READABLE);
5669 * ClutterActor:request-mode:
5671 * Request mode for the #ClutterActor. The request mode determines the
5672 * type of geometry management used by the actor, either height for width
5673 * (the default) or width for height.
5675 * For actors implementing height for width, the parent container should get
5676 * the preferred width first, and then the preferred height for that width.
5678 * For actors implementing width for height, the parent container should get
5679 * the preferred height first, and then the preferred width for that height.
5684 * ClutterRequestMode mode;
5685 * gfloat natural_width, min_width;
5686 * gfloat natural_height, min_height;
5688 * mode = clutter_actor_get_request_mode (child);
5689 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5691 * clutter_actor_get_preferred_width (child, -1,
5693 * &natural_width);
5694 * clutter_actor_get_preferred_height (child, natural_width,
5696 * &natural_height);
5700 * clutter_actor_get_preferred_height (child, -1,
5702 * &natural_height);
5703 * clutter_actor_get_preferred_width (child, natural_height,
5705 * &natural_width);
5709 * will retrieve the minimum and natural width and height depending on the
5710 * preferred request mode of the #ClutterActor "child".
5712 * The clutter_actor_get_preferred_size() function will implement this
5717 obj_props[PROP_REQUEST_MODE] =
5718 g_param_spec_enum ("request-mode",
5720 P_("The actor's request mode"),
5721 CLUTTER_TYPE_REQUEST_MODE,
5722 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5723 CLUTTER_PARAM_READWRITE);
5726 * ClutterActor:depth:
5728 * The position of the actor on the Z axis.
5730 * The #ClutterActor:depth property is relative to the parent's
5733 * The #ClutterActor:depth property is animatable.
5737 obj_props[PROP_DEPTH] =
5738 g_param_spec_float ("depth",
5740 P_("Position on the Z axis"),
5741 -G_MAXFLOAT, G_MAXFLOAT,
5744 G_PARAM_STATIC_STRINGS |
5745 CLUTTER_PARAM_ANIMATABLE);
5748 * ClutterActor:opacity:
5750 * Opacity of an actor, between 0 (fully transparent) and
5751 * 255 (fully opaque)
5753 * The #ClutterActor:opacity property is animatable.
5755 obj_props[PROP_OPACITY] =
5756 g_param_spec_uint ("opacity",
5758 P_("Opacity of an actor"),
5762 G_PARAM_STATIC_STRINGS |
5763 CLUTTER_PARAM_ANIMATABLE);
5766 * ClutterActor:offscreen-redirect:
5768 * Determines the conditions in which the actor will be redirected
5769 * to an offscreen framebuffer while being painted. For example this
5770 * can be used to cache an actor in a framebuffer or for improved
5771 * handling of transparent actors. See
5772 * clutter_actor_set_offscreen_redirect() for details.
5776 obj_props[PROP_OFFSCREEN_REDIRECT] =
5777 g_param_spec_flags ("offscreen-redirect",
5778 P_("Offscreen redirect"),
5779 P_("Flags controlling when to flatten the actor into a single image"),
5780 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5782 CLUTTER_PARAM_READWRITE);
5785 * ClutterActor:visible:
5787 * Whether the actor is set to be visible or not
5789 * See also #ClutterActor:mapped
5791 obj_props[PROP_VISIBLE] =
5792 g_param_spec_boolean ("visible",
5794 P_("Whether the actor is visible or not"),
5796 CLUTTER_PARAM_READWRITE);
5799 * ClutterActor:mapped:
5801 * Whether the actor is mapped (will be painted when the stage
5802 * to which it belongs is mapped)
5806 obj_props[PROP_MAPPED] =
5807 g_param_spec_boolean ("mapped",
5809 P_("Whether the actor will be painted"),
5811 CLUTTER_PARAM_READABLE);
5814 * ClutterActor:realized:
5816 * Whether the actor has been realized
5820 obj_props[PROP_REALIZED] =
5821 g_param_spec_boolean ("realized",
5823 P_("Whether the actor has been realized"),
5825 CLUTTER_PARAM_READABLE);
5828 * ClutterActor:reactive:
5830 * Whether the actor is reactive to events or not
5832 * Only reactive actors will emit event-related signals
5836 obj_props[PROP_REACTIVE] =
5837 g_param_spec_boolean ("reactive",
5839 P_("Whether the actor is reactive to events"),
5841 CLUTTER_PARAM_READWRITE);
5844 * ClutterActor:has-clip:
5846 * Whether the actor has the #ClutterActor:clip property set or not
5848 obj_props[PROP_HAS_CLIP] =
5849 g_param_spec_boolean ("has-clip",
5851 P_("Whether the actor has a clip set"),
5853 CLUTTER_PARAM_READABLE);
5856 * ClutterActor:clip:
5858 * The clip region for the actor, in actor-relative coordinates
5860 * Every part of the actor outside the clip region will not be
5863 obj_props[PROP_CLIP] =
5864 g_param_spec_boxed ("clip",
5866 P_("The clip region for the actor"),
5867 CLUTTER_TYPE_GEOMETRY,
5868 CLUTTER_PARAM_READWRITE);
5871 * ClutterActor:name:
5873 * The name of the actor
5877 obj_props[PROP_NAME] =
5878 g_param_spec_string ("name",
5880 P_("Name of the actor"),
5882 CLUTTER_PARAM_READWRITE);
5885 * ClutterActor:scale-x:
5887 * The horizontal scale of the actor.
5889 * The #ClutterActor:scale-x property is animatable.
5893 obj_props[PROP_SCALE_X] =
5894 g_param_spec_double ("scale-x",
5896 P_("Scale factor on the X axis"),
5900 G_PARAM_STATIC_STRINGS |
5901 CLUTTER_PARAM_ANIMATABLE);
5904 * ClutterActor:scale-y:
5906 * The vertical scale of the actor.
5908 * The #ClutterActor:scale-y property is animatable.
5912 obj_props[PROP_SCALE_Y] =
5913 g_param_spec_double ("scale-y",
5915 P_("Scale factor on the Y axis"),
5919 G_PARAM_STATIC_STRINGS |
5920 CLUTTER_PARAM_ANIMATABLE);
5923 * ClutterActor:scale-center-x:
5925 * The horizontal center point for scaling
5929 obj_props[PROP_SCALE_CENTER_X] =
5930 g_param_spec_float ("scale-center-x",
5931 P_("Scale Center X"),
5932 P_("Horizontal scale center"),
5933 -G_MAXFLOAT, G_MAXFLOAT,
5935 CLUTTER_PARAM_READWRITE);
5938 * ClutterActor:scale-center-y:
5940 * The vertical center point for scaling
5944 obj_props[PROP_SCALE_CENTER_Y] =
5945 g_param_spec_float ("scale-center-y",
5946 P_("Scale Center Y"),
5947 P_("Vertical scale center"),
5948 -G_MAXFLOAT, G_MAXFLOAT,
5950 CLUTTER_PARAM_READWRITE);
5953 * ClutterActor:scale-gravity:
5955 * The center point for scaling expressed as a #ClutterGravity
5959 obj_props[PROP_SCALE_GRAVITY] =
5960 g_param_spec_enum ("scale-gravity",
5961 P_("Scale Gravity"),
5962 P_("The center of scaling"),
5963 CLUTTER_TYPE_GRAVITY,
5964 CLUTTER_GRAVITY_NONE,
5965 CLUTTER_PARAM_READWRITE);
5968 * ClutterActor:rotation-angle-x:
5970 * The rotation angle on the X axis.
5972 * The #ClutterActor:rotation-angle-x property is animatable.
5976 obj_props[PROP_ROTATION_ANGLE_X] =
5977 g_param_spec_double ("rotation-angle-x",
5978 P_("Rotation Angle X"),
5979 P_("The rotation angle on the X axis"),
5980 -G_MAXDOUBLE, G_MAXDOUBLE,
5983 G_PARAM_STATIC_STRINGS |
5984 CLUTTER_PARAM_ANIMATABLE);
5987 * ClutterActor:rotation-angle-y:
5989 * The rotation angle on the Y axis
5991 * The #ClutterActor:rotation-angle-y property is animatable.
5995 obj_props[PROP_ROTATION_ANGLE_Y] =
5996 g_param_spec_double ("rotation-angle-y",
5997 P_("Rotation Angle Y"),
5998 P_("The rotation angle on the Y axis"),
5999 -G_MAXDOUBLE, G_MAXDOUBLE,
6002 G_PARAM_STATIC_STRINGS |
6003 CLUTTER_PARAM_ANIMATABLE);
6006 * ClutterActor:rotation-angle-z:
6008 * The rotation angle on the Z axis
6010 * The #ClutterActor:rotation-angle-z property is animatable.
6014 obj_props[PROP_ROTATION_ANGLE_Z] =
6015 g_param_spec_double ("rotation-angle-z",
6016 P_("Rotation Angle Z"),
6017 P_("The rotation angle on the Z axis"),
6018 -G_MAXDOUBLE, G_MAXDOUBLE,
6021 G_PARAM_STATIC_STRINGS |
6022 CLUTTER_PARAM_ANIMATABLE);
6025 * ClutterActor:rotation-center-x:
6027 * The rotation center on the X axis.
6031 obj_props[PROP_ROTATION_CENTER_X] =
6032 g_param_spec_boxed ("rotation-center-x",
6033 P_("Rotation Center X"),
6034 P_("The rotation center on the X axis"),
6035 CLUTTER_TYPE_VERTEX,
6036 CLUTTER_PARAM_READWRITE);
6039 * ClutterActor:rotation-center-y:
6041 * The rotation center on the Y axis.
6045 obj_props[PROP_ROTATION_CENTER_Y] =
6046 g_param_spec_boxed ("rotation-center-y",
6047 P_("Rotation Center Y"),
6048 P_("The rotation center on the Y axis"),
6049 CLUTTER_TYPE_VERTEX,
6050 CLUTTER_PARAM_READWRITE);
6053 * ClutterActor:rotation-center-z:
6055 * The rotation center on the Z axis.
6059 obj_props[PROP_ROTATION_CENTER_Z] =
6060 g_param_spec_boxed ("rotation-center-z",
6061 P_("Rotation Center Z"),
6062 P_("The rotation center on the Z axis"),
6063 CLUTTER_TYPE_VERTEX,
6064 CLUTTER_PARAM_READWRITE);
6067 * ClutterActor:rotation-center-z-gravity:
6069 * The rotation center on the Z axis expressed as a #ClutterGravity.
6073 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6074 g_param_spec_enum ("rotation-center-z-gravity",
6075 P_("Rotation Center Z Gravity"),
6076 P_("Center point for rotation around the Z axis"),
6077 CLUTTER_TYPE_GRAVITY,
6078 CLUTTER_GRAVITY_NONE,
6079 CLUTTER_PARAM_READWRITE);
6082 * ClutterActor:anchor-x:
6084 * The X coordinate of an actor's anchor point, relative to
6085 * the actor coordinate space, in pixels
6089 obj_props[PROP_ANCHOR_X] =
6090 g_param_spec_float ("anchor-x",
6092 P_("X coordinate of the anchor point"),
6093 -G_MAXFLOAT, G_MAXFLOAT,
6095 CLUTTER_PARAM_READWRITE);
6098 * ClutterActor:anchor-y:
6100 * The Y coordinate of an actor's anchor point, relative to
6101 * the actor coordinate space, in pixels
6105 obj_props[PROP_ANCHOR_Y] =
6106 g_param_spec_float ("anchor-y",
6108 P_("Y coordinate of the anchor point"),
6109 -G_MAXFLOAT, G_MAXFLOAT,
6111 CLUTTER_PARAM_READWRITE);
6114 * ClutterActor:anchor-gravity:
6116 * The anchor point expressed as a #ClutterGravity
6120 obj_props[PROP_ANCHOR_GRAVITY] =
6121 g_param_spec_enum ("anchor-gravity",
6122 P_("Anchor Gravity"),
6123 P_("The anchor point as a ClutterGravity"),
6124 CLUTTER_TYPE_GRAVITY,
6125 CLUTTER_GRAVITY_NONE,
6126 CLUTTER_PARAM_READWRITE);
6129 * ClutterActor:show-on-set-parent:
6131 * If %TRUE, the actor is automatically shown when parented.
6133 * Calling clutter_actor_hide() on an actor which has not been
6134 * parented will set this property to %FALSE as a side effect.
6138 obj_props[PROP_SHOW_ON_SET_PARENT] =
6139 g_param_spec_boolean ("show-on-set-parent",
6140 P_("Show on set parent"),
6141 P_("Whether the actor is shown when parented"),
6143 CLUTTER_PARAM_READWRITE);
6146 * ClutterActor:clip-to-allocation:
6148 * Whether the clip region should track the allocated area
6151 * This property is ignored if a clip area has been explicitly
6152 * set using clutter_actor_set_clip().
6156 obj_props[PROP_CLIP_TO_ALLOCATION] =
6157 g_param_spec_boolean ("clip-to-allocation",
6158 P_("Clip to Allocation"),
6159 P_("Sets the clip region to track the actor's allocation"),
6161 CLUTTER_PARAM_READWRITE);
6164 * ClutterActor:text-direction:
6166 * The direction of the text inside a #ClutterActor.
6170 obj_props[PROP_TEXT_DIRECTION] =
6171 g_param_spec_enum ("text-direction",
6172 P_("Text Direction"),
6173 P_("Direction of the text"),
6174 CLUTTER_TYPE_TEXT_DIRECTION,
6175 CLUTTER_TEXT_DIRECTION_LTR,
6176 CLUTTER_PARAM_READWRITE);
6179 * ClutterActor:has-pointer:
6181 * Whether the actor contains the pointer of a #ClutterInputDevice
6186 obj_props[PROP_HAS_POINTER] =
6187 g_param_spec_boolean ("has-pointer",
6189 P_("Whether the actor contains the pointer of an input device"),
6191 CLUTTER_PARAM_READABLE);
6194 * ClutterActor:actions:
6196 * Adds a #ClutterAction to the actor
6200 obj_props[PROP_ACTIONS] =
6201 g_param_spec_object ("actions",
6203 P_("Adds an action to the actor"),
6204 CLUTTER_TYPE_ACTION,
6205 CLUTTER_PARAM_WRITABLE);
6208 * ClutterActor:constraints:
6210 * Adds a #ClutterConstraint to the actor
6214 obj_props[PROP_CONSTRAINTS] =
6215 g_param_spec_object ("constraints",
6217 P_("Adds a constraint to the actor"),
6218 CLUTTER_TYPE_CONSTRAINT,
6219 CLUTTER_PARAM_WRITABLE);
6222 * ClutterActor:effect:
6224 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6228 obj_props[PROP_EFFECT] =
6229 g_param_spec_object ("effect",
6231 P_("Add an effect to be applied on the actor"),
6232 CLUTTER_TYPE_EFFECT,
6233 CLUTTER_PARAM_WRITABLE);
6236 * ClutterActor:layout-manager:
6238 * A delegate object for controlling the layout of the children of
6243 obj_props[PROP_LAYOUT_MANAGER] =
6244 g_param_spec_object ("layout-manager",
6245 P_("Layout Manager"),
6246 P_("The object controlling the layout of an actor's children"),
6247 CLUTTER_TYPE_LAYOUT_MANAGER,
6248 CLUTTER_PARAM_READWRITE);
6252 * ClutterActor:x-align:
6254 * The alignment of an actor on the X axis, if the actor has been given
6255 * extra space for its allocation.
6259 obj_props[PROP_X_ALIGN] =
6260 g_param_spec_enum ("x-align",
6262 P_("The alignment of the actor on the X axis within its allocation"),
6263 CLUTTER_TYPE_ACTOR_ALIGN,
6264 CLUTTER_ACTOR_ALIGN_FILL,
6265 CLUTTER_PARAM_READWRITE);
6268 * ClutterActor:y-align:
6270 * The alignment of an actor on the Y axis, if the actor has been given
6271 * extra space for its allocation.
6275 obj_props[PROP_Y_ALIGN] =
6276 g_param_spec_enum ("y-align",
6278 P_("The alignment of the actor on the Y axis within its allocation"),
6279 CLUTTER_TYPE_ACTOR_ALIGN,
6280 CLUTTER_ACTOR_ALIGN_FILL,
6281 CLUTTER_PARAM_READWRITE);
6284 * ClutterActor:margin-top:
6286 * The margin (in pixels) from the top of the actor.
6288 * This property adds a margin to the actor's preferred size; the margin
6289 * will be automatically taken into account when allocating the actor.
6293 obj_props[PROP_MARGIN_TOP] =
6294 g_param_spec_float ("margin-top",
6296 P_("Extra space at the top"),
6299 CLUTTER_PARAM_READWRITE);
6302 * ClutterActor:margin-bottom:
6304 * The margin (in pixels) from the bottom of the actor.
6306 * This property adds a margin to the actor's preferred size; the margin
6307 * will be automatically taken into account when allocating the actor.
6311 obj_props[PROP_MARGIN_BOTTOM] =
6312 g_param_spec_float ("margin-bottom",
6313 P_("Margin Bottom"),
6314 P_("Extra space at the bottom"),
6317 CLUTTER_PARAM_READWRITE);
6320 * ClutterActor:margin-left:
6322 * The margin (in pixels) from the left of the actor.
6324 * This property adds a margin to the actor's preferred size; the margin
6325 * will be automatically taken into account when allocating the actor.
6329 obj_props[PROP_MARGIN_LEFT] =
6330 g_param_spec_float ("margin-left",
6332 P_("Extra space at the left"),
6335 CLUTTER_PARAM_READWRITE);
6338 * ClutterActor:margin-right:
6340 * The margin (in pixels) from the right of the actor.
6342 * This property adds a margin to the actor's preferred size; the margin
6343 * will be automatically taken into account when allocating the actor.
6347 obj_props[PROP_MARGIN_RIGHT] =
6348 g_param_spec_float ("margin-right",
6350 P_("Extra space at the right"),
6353 CLUTTER_PARAM_READWRITE);
6356 * ClutterActor:background-color-set:
6358 * Whether the #ClutterActor:background-color property has been set.
6362 obj_props[PROP_BACKGROUND_COLOR_SET] =
6363 g_param_spec_boolean ("background-color-set",
6364 P_("Background Color Set"),
6365 P_("Whether the background color is set"),
6367 CLUTTER_PARAM_READABLE);
6370 * ClutterActor:background-color:
6372 * Paints a solid fill of the actor's allocation using the specified
6375 * The #ClutterActor:background-color property is animatable.
6379 obj_props[PROP_BACKGROUND_COLOR] =
6380 clutter_param_spec_color ("background-color",
6381 P_("Background color"),
6382 P_("The actor's background color"),
6383 CLUTTER_COLOR_Transparent,
6385 G_PARAM_STATIC_STRINGS |
6386 CLUTTER_PARAM_ANIMATABLE);
6389 * ClutterActor:first-child:
6391 * The actor's first child.
6395 obj_props[PROP_FIRST_CHILD] =
6396 g_param_spec_object ("first-child",
6398 P_("The actor's first child"),
6400 CLUTTER_PARAM_READABLE);
6403 * ClutterActor:last-child:
6405 * The actor's last child.
6409 obj_props[PROP_LAST_CHILD] =
6410 g_param_spec_object ("last-child",
6412 P_("The actor's last child"),
6414 CLUTTER_PARAM_READABLE);
6417 * ClutterActor:content:
6419 * The #ClutterContent implementation that controls the content
6424 obj_props[PROP_CONTENT] =
6425 g_param_spec_object ("content",
6427 P_("Delegate object for painting the actor's content"),
6428 CLUTTER_TYPE_CONTENT,
6429 CLUTTER_PARAM_READWRITE);
6432 * ClutterActor:content-gravity:
6434 * The alignment that should be honoured by the #ClutterContent
6435 * set with the #ClutterActor:content property.
6437 * Changing the value of this property will change the bounding box of
6438 * the content; you can use the #ClutterActor:content-box property to
6439 * get the position and size of the content within the actor's
6442 * This property is meaningful only for #ClutterContent implementations
6443 * that have a preferred size, and if the preferred size is smaller than
6444 * the actor's allocation.
6448 obj_props[PROP_CONTENT_GRAVITY] =
6449 g_param_spec_enum ("content-gravity",
6450 P_("Content Gravity"),
6451 P_("Alignment of the actor's content"),
6452 CLUTTER_TYPE_CONTENT_GRAVITY,
6453 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6454 CLUTTER_PARAM_READWRITE);
6457 * ClutterActor:content-box:
6459 * The bounding box for the #ClutterContent used by the actor.
6461 * The value of this property is controlled by the #ClutterActor:allocation
6462 * and #ClutterActor:content-gravity properties of #ClutterActor.
6464 * The bounding box for the content is guaranteed to never exceed the
6465 * allocation's of the actor.
6469 obj_props[PROP_CONTENT_BOX] =
6470 g_param_spec_boxed ("content-box",
6472 P_("The bounding box of the actor's content"),
6473 CLUTTER_TYPE_ACTOR_BOX,
6474 CLUTTER_PARAM_READABLE);
6476 obj_props[PROP_MINIFICATION_FILTER] =
6477 g_param_spec_enum ("minification-filter",
6478 P_("Minification Filter"),
6479 P_("The filter used when reducing the size of the content"),
6480 CLUTTER_TYPE_SCALING_FILTER,
6481 CLUTTER_SCALING_FILTER_LINEAR,
6482 CLUTTER_PARAM_READWRITE);
6484 obj_props[PROP_MAGNIFICATION_FILTER] =
6485 g_param_spec_enum ("magnification-filter",
6486 P_("Magnification Filter"),
6487 P_("The filter used when increasing the size of the content"),
6488 CLUTTER_TYPE_SCALING_FILTER,
6489 CLUTTER_SCALING_FILTER_LINEAR,
6490 CLUTTER_PARAM_READWRITE);
6492 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6495 * ClutterActor::destroy:
6496 * @actor: the #ClutterActor which emitted the signal
6498 * The ::destroy signal notifies that all references held on the
6499 * actor which emitted it should be released.
6501 * The ::destroy signal should be used by all holders of a reference
6504 * This signal might result in the finalization of the #ClutterActor
6505 * if all references are released.
6507 * Composite actors and actors implementing the #ClutterContainer
6508 * interface should override the default implementation of the
6509 * class handler of this signal and call clutter_actor_destroy() on
6510 * their children. When overriding the default class handler, it is
6511 * required to chain up to the parent's implementation.
6515 actor_signals[DESTROY] =
6516 g_signal_new (I_("destroy"),
6517 G_TYPE_FROM_CLASS (object_class),
6518 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6519 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6521 _clutter_marshal_VOID__VOID,
6524 * ClutterActor::show:
6525 * @actor: the object which received the signal
6527 * The ::show signal is emitted when an actor is visible and
6528 * rendered on the stage.
6532 actor_signals[SHOW] =
6533 g_signal_new (I_("show"),
6534 G_TYPE_FROM_CLASS (object_class),
6536 G_STRUCT_OFFSET (ClutterActorClass, show),
6538 _clutter_marshal_VOID__VOID,
6541 * ClutterActor::hide:
6542 * @actor: the object which received the signal
6544 * The ::hide signal is emitted when an actor is no longer rendered
6549 actor_signals[HIDE] =
6550 g_signal_new (I_("hide"),
6551 G_TYPE_FROM_CLASS (object_class),
6553 G_STRUCT_OFFSET (ClutterActorClass, hide),
6555 _clutter_marshal_VOID__VOID,
6558 * ClutterActor::parent-set:
6559 * @actor: the object which received the signal
6560 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6562 * This signal is emitted when the parent of the actor changes.
6566 actor_signals[PARENT_SET] =
6567 g_signal_new (I_("parent-set"),
6568 G_TYPE_FROM_CLASS (object_class),
6570 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6572 _clutter_marshal_VOID__OBJECT,
6574 CLUTTER_TYPE_ACTOR);
6577 * ClutterActor::queue-redraw:
6578 * @actor: the actor we're bubbling the redraw request through
6579 * @origin: the actor which initiated the redraw request
6581 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6582 * is called on @origin.
6584 * The default implementation for #ClutterActor chains up to the
6585 * parent actor and queues a redraw on the parent, thus "bubbling"
6586 * the redraw queue up through the actor graph. The default
6587 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6588 * in a main loop idle handler.
6590 * Note that the @origin actor may be the stage, or a container; it
6591 * does not have to be a leaf node in the actor graph.
6593 * Toolkits embedding a #ClutterStage which require a redraw and
6594 * relayout cycle can stop the emission of this signal using the
6595 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6600 * on_redraw_complete (gpointer data)
6602 * ClutterStage *stage = data;
6604 * /* execute the Clutter drawing pipeline */
6605 * clutter_stage_ensure_redraw (stage);
6609 * on_stage_queue_redraw (ClutterStage *stage)
6611 * /* this prevents the default handler to run */
6612 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6614 * /* queue a redraw with the host toolkit and call
6615 * * a function when the redraw has been completed
6617 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6621 * <note><para>This signal is emitted before the Clutter paint
6622 * pipeline is executed. If you want to know when the pipeline has
6623 * been completed you should connect to the ::paint signal on the
6624 * Stage with g_signal_connect_after().</para></note>
6628 actor_signals[QUEUE_REDRAW] =
6629 g_signal_new (I_("queue-redraw"),
6630 G_TYPE_FROM_CLASS (object_class),
6633 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6635 _clutter_marshal_VOID__OBJECT,
6637 CLUTTER_TYPE_ACTOR);
6640 * ClutterActor::queue-relayout
6641 * @actor: the actor being queued for relayout
6643 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6644 * is called on an actor.
6646 * The default implementation for #ClutterActor chains up to the
6647 * parent actor and queues a relayout on the parent, thus "bubbling"
6648 * the relayout queue up through the actor graph.
6650 * The main purpose of this signal is to allow relayout to be propagated
6651 * properly in the procense of #ClutterClone actors. Applications will
6652 * not normally need to connect to this signal.
6656 actor_signals[QUEUE_RELAYOUT] =
6657 g_signal_new (I_("queue-relayout"),
6658 G_TYPE_FROM_CLASS (object_class),
6661 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6663 _clutter_marshal_VOID__VOID,
6667 * ClutterActor::event:
6668 * @actor: the actor which received the event
6669 * @event: a #ClutterEvent
6671 * The ::event signal is emitted each time an event is received
6672 * by the @actor. This signal will be emitted on every actor,
6673 * following the hierarchy chain, until it reaches the top-level
6674 * container (the #ClutterStage).
6676 * Return value: %TRUE if the event has been handled by the actor,
6677 * or %FALSE to continue the emission.
6681 actor_signals[EVENT] =
6682 g_signal_new (I_("event"),
6683 G_TYPE_FROM_CLASS (object_class),
6685 G_STRUCT_OFFSET (ClutterActorClass, event),
6686 _clutter_boolean_handled_accumulator, NULL,
6687 _clutter_marshal_BOOLEAN__BOXED,
6689 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6691 * ClutterActor::button-press-event:
6692 * @actor: the actor which received the event
6693 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6695 * The ::button-press-event signal is emitted each time a mouse button
6696 * is pressed on @actor.
6698 * Return value: %TRUE if the event has been handled by the actor,
6699 * or %FALSE to continue the emission.
6703 actor_signals[BUTTON_PRESS_EVENT] =
6704 g_signal_new (I_("button-press-event"),
6705 G_TYPE_FROM_CLASS (object_class),
6707 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6708 _clutter_boolean_handled_accumulator, NULL,
6709 _clutter_marshal_BOOLEAN__BOXED,
6711 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6713 * ClutterActor::button-release-event:
6714 * @actor: the actor which received the event
6715 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6717 * The ::button-release-event signal is emitted each time a mouse button
6718 * is released on @actor.
6720 * Return value: %TRUE if the event has been handled by the actor,
6721 * or %FALSE to continue the emission.
6725 actor_signals[BUTTON_RELEASE_EVENT] =
6726 g_signal_new (I_("button-release-event"),
6727 G_TYPE_FROM_CLASS (object_class),
6729 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6730 _clutter_boolean_handled_accumulator, NULL,
6731 _clutter_marshal_BOOLEAN__BOXED,
6733 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6735 * ClutterActor::scroll-event:
6736 * @actor: the actor which received the event
6737 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6739 * The ::scroll-event signal is emitted each time the mouse is
6740 * scrolled on @actor
6742 * Return value: %TRUE if the event has been handled by the actor,
6743 * or %FALSE to continue the emission.
6747 actor_signals[SCROLL_EVENT] =
6748 g_signal_new (I_("scroll-event"),
6749 G_TYPE_FROM_CLASS (object_class),
6751 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6752 _clutter_boolean_handled_accumulator, NULL,
6753 _clutter_marshal_BOOLEAN__BOXED,
6755 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6757 * ClutterActor::key-press-event:
6758 * @actor: the actor which received the event
6759 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6761 * The ::key-press-event signal is emitted each time a keyboard button
6762 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6764 * Return value: %TRUE if the event has been handled by the actor,
6765 * or %FALSE to continue the emission.
6769 actor_signals[KEY_PRESS_EVENT] =
6770 g_signal_new (I_("key-press-event"),
6771 G_TYPE_FROM_CLASS (object_class),
6773 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6774 _clutter_boolean_handled_accumulator, NULL,
6775 _clutter_marshal_BOOLEAN__BOXED,
6777 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6779 * ClutterActor::key-release-event:
6780 * @actor: the actor which received the event
6781 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6783 * The ::key-release-event signal is emitted each time a keyboard button
6784 * is released while @actor has key focus (see
6785 * clutter_stage_set_key_focus()).
6787 * Return value: %TRUE if the event has been handled by the actor,
6788 * or %FALSE to continue the emission.
6792 actor_signals[KEY_RELEASE_EVENT] =
6793 g_signal_new (I_("key-release-event"),
6794 G_TYPE_FROM_CLASS (object_class),
6796 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6797 _clutter_boolean_handled_accumulator, NULL,
6798 _clutter_marshal_BOOLEAN__BOXED,
6800 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6802 * ClutterActor::motion-event:
6803 * @actor: the actor which received the event
6804 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6806 * The ::motion-event signal is emitted each time the mouse pointer is
6807 * moved over @actor.
6809 * Return value: %TRUE if the event has been handled by the actor,
6810 * or %FALSE to continue the emission.
6814 actor_signals[MOTION_EVENT] =
6815 g_signal_new (I_("motion-event"),
6816 G_TYPE_FROM_CLASS (object_class),
6818 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6819 _clutter_boolean_handled_accumulator, NULL,
6820 _clutter_marshal_BOOLEAN__BOXED,
6822 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6825 * ClutterActor::key-focus-in:
6826 * @actor: the actor which now has key focus
6828 * The ::key-focus-in signal is emitted when @actor receives key focus.
6832 actor_signals[KEY_FOCUS_IN] =
6833 g_signal_new (I_("key-focus-in"),
6834 G_TYPE_FROM_CLASS (object_class),
6836 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6838 _clutter_marshal_VOID__VOID,
6842 * ClutterActor::key-focus-out:
6843 * @actor: the actor which now has key focus
6845 * The ::key-focus-out signal is emitted when @actor loses key focus.
6849 actor_signals[KEY_FOCUS_OUT] =
6850 g_signal_new (I_("key-focus-out"),
6851 G_TYPE_FROM_CLASS (object_class),
6853 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6855 _clutter_marshal_VOID__VOID,
6859 * ClutterActor::enter-event:
6860 * @actor: the actor which the pointer has entered.
6861 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6863 * The ::enter-event signal is emitted when the pointer enters the @actor
6865 * Return value: %TRUE if the event has been handled by the actor,
6866 * or %FALSE to continue the emission.
6870 actor_signals[ENTER_EVENT] =
6871 g_signal_new (I_("enter-event"),
6872 G_TYPE_FROM_CLASS (object_class),
6874 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6875 _clutter_boolean_handled_accumulator, NULL,
6876 _clutter_marshal_BOOLEAN__BOXED,
6878 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6881 * ClutterActor::leave-event:
6882 * @actor: the actor which the pointer has left
6883 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6885 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6887 * Return value: %TRUE if the event has been handled by the actor,
6888 * or %FALSE to continue the emission.
6892 actor_signals[LEAVE_EVENT] =
6893 g_signal_new (I_("leave-event"),
6894 G_TYPE_FROM_CLASS (object_class),
6896 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6897 _clutter_boolean_handled_accumulator, NULL,
6898 _clutter_marshal_BOOLEAN__BOXED,
6900 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6903 * ClutterActor::captured-event:
6904 * @actor: the actor which received the signal
6905 * @event: a #ClutterEvent
6907 * The ::captured-event signal is emitted when an event is captured
6908 * by Clutter. This signal will be emitted starting from the top-level
6909 * container (the #ClutterStage) to the actor which received the event
6910 * going down the hierarchy. This signal can be used to intercept every
6911 * event before the specialized events (like
6912 * ClutterActor::button-press-event or ::key-released-event) are
6915 * Return value: %TRUE if the event has been handled by the actor,
6916 * or %FALSE to continue the emission.
6920 actor_signals[CAPTURED_EVENT] =
6921 g_signal_new (I_("captured-event"),
6922 G_TYPE_FROM_CLASS (object_class),
6924 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6925 _clutter_boolean_handled_accumulator, NULL,
6926 _clutter_marshal_BOOLEAN__BOXED,
6928 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6931 * ClutterActor::paint:
6932 * @actor: the #ClutterActor that received the signal
6934 * The ::paint signal is emitted each time an actor is being painted.
6936 * Subclasses of #ClutterActor should override the class signal handler
6937 * and paint themselves in that function.
6939 * It is possible to connect a handler to the ::paint signal in order
6940 * to set up some custom aspect of a paint.
6944 actor_signals[PAINT] =
6945 g_signal_new (I_("paint"),
6946 G_TYPE_FROM_CLASS (object_class),
6949 G_STRUCT_OFFSET (ClutterActorClass, paint),
6951 _clutter_marshal_VOID__VOID,
6954 * ClutterActor::realize:
6955 * @actor: the #ClutterActor that received the signal
6957 * The ::realize signal is emitted each time an actor is being
6962 actor_signals[REALIZE] =
6963 g_signal_new (I_("realize"),
6964 G_TYPE_FROM_CLASS (object_class),
6966 G_STRUCT_OFFSET (ClutterActorClass, realize),
6968 _clutter_marshal_VOID__VOID,
6971 * ClutterActor::unrealize:
6972 * @actor: the #ClutterActor that received the signal
6974 * The ::unrealize signal is emitted each time an actor is being
6979 actor_signals[UNREALIZE] =
6980 g_signal_new (I_("unrealize"),
6981 G_TYPE_FROM_CLASS (object_class),
6983 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6985 _clutter_marshal_VOID__VOID,
6989 * ClutterActor::pick:
6990 * @actor: the #ClutterActor that received the signal
6991 * @color: the #ClutterColor to be used when picking
6993 * The ::pick signal is emitted each time an actor is being painted
6994 * in "pick mode". The pick mode is used to identify the actor during
6995 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6996 * The actor should paint its shape using the passed @pick_color.
6998 * Subclasses of #ClutterActor should override the class signal handler
6999 * and paint themselves in that function.
7001 * It is possible to connect a handler to the ::pick signal in order
7002 * to set up some custom aspect of a paint in pick mode.
7006 actor_signals[PICK] =
7007 g_signal_new (I_("pick"),
7008 G_TYPE_FROM_CLASS (object_class),
7010 G_STRUCT_OFFSET (ClutterActorClass, pick),
7012 _clutter_marshal_VOID__BOXED,
7014 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7017 * ClutterActor::allocation-changed:
7018 * @actor: the #ClutterActor that emitted the signal
7019 * @box: a #ClutterActorBox with the new allocation
7020 * @flags: #ClutterAllocationFlags for the allocation
7022 * The ::allocation-changed signal is emitted when the
7023 * #ClutterActor:allocation property changes. Usually, application
7024 * code should just use the notifications for the :allocation property
7025 * but if you want to track the allocation flags as well, for instance
7026 * to know whether the absolute origin of @actor changed, then you might
7027 * want use this signal instead.
7031 actor_signals[ALLOCATION_CHANGED] =
7032 g_signal_new (I_("allocation-changed"),
7033 G_TYPE_FROM_CLASS (object_class),
7037 _clutter_marshal_VOID__BOXED_FLAGS,
7039 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7040 CLUTTER_TYPE_ALLOCATION_FLAGS);
7043 * ClutterActor::transitions-completed:
7044 * @actor: a #ClutterActor
7046 * The ::transitions-completed signal is emitted once all transitions
7047 * involving @actor are complete.
7051 actor_signals[TRANSITIONS_COMPLETED] =
7052 g_signal_new (I_("transitions-completed"),
7053 G_TYPE_FROM_CLASS (object_class),
7057 _clutter_marshal_VOID__VOID,
7062 clutter_actor_init (ClutterActor *self)
7064 ClutterActorPrivate *priv;
7066 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7068 priv->id = _clutter_context_acquire_id (self);
7071 priv->opacity = 0xff;
7072 priv->show_on_set_parent = TRUE;
7074 priv->needs_width_request = TRUE;
7075 priv->needs_height_request = TRUE;
7076 priv->needs_allocation = TRUE;
7078 priv->cached_width_age = 1;
7079 priv->cached_height_age = 1;
7081 priv->opacity_override = -1;
7082 priv->enable_model_view_transform = TRUE;
7084 /* Initialize an empty paint volume to start with */
7085 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7086 priv->last_paint_volume_valid = TRUE;
7088 priv->transform_valid = FALSE;
7090 /* the default is to stretch the content, to match the
7091 * current behaviour of basically all actors. also, it's
7092 * the easiest thing to compute.
7094 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7095 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7096 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7100 * clutter_actor_new:
7102 * Creates a new #ClutterActor.
7104 * A newly created actor has a floating reference, which will be sunk
7105 * when it is added to another actor.
7107 * Return value: (transfer full): the newly created #ClutterActor
7112 clutter_actor_new (void)
7114 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7118 * clutter_actor_destroy:
7119 * @self: a #ClutterActor
7121 * Destroys an actor. When an actor is destroyed, it will break any
7122 * references it holds to other objects. If the actor is inside a
7123 * container, the actor will be removed.
7125 * When you destroy a container, its children will be destroyed as well.
7127 * Note: you cannot destroy the #ClutterStage returned by
7128 * clutter_stage_get_default().
7131 clutter_actor_destroy (ClutterActor *self)
7133 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7135 g_object_ref (self);
7137 /* avoid recursion while destroying */
7138 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7140 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7142 g_object_run_dispose (G_OBJECT (self));
7144 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7147 g_object_unref (self);
7151 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7152 ClutterPaintVolume *clip)
7154 ClutterActorPrivate *priv = self->priv;
7155 ClutterPaintVolume *pv;
7158 /* Remove queue entry early in the process, otherwise a new
7159 queue_redraw() during signal handling could put back this
7160 object in the stage redraw list (but the entry is freed as
7161 soon as we return from this function, causing a segfault
7164 priv->queue_redraw_entry = NULL;
7166 /* If we've been explicitly passed a clip volume then there's
7167 * nothing more to calculate, but otherwise the only thing we know
7168 * is that the change is constrained to the given actor.
7170 * The idea is that if we know the paint volume for where the actor
7171 * was last drawn (in eye coordinates) and we also have the paint
7172 * volume for where it will be drawn next (in actor coordinates)
7173 * then if we queue a redraw for both these volumes that will cover
7174 * everything that needs to be redrawn to clear the old view and
7175 * show the latest view of the actor.
7177 * Don't clip this redraw if we don't know what position we had for
7178 * the previous redraw since we don't know where to set the clip so
7179 * it will clear the actor as it is currently.
7183 _clutter_actor_set_queue_redraw_clip (self, clip);
7186 else if (G_LIKELY (priv->last_paint_volume_valid))
7188 pv = _clutter_actor_get_paint_volume_mutable (self);
7191 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7193 /* make sure we redraw the actors old position... */
7194 _clutter_actor_set_queue_redraw_clip (stage,
7195 &priv->last_paint_volume);
7196 _clutter_actor_signal_queue_redraw (stage, stage);
7197 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7199 /* XXX: Ideally the redraw signal would take a clip volume
7200 * argument, but that would be an ABI break. Until we can
7201 * break the ABI we pass the argument out-of-band
7204 /* setup the clip for the actors new position... */
7205 _clutter_actor_set_queue_redraw_clip (self, pv);
7214 _clutter_actor_signal_queue_redraw (self, self);
7216 /* Just in case anyone is manually firing redraw signals without
7217 * using the public queue_redraw() API we are careful to ensure that
7218 * our out-of-band clip member is cleared before returning...
7220 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7222 if (G_LIKELY (clipped))
7223 _clutter_actor_set_queue_redraw_clip (self, NULL);
7227 _clutter_actor_get_allocation_clip (ClutterActor *self,
7228 ClutterActorBox *clip)
7230 ClutterActorBox allocation;
7232 /* XXX: we don't care if we get an out of date allocation here
7233 * because clutter_actor_queue_redraw_with_clip knows to ignore
7234 * the clip if the actor's allocation is invalid.
7236 * This is noted because clutter_actor_get_allocation_box does some
7237 * unnecessary work to support buggy code with a comment suggesting
7238 * that it could be changed later which would be good for this use
7241 clutter_actor_get_allocation_box (self, &allocation);
7243 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7244 * actor's own coordinate space but the allocation is in parent
7248 clip->x2 = allocation.x2 - allocation.x1;
7249 clip->y2 = allocation.y2 - allocation.y1;
7253 _clutter_actor_queue_redraw_full (ClutterActor *self,
7254 ClutterRedrawFlags flags,
7255 ClutterPaintVolume *volume,
7256 ClutterEffect *effect)
7258 ClutterActorPrivate *priv = self->priv;
7259 ClutterPaintVolume allocation_pv;
7260 ClutterPaintVolume *pv;
7261 gboolean should_free_pv;
7262 ClutterActor *stage;
7264 /* Here's an outline of the actor queue redraw mechanism:
7266 * The process starts in one of the following two functions which
7267 * are wrappers for this function:
7268 * clutter_actor_queue_redraw
7269 * _clutter_actor_queue_redraw_with_clip
7271 * additionally, an effect can queue a redraw by wrapping this
7272 * function in clutter_effect_queue_rerun
7274 * This functions queues an entry in a list associated with the
7275 * stage which is a list of actors that queued a redraw while
7276 * updating the timelines, performing layouting and processing other
7277 * mainloop sources before the next paint starts.
7279 * We aim to minimize the processing done at this point because
7280 * there is a good chance other events will happen while updating
7281 * the scenegraph that would invalidate any expensive work we might
7282 * otherwise try to do here. For example we don't try and resolve
7283 * the screen space bounding box of an actor at this stage so as to
7284 * minimize how much of the screen redraw because it's possible
7285 * something else will happen which will force a full redraw anyway.
7287 * When all updates are complete and we come to paint the stage then
7288 * we iterate this list and actually emit the "queue-redraw" signals
7289 * for each of the listed actors which will bubble up to the stage
7290 * for each actor and at that point we will transform the actors
7291 * paint volume into screen coordinates to determine the clip region
7292 * for what needs to be redrawn in the next paint.
7294 * Besides minimizing redundant work another reason for this
7295 * deferred design is that it's more likely we will be able to
7296 * determine the paint volume of an actor once we've finished
7297 * updating the scenegraph because its allocation should be up to
7298 * date. NB: If we can't determine an actors paint volume then we
7299 * can't automatically queue a clipped redraw which can make a big
7300 * difference to performance.
7302 * So the control flow goes like this:
7303 * One of clutter_actor_queue_redraw,
7304 * _clutter_actor_queue_redraw_with_clip
7305 * or clutter_effect_queue_rerun
7307 * then control moves to:
7308 * _clutter_stage_queue_actor_redraw
7310 * later during _clutter_stage_do_update, once relayouting is done
7311 * and the scenegraph has been updated we will call:
7312 * _clutter_stage_finish_queue_redraws
7314 * _clutter_stage_finish_queue_redraws will call
7315 * _clutter_actor_finish_queue_redraw for each listed actor.
7316 * Note: actors *are* allowed to queue further redraws during this
7317 * process (considering clone actors or texture_new_from_actor which
7318 * respond to their source queueing a redraw by queuing a redraw
7319 * themselves). We repeat the process until the list is empty.
7321 * This will result in the "queue-redraw" signal being fired for
7322 * each actor which will pass control to the default signal handler:
7323 * clutter_actor_real_queue_redraw
7325 * This will bubble up to the stages handler:
7326 * clutter_stage_real_queue_redraw
7328 * clutter_stage_real_queue_redraw will transform the actors paint
7329 * volume into screen space and add it as a clip region for the next
7333 /* ignore queueing a redraw for actors being destroyed */
7334 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7337 stage = _clutter_actor_get_stage_internal (self);
7339 /* Ignore queueing a redraw for actors not descended from a stage */
7343 /* ignore queueing a redraw on stages that are being destroyed */
7344 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7347 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7349 ClutterActorBox allocation_clip;
7350 ClutterVertex origin;
7352 /* If the actor doesn't have a valid allocation then we will
7353 * queue a full stage redraw. */
7354 if (priv->needs_allocation)
7356 /* NB: NULL denotes an undefined clip which will result in a
7358 _clutter_actor_set_queue_redraw_clip (self, NULL);
7359 _clutter_actor_signal_queue_redraw (self, self);
7363 _clutter_paint_volume_init_static (&allocation_pv, self);
7364 pv = &allocation_pv;
7366 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7368 origin.x = allocation_clip.x1;
7369 origin.y = allocation_clip.y1;
7371 clutter_paint_volume_set_origin (pv, &origin);
7372 clutter_paint_volume_set_width (pv,
7373 allocation_clip.x2 - allocation_clip.x1);
7374 clutter_paint_volume_set_height (pv,
7375 allocation_clip.y2 -
7376 allocation_clip.y1);
7377 should_free_pv = TRUE;
7382 should_free_pv = FALSE;
7385 self->priv->queue_redraw_entry =
7386 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7387 priv->queue_redraw_entry,
7392 clutter_paint_volume_free (pv);
7394 /* If this is the first redraw queued then we can directly use the
7396 if (!priv->is_dirty)
7397 priv->effect_to_redraw = effect;
7398 /* Otherwise we need to merge it with the existing effect parameter */
7399 else if (effect != NULL)
7401 /* If there's already an effect then we need to use whichever is
7402 later in the chain of actors. Otherwise a full redraw has
7403 already been queued on the actor so we need to ignore the
7405 if (priv->effect_to_redraw != NULL)
7407 if (priv->effects == NULL)
7408 g_warning ("Redraw queued with an effect that is "
7409 "not applied to the actor");
7414 for (l = _clutter_meta_group_peek_metas (priv->effects);
7418 if (l->data == priv->effect_to_redraw ||
7420 priv->effect_to_redraw = l->data;
7427 /* If no effect is specified then we need to redraw the whole
7429 priv->effect_to_redraw = NULL;
7432 priv->is_dirty = TRUE;
7436 * clutter_actor_queue_redraw:
7437 * @self: A #ClutterActor
7439 * Queues up a redraw of an actor and any children. The redraw occurs
7440 * once the main loop becomes idle (after the current batch of events
7441 * has been processed, roughly).
7443 * Applications rarely need to call this, as redraws are handled
7444 * automatically by modification functions.
7446 * This function will not do anything if @self is not visible, or
7447 * if the actor is inside an invisible part of the scenegraph.
7449 * Also be aware that painting is a NOP for actors with an opacity of
7452 * When you are implementing a custom actor you must queue a redraw
7453 * whenever some private state changes that will affect painting or
7454 * picking of your actor.
7457 clutter_actor_queue_redraw (ClutterActor *self)
7459 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7461 _clutter_actor_queue_redraw_full (self,
7463 NULL, /* clip volume */
7468 * _clutter_actor_queue_redraw_with_clip:
7469 * @self: A #ClutterActor
7470 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7471 * this queue redraw.
7472 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7473 * redrawn or %NULL if you are just using a @flag to state your
7476 * Queues up a clipped redraw of an actor and any children. The redraw
7477 * occurs once the main loop becomes idle (after the current batch of
7478 * events has been processed, roughly).
7480 * If no flags are given the clip volume is defined by @volume
7481 * specified in actor coordinates and tells Clutter that only content
7482 * within this volume has been changed so Clutter can optionally
7483 * optimize the redraw.
7485 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7486 * should be %NULL and this tells Clutter to use the actor's current
7487 * allocation as a clip box. This flag can only be used for 2D actors,
7488 * because any actor with depth may be projected outside its
7491 * Applications rarely need to call this, as redraws are handled
7492 * automatically by modification functions.
7494 * This function will not do anything if @self is not visible, or if
7495 * the actor is inside an invisible part of the scenegraph.
7497 * Also be aware that painting is a NOP for actors with an opacity of
7500 * When you are implementing a custom actor you must queue a redraw
7501 * whenever some private state changes that will affect painting or
7502 * picking of your actor.
7505 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7506 ClutterRedrawFlags flags,
7507 ClutterPaintVolume *volume)
7509 _clutter_actor_queue_redraw_full (self,
7511 volume, /* clip volume */
7516 _clutter_actor_queue_only_relayout (ClutterActor *self)
7518 ClutterActorPrivate *priv = self->priv;
7520 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7523 if (priv->needs_width_request &&
7524 priv->needs_height_request &&
7525 priv->needs_allocation)
7526 return; /* save some cpu cycles */
7528 #if CLUTTER_ENABLE_DEBUG
7529 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7531 g_warning ("The actor '%s' is currently inside an allocation "
7532 "cycle; calling clutter_actor_queue_relayout() is "
7534 _clutter_actor_get_debug_name (self));
7536 #endif /* CLUTTER_ENABLE_DEBUG */
7538 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7542 * clutter_actor_queue_redraw_with_clip:
7543 * @self: a #ClutterActor
7544 * @clip: (allow-none): a rectangular clip region, or %NULL
7546 * Queues a redraw on @self limited to a specific, actor-relative
7549 * If @clip is %NULL this function is equivalent to
7550 * clutter_actor_queue_redraw().
7555 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7556 const cairo_rectangle_int_t *clip)
7558 ClutterPaintVolume volume;
7559 ClutterVertex origin;
7561 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7565 clutter_actor_queue_redraw (self);
7569 _clutter_paint_volume_init_static (&volume, self);
7575 clutter_paint_volume_set_origin (&volume, &origin);
7576 clutter_paint_volume_set_width (&volume, clip->width);
7577 clutter_paint_volume_set_height (&volume, clip->height);
7579 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7581 clutter_paint_volume_free (&volume);
7585 * clutter_actor_queue_relayout:
7586 * @self: A #ClutterActor
7588 * Indicates that the actor's size request or other layout-affecting
7589 * properties may have changed. This function is used inside #ClutterActor
7590 * subclass implementations, not by applications directly.
7592 * Queueing a new layout automatically queues a redraw as well.
7597 clutter_actor_queue_relayout (ClutterActor *self)
7599 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7601 _clutter_actor_queue_only_relayout (self);
7602 clutter_actor_queue_redraw (self);
7606 * clutter_actor_get_preferred_size:
7607 * @self: a #ClutterActor
7608 * @min_width_p: (out) (allow-none): return location for the minimum
7610 * @min_height_p: (out) (allow-none): return location for the minimum
7612 * @natural_width_p: (out) (allow-none): return location for the natural
7614 * @natural_height_p: (out) (allow-none): return location for the natural
7617 * Computes the preferred minimum and natural size of an actor, taking into
7618 * account the actor's geometry management (either height-for-width
7619 * or width-for-height).
7621 * The width and height used to compute the preferred height and preferred
7622 * width are the actor's natural ones.
7624 * If you need to control the height for the preferred width, or the width for
7625 * the preferred height, you should use clutter_actor_get_preferred_width()
7626 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7627 * geometry management using the #ClutterActor:request-mode property.
7632 clutter_actor_get_preferred_size (ClutterActor *self,
7633 gfloat *min_width_p,
7634 gfloat *min_height_p,
7635 gfloat *natural_width_p,
7636 gfloat *natural_height_p)
7638 ClutterActorPrivate *priv;
7639 gfloat min_width, min_height;
7640 gfloat natural_width, natural_height;
7642 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7646 min_width = min_height = 0;
7647 natural_width = natural_height = 0;
7649 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7651 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7652 clutter_actor_get_preferred_width (self, -1,
7655 clutter_actor_get_preferred_height (self, natural_width,
7661 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7662 clutter_actor_get_preferred_height (self, -1,
7665 clutter_actor_get_preferred_width (self, natural_height,
7671 *min_width_p = min_width;
7674 *min_height_p = min_height;
7676 if (natural_width_p)
7677 *natural_width_p = natural_width;
7679 if (natural_height_p)
7680 *natural_height_p = natural_height;
7685 * @align: a #ClutterActorAlign
7686 * @direction: a #ClutterTextDirection
7688 * Retrieves the correct alignment depending on the text direction
7690 * Return value: the effective alignment
7692 static ClutterActorAlign
7693 effective_align (ClutterActorAlign align,
7694 ClutterTextDirection direction)
7696 ClutterActorAlign res;
7700 case CLUTTER_ACTOR_ALIGN_START:
7701 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7702 ? CLUTTER_ACTOR_ALIGN_END
7703 : CLUTTER_ACTOR_ALIGN_START;
7706 case CLUTTER_ACTOR_ALIGN_END:
7707 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7708 ? CLUTTER_ACTOR_ALIGN_START
7709 : CLUTTER_ACTOR_ALIGN_END;
7721 adjust_for_margin (float margin_start,
7723 float *minimum_size,
7724 float *natural_size,
7725 float *allocated_start,
7726 float *allocated_end)
7728 *minimum_size -= (margin_start + margin_end);
7729 *natural_size -= (margin_start + margin_end);
7730 *allocated_start += margin_start;
7731 *allocated_end -= margin_end;
7735 adjust_for_alignment (ClutterActorAlign alignment,
7737 float *allocated_start,
7738 float *allocated_end)
7740 float allocated_size = *allocated_end - *allocated_start;
7744 case CLUTTER_ACTOR_ALIGN_FILL:
7748 case CLUTTER_ACTOR_ALIGN_START:
7750 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7753 case CLUTTER_ACTOR_ALIGN_END:
7754 if (allocated_size > natural_size)
7756 *allocated_start += (allocated_size - natural_size);
7757 *allocated_end = *allocated_start + natural_size;
7761 case CLUTTER_ACTOR_ALIGN_CENTER:
7762 if (allocated_size > natural_size)
7764 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7765 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7772 * clutter_actor_adjust_width:
7773 * @self: a #ClutterActor
7774 * @minimum_width: (inout): the actor's preferred minimum width, which
7775 * will be adjusted depending on the margin
7776 * @natural_width: (inout): the actor's preferred natural width, which
7777 * will be adjusted depending on the margin
7778 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7779 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7781 * Adjusts the preferred and allocated position and size of an actor,
7782 * depending on the margin and alignment properties.
7785 clutter_actor_adjust_width (ClutterActor *self,
7786 gfloat *minimum_width,
7787 gfloat *natural_width,
7788 gfloat *adjusted_x1,
7789 gfloat *adjusted_x2)
7791 ClutterTextDirection text_dir;
7792 const ClutterLayoutInfo *info;
7794 info = _clutter_actor_get_layout_info_or_defaults (self);
7795 text_dir = clutter_actor_get_text_direction (self);
7797 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7799 /* this will tweak natural_width to remove the margin, so that
7800 * adjust_for_alignment() will use the correct size
7802 adjust_for_margin (info->margin.left, info->margin.right,
7803 minimum_width, natural_width,
7804 adjusted_x1, adjusted_x2);
7806 adjust_for_alignment (effective_align (info->x_align, text_dir),
7808 adjusted_x1, adjusted_x2);
7812 * clutter_actor_adjust_height:
7813 * @self: a #ClutterActor
7814 * @minimum_height: (inout): the actor's preferred minimum height, which
7815 * will be adjusted depending on the margin
7816 * @natural_height: (inout): the actor's preferred natural height, which
7817 * will be adjusted depending on the margin
7818 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7819 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7821 * Adjusts the preferred and allocated position and size of an actor,
7822 * depending on the margin and alignment properties.
7825 clutter_actor_adjust_height (ClutterActor *self,
7826 gfloat *minimum_height,
7827 gfloat *natural_height,
7828 gfloat *adjusted_y1,
7829 gfloat *adjusted_y2)
7831 const ClutterLayoutInfo *info;
7833 info = _clutter_actor_get_layout_info_or_defaults (self);
7835 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7837 /* this will tweak natural_height to remove the margin, so that
7838 * adjust_for_alignment() will use the correct size
7840 adjust_for_margin (info->margin.top, info->margin.bottom,
7841 minimum_height, natural_height,
7845 /* we don't use effective_align() here, because text direction
7846 * only affects the horizontal axis
7848 adjust_for_alignment (info->y_align,
7855 /* looks for a cached size request for this for_size. If not
7856 * found, returns the oldest entry so it can be overwritten */
7858 _clutter_actor_get_cached_size_request (gfloat for_size,
7859 SizeRequest *cached_size_requests,
7860 SizeRequest **result)
7864 *result = &cached_size_requests[0];
7866 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7870 sr = &cached_size_requests[i];
7873 sr->for_size == for_size)
7875 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7879 else if (sr->age < (*result)->age)
7885 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7891 * clutter_actor_get_preferred_width:
7892 * @self: A #ClutterActor
7893 * @for_height: available height when computing the preferred width,
7894 * or a negative value to indicate that no height is defined
7895 * @min_width_p: (out) (allow-none): return location for minimum width,
7897 * @natural_width_p: (out) (allow-none): return location for the natural
7900 * Computes the requested minimum and natural widths for an actor,
7901 * optionally depending on the specified height, or if they are
7902 * already computed, returns the cached values.
7904 * An actor may not get its request - depending on the layout
7905 * manager that's in effect.
7907 * A request should not incorporate the actor's scale or anchor point;
7908 * those transformations do not affect layout, only rendering.
7913 clutter_actor_get_preferred_width (ClutterActor *self,
7915 gfloat *min_width_p,
7916 gfloat *natural_width_p)
7918 float request_min_width, request_natural_width;
7919 SizeRequest *cached_size_request;
7920 const ClutterLayoutInfo *info;
7921 ClutterActorPrivate *priv;
7922 gboolean found_in_cache;
7924 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7928 info = _clutter_actor_get_layout_info_or_defaults (self);
7930 /* we shortcircuit the case of a fixed size set using set_width() */
7931 if (priv->min_width_set && priv->natural_width_set)
7933 if (min_width_p != NULL)
7934 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7936 if (natural_width_p != NULL)
7937 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7942 /* the remaining cases are:
7944 * - either min_width or natural_width have been set
7945 * - neither min_width or natural_width have been set
7947 * in both cases, we go through the cache (and through the actor in case
7948 * of cache misses) and determine the authoritative value depending on
7952 if (!priv->needs_width_request)
7955 _clutter_actor_get_cached_size_request (for_height,
7956 priv->width_requests,
7957 &cached_size_request);
7961 /* if the actor needs a width request we use the first slot */
7962 found_in_cache = FALSE;
7963 cached_size_request = &priv->width_requests[0];
7966 if (!found_in_cache)
7968 gfloat minimum_width, natural_width;
7969 ClutterActorClass *klass;
7971 minimum_width = natural_width = 0;
7973 /* adjust for the margin */
7974 if (for_height >= 0)
7976 for_height -= (info->margin.top + info->margin.bottom);
7981 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7983 klass = CLUTTER_ACTOR_GET_CLASS (self);
7984 klass->get_preferred_width (self, for_height,
7988 /* adjust for the margin */
7989 minimum_width += (info->margin.left + info->margin.right);
7990 natural_width += (info->margin.left + info->margin.right);
7992 /* Due to accumulated float errors, it's better not to warn
7993 * on this, but just fix it.
7995 if (natural_width < minimum_width)
7996 natural_width = minimum_width;
7998 cached_size_request->min_size = minimum_width;
7999 cached_size_request->natural_size = natural_width;
8000 cached_size_request->for_size = for_height;
8001 cached_size_request->age = priv->cached_width_age;
8003 priv->cached_width_age += 1;
8004 priv->needs_width_request = FALSE;
8007 if (!priv->min_width_set)
8008 request_min_width = cached_size_request->min_size;
8010 request_min_width = info->min_width;
8012 if (!priv->natural_width_set)
8013 request_natural_width = cached_size_request->natural_size;
8015 request_natural_width = info->natural_width;
8018 *min_width_p = request_min_width;
8020 if (natural_width_p)
8021 *natural_width_p = request_natural_width;
8025 * clutter_actor_get_preferred_height:
8026 * @self: A #ClutterActor
8027 * @for_width: available width to assume in computing desired height,
8028 * or a negative value to indicate that no width is defined
8029 * @min_height_p: (out) (allow-none): return location for minimum height,
8031 * @natural_height_p: (out) (allow-none): return location for natural
8034 * Computes the requested minimum and natural heights for an actor,
8035 * or if they are already computed, returns the cached values.
8037 * An actor may not get its request - depending on the layout
8038 * manager that's in effect.
8040 * A request should not incorporate the actor's scale or anchor point;
8041 * those transformations do not affect layout, only rendering.
8046 clutter_actor_get_preferred_height (ClutterActor *self,
8048 gfloat *min_height_p,
8049 gfloat *natural_height_p)
8051 float request_min_height, request_natural_height;
8052 SizeRequest *cached_size_request;
8053 const ClutterLayoutInfo *info;
8054 ClutterActorPrivate *priv;
8055 gboolean found_in_cache;
8057 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8061 info = _clutter_actor_get_layout_info_or_defaults (self);
8063 /* we shortcircuit the case of a fixed size set using set_height() */
8064 if (priv->min_height_set && priv->natural_height_set)
8066 if (min_height_p != NULL)
8067 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8069 if (natural_height_p != NULL)
8070 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8075 /* the remaining cases are:
8077 * - either min_height or natural_height have been set
8078 * - neither min_height or natural_height have been set
8080 * in both cases, we go through the cache (and through the actor in case
8081 * of cache misses) and determine the authoritative value depending on
8085 if (!priv->needs_height_request)
8088 _clutter_actor_get_cached_size_request (for_width,
8089 priv->height_requests,
8090 &cached_size_request);
8094 found_in_cache = FALSE;
8095 cached_size_request = &priv->height_requests[0];
8098 if (!found_in_cache)
8100 gfloat minimum_height, natural_height;
8101 ClutterActorClass *klass;
8103 minimum_height = natural_height = 0;
8105 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8107 /* adjust for margin */
8110 for_width -= (info->margin.left + info->margin.right);
8115 klass = CLUTTER_ACTOR_GET_CLASS (self);
8116 klass->get_preferred_height (self, for_width,
8120 /* adjust for margin */
8121 minimum_height += (info->margin.top + info->margin.bottom);
8122 natural_height += (info->margin.top + info->margin.bottom);
8124 /* Due to accumulated float errors, it's better not to warn
8125 * on this, but just fix it.
8127 if (natural_height < minimum_height)
8128 natural_height = minimum_height;
8130 cached_size_request->min_size = minimum_height;
8131 cached_size_request->natural_size = natural_height;
8132 cached_size_request->for_size = for_width;
8133 cached_size_request->age = priv->cached_height_age;
8135 priv->cached_height_age += 1;
8136 priv->needs_height_request = FALSE;
8139 if (!priv->min_height_set)
8140 request_min_height = cached_size_request->min_size;
8142 request_min_height = info->min_height;
8144 if (!priv->natural_height_set)
8145 request_natural_height = cached_size_request->natural_size;
8147 request_natural_height = info->natural_height;
8150 *min_height_p = request_min_height;
8152 if (natural_height_p)
8153 *natural_height_p = request_natural_height;
8157 * clutter_actor_get_allocation_box:
8158 * @self: A #ClutterActor
8159 * @box: (out): the function fills this in with the actor's allocation
8161 * Gets the layout box an actor has been assigned. The allocation can
8162 * only be assumed valid inside a paint() method; anywhere else, it
8163 * may be out-of-date.
8165 * An allocation does not incorporate the actor's scale or anchor point;
8166 * those transformations do not affect layout, only rendering.
8168 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8169 * of functions inside the implementation of the get_preferred_width()
8170 * or get_preferred_height() virtual functions.</note>
8175 clutter_actor_get_allocation_box (ClutterActor *self,
8176 ClutterActorBox *box)
8178 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8180 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8181 * which limits calling get_allocation to inside paint() basically; or
8182 * we can 2) force a layout, which could be expensive if someone calls
8183 * get_allocation somewhere silly; or we can 3) just return the latest
8184 * value, allowing it to be out-of-date, and assume people know what
8187 * The least-surprises approach that keeps existing code working is
8188 * likely to be 2). People can end up doing some inefficient things,
8189 * though, and in general code that requires 2) is probably broken.
8192 /* this implements 2) */
8193 if (G_UNLIKELY (self->priv->needs_allocation))
8195 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8197 /* do not queue a relayout on an unparented actor */
8199 _clutter_stage_maybe_relayout (stage);
8202 /* commenting out the code above and just keeping this assigment
8205 *box = self->priv->allocation;
8209 * clutter_actor_get_allocation_geometry:
8210 * @self: A #ClutterActor
8211 * @geom: (out): allocation geometry in pixels
8213 * Gets the layout box an actor has been assigned. The allocation can
8214 * only be assumed valid inside a paint() method; anywhere else, it
8215 * may be out-of-date.
8217 * An allocation does not incorporate the actor's scale or anchor point;
8218 * those transformations do not affect layout, only rendering.
8220 * The returned rectangle is in pixels.
8225 clutter_actor_get_allocation_geometry (ClutterActor *self,
8226 ClutterGeometry *geom)
8228 ClutterActorBox box;
8230 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8231 g_return_if_fail (geom != NULL);
8233 clutter_actor_get_allocation_box (self, &box);
8235 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8236 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8237 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8238 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8242 clutter_actor_update_constraints (ClutterActor *self,
8243 ClutterActorBox *allocation)
8245 ClutterActorPrivate *priv = self->priv;
8246 const GList *constraints, *l;
8248 if (priv->constraints == NULL)
8251 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8252 for (l = constraints; l != NULL; l = l->next)
8254 ClutterConstraint *constraint = l->data;
8255 ClutterActorMeta *meta = l->data;
8257 if (clutter_actor_meta_get_enabled (meta))
8259 _clutter_constraint_update_allocation (constraint,
8263 CLUTTER_NOTE (LAYOUT,
8264 "Allocation of '%s' after constraint '%s': "
8265 "{ %.2f, %.2f, %.2f, %.2f }",
8266 _clutter_actor_get_debug_name (self),
8267 _clutter_actor_meta_get_debug_name (meta),
8277 * clutter_actor_adjust_allocation:
8278 * @self: a #ClutterActor
8279 * @allocation: (inout): the allocation to adjust
8281 * Adjusts the passed allocation box taking into account the actor's
8282 * layout information, like alignment, expansion, and margin.
8285 clutter_actor_adjust_allocation (ClutterActor *self,
8286 ClutterActorBox *allocation)
8288 ClutterActorBox adj_allocation;
8289 float alloc_width, alloc_height;
8290 float min_width, min_height;
8291 float nat_width, nat_height;
8292 ClutterRequestMode req_mode;
8294 adj_allocation = *allocation;
8296 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8298 /* we want to hit the cache, so we use the public API */
8299 req_mode = clutter_actor_get_request_mode (self);
8301 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8303 clutter_actor_get_preferred_width (self, -1,
8306 clutter_actor_get_preferred_height (self, alloc_width,
8310 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8312 clutter_actor_get_preferred_height (self, -1,
8315 clutter_actor_get_preferred_height (self, alloc_height,
8320 #ifdef CLUTTER_ENABLE_DEBUG
8321 /* warn about underallocations */
8322 if (_clutter_diagnostic_enabled () &&
8323 (floorf (min_width - alloc_width) > 0 ||
8324 floorf (min_height - alloc_height) > 0))
8326 ClutterActor *parent = clutter_actor_get_parent (self);
8328 /* the only actors that are allowed to be underallocated are the Stage,
8329 * as it doesn't have an implicit size, and Actors that specifically
8330 * told us that they want to opt-out from layout control mechanisms
8331 * through the NO_LAYOUT escape hatch.
8333 if (parent != NULL &&
8334 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8336 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8337 "of %.2f x %.2f from its parent actor '%s', but its "
8338 "requested minimum size is of %.2f x %.2f",
8339 _clutter_actor_get_debug_name (self),
8340 alloc_width, alloc_height,
8341 _clutter_actor_get_debug_name (parent),
8342 min_width, min_height);
8347 clutter_actor_adjust_width (self,
8351 &adj_allocation.x2);
8353 clutter_actor_adjust_height (self,
8357 &adj_allocation.y2);
8359 /* we maintain the invariant that an allocation cannot be adjusted
8360 * to be outside the parent-given box
8362 if (adj_allocation.x1 < allocation->x1 ||
8363 adj_allocation.y1 < allocation->y1 ||
8364 adj_allocation.x2 > allocation->x2 ||
8365 adj_allocation.y2 > allocation->y2)
8367 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8368 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8369 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8370 _clutter_actor_get_debug_name (self),
8371 adj_allocation.x1, adj_allocation.y1,
8372 adj_allocation.x2 - adj_allocation.x1,
8373 adj_allocation.y2 - adj_allocation.y1,
8374 allocation->x1, allocation->y1,
8375 allocation->x2 - allocation->x1,
8376 allocation->y2 - allocation->y1);
8380 *allocation = adj_allocation;
8384 * clutter_actor_allocate:
8385 * @self: A #ClutterActor
8386 * @box: new allocation of the actor, in parent-relative coordinates
8387 * @flags: flags that control the allocation
8389 * Called by the parent of an actor to assign the actor its size.
8390 * Should never be called by applications (except when implementing
8391 * a container or layout manager).
8393 * Actors can know from their allocation box whether they have moved
8394 * with respect to their parent actor. The @flags parameter describes
8395 * additional information about the allocation, for instance whether
8396 * the parent has moved with respect to the stage, for example because
8397 * a grandparent's origin has moved.
8402 clutter_actor_allocate (ClutterActor *self,
8403 const ClutterActorBox *box,
8404 ClutterAllocationFlags flags)
8406 ClutterActorPrivate *priv;
8407 ClutterActorClass *klass;
8408 ClutterActorBox old_allocation, real_allocation;
8409 gboolean origin_changed, child_moved, size_changed;
8410 gboolean stage_allocation_changed;
8412 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8413 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8415 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8416 "which isn't a descendent of the stage!\n",
8417 self, _clutter_actor_get_debug_name (self));
8423 old_allocation = priv->allocation;
8424 real_allocation = *box;
8426 /* constraints are allowed to modify the allocation only here; we do
8427 * this prior to all the other checks so that we can bail out if the
8428 * allocation did not change
8430 clutter_actor_update_constraints (self, &real_allocation);
8432 /* adjust the allocation depending on the align/margin properties */
8433 clutter_actor_adjust_allocation (self, &real_allocation);
8435 if (real_allocation.x2 < real_allocation.x1 ||
8436 real_allocation.y2 < real_allocation.y1)
8438 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8439 _clutter_actor_get_debug_name (self),
8440 real_allocation.x2 - real_allocation.x1,
8441 real_allocation.y2 - real_allocation.y1);
8444 /* we allow 0-sized actors, but not negative-sized ones */
8445 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8446 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8448 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8450 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8451 real_allocation.y1 != old_allocation.y1);
8453 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8454 real_allocation.y2 != old_allocation.y2);
8456 if (origin_changed || child_moved || size_changed)
8457 stage_allocation_changed = TRUE;
8459 stage_allocation_changed = FALSE;
8461 /* If we get an allocation "out of the blue"
8462 * (we did not queue relayout), then we want to
8463 * ignore it. But if we have needs_allocation set,
8464 * we want to guarantee that allocate() virtual
8465 * method is always called, i.e. that queue_relayout()
8466 * always results in an allocate() invocation on
8469 * The optimization here is to avoid re-allocating
8470 * actors that did not queue relayout and were
8473 if (!priv->needs_allocation && !stage_allocation_changed)
8475 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8479 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8480 * clutter_actor_allocate(), it indicates whether the parent has its
8481 * absolute origin moved; when passed in to ClutterActor::allocate()
8482 * virtual method though, it indicates whether the child has its
8483 * absolute origin moved. So we set it when child_moved is TRUE
8486 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8488 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8490 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8491 _clutter_actor_get_debug_name (self));
8493 klass = CLUTTER_ACTOR_GET_CLASS (self);
8494 klass->allocate (self, &real_allocation, flags);
8496 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8498 if (stage_allocation_changed)
8499 clutter_actor_queue_redraw (self);
8503 * clutter_actor_set_allocation:
8504 * @self: a #ClutterActor
8505 * @box: a #ClutterActorBox
8506 * @flags: allocation flags
8508 * Stores the allocation of @self as defined by @box.
8510 * This function can only be called from within the implementation of
8511 * the #ClutterActorClass.allocate() virtual function.
8513 * The allocation should have been adjusted to take into account constraints,
8514 * alignment, and margin properties. If you are implementing a #ClutterActor
8515 * subclass that provides its own layout management policy for its children
8516 * instead of using a #ClutterLayoutManager delegate, you should not call
8517 * this function on the children of @self; instead, you should call
8518 * clutter_actor_allocate(), which will adjust the allocation box for
8521 * This function should only be used by subclasses of #ClutterActor
8522 * that wish to store their allocation but cannot chain up to the
8523 * parent's implementation; the default implementation of the
8524 * #ClutterActorClass.allocate() virtual function will call this
8527 * It is important to note that, while chaining up was the recommended
8528 * behaviour for #ClutterActor subclasses prior to the introduction of
8529 * this function, it is recommended to call clutter_actor_set_allocation()
8532 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8533 * to handle the allocation of its children, this function will call
8534 * the clutter_layout_manager_allocate() function only if the
8535 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8536 * expected that the subclass will call clutter_layout_manager_allocate()
8537 * by itself. For instance, the following code:
8541 * my_actor_allocate (ClutterActor *actor,
8542 * const ClutterActorBox *allocation,
8543 * ClutterAllocationFlags flags)
8545 * ClutterActorBox new_alloc;
8546 * ClutterAllocationFlags new_flags;
8548 * adjust_allocation (allocation, &new_alloc);
8550 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8552 * /* this will use the layout manager set on the actor */
8553 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8557 * is equivalent to this:
8561 * my_actor_allocate (ClutterActor *actor,
8562 * const ClutterActorBox *allocation,
8563 * ClutterAllocationFlags flags)
8565 * ClutterLayoutManager *layout;
8566 * ClutterActorBox new_alloc;
8568 * adjust_allocation (allocation, &new_alloc);
8570 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8572 * layout = clutter_actor_get_layout_manager (actor);
8573 * clutter_layout_manager_allocate (layout,
8574 * CLUTTER_CONTAINER (actor),
8583 clutter_actor_set_allocation (ClutterActor *self,
8584 const ClutterActorBox *box,
8585 ClutterAllocationFlags flags)
8587 ClutterActorPrivate *priv;
8590 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8591 g_return_if_fail (box != NULL);
8593 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8595 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8596 "can only be called from within the implementation of "
8597 "the ClutterActor::allocate() virtual function.");
8603 g_object_freeze_notify (G_OBJECT (self));
8605 changed = clutter_actor_set_allocation_internal (self, box, flags);
8607 /* we allocate our children before we notify changes in our geometry,
8608 * so that people connecting to properties will be able to get valid
8609 * data out of the sub-tree of the scene graph that has this actor at
8612 clutter_actor_maybe_layout_children (self, box, flags);
8616 ClutterActorBox signal_box = priv->allocation;
8617 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8619 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8624 g_object_thaw_notify (G_OBJECT (self));
8628 * clutter_actor_set_geometry:
8629 * @self: A #ClutterActor
8630 * @geometry: A #ClutterGeometry
8632 * Sets the actor's fixed position and forces its minimum and natural
8633 * size, in pixels. This means the untransformed actor will have the
8634 * given geometry. This is the same as calling clutter_actor_set_position()
8635 * and clutter_actor_set_size().
8637 * Deprecated: 1.10: Use clutter_actor_set_position() and
8638 * clutter_actor_set_size() instead.
8641 clutter_actor_set_geometry (ClutterActor *self,
8642 const ClutterGeometry *geometry)
8644 g_object_freeze_notify (G_OBJECT (self));
8646 clutter_actor_set_position (self, geometry->x, geometry->y);
8647 clutter_actor_set_size (self, geometry->width, geometry->height);
8649 g_object_thaw_notify (G_OBJECT (self));
8653 * clutter_actor_get_geometry:
8654 * @self: A #ClutterActor
8655 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8657 * Gets the size and position of an actor relative to its parent
8658 * actor. This is the same as calling clutter_actor_get_position() and
8659 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8660 * requested size and position if the actor's allocation is invalid.
8662 * Deprecated: 1.10: Use clutter_actor_get_position() and
8663 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8667 clutter_actor_get_geometry (ClutterActor *self,
8668 ClutterGeometry *geometry)
8670 gfloat x, y, width, height;
8672 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8673 g_return_if_fail (geometry != NULL);
8675 clutter_actor_get_position (self, &x, &y);
8676 clutter_actor_get_size (self, &width, &height);
8678 geometry->x = (int) x;
8679 geometry->y = (int) y;
8680 geometry->width = (int) width;
8681 geometry->height = (int) height;
8685 * clutter_actor_set_position:
8686 * @self: A #ClutterActor
8687 * @x: New left position of actor in pixels.
8688 * @y: New top position of actor in pixels.
8690 * Sets the actor's fixed position in pixels relative to any parent
8693 * If a layout manager is in use, this position will override the
8694 * layout manager and force a fixed position.
8697 clutter_actor_set_position (ClutterActor *self,
8701 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8703 g_object_freeze_notify (G_OBJECT (self));
8705 clutter_actor_set_x (self, x);
8706 clutter_actor_set_y (self, y);
8708 g_object_thaw_notify (G_OBJECT (self));
8712 * clutter_actor_get_fixed_position_set:
8713 * @self: A #ClutterActor
8715 * Checks whether an actor has a fixed position set (and will thus be
8716 * unaffected by any layout manager).
8718 * Return value: %TRUE if the fixed position is set on the actor
8723 clutter_actor_get_fixed_position_set (ClutterActor *self)
8725 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8727 return self->priv->position_set;
8731 * clutter_actor_set_fixed_position_set:
8732 * @self: A #ClutterActor
8733 * @is_set: whether to use fixed position
8735 * Sets whether an actor has a fixed position set (and will thus be
8736 * unaffected by any layout manager).
8741 clutter_actor_set_fixed_position_set (ClutterActor *self,
8744 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8746 if (self->priv->position_set == (is_set != FALSE))
8749 self->priv->position_set = is_set != FALSE;
8750 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8752 clutter_actor_queue_relayout (self);
8756 * clutter_actor_move_by:
8757 * @self: A #ClutterActor
8758 * @dx: Distance to move Actor on X axis.
8759 * @dy: Distance to move Actor on Y axis.
8761 * Moves an actor by the specified distance relative to its current
8762 * position in pixels.
8764 * This function modifies the fixed position of an actor and thus removes
8765 * it from any layout management. Another way to move an actor is with an
8766 * anchor point, see clutter_actor_set_anchor_point().
8771 clutter_actor_move_by (ClutterActor *self,
8775 const ClutterLayoutInfo *info;
8778 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8780 info = _clutter_actor_get_layout_info_or_defaults (self);
8784 clutter_actor_set_position (self, x + dx, y + dy);
8788 clutter_actor_set_min_width (ClutterActor *self,
8791 ClutterActorPrivate *priv = self->priv;
8792 ClutterActorBox old = { 0, };
8793 ClutterLayoutInfo *info;
8795 /* if we are setting the size on a top-level actor and the
8796 * backend only supports static top-levels (e.g. framebuffers)
8797 * then we ignore the passed value and we override it with
8798 * the stage implementation's preferred size.
8800 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8801 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8804 info = _clutter_actor_get_layout_info (self);
8806 if (priv->min_width_set && min_width == info->min_width)
8809 g_object_freeze_notify (G_OBJECT (self));
8811 clutter_actor_store_old_geometry (self, &old);
8813 info->min_width = min_width;
8814 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8815 clutter_actor_set_min_width_set (self, TRUE);
8817 clutter_actor_notify_if_geometry_changed (self, &old);
8819 g_object_thaw_notify (G_OBJECT (self));
8821 clutter_actor_queue_relayout (self);
8825 clutter_actor_set_min_height (ClutterActor *self,
8829 ClutterActorPrivate *priv = self->priv;
8830 ClutterActorBox old = { 0, };
8831 ClutterLayoutInfo *info;
8833 /* if we are setting the size on a top-level actor and the
8834 * backend only supports static top-levels (e.g. framebuffers)
8835 * then we ignore the passed value and we override it with
8836 * the stage implementation's preferred size.
8838 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8839 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8842 info = _clutter_actor_get_layout_info (self);
8844 if (priv->min_height_set && min_height == info->min_height)
8847 g_object_freeze_notify (G_OBJECT (self));
8849 clutter_actor_store_old_geometry (self, &old);
8851 info->min_height = min_height;
8852 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8853 clutter_actor_set_min_height_set (self, TRUE);
8855 clutter_actor_notify_if_geometry_changed (self, &old);
8857 g_object_thaw_notify (G_OBJECT (self));
8859 clutter_actor_queue_relayout (self);
8863 clutter_actor_set_natural_width (ClutterActor *self,
8864 gfloat natural_width)
8866 ClutterActorPrivate *priv = self->priv;
8867 ClutterActorBox old = { 0, };
8868 ClutterLayoutInfo *info;
8870 /* if we are setting the size on a top-level actor and the
8871 * backend only supports static top-levels (e.g. framebuffers)
8872 * then we ignore the passed value and we override it with
8873 * the stage implementation's preferred size.
8875 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8876 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8879 info = _clutter_actor_get_layout_info (self);
8881 if (priv->natural_width_set && natural_width == info->natural_width)
8884 g_object_freeze_notify (G_OBJECT (self));
8886 clutter_actor_store_old_geometry (self, &old);
8888 info->natural_width = natural_width;
8889 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8890 clutter_actor_set_natural_width_set (self, TRUE);
8892 clutter_actor_notify_if_geometry_changed (self, &old);
8894 g_object_thaw_notify (G_OBJECT (self));
8896 clutter_actor_queue_relayout (self);
8900 clutter_actor_set_natural_height (ClutterActor *self,
8901 gfloat natural_height)
8903 ClutterActorPrivate *priv = self->priv;
8904 ClutterActorBox old = { 0, };
8905 ClutterLayoutInfo *info;
8907 /* if we are setting the size on a top-level actor and the
8908 * backend only supports static top-levels (e.g. framebuffers)
8909 * then we ignore the passed value and we override it with
8910 * the stage implementation's preferred size.
8912 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8913 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8916 info = _clutter_actor_get_layout_info (self);
8918 if (priv->natural_height_set && natural_height == info->natural_height)
8921 g_object_freeze_notify (G_OBJECT (self));
8923 clutter_actor_store_old_geometry (self, &old);
8925 info->natural_height = natural_height;
8926 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8927 clutter_actor_set_natural_height_set (self, TRUE);
8929 clutter_actor_notify_if_geometry_changed (self, &old);
8931 g_object_thaw_notify (G_OBJECT (self));
8933 clutter_actor_queue_relayout (self);
8937 clutter_actor_set_min_width_set (ClutterActor *self,
8938 gboolean use_min_width)
8940 ClutterActorPrivate *priv = self->priv;
8941 ClutterActorBox old = { 0, };
8943 if (priv->min_width_set == (use_min_width != FALSE))
8946 clutter_actor_store_old_geometry (self, &old);
8948 priv->min_width_set = use_min_width != FALSE;
8949 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8951 clutter_actor_notify_if_geometry_changed (self, &old);
8953 clutter_actor_queue_relayout (self);
8957 clutter_actor_set_min_height_set (ClutterActor *self,
8958 gboolean use_min_height)
8960 ClutterActorPrivate *priv = self->priv;
8961 ClutterActorBox old = { 0, };
8963 if (priv->min_height_set == (use_min_height != FALSE))
8966 clutter_actor_store_old_geometry (self, &old);
8968 priv->min_height_set = use_min_height != FALSE;
8969 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8971 clutter_actor_notify_if_geometry_changed (self, &old);
8973 clutter_actor_queue_relayout (self);
8977 clutter_actor_set_natural_width_set (ClutterActor *self,
8978 gboolean use_natural_width)
8980 ClutterActorPrivate *priv = self->priv;
8981 ClutterActorBox old = { 0, };
8983 if (priv->natural_width_set == (use_natural_width != FALSE))
8986 clutter_actor_store_old_geometry (self, &old);
8988 priv->natural_width_set = use_natural_width != FALSE;
8989 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8991 clutter_actor_notify_if_geometry_changed (self, &old);
8993 clutter_actor_queue_relayout (self);
8997 clutter_actor_set_natural_height_set (ClutterActor *self,
8998 gboolean use_natural_height)
9000 ClutterActorPrivate *priv = self->priv;
9001 ClutterActorBox old = { 0, };
9003 if (priv->natural_height_set == (use_natural_height != FALSE))
9006 clutter_actor_store_old_geometry (self, &old);
9008 priv->natural_height_set = use_natural_height != FALSE;
9009 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9011 clutter_actor_notify_if_geometry_changed (self, &old);
9013 clutter_actor_queue_relayout (self);
9017 * clutter_actor_set_request_mode:
9018 * @self: a #ClutterActor
9019 * @mode: the request mode
9021 * Sets the geometry request mode of @self.
9023 * The @mode determines the order for invoking
9024 * clutter_actor_get_preferred_width() and
9025 * clutter_actor_get_preferred_height()
9030 clutter_actor_set_request_mode (ClutterActor *self,
9031 ClutterRequestMode mode)
9033 ClutterActorPrivate *priv;
9035 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9039 if (priv->request_mode == mode)
9042 priv->request_mode = mode;
9044 priv->needs_width_request = TRUE;
9045 priv->needs_height_request = TRUE;
9047 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9049 clutter_actor_queue_relayout (self);
9053 * clutter_actor_get_request_mode:
9054 * @self: a #ClutterActor
9056 * Retrieves the geometry request mode of @self
9058 * Return value: the request mode for the actor
9063 clutter_actor_get_request_mode (ClutterActor *self)
9065 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9066 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9068 return self->priv->request_mode;
9071 /* variant of set_width() without checks and without notification
9072 * freeze+thaw, for internal usage only
9075 clutter_actor_set_width_internal (ClutterActor *self,
9080 /* the Stage will use the :min-width to control the minimum
9081 * width to be resized to, so we should not be setting it
9082 * along with the :natural-width
9084 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9085 clutter_actor_set_min_width (self, width);
9087 clutter_actor_set_natural_width (self, width);
9091 /* we only unset the :natural-width for the Stage */
9092 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9093 clutter_actor_set_min_width_set (self, FALSE);
9095 clutter_actor_set_natural_width_set (self, FALSE);
9099 /* variant of set_height() without checks and without notification
9100 * freeze+thaw, for internal usage only
9103 clutter_actor_set_height_internal (ClutterActor *self,
9108 /* see the comment above in set_width_internal() */
9109 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9110 clutter_actor_set_min_height (self, height);
9112 clutter_actor_set_natural_height (self, height);
9116 /* see the comment above in set_width_internal() */
9117 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9118 clutter_actor_set_min_height_set (self, FALSE);
9120 clutter_actor_set_natural_height_set (self, FALSE);
9125 * clutter_actor_set_size:
9126 * @self: A #ClutterActor
9127 * @width: New width of actor in pixels, or -1
9128 * @height: New height of actor in pixels, or -1
9130 * Sets the actor's size request in pixels. This overrides any
9131 * "normal" size request the actor would have. For example
9132 * a text actor might normally request the size of the text;
9133 * this function would force a specific size instead.
9135 * If @width and/or @height are -1 the actor will use its
9136 * "normal" size request instead of overriding it, i.e.
9137 * you can "unset" the size with -1.
9139 * This function sets or unsets both the minimum and natural size.
9142 clutter_actor_set_size (ClutterActor *self,
9146 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9148 g_object_freeze_notify (G_OBJECT (self));
9150 clutter_actor_set_width (self, width);
9151 clutter_actor_set_height (self, height);
9153 g_object_thaw_notify (G_OBJECT (self));
9157 * clutter_actor_get_size:
9158 * @self: A #ClutterActor
9159 * @width: (out) (allow-none): return location for the width, or %NULL.
9160 * @height: (out) (allow-none): return location for the height, or %NULL.
9162 * This function tries to "do what you mean" and return
9163 * the size an actor will have. If the actor has a valid
9164 * allocation, the allocation will be returned; otherwise,
9165 * the actors natural size request will be returned.
9167 * If you care whether you get the request vs. the allocation, you
9168 * should probably call a different function like
9169 * clutter_actor_get_allocation_box() or
9170 * clutter_actor_get_preferred_width().
9175 clutter_actor_get_size (ClutterActor *self,
9179 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9182 *width = clutter_actor_get_width (self);
9185 *height = clutter_actor_get_height (self);
9189 * clutter_actor_get_position:
9190 * @self: a #ClutterActor
9191 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9192 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9194 * This function tries to "do what you mean" and tell you where the
9195 * actor is, prior to any transformations. Retrieves the fixed
9196 * position of an actor in pixels, if one has been set; otherwise, if
9197 * the allocation is valid, returns the actor's allocated position;
9198 * otherwise, returns 0,0.
9200 * The returned position is in pixels.
9205 clutter_actor_get_position (ClutterActor *self,
9209 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9212 *x = clutter_actor_get_x (self);
9215 *y = clutter_actor_get_y (self);
9219 * clutter_actor_get_transformed_position:
9220 * @self: A #ClutterActor
9221 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9222 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9224 * Gets the absolute position of an actor, in pixels relative to the stage.
9229 clutter_actor_get_transformed_position (ClutterActor *self,
9236 v1.x = v1.y = v1.z = 0;
9237 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9247 * clutter_actor_get_transformed_size:
9248 * @self: A #ClutterActor
9249 * @width: (out) (allow-none): return location for the width, or %NULL
9250 * @height: (out) (allow-none): return location for the height, or %NULL
9252 * Gets the absolute size of an actor in pixels, taking into account the
9255 * If the actor has a valid allocation, the allocated size will be used.
9256 * If the actor has not a valid allocation then the preferred size will
9257 * be transformed and returned.
9259 * If you want the transformed allocation, see
9260 * clutter_actor_get_abs_allocation_vertices() instead.
9262 * <note>When the actor (or one of its ancestors) is rotated around the
9263 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9264 * as a generic quadrangle; in that case this function returns the size
9265 * of the smallest rectangle that encapsulates the entire quad. Please
9266 * note that in this case no assumptions can be made about the relative
9267 * position of this envelope to the absolute position of the actor, as
9268 * returned by clutter_actor_get_transformed_position(); if you need this
9269 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9270 * to get the coords of the actual quadrangle.</note>
9275 clutter_actor_get_transformed_size (ClutterActor *self,
9279 ClutterActorPrivate *priv;
9281 gfloat x_min, x_max, y_min, y_max;
9284 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9288 /* if the actor hasn't been allocated yet, get the preferred
9289 * size and transform that
9291 if (priv->needs_allocation)
9293 gfloat natural_width, natural_height;
9294 ClutterActorBox box;
9296 /* Make a fake allocation to transform.
9298 * NB: _clutter_actor_transform_and_project_box expects a box in
9299 * the actor's coordinate space... */
9304 natural_width = natural_height = 0;
9305 clutter_actor_get_preferred_size (self, NULL, NULL,
9309 box.x2 = natural_width;
9310 box.y2 = natural_height;
9312 _clutter_actor_transform_and_project_box (self, &box, v);
9315 clutter_actor_get_abs_allocation_vertices (self, v);
9317 x_min = x_max = v[0].x;
9318 y_min = y_max = v[0].y;
9320 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9336 *width = x_max - x_min;
9339 *height = y_max - y_min;
9343 * clutter_actor_get_width:
9344 * @self: A #ClutterActor
9346 * Retrieves the width of a #ClutterActor.
9348 * If the actor has a valid allocation, this function will return the
9349 * width of the allocated area given to the actor.
9351 * If the actor does not have a valid allocation, this function will
9352 * return the actor's natural width, that is the preferred width of
9355 * If you care whether you get the preferred width or the width that
9356 * has been assigned to the actor, you should probably call a different
9357 * function like clutter_actor_get_allocation_box() to retrieve the
9358 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9361 * If an actor has a fixed width, for instance a width that has been
9362 * assigned using clutter_actor_set_width(), the width returned will
9363 * be the same value.
9365 * Return value: the width of the actor, in pixels
9368 clutter_actor_get_width (ClutterActor *self)
9370 ClutterActorPrivate *priv;
9372 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9376 if (priv->needs_allocation)
9378 gfloat natural_width = 0;
9380 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9381 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9384 gfloat natural_height = 0;
9386 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9387 clutter_actor_get_preferred_width (self, natural_height,
9392 return natural_width;
9395 return priv->allocation.x2 - priv->allocation.x1;
9399 * clutter_actor_get_height:
9400 * @self: A #ClutterActor
9402 * Retrieves the height of a #ClutterActor.
9404 * If the actor has a valid allocation, this function will return the
9405 * height of the allocated area given to the actor.
9407 * If the actor does not have a valid allocation, this function will
9408 * return the actor's natural height, that is the preferred height of
9411 * If you care whether you get the preferred height or the height that
9412 * has been assigned to the actor, you should probably call a different
9413 * function like clutter_actor_get_allocation_box() to retrieve the
9414 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9417 * If an actor has a fixed height, for instance a height that has been
9418 * assigned using clutter_actor_set_height(), the height returned will
9419 * be the same value.
9421 * Return value: the height of the actor, in pixels
9424 clutter_actor_get_height (ClutterActor *self)
9426 ClutterActorPrivate *priv;
9428 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9432 if (priv->needs_allocation)
9434 gfloat natural_height = 0;
9436 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9438 gfloat natural_width = 0;
9440 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9441 clutter_actor_get_preferred_height (self, natural_width,
9442 NULL, &natural_height);
9445 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9447 return natural_height;
9450 return priv->allocation.y2 - priv->allocation.y1;
9454 * clutter_actor_set_width:
9455 * @self: A #ClutterActor
9456 * @width: Requested new width for the actor, in pixels, or -1
9458 * Forces a width on an actor, causing the actor's preferred width
9459 * and height (if any) to be ignored.
9461 * If @width is -1 the actor will use its preferred width request
9462 * instead of overriding it, i.e. you can "unset" the width with -1.
9464 * This function sets both the minimum and natural size of the actor.
9469 clutter_actor_set_width (ClutterActor *self,
9472 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9474 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9478 /* minor optimization: if we don't have a duration
9479 * then we can skip the get_width() below, to avoid
9480 * the chance of going through get_preferred_width()
9481 * just to jump to a new desired width.
9483 if (clutter_actor_get_easing_duration (self) == 0)
9485 g_object_freeze_notify (G_OBJECT (self));
9487 clutter_actor_set_width_internal (self, width);
9489 g_object_thaw_notify (G_OBJECT (self));
9494 cur_size = clutter_actor_get_width (self);
9496 _clutter_actor_create_transition (self,
9497 obj_props[PROP_WIDTH],
9502 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9504 clutter_actor_queue_relayout (self);
9508 * clutter_actor_set_height:
9509 * @self: A #ClutterActor
9510 * @height: Requested new height for the actor, in pixels, or -1
9512 * Forces a height on an actor, causing the actor's preferred width
9513 * and height (if any) to be ignored.
9515 * If @height is -1 the actor will use its preferred height instead of
9516 * overriding it, i.e. you can "unset" the height with -1.
9518 * This function sets both the minimum and natural size of the actor.
9523 clutter_actor_set_height (ClutterActor *self,
9526 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9528 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9532 /* see the comment in clutter_actor_set_width() above */
9533 if (clutter_actor_get_easing_duration (self) == 0)
9535 g_object_freeze_notify (G_OBJECT (self));
9537 clutter_actor_set_height_internal (self, height);
9539 g_object_thaw_notify (G_OBJECT (self));
9544 cur_size = clutter_actor_get_height (self);
9546 _clutter_actor_create_transition (self,
9547 obj_props[PROP_HEIGHT],
9552 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9554 clutter_actor_queue_relayout (self);
9558 clutter_actor_set_x_internal (ClutterActor *self,
9561 ClutterActorPrivate *priv = self->priv;
9562 ClutterLayoutInfo *linfo;
9563 ClutterActorBox old = { 0, };
9565 linfo = _clutter_actor_get_layout_info (self);
9567 if (priv->position_set && linfo->fixed_x == x)
9570 clutter_actor_store_old_geometry (self, &old);
9573 clutter_actor_set_fixed_position_set (self, TRUE);
9575 clutter_actor_notify_if_geometry_changed (self, &old);
9577 clutter_actor_queue_relayout (self);
9581 clutter_actor_set_y_internal (ClutterActor *self,
9584 ClutterActorPrivate *priv = self->priv;
9585 ClutterLayoutInfo *linfo;
9586 ClutterActorBox old = { 0, };
9588 linfo = _clutter_actor_get_layout_info (self);
9590 if (priv->position_set && linfo->fixed_y == y)
9593 clutter_actor_store_old_geometry (self, &old);
9596 clutter_actor_set_fixed_position_set (self, TRUE);
9598 clutter_actor_notify_if_geometry_changed (self, &old);
9600 clutter_actor_queue_relayout (self);
9604 * clutter_actor_set_x:
9605 * @self: a #ClutterActor
9606 * @x: the actor's position on the X axis
9608 * Sets the actor's X coordinate, relative to its parent, in pixels.
9610 * Overrides any layout manager and forces a fixed position for
9613 * The #ClutterActor:x property is animatable.
9618 clutter_actor_set_x (ClutterActor *self,
9621 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9623 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9625 float cur_position = clutter_actor_get_x (self);
9627 _clutter_actor_create_transition (self, obj_props[PROP_X],
9632 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9634 clutter_actor_queue_relayout (self);
9638 * clutter_actor_set_y:
9639 * @self: a #ClutterActor
9640 * @y: the actor's position on the Y axis
9642 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9644 * Overrides any layout manager and forces a fixed position for
9647 * The #ClutterActor:y property is animatable.
9652 clutter_actor_set_y (ClutterActor *self,
9655 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9657 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9659 float cur_position = clutter_actor_get_y (self);
9661 _clutter_actor_create_transition (self, obj_props[PROP_Y],
9666 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9668 clutter_actor_queue_relayout (self);
9672 * clutter_actor_get_x:
9673 * @self: A #ClutterActor
9675 * Retrieves the X coordinate of a #ClutterActor.
9677 * This function tries to "do what you mean", by returning the
9678 * correct value depending on the actor's state.
9680 * If the actor has a valid allocation, this function will return
9681 * the X coordinate of the origin of the allocation box.
9683 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9684 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9685 * function will return that coordinate.
9687 * If both the allocation and a fixed position are missing, this function
9690 * Return value: the X coordinate, in pixels, ignoring any
9691 * transformation (i.e. scaling, rotation)
9694 clutter_actor_get_x (ClutterActor *self)
9696 ClutterActorPrivate *priv;
9698 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9702 if (priv->needs_allocation)
9704 if (priv->position_set)
9706 const ClutterLayoutInfo *info;
9708 info = _clutter_actor_get_layout_info_or_defaults (self);
9710 return info->fixed_x;
9716 return priv->allocation.x1;
9720 * clutter_actor_get_y:
9721 * @self: A #ClutterActor
9723 * Retrieves the Y coordinate of a #ClutterActor.
9725 * This function tries to "do what you mean", by returning the
9726 * correct value depending on the actor's state.
9728 * If the actor has a valid allocation, this function will return
9729 * the Y coordinate of the origin of the allocation box.
9731 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9732 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9733 * function will return that coordinate.
9735 * If both the allocation and a fixed position are missing, this function
9738 * Return value: the Y coordinate, in pixels, ignoring any
9739 * transformation (i.e. scaling, rotation)
9742 clutter_actor_get_y (ClutterActor *self)
9744 ClutterActorPrivate *priv;
9746 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9750 if (priv->needs_allocation)
9752 if (priv->position_set)
9754 const ClutterLayoutInfo *info;
9756 info = _clutter_actor_get_layout_info_or_defaults (self);
9758 return info->fixed_y;
9764 return priv->allocation.y1;
9768 * clutter_actor_set_scale:
9769 * @self: A #ClutterActor
9770 * @scale_x: double factor to scale actor by horizontally.
9771 * @scale_y: double factor to scale actor by vertically.
9773 * Scales an actor with the given factors. The scaling is relative to
9774 * the scale center and the anchor point. The scale center is
9775 * unchanged by this function and defaults to 0,0.
9777 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9783 clutter_actor_set_scale (ClutterActor *self,
9787 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9789 g_object_freeze_notify (G_OBJECT (self));
9791 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9792 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9794 g_object_thaw_notify (G_OBJECT (self));
9798 * clutter_actor_set_scale_full:
9799 * @self: A #ClutterActor
9800 * @scale_x: double factor to scale actor by horizontally.
9801 * @scale_y: double factor to scale actor by vertically.
9802 * @center_x: X coordinate of the center of the scale.
9803 * @center_y: Y coordinate of the center of the scale
9805 * Scales an actor with the given factors around the given center
9806 * point. The center point is specified in pixels relative to the
9807 * anchor point (usually the top left corner of the actor).
9809 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9815 clutter_actor_set_scale_full (ClutterActor *self,
9821 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9823 g_object_freeze_notify (G_OBJECT (self));
9825 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9826 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9827 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9828 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9830 g_object_thaw_notify (G_OBJECT (self));
9834 * clutter_actor_set_scale_with_gravity:
9835 * @self: A #ClutterActor
9836 * @scale_x: double factor to scale actor by horizontally.
9837 * @scale_y: double factor to scale actor by vertically.
9838 * @gravity: the location of the scale center expressed as a compass
9841 * Scales an actor with the given factors around the given
9842 * center point. The center point is specified as one of the compass
9843 * directions in #ClutterGravity. For example, setting it to north
9844 * will cause the top of the actor to remain unchanged and the rest of
9845 * the actor to expand left, right and downwards.
9847 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9853 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9856 ClutterGravity gravity)
9858 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9860 g_object_freeze_notify (G_OBJECT (self));
9862 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9863 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9864 clutter_actor_set_scale_gravity (self, gravity);
9866 g_object_thaw_notify (G_OBJECT (self));
9870 * clutter_actor_get_scale:
9871 * @self: A #ClutterActor
9872 * @scale_x: (out) (allow-none): Location to store horizonal
9873 * scale factor, or %NULL.
9874 * @scale_y: (out) (allow-none): Location to store vertical
9875 * scale factor, or %NULL.
9877 * Retrieves an actors scale factors.
9882 clutter_actor_get_scale (ClutterActor *self,
9886 const ClutterTransformInfo *info;
9888 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9890 info = _clutter_actor_get_transform_info_or_defaults (self);
9893 *scale_x = info->scale_x;
9896 *scale_y = info->scale_y;
9900 * clutter_actor_get_scale_center:
9901 * @self: A #ClutterActor
9902 * @center_x: (out) (allow-none): Location to store the X position
9903 * of the scale center, or %NULL.
9904 * @center_y: (out) (allow-none): Location to store the Y position
9905 * of the scale center, or %NULL.
9907 * Retrieves the scale center coordinate in pixels relative to the top
9908 * left corner of the actor. If the scale center was specified using a
9909 * #ClutterGravity this will calculate the pixel offset using the
9910 * current size of the actor.
9915 clutter_actor_get_scale_center (ClutterActor *self,
9919 const ClutterTransformInfo *info;
9921 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9923 info = _clutter_actor_get_transform_info_or_defaults (self);
9925 clutter_anchor_coord_get_units (self, &info->scale_center,
9932 * clutter_actor_get_scale_gravity:
9933 * @self: A #ClutterActor
9935 * Retrieves the scale center as a compass direction. If the scale
9936 * center was specified in pixels or units this will return
9937 * %CLUTTER_GRAVITY_NONE.
9939 * Return value: the scale gravity
9944 clutter_actor_get_scale_gravity (ClutterActor *self)
9946 const ClutterTransformInfo *info;
9948 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9950 info = _clutter_actor_get_transform_info_or_defaults (self);
9952 return clutter_anchor_coord_get_gravity (&info->scale_center);
9956 clutter_actor_set_opacity_internal (ClutterActor *self,
9959 ClutterActorPrivate *priv = self->priv;
9961 if (priv->opacity != opacity)
9963 priv->opacity = opacity;
9965 /* Queue a redraw from the flatten effect so that it can use
9966 its cached image if available instead of having to redraw the
9967 actual actor. If it doesn't end up using the FBO then the
9968 effect is still able to continue the paint anyway. If there
9969 is no flatten effect yet then this is equivalent to queueing
9971 _clutter_actor_queue_redraw_full (self,
9974 priv->flatten_effect);
9976 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9981 * clutter_actor_set_opacity:
9982 * @self: A #ClutterActor
9983 * @opacity: New opacity value for the actor.
9985 * Sets the actor's opacity, with zero being completely transparent and
9986 * 255 (0xff) being fully opaque.
9988 * The #ClutterActor:opacity property is animatable.
9991 clutter_actor_set_opacity (ClutterActor *self,
9994 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9996 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
9998 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
9999 self->priv->opacity,
10003 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10005 clutter_actor_queue_redraw (self);
10009 * clutter_actor_get_paint_opacity_internal:
10010 * @self: a #ClutterActor
10012 * Retrieves the absolute opacity of the actor, as it appears on the stage
10014 * This function does not do type checks
10016 * Return value: the absolute opacity of the actor
10019 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10021 ClutterActorPrivate *priv = self->priv;
10022 ClutterActor *parent;
10024 /* override the top-level opacity to always be 255; even in
10025 * case of ClutterStage:use-alpha being TRUE we want the rest
10026 * of the scene to be painted
10028 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10031 if (priv->opacity_override >= 0)
10032 return priv->opacity_override;
10034 parent = priv->parent;
10036 /* Factor in the actual actors opacity with parents */
10037 if (parent != NULL)
10039 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10041 if (opacity != 0xff)
10042 return (opacity * priv->opacity) / 0xff;
10045 return priv->opacity;
10050 * clutter_actor_get_paint_opacity:
10051 * @self: A #ClutterActor
10053 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10055 * This function traverses the hierarchy chain and composites the opacity of
10056 * the actor with that of its parents.
10058 * This function is intended for subclasses to use in the paint virtual
10059 * function, to paint themselves with the correct opacity.
10061 * Return value: The actor opacity value.
10066 clutter_actor_get_paint_opacity (ClutterActor *self)
10068 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10070 return clutter_actor_get_paint_opacity_internal (self);
10074 * clutter_actor_get_opacity:
10075 * @self: a #ClutterActor
10077 * Retrieves the opacity value of an actor, as set by
10078 * clutter_actor_set_opacity().
10080 * For retrieving the absolute opacity of the actor inside a paint
10081 * virtual function, see clutter_actor_get_paint_opacity().
10083 * Return value: the opacity of the actor
10086 clutter_actor_get_opacity (ClutterActor *self)
10088 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10090 return self->priv->opacity;
10094 * clutter_actor_set_offscreen_redirect:
10095 * @self: A #ClutterActor
10096 * @redirect: New offscreen redirect flags for the actor.
10098 * Defines the circumstances where the actor should be redirected into
10099 * an offscreen image. The offscreen image is used to flatten the
10100 * actor into a single image while painting for two main reasons.
10101 * Firstly, when the actor is painted a second time without any of its
10102 * contents changing it can simply repaint the cached image without
10103 * descending further down the actor hierarchy. Secondly, it will make
10104 * the opacity look correct even if there are overlapping primitives
10107 * Caching the actor could in some cases be a performance win and in
10108 * some cases be a performance lose so it is important to determine
10109 * which value is right for an actor before modifying this value. For
10110 * example, there is never any reason to flatten an actor that is just
10111 * a single texture (such as a #ClutterTexture) because it is
10112 * effectively already cached in an image so the offscreen would be
10113 * redundant. Also if the actor contains primitives that are far apart
10114 * with a large transparent area in the middle (such as a large
10115 * CluterGroup with a small actor in the top left and a small actor in
10116 * the bottom right) then the cached image will contain the entire
10117 * image of the large area and the paint will waste time blending all
10118 * of the transparent pixels in the middle.
10120 * The default method of implementing opacity on a container simply
10121 * forwards on the opacity to all of the children. If the children are
10122 * overlapping then it will appear as if they are two separate glassy
10123 * objects and there will be a break in the color where they
10124 * overlap. By redirecting to an offscreen buffer it will be as if the
10125 * two opaque objects are combined into one and then made transparent
10126 * which is usually what is expected.
10128 * The image below demonstrates the difference between redirecting and
10129 * not. The image shows two Clutter groups, each containing a red and
10130 * a green rectangle which overlap. The opacity on the group is set to
10131 * 128 (which is 50%). When the offscreen redirect is not used, the
10132 * red rectangle can be seen through the blue rectangle as if the two
10133 * rectangles were separately transparent. When the redirect is used
10134 * the group as a whole is transparent instead so the red rectangle is
10135 * not visible where they overlap.
10137 * <figure id="offscreen-redirect">
10138 * <title>Sample of using an offscreen redirect for transparency</title>
10139 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10142 * The default value for this property is 0, so we effectively will
10143 * never redirect an actor offscreen by default. This means that there
10144 * are times that transparent actors may look glassy as described
10145 * above. The reason this is the default is because there is a
10146 * performance trade off between quality and performance here. In many
10147 * cases the default form of glassy opacity looks good enough, but if
10148 * it's not you will need to set the
10149 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10150 * redirection for opacity.
10152 * Custom actors that don't contain any overlapping primitives are
10153 * recommended to override the has_overlaps() virtual to return %FALSE
10154 * for maximum efficiency.
10159 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10160 ClutterOffscreenRedirect redirect)
10162 ClutterActorPrivate *priv;
10164 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10168 if (priv->offscreen_redirect != redirect)
10170 priv->offscreen_redirect = redirect;
10172 /* Queue a redraw from the effect so that it can use its cached
10173 image if available instead of having to redraw the actual
10174 actor. If it doesn't end up using the FBO then the effect is
10175 still able to continue the paint anyway. If there is no
10176 effect then this is equivalent to queuing a full redraw */
10177 _clutter_actor_queue_redraw_full (self,
10180 priv->flatten_effect);
10182 g_object_notify_by_pspec (G_OBJECT (self),
10183 obj_props[PROP_OFFSCREEN_REDIRECT]);
10188 * clutter_actor_get_offscreen_redirect:
10189 * @self: a #ClutterActor
10191 * Retrieves whether to redirect the actor to an offscreen buffer, as
10192 * set by clutter_actor_set_offscreen_redirect().
10194 * Return value: the value of the offscreen-redirect property of the actor
10198 ClutterOffscreenRedirect
10199 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10201 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10203 return self->priv->offscreen_redirect;
10207 * clutter_actor_set_name:
10208 * @self: A #ClutterActor
10209 * @name: Textual tag to apply to actor
10211 * Sets the given name to @self. The name can be used to identify
10215 clutter_actor_set_name (ClutterActor *self,
10218 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10220 g_free (self->priv->name);
10221 self->priv->name = g_strdup (name);
10223 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10227 * clutter_actor_get_name:
10228 * @self: A #ClutterActor
10230 * Retrieves the name of @self.
10232 * Return value: the name of the actor, or %NULL. The returned string is
10233 * owned by the actor and should not be modified or freed.
10236 clutter_actor_get_name (ClutterActor *self)
10238 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10240 return self->priv->name;
10244 * clutter_actor_get_gid:
10245 * @self: A #ClutterActor
10247 * Retrieves the unique id for @self.
10249 * Return value: Globally unique value for this object instance.
10253 * Deprecated: 1.8: The id is not used any longer.
10256 clutter_actor_get_gid (ClutterActor *self)
10258 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10260 return self->priv->id;
10264 clutter_actor_set_depth_internal (ClutterActor *self,
10267 ClutterTransformInfo *info;
10269 info = _clutter_actor_get_transform_info (self);
10271 if (info->depth != depth)
10273 /* Sets Z value - XXX 2.0: should we invert? */
10274 info->depth = depth;
10276 self->priv->transform_valid = FALSE;
10278 /* FIXME - remove this crap; sadly, there are still containers
10279 * in Clutter that depend on this utter brain damage
10281 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10283 clutter_actor_queue_redraw (self);
10285 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10290 * clutter_actor_set_depth:
10291 * @self: a #ClutterActor
10294 * Sets the Z coordinate of @self to @depth.
10296 * The unit used by @depth is dependant on the perspective setup. See
10297 * also clutter_stage_set_perspective().
10300 clutter_actor_set_depth (ClutterActor *self,
10303 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10305 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10307 const ClutterTransformInfo *info;
10309 info = _clutter_actor_get_transform_info_or_defaults (self);
10311 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10316 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10318 clutter_actor_queue_redraw (self);
10322 * clutter_actor_get_depth:
10323 * @self: a #ClutterActor
10325 * Retrieves the depth of @self.
10327 * Return value: the depth of the actor
10330 clutter_actor_get_depth (ClutterActor *self)
10332 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10334 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10338 * clutter_actor_set_rotation:
10339 * @self: a #ClutterActor
10340 * @axis: the axis of rotation
10341 * @angle: the angle of rotation
10342 * @x: X coordinate of the rotation center
10343 * @y: Y coordinate of the rotation center
10344 * @z: Z coordinate of the rotation center
10346 * Sets the rotation angle of @self around the given axis.
10348 * The rotation center coordinates used depend on the value of @axis:
10350 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10351 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10352 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10355 * The rotation coordinates are relative to the anchor point of the
10356 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10357 * point is set, the upper left corner is assumed as the origin.
10362 clutter_actor_set_rotation (ClutterActor *self,
10363 ClutterRotateAxis axis,
10371 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10377 g_object_freeze_notify (G_OBJECT (self));
10379 clutter_actor_set_rotation_angle (self, axis, angle);
10380 clutter_actor_set_rotation_center_internal (self, axis, &v);
10382 g_object_thaw_notify (G_OBJECT (self));
10386 * clutter_actor_set_z_rotation_from_gravity:
10387 * @self: a #ClutterActor
10388 * @angle: the angle of rotation
10389 * @gravity: the center point of the rotation
10391 * Sets the rotation angle of @self around the Z axis using the center
10392 * point specified as a compass point. For example to rotate such that
10393 * the center of the actor remains static you can use
10394 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10395 * will move accordingly.
10400 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10402 ClutterGravity gravity)
10404 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10406 if (gravity == CLUTTER_GRAVITY_NONE)
10407 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10410 GObject *obj = G_OBJECT (self);
10411 ClutterTransformInfo *info;
10413 info = _clutter_actor_get_transform_info (self);
10415 g_object_freeze_notify (obj);
10417 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10419 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10420 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10421 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10423 g_object_thaw_notify (obj);
10428 * clutter_actor_get_rotation:
10429 * @self: a #ClutterActor
10430 * @axis: the axis of rotation
10431 * @x: (out): return value for the X coordinate of the center of rotation
10432 * @y: (out): return value for the Y coordinate of the center of rotation
10433 * @z: (out): return value for the Z coordinate of the center of rotation
10435 * Retrieves the angle and center of rotation on the given axis,
10436 * set using clutter_actor_set_rotation().
10438 * Return value: the angle of rotation
10443 clutter_actor_get_rotation (ClutterActor *self,
10444 ClutterRotateAxis axis,
10449 const ClutterTransformInfo *info;
10450 const AnchorCoord *anchor_coord;
10451 gdouble retval = 0;
10453 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10455 info = _clutter_actor_get_transform_info_or_defaults (self);
10459 case CLUTTER_X_AXIS:
10460 anchor_coord = &info->rx_center;
10461 retval = info->rx_angle;
10464 case CLUTTER_Y_AXIS:
10465 anchor_coord = &info->ry_center;
10466 retval = info->ry_angle;
10469 case CLUTTER_Z_AXIS:
10470 anchor_coord = &info->rz_center;
10471 retval = info->rz_angle;
10475 anchor_coord = NULL;
10480 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10486 * clutter_actor_get_z_rotation_gravity:
10487 * @self: A #ClutterActor
10489 * Retrieves the center for the rotation around the Z axis as a
10490 * compass direction. If the center was specified in pixels or units
10491 * this will return %CLUTTER_GRAVITY_NONE.
10493 * Return value: the Z rotation center
10498 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10500 const ClutterTransformInfo *info;
10502 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10504 info = _clutter_actor_get_transform_info_or_defaults (self);
10506 return clutter_anchor_coord_get_gravity (&info->rz_center);
10510 * clutter_actor_set_clip:
10511 * @self: A #ClutterActor
10512 * @xoff: X offset of the clip rectangle
10513 * @yoff: Y offset of the clip rectangle
10514 * @width: Width of the clip rectangle
10515 * @height: Height of the clip rectangle
10517 * Sets clip area for @self. The clip area is always computed from the
10518 * upper left corner of the actor, even if the anchor point is set
10524 clutter_actor_set_clip (ClutterActor *self,
10530 ClutterActorPrivate *priv;
10532 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10536 if (priv->has_clip &&
10537 priv->clip.x == xoff &&
10538 priv->clip.y == yoff &&
10539 priv->clip.width == width &&
10540 priv->clip.height == height)
10543 priv->clip.x = xoff;
10544 priv->clip.y = yoff;
10545 priv->clip.width = width;
10546 priv->clip.height = height;
10548 priv->has_clip = TRUE;
10550 clutter_actor_queue_redraw (self);
10552 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10553 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10557 * clutter_actor_remove_clip:
10558 * @self: A #ClutterActor
10560 * Removes clip area from @self.
10563 clutter_actor_remove_clip (ClutterActor *self)
10565 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10567 if (!self->priv->has_clip)
10570 self->priv->has_clip = FALSE;
10572 clutter_actor_queue_redraw (self);
10574 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10578 * clutter_actor_has_clip:
10579 * @self: a #ClutterActor
10581 * Determines whether the actor has a clip area set or not.
10583 * Return value: %TRUE if the actor has a clip area set.
10588 clutter_actor_has_clip (ClutterActor *self)
10590 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10592 return self->priv->has_clip;
10596 * clutter_actor_get_clip:
10597 * @self: a #ClutterActor
10598 * @xoff: (out) (allow-none): return location for the X offset of
10599 * the clip rectangle, or %NULL
10600 * @yoff: (out) (allow-none): return location for the Y offset of
10601 * the clip rectangle, or %NULL
10602 * @width: (out) (allow-none): return location for the width of
10603 * the clip rectangle, or %NULL
10604 * @height: (out) (allow-none): return location for the height of
10605 * the clip rectangle, or %NULL
10607 * Gets the clip area for @self, if any is set
10612 clutter_actor_get_clip (ClutterActor *self,
10618 ClutterActorPrivate *priv;
10620 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10624 if (!priv->has_clip)
10628 *xoff = priv->clip.x;
10631 *yoff = priv->clip.y;
10634 *width = priv->clip.width;
10636 if (height != NULL)
10637 *height = priv->clip.height;
10641 * clutter_actor_get_children:
10642 * @self: a #ClutterActor
10644 * Retrieves the list of children of @self.
10646 * Return value: (transfer container) (element-type ClutterActor): A newly
10647 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10653 clutter_actor_get_children (ClutterActor *self)
10655 ClutterActor *iter;
10658 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10660 /* we walk the list backward so that we can use prepend(),
10663 for (iter = self->priv->last_child, res = NULL;
10665 iter = iter->priv->prev_sibling)
10667 res = g_list_prepend (res, iter);
10674 * insert_child_at_depth:
10675 * @self: a #ClutterActor
10676 * @child: a #ClutterActor
10678 * Inserts @child inside the list of children held by @self, using
10679 * the depth as the insertion criteria.
10681 * This sadly makes the insertion not O(1), but we can keep the
10682 * list sorted so that the painters algorithm we use for painting
10683 * the children will work correctly.
10686 insert_child_at_depth (ClutterActor *self,
10687 ClutterActor *child,
10688 gpointer dummy G_GNUC_UNUSED)
10690 ClutterActor *iter;
10693 child->priv->parent = self;
10696 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10698 /* special-case the first child */
10699 if (self->priv->n_children == 0)
10701 self->priv->first_child = child;
10702 self->priv->last_child = child;
10704 child->priv->next_sibling = NULL;
10705 child->priv->prev_sibling = NULL;
10710 /* Find the right place to insert the child so that it will still be
10711 sorted and the child will be after all of the actors at the same
10713 for (iter = self->priv->first_child;
10715 iter = iter->priv->next_sibling)
10720 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10722 if (iter_depth > child_depth)
10728 ClutterActor *tmp = iter->priv->prev_sibling;
10731 tmp->priv->next_sibling = child;
10733 /* Insert the node before the found one */
10734 child->priv->prev_sibling = iter->priv->prev_sibling;
10735 child->priv->next_sibling = iter;
10736 iter->priv->prev_sibling = child;
10740 ClutterActor *tmp = self->priv->last_child;
10743 tmp->priv->next_sibling = child;
10745 /* insert the node at the end of the list */
10746 child->priv->prev_sibling = self->priv->last_child;
10747 child->priv->next_sibling = NULL;
10750 if (child->priv->prev_sibling == NULL)
10751 self->priv->first_child = child;
10753 if (child->priv->next_sibling == NULL)
10754 self->priv->last_child = child;
10758 insert_child_at_index (ClutterActor *self,
10759 ClutterActor *child,
10762 gint index_ = GPOINTER_TO_INT (data_);
10764 child->priv->parent = self;
10768 ClutterActor *tmp = self->priv->first_child;
10771 tmp->priv->prev_sibling = child;
10773 child->priv->prev_sibling = NULL;
10774 child->priv->next_sibling = tmp;
10776 else if (index_ < 0 || index_ >= self->priv->n_children)
10778 ClutterActor *tmp = self->priv->last_child;
10781 tmp->priv->next_sibling = child;
10783 child->priv->prev_sibling = tmp;
10784 child->priv->next_sibling = NULL;
10788 ClutterActor *iter;
10791 for (iter = self->priv->first_child, i = 0;
10793 iter = iter->priv->next_sibling, i += 1)
10797 ClutterActor *tmp = iter->priv->prev_sibling;
10799 child->priv->prev_sibling = tmp;
10800 child->priv->next_sibling = iter;
10802 iter->priv->prev_sibling = child;
10805 tmp->priv->next_sibling = child;
10812 if (child->priv->prev_sibling == NULL)
10813 self->priv->first_child = child;
10815 if (child->priv->next_sibling == NULL)
10816 self->priv->last_child = child;
10820 insert_child_above (ClutterActor *self,
10821 ClutterActor *child,
10824 ClutterActor *sibling = data;
10826 child->priv->parent = self;
10828 if (sibling == NULL)
10829 sibling = self->priv->last_child;
10831 child->priv->prev_sibling = sibling;
10833 if (sibling != NULL)
10835 ClutterActor *tmp = sibling->priv->next_sibling;
10837 child->priv->next_sibling = tmp;
10840 tmp->priv->prev_sibling = child;
10842 sibling->priv->next_sibling = child;
10845 child->priv->next_sibling = NULL;
10847 if (child->priv->prev_sibling == NULL)
10848 self->priv->first_child = child;
10850 if (child->priv->next_sibling == NULL)
10851 self->priv->last_child = child;
10855 insert_child_below (ClutterActor *self,
10856 ClutterActor *child,
10859 ClutterActor *sibling = data;
10861 child->priv->parent = self;
10863 if (sibling == NULL)
10864 sibling = self->priv->first_child;
10866 child->priv->next_sibling = sibling;
10868 if (sibling != NULL)
10870 ClutterActor *tmp = sibling->priv->prev_sibling;
10872 child->priv->prev_sibling = tmp;
10875 tmp->priv->next_sibling = child;
10877 sibling->priv->prev_sibling = child;
10880 child->priv->prev_sibling = NULL;
10882 if (child->priv->prev_sibling == NULL)
10883 self->priv->first_child = child;
10885 if (child->priv->next_sibling == NULL)
10886 self->priv->last_child = child;
10889 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10890 ClutterActor *child,
10894 ADD_CHILD_CREATE_META = 1 << 0,
10895 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10896 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10897 ADD_CHILD_CHECK_STATE = 1 << 3,
10898 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10900 /* default flags for public API */
10901 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10902 ADD_CHILD_EMIT_PARENT_SET |
10903 ADD_CHILD_EMIT_ACTOR_ADDED |
10904 ADD_CHILD_CHECK_STATE |
10905 ADD_CHILD_NOTIFY_FIRST_LAST,
10907 /* flags for legacy/deprecated API */
10908 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10909 ADD_CHILD_CHECK_STATE |
10910 ADD_CHILD_NOTIFY_FIRST_LAST
10911 } ClutterActorAddChildFlags;
10914 * clutter_actor_add_child_internal:
10915 * @self: a #ClutterActor
10916 * @child: a #ClutterActor
10917 * @flags: control flags for actions
10918 * @add_func: delegate function
10919 * @data: (closure): data to pass to @add_func
10921 * Adds @child to the list of children of @self.
10923 * The actual insertion inside the list is delegated to @add_func: this
10924 * function will just set up the state, perform basic checks, and emit
10927 * The @flags argument is used to perform additional operations.
10930 clutter_actor_add_child_internal (ClutterActor *self,
10931 ClutterActor *child,
10932 ClutterActorAddChildFlags flags,
10933 ClutterActorAddChildFunc add_func,
10936 ClutterTextDirection text_dir;
10937 gboolean create_meta;
10938 gboolean emit_parent_set, emit_actor_added;
10939 gboolean check_state;
10940 gboolean notify_first_last;
10941 ClutterActor *old_first_child, *old_last_child;
10943 if (child->priv->parent != NULL)
10945 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10946 "use clutter_actor_remove_child() first.",
10947 _clutter_actor_get_debug_name (child),
10948 _clutter_actor_get_debug_name (child->priv->parent));
10952 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10954 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10955 "a child of another actor.",
10956 _clutter_actor_get_debug_name (child));
10961 /* XXX - this check disallows calling methods that change the stacking
10962 * order within the destruction sequence, by triggering a critical
10963 * warning first, and leaving the actor in an undefined state, which
10964 * then ends up being caught by an assertion.
10966 * the reproducible sequence is:
10968 * - actor gets destroyed;
10969 * - another actor, linked to the first, will try to change the
10970 * stacking order of the first actor;
10971 * - changing the stacking order is a composite operation composed
10972 * by the following steps:
10973 * 1. ref() the child;
10974 * 2. remove_child_internal(), which removes the reference;
10975 * 3. add_child_internal(), which adds a reference;
10976 * - the state of the actor is not changed between (2) and (3), as
10977 * it could be an expensive recomputation;
10978 * - if (3) bails out, then the actor is in an undefined state, but
10980 * - the destruction sequence terminates, but the actor is unparented
10981 * while its state indicates being parented instead.
10982 * - assertion failure.
10984 * the obvious fix would be to decompose each set_child_*_sibling()
10985 * method into proper remove_child()/add_child(), with state validation;
10986 * this may cause excessive work, though, and trigger a cascade of other
10987 * bugs in code that assumes that a change in the stacking order is an
10988 * atomic operation.
10990 * another potential fix is to just remove this check here, and let
10991 * code doing stacking order changes inside the destruction sequence
10992 * of an actor continue doing the work.
10994 * the third fix is to silently bail out early from every
10995 * set_child_*_sibling() and set_child_at_index() method, and avoid
10998 * I have a preference for the second solution, since it involves the
10999 * least amount of work, and the least amount of code duplication.
11001 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11003 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11005 g_warning ("The actor '%s' is currently being destroyed, and "
11006 "cannot be added as a child of another actor.",
11007 _clutter_actor_get_debug_name (child));
11012 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11013 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11014 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11015 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11016 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11018 old_first_child = self->priv->first_child;
11019 old_last_child = self->priv->last_child;
11021 g_object_freeze_notify (G_OBJECT (self));
11024 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11026 g_object_ref_sink (child);
11027 child->priv->parent = NULL;
11028 child->priv->next_sibling = NULL;
11029 child->priv->prev_sibling = NULL;
11031 /* delegate the actual insertion */
11032 add_func (self, child, data);
11034 g_assert (child->priv->parent == self);
11036 self->priv->n_children += 1;
11038 self->priv->age += 1;
11040 /* if push_internal() has been called then we automatically set
11041 * the flag on the actor
11043 if (self->priv->internal_child)
11044 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11046 /* clutter_actor_reparent() will emit ::parent-set for us */
11047 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11048 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11052 /* If parent is mapped or realized, we need to also be mapped or
11053 * realized once we're inside the parent.
11055 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11057 /* propagate the parent's text direction to the child */
11058 text_dir = clutter_actor_get_text_direction (self);
11059 clutter_actor_set_text_direction (child, text_dir);
11062 if (child->priv->show_on_set_parent)
11063 clutter_actor_show (child);
11065 if (CLUTTER_ACTOR_IS_MAPPED (child))
11066 clutter_actor_queue_redraw (child);
11068 /* maintain the invariant that if an actor needs layout,
11069 * its parents do as well
11071 if (child->priv->needs_width_request ||
11072 child->priv->needs_height_request ||
11073 child->priv->needs_allocation)
11075 /* we work around the short-circuiting we do
11076 * in clutter_actor_queue_relayout() since we
11077 * want to force a relayout
11079 child->priv->needs_width_request = TRUE;
11080 child->priv->needs_height_request = TRUE;
11081 child->priv->needs_allocation = TRUE;
11083 clutter_actor_queue_relayout (child->priv->parent);
11086 if (emit_actor_added)
11087 g_signal_emit_by_name (self, "actor-added", child);
11089 if (notify_first_last)
11091 if (old_first_child != self->priv->first_child)
11092 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11094 if (old_last_child != self->priv->last_child)
11095 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11098 g_object_thaw_notify (G_OBJECT (self));
11102 * clutter_actor_add_child:
11103 * @self: a #ClutterActor
11104 * @child: a #ClutterActor
11106 * Adds @child to the children of @self.
11108 * This function will acquire a reference on @child that will only
11109 * be released when calling clutter_actor_remove_child().
11111 * This function will take into consideration the #ClutterActor:depth
11112 * of @child, and will keep the list of children sorted.
11114 * This function will emit the #ClutterContainer::actor-added signal
11120 clutter_actor_add_child (ClutterActor *self,
11121 ClutterActor *child)
11123 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11124 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11125 g_return_if_fail (self != child);
11126 g_return_if_fail (child->priv->parent == NULL);
11128 clutter_actor_add_child_internal (self, child,
11129 ADD_CHILD_DEFAULT_FLAGS,
11130 insert_child_at_depth,
11135 * clutter_actor_insert_child_at_index:
11136 * @self: a #ClutterActor
11137 * @child: a #ClutterActor
11138 * @index_: the index
11140 * Inserts @child into the list of children of @self, using the
11141 * given @index_. If @index_ is greater than the number of children
11142 * in @self, or is less than 0, then the new child is added at the end.
11144 * This function will acquire a reference on @child that will only
11145 * be released when calling clutter_actor_remove_child().
11147 * This function will not take into consideration the #ClutterActor:depth
11150 * This function will emit the #ClutterContainer::actor-added signal
11156 clutter_actor_insert_child_at_index (ClutterActor *self,
11157 ClutterActor *child,
11160 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11161 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11162 g_return_if_fail (self != child);
11163 g_return_if_fail (child->priv->parent == NULL);
11165 clutter_actor_add_child_internal (self, child,
11166 ADD_CHILD_DEFAULT_FLAGS,
11167 insert_child_at_index,
11168 GINT_TO_POINTER (index_));
11172 * clutter_actor_insert_child_above:
11173 * @self: a #ClutterActor
11174 * @child: a #ClutterActor
11175 * @sibling: (allow-none): a child of @self, or %NULL
11177 * Inserts @child into the list of children of @self, above another
11178 * child of @self or, if @sibling is %NULL, above all the children
11181 * This function will acquire a reference on @child that will only
11182 * be released when calling clutter_actor_remove_child().
11184 * This function will not take into consideration the #ClutterActor:depth
11187 * This function will emit the #ClutterContainer::actor-added signal
11193 clutter_actor_insert_child_above (ClutterActor *self,
11194 ClutterActor *child,
11195 ClutterActor *sibling)
11197 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11198 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11199 g_return_if_fail (self != child);
11200 g_return_if_fail (child != sibling);
11201 g_return_if_fail (child->priv->parent == NULL);
11202 g_return_if_fail (sibling == NULL ||
11203 (CLUTTER_IS_ACTOR (sibling) &&
11204 sibling->priv->parent == self));
11206 clutter_actor_add_child_internal (self, child,
11207 ADD_CHILD_DEFAULT_FLAGS,
11208 insert_child_above,
11213 * clutter_actor_insert_child_below:
11214 * @self: a #ClutterActor
11215 * @child: a #ClutterActor
11216 * @sibling: (allow-none): a child of @self, or %NULL
11218 * Inserts @child into the list of children of @self, below another
11219 * child of @self or, if @sibling is %NULL, below all the children
11222 * This function will acquire a reference on @child that will only
11223 * be released when calling clutter_actor_remove_child().
11225 * This function will not take into consideration the #ClutterActor:depth
11228 * This function will emit the #ClutterContainer::actor-added signal
11234 clutter_actor_insert_child_below (ClutterActor *self,
11235 ClutterActor *child,
11236 ClutterActor *sibling)
11238 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11239 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11240 g_return_if_fail (self != child);
11241 g_return_if_fail (child != sibling);
11242 g_return_if_fail (child->priv->parent == NULL);
11243 g_return_if_fail (sibling == NULL ||
11244 (CLUTTER_IS_ACTOR (sibling) &&
11245 sibling->priv->parent == self));
11247 clutter_actor_add_child_internal (self, child,
11248 ADD_CHILD_DEFAULT_FLAGS,
11249 insert_child_below,
11254 * clutter_actor_set_parent:
11255 * @self: A #ClutterActor
11256 * @parent: A new #ClutterActor parent
11258 * Sets the parent of @self to @parent.
11260 * This function will result in @parent acquiring a reference on @self,
11261 * eventually by sinking its floating reference first. The reference
11262 * will be released by clutter_actor_unparent().
11264 * This function should only be called by legacy #ClutterActor<!-- -->s
11265 * implementing the #ClutterContainer interface.
11267 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11270 clutter_actor_set_parent (ClutterActor *self,
11271 ClutterActor *parent)
11273 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11274 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11275 g_return_if_fail (self != parent);
11276 g_return_if_fail (self->priv->parent == NULL);
11278 /* as this function will be called inside ClutterContainer::add
11279 * implementations or when building up a composite actor, we have
11280 * to preserve the old behaviour, and not create child meta or
11281 * emit the ::actor-added signal, to avoid recursion or double
11284 clutter_actor_add_child_internal (parent, self,
11285 ADD_CHILD_LEGACY_FLAGS,
11286 insert_child_at_depth,
11291 * clutter_actor_get_parent:
11292 * @self: A #ClutterActor
11294 * Retrieves the parent of @self.
11296 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11297 * if no parent is set
11300 clutter_actor_get_parent (ClutterActor *self)
11302 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11304 return self->priv->parent;
11308 * clutter_actor_get_paint_visibility:
11309 * @self: A #ClutterActor
11311 * Retrieves the 'paint' visibility of an actor recursively checking for non
11314 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11316 * Return Value: %TRUE if the actor is visibile and will be painted.
11321 clutter_actor_get_paint_visibility (ClutterActor *actor)
11323 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11325 return CLUTTER_ACTOR_IS_MAPPED (actor);
11329 * clutter_actor_remove_child:
11330 * @self: a #ClutterActor
11331 * @child: a #ClutterActor
11333 * Removes @child from the children of @self.
11335 * This function will release the reference added by
11336 * clutter_actor_add_child(), so if you want to keep using @child
11337 * you will have to acquire a referenced on it before calling this
11340 * This function will emit the #ClutterContainer::actor-removed
11346 clutter_actor_remove_child (ClutterActor *self,
11347 ClutterActor *child)
11349 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11350 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11351 g_return_if_fail (self != child);
11352 g_return_if_fail (child->priv->parent != NULL);
11353 g_return_if_fail (child->priv->parent == self);
11355 clutter_actor_remove_child_internal (self, child,
11356 REMOVE_CHILD_DEFAULT_FLAGS);
11360 * clutter_actor_remove_all_children:
11361 * @self: a #ClutterActor
11363 * Removes all children of @self.
11365 * This function releases the reference added by inserting a child actor
11366 * in the list of children of @self.
11368 * If the reference count of a child drops to zero, the child will be
11369 * destroyed. If you want to ensure the destruction of all the children
11370 * of @self, use clutter_actor_destroy_all_children().
11375 clutter_actor_remove_all_children (ClutterActor *self)
11377 ClutterActorIter iter;
11379 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11381 if (self->priv->n_children == 0)
11384 g_object_freeze_notify (G_OBJECT (self));
11386 clutter_actor_iter_init (&iter, self);
11387 while (clutter_actor_iter_next (&iter, NULL))
11388 clutter_actor_iter_remove (&iter);
11390 g_object_thaw_notify (G_OBJECT (self));
11393 g_assert (self->priv->first_child == NULL);
11394 g_assert (self->priv->last_child == NULL);
11395 g_assert (self->priv->n_children == 0);
11399 * clutter_actor_destroy_all_children:
11400 * @self: a #ClutterActor
11402 * Destroys all children of @self.
11404 * This function releases the reference added by inserting a child
11405 * actor in the list of children of @self, and ensures that the
11406 * #ClutterActor::destroy signal is emitted on each child of the
11409 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11410 * when its reference count drops to 0; the default handler of the
11411 * #ClutterActor::destroy signal will destroy all the children of an
11412 * actor. This function ensures that all children are destroyed, instead
11413 * of just removed from @self, unlike clutter_actor_remove_all_children()
11414 * which will merely release the reference and remove each child.
11416 * Unless you acquired an additional reference on each child of @self
11417 * prior to calling clutter_actor_remove_all_children() and want to reuse
11418 * the actors, you should use clutter_actor_destroy_all_children() in
11419 * order to make sure that children are destroyed and signal handlers
11420 * are disconnected even in cases where circular references prevent this
11421 * from automatically happening through reference counting alone.
11426 clutter_actor_destroy_all_children (ClutterActor *self)
11428 ClutterActorIter iter;
11430 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11432 if (self->priv->n_children == 0)
11435 g_object_freeze_notify (G_OBJECT (self));
11437 clutter_actor_iter_init (&iter, self);
11438 while (clutter_actor_iter_next (&iter, NULL))
11439 clutter_actor_iter_destroy (&iter);
11441 g_object_thaw_notify (G_OBJECT (self));
11444 g_assert (self->priv->first_child == NULL);
11445 g_assert (self->priv->last_child == NULL);
11446 g_assert (self->priv->n_children == 0);
11449 typedef struct _InsertBetweenData {
11450 ClutterActor *prev_sibling;
11451 ClutterActor *next_sibling;
11452 } InsertBetweenData;
11455 insert_child_between (ClutterActor *self,
11456 ClutterActor *child,
11459 InsertBetweenData *data = data_;
11460 ClutterActor *prev_sibling = data->prev_sibling;
11461 ClutterActor *next_sibling = data->next_sibling;
11463 child->priv->parent = self;
11464 child->priv->prev_sibling = prev_sibling;
11465 child->priv->next_sibling = next_sibling;
11467 if (prev_sibling != NULL)
11468 prev_sibling->priv->next_sibling = child;
11470 if (next_sibling != NULL)
11471 next_sibling->priv->prev_sibling = child;
11473 if (child->priv->prev_sibling == NULL)
11474 self->priv->first_child = child;
11476 if (child->priv->next_sibling == NULL)
11477 self->priv->last_child = child;
11481 * clutter_actor_replace_child:
11482 * @self: a #ClutterActor
11483 * @old_child: the child of @self to replace
11484 * @new_child: the #ClutterActor to replace @old_child
11486 * Replaces @old_child with @new_child in the list of children of @self.
11491 clutter_actor_replace_child (ClutterActor *self,
11492 ClutterActor *old_child,
11493 ClutterActor *new_child)
11495 ClutterActor *prev_sibling, *next_sibling;
11496 InsertBetweenData clos;
11498 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11499 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11500 g_return_if_fail (old_child->priv->parent == self);
11501 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11502 g_return_if_fail (old_child != new_child);
11503 g_return_if_fail (new_child != self);
11504 g_return_if_fail (new_child->priv->parent == NULL);
11506 prev_sibling = old_child->priv->prev_sibling;
11507 next_sibling = old_child->priv->next_sibling;
11508 clutter_actor_remove_child_internal (self, old_child,
11509 REMOVE_CHILD_DEFAULT_FLAGS);
11511 clos.prev_sibling = prev_sibling;
11512 clos.next_sibling = next_sibling;
11513 clutter_actor_add_child_internal (self, new_child,
11514 ADD_CHILD_DEFAULT_FLAGS,
11515 insert_child_between,
11520 * clutter_actor_unparent:
11521 * @self: a #ClutterActor
11523 * Removes the parent of @self.
11525 * This will cause the parent of @self to release the reference
11526 * acquired when calling clutter_actor_set_parent(), so if you
11527 * want to keep @self you will have to acquire a reference of
11528 * your own, through g_object_ref().
11530 * This function should only be called by legacy #ClutterActor<!-- -->s
11531 * implementing the #ClutterContainer interface.
11535 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11538 clutter_actor_unparent (ClutterActor *self)
11540 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11542 if (self->priv->parent == NULL)
11545 clutter_actor_remove_child_internal (self->priv->parent, self,
11546 REMOVE_CHILD_LEGACY_FLAGS);
11550 * clutter_actor_reparent:
11551 * @self: a #ClutterActor
11552 * @new_parent: the new #ClutterActor parent
11554 * Resets the parent actor of @self.
11556 * This function is logically equivalent to calling clutter_actor_unparent()
11557 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11558 * ensures the child is not finalized when unparented, and emits the
11559 * #ClutterActor::parent-set signal only once.
11561 * In reality, calling this function is less useful than it sounds, as some
11562 * application code may rely on changes in the intermediate state between
11563 * removal and addition of the actor from its old parent to the @new_parent.
11564 * Thus, it is strongly encouraged to avoid using this function in application
11569 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11570 * clutter_actor_add_child() instead; remember to take a reference on
11571 * the actor being removed before calling clutter_actor_remove_child()
11572 * to avoid the reference count dropping to zero and the actor being
11576 clutter_actor_reparent (ClutterActor *self,
11577 ClutterActor *new_parent)
11579 ClutterActorPrivate *priv;
11581 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11582 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11583 g_return_if_fail (self != new_parent);
11585 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11587 g_warning ("Cannot set a parent on a toplevel actor");
11591 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11593 g_warning ("Cannot set a parent currently being destroyed");
11599 if (priv->parent != new_parent)
11601 ClutterActor *old_parent;
11603 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11605 old_parent = priv->parent;
11607 g_object_ref (self);
11609 if (old_parent != NULL)
11611 /* go through the Container implementation if this is a regular
11612 * child and not an internal one
11614 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11616 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11618 /* this will have to call unparent() */
11619 clutter_container_remove_actor (parent, self);
11622 clutter_actor_remove_child_internal (old_parent, self,
11623 REMOVE_CHILD_LEGACY_FLAGS);
11626 /* Note, will call set_parent() */
11627 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11628 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11630 clutter_actor_add_child_internal (new_parent, self,
11631 ADD_CHILD_LEGACY_FLAGS,
11632 insert_child_at_depth,
11635 /* we emit the ::parent-set signal once */
11636 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11638 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11640 /* the IN_REPARENT flag suspends state updates */
11641 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11643 g_object_unref (self);
11648 * clutter_actor_contains:
11649 * @self: A #ClutterActor
11650 * @descendant: A #ClutterActor, possibly contained in @self
11652 * Determines if @descendant is contained inside @self (either as an
11653 * immediate child, or as a deeper descendant). If @self and
11654 * @descendant point to the same actor then it will also return %TRUE.
11656 * Return value: whether @descendent is contained within @self
11661 clutter_actor_contains (ClutterActor *self,
11662 ClutterActor *descendant)
11664 ClutterActor *actor;
11666 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11667 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11669 for (actor = descendant; actor; actor = actor->priv->parent)
11677 * clutter_actor_set_child_above_sibling:
11678 * @self: a #ClutterActor
11679 * @child: a #ClutterActor child of @self
11680 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11682 * Sets @child to be above @sibling in the list of children of @self.
11684 * If @sibling is %NULL, @child will be the new last child of @self.
11686 * This function is logically equivalent to removing @child and using
11687 * clutter_actor_insert_child_above(), but it will not emit signals
11688 * or change state on @child.
11693 clutter_actor_set_child_above_sibling (ClutterActor *self,
11694 ClutterActor *child,
11695 ClutterActor *sibling)
11697 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11698 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11699 g_return_if_fail (child->priv->parent == self);
11700 g_return_if_fail (child != sibling);
11701 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11703 if (sibling != NULL)
11704 g_return_if_fail (sibling->priv->parent == self);
11706 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11707 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11708 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11711 /* we don't want to change the state of child, or emit signals, or
11712 * regenerate ChildMeta instances here, but we still want to follow
11713 * the correct sequence of steps encoded in remove_child() and
11714 * add_child(), so that correctness is ensured, and we only go
11715 * through one known code path.
11717 g_object_ref (child);
11718 clutter_actor_remove_child_internal (self, child, 0);
11719 clutter_actor_add_child_internal (self, child,
11720 ADD_CHILD_NOTIFY_FIRST_LAST,
11721 insert_child_above,
11724 clutter_actor_queue_relayout (self);
11728 * clutter_actor_set_child_below_sibling:
11729 * @self: a #ClutterActor
11730 * @child: a #ClutterActor child of @self
11731 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11733 * Sets @child to be below @sibling in the list of children of @self.
11735 * If @sibling is %NULL, @child will be the new first child of @self.
11737 * This function is logically equivalent to removing @self and using
11738 * clutter_actor_insert_child_below(), but it will not emit signals
11739 * or change state on @child.
11744 clutter_actor_set_child_below_sibling (ClutterActor *self,
11745 ClutterActor *child,
11746 ClutterActor *sibling)
11748 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11749 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11750 g_return_if_fail (child->priv->parent == self);
11751 g_return_if_fail (child != sibling);
11752 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11754 if (sibling != NULL)
11755 g_return_if_fail (sibling->priv->parent == self);
11757 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11758 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11759 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11762 /* see the comment in set_child_above_sibling() */
11763 g_object_ref (child);
11764 clutter_actor_remove_child_internal (self, child, 0);
11765 clutter_actor_add_child_internal (self, child,
11766 ADD_CHILD_NOTIFY_FIRST_LAST,
11767 insert_child_below,
11770 clutter_actor_queue_relayout (self);
11774 * clutter_actor_set_child_at_index:
11775 * @self: a #ClutterActor
11776 * @child: a #ClutterActor child of @self
11777 * @index_: the new index for @child
11779 * Changes the index of @child in the list of children of @self.
11781 * This function is logically equivalent to removing @child and
11782 * calling clutter_actor_insert_child_at_index(), but it will not
11783 * emit signals or change state on @child.
11788 clutter_actor_set_child_at_index (ClutterActor *self,
11789 ClutterActor *child,
11792 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11793 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11794 g_return_if_fail (child->priv->parent == self);
11795 g_return_if_fail (index_ <= self->priv->n_children);
11797 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11798 CLUTTER_ACTOR_IN_DESTRUCTION (child))
11801 g_object_ref (child);
11802 clutter_actor_remove_child_internal (self, child, 0);
11803 clutter_actor_add_child_internal (self, child,
11804 ADD_CHILD_NOTIFY_FIRST_LAST,
11805 insert_child_at_index,
11806 GINT_TO_POINTER (index_));
11808 clutter_actor_queue_relayout (self);
11812 * clutter_actor_raise:
11813 * @self: A #ClutterActor
11814 * @below: (allow-none): A #ClutterActor to raise above.
11816 * Puts @self above @below.
11818 * Both actors must have the same parent, and the parent must implement
11819 * the #ClutterContainer interface
11821 * This function calls clutter_container_raise_child() internally.
11823 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11826 clutter_actor_raise (ClutterActor *self,
11827 ClutterActor *below)
11829 ClutterActor *parent;
11831 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11833 parent = clutter_actor_get_parent (self);
11834 if (parent == NULL)
11836 g_warning ("%s: Actor '%s' is not inside a container",
11838 _clutter_actor_get_debug_name (self));
11844 if (parent != clutter_actor_get_parent (below))
11846 g_warning ("%s Actor '%s' is not in the same container as "
11849 _clutter_actor_get_debug_name (self),
11850 _clutter_actor_get_debug_name (below));
11855 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11859 * clutter_actor_lower:
11860 * @self: A #ClutterActor
11861 * @above: (allow-none): A #ClutterActor to lower below
11863 * Puts @self below @above.
11865 * Both actors must have the same parent, and the parent must implement
11866 * the #ClutterContainer interface.
11868 * This function calls clutter_container_lower_child() internally.
11870 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11873 clutter_actor_lower (ClutterActor *self,
11874 ClutterActor *above)
11876 ClutterActor *parent;
11878 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11880 parent = clutter_actor_get_parent (self);
11881 if (parent == NULL)
11883 g_warning ("%s: Actor of type %s is not inside a container",
11885 _clutter_actor_get_debug_name (self));
11891 if (parent != clutter_actor_get_parent (above))
11893 g_warning ("%s: Actor '%s' is not in the same container as "
11896 _clutter_actor_get_debug_name (self),
11897 _clutter_actor_get_debug_name (above));
11902 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11906 * clutter_actor_raise_top:
11907 * @self: A #ClutterActor
11909 * Raises @self to the top.
11911 * This function calls clutter_actor_raise() internally.
11913 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11914 * a %NULL sibling, instead.
11917 clutter_actor_raise_top (ClutterActor *self)
11919 clutter_actor_raise (self, NULL);
11923 * clutter_actor_lower_bottom:
11924 * @self: A #ClutterActor
11926 * Lowers @self to the bottom.
11928 * This function calls clutter_actor_lower() internally.
11930 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11931 * a %NULL sibling, instead.
11934 clutter_actor_lower_bottom (ClutterActor *self)
11936 clutter_actor_lower (self, NULL);
11944 * clutter_actor_event:
11945 * @actor: a #ClutterActor
11946 * @event: a #ClutterEvent
11947 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11949 * This function is used to emit an event on the main stage.
11950 * You should rarely need to use this function, except for
11951 * synthetising events.
11953 * Return value: the return value from the signal emission: %TRUE
11954 * if the actor handled the event, or %FALSE if the event was
11960 clutter_actor_event (ClutterActor *actor,
11961 ClutterEvent *event,
11964 gboolean retval = FALSE;
11965 gint signal_num = -1;
11967 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11968 g_return_val_if_fail (event != NULL, FALSE);
11970 g_object_ref (actor);
11974 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11980 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11984 switch (event->type)
11986 case CLUTTER_NOTHING:
11988 case CLUTTER_BUTTON_PRESS:
11989 signal_num = BUTTON_PRESS_EVENT;
11991 case CLUTTER_BUTTON_RELEASE:
11992 signal_num = BUTTON_RELEASE_EVENT;
11994 case CLUTTER_SCROLL:
11995 signal_num = SCROLL_EVENT;
11997 case CLUTTER_KEY_PRESS:
11998 signal_num = KEY_PRESS_EVENT;
12000 case CLUTTER_KEY_RELEASE:
12001 signal_num = KEY_RELEASE_EVENT;
12003 case CLUTTER_MOTION:
12004 signal_num = MOTION_EVENT;
12006 case CLUTTER_ENTER:
12007 signal_num = ENTER_EVENT;
12009 case CLUTTER_LEAVE:
12010 signal_num = LEAVE_EVENT;
12012 case CLUTTER_DELETE:
12013 case CLUTTER_DESTROY_NOTIFY:
12014 case CLUTTER_CLIENT_MESSAGE:
12020 if (signal_num != -1)
12021 g_signal_emit (actor, actor_signals[signal_num], 0,
12026 g_object_unref (actor);
12032 * clutter_actor_set_reactive:
12033 * @actor: a #ClutterActor
12034 * @reactive: whether the actor should be reactive to events
12036 * Sets @actor as reactive. Reactive actors will receive events.
12041 clutter_actor_set_reactive (ClutterActor *actor,
12044 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12046 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12050 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12052 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12054 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12058 * clutter_actor_get_reactive:
12059 * @actor: a #ClutterActor
12061 * Checks whether @actor is marked as reactive.
12063 * Return value: %TRUE if the actor is reactive
12068 clutter_actor_get_reactive (ClutterActor *actor)
12070 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12072 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12076 * clutter_actor_get_anchor_point:
12077 * @self: a #ClutterActor
12078 * @anchor_x: (out): return location for the X coordinate of the anchor point
12079 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12081 * Gets the current anchor point of the @actor in pixels.
12086 clutter_actor_get_anchor_point (ClutterActor *self,
12090 const ClutterTransformInfo *info;
12092 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12094 info = _clutter_actor_get_transform_info_or_defaults (self);
12095 clutter_anchor_coord_get_units (self, &info->anchor,
12102 * clutter_actor_set_anchor_point:
12103 * @self: a #ClutterActor
12104 * @anchor_x: X coordinate of the anchor point
12105 * @anchor_y: Y coordinate of the anchor point
12107 * Sets an anchor point for @self. The anchor point is a point in the
12108 * coordinate space of an actor to which the actor position within its
12109 * parent is relative; the default is (0, 0), i.e. the top-left corner
12115 clutter_actor_set_anchor_point (ClutterActor *self,
12119 ClutterTransformInfo *info;
12120 ClutterActorPrivate *priv;
12121 gboolean changed = FALSE;
12122 gfloat old_anchor_x, old_anchor_y;
12125 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12127 obj = G_OBJECT (self);
12129 info = _clutter_actor_get_transform_info (self);
12131 g_object_freeze_notify (obj);
12133 clutter_anchor_coord_get_units (self, &info->anchor,
12138 if (info->anchor.is_fractional)
12139 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12141 if (old_anchor_x != anchor_x)
12143 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12147 if (old_anchor_y != anchor_y)
12149 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12153 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12157 priv->transform_valid = FALSE;
12158 clutter_actor_queue_redraw (self);
12161 g_object_thaw_notify (obj);
12165 * clutter_actor_get_anchor_point_gravity:
12166 * @self: a #ClutterActor
12168 * Retrieves the anchor position expressed as a #ClutterGravity. If
12169 * the anchor point was specified using pixels or units this will
12170 * return %CLUTTER_GRAVITY_NONE.
12172 * Return value: the #ClutterGravity used by the anchor point
12177 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12179 const ClutterTransformInfo *info;
12181 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12183 info = _clutter_actor_get_transform_info_or_defaults (self);
12185 return clutter_anchor_coord_get_gravity (&info->anchor);
12189 * clutter_actor_move_anchor_point:
12190 * @self: a #ClutterActor
12191 * @anchor_x: X coordinate of the anchor point
12192 * @anchor_y: Y coordinate of the anchor point
12194 * Sets an anchor point for the actor, and adjusts the actor postion so that
12195 * the relative position of the actor toward its parent remains the same.
12200 clutter_actor_move_anchor_point (ClutterActor *self,
12204 gfloat old_anchor_x, old_anchor_y;
12205 const ClutterTransformInfo *info;
12207 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12209 info = _clutter_actor_get_transform_info (self);
12210 clutter_anchor_coord_get_units (self, &info->anchor,
12215 g_object_freeze_notify (G_OBJECT (self));
12217 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12219 if (self->priv->position_set)
12220 clutter_actor_move_by (self,
12221 anchor_x - old_anchor_x,
12222 anchor_y - old_anchor_y);
12224 g_object_thaw_notify (G_OBJECT (self));
12228 * clutter_actor_move_anchor_point_from_gravity:
12229 * @self: a #ClutterActor
12230 * @gravity: #ClutterGravity.
12232 * Sets an anchor point on the actor based on the given gravity, adjusting the
12233 * actor postion so that its relative position within its parent remains
12236 * Since version 1.0 the anchor point will be stored as a gravity so
12237 * that if the actor changes size then the anchor point will move. For
12238 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12239 * and later double the size of the actor, the anchor point will move
12240 * to the bottom right.
12245 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12246 ClutterGravity gravity)
12248 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12249 const ClutterTransformInfo *info;
12250 ClutterActorPrivate *priv;
12252 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12255 info = _clutter_actor_get_transform_info (self);
12257 g_object_freeze_notify (G_OBJECT (self));
12259 clutter_anchor_coord_get_units (self, &info->anchor,
12263 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12264 clutter_anchor_coord_get_units (self, &info->anchor,
12269 if (priv->position_set)
12270 clutter_actor_move_by (self,
12271 new_anchor_x - old_anchor_x,
12272 new_anchor_y - old_anchor_y);
12274 g_object_thaw_notify (G_OBJECT (self));
12278 * clutter_actor_set_anchor_point_from_gravity:
12279 * @self: a #ClutterActor
12280 * @gravity: #ClutterGravity.
12282 * Sets an anchor point on the actor, based on the given gravity (this is a
12283 * convenience function wrapping clutter_actor_set_anchor_point()).
12285 * Since version 1.0 the anchor point will be stored as a gravity so
12286 * that if the actor changes size then the anchor point will move. For
12287 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12288 * and later double the size of the actor, the anchor point will move
12289 * to the bottom right.
12294 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12295 ClutterGravity gravity)
12297 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12299 if (gravity == CLUTTER_GRAVITY_NONE)
12300 clutter_actor_set_anchor_point (self, 0, 0);
12303 GObject *obj = G_OBJECT (self);
12304 ClutterTransformInfo *info;
12306 g_object_freeze_notify (obj);
12308 info = _clutter_actor_get_transform_info (self);
12309 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12311 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12312 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12313 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12315 self->priv->transform_valid = FALSE;
12317 clutter_actor_queue_redraw (self);
12319 g_object_thaw_notify (obj);
12324 clutter_container_iface_init (ClutterContainerIface *iface)
12326 /* we don't override anything, as ClutterContainer already has a default
12327 * implementation that we can use, and which calls into our own API.
12342 parse_units (ClutterActor *self,
12343 ParseDimension dimension,
12346 GValue value = G_VALUE_INIT;
12349 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12352 json_node_get_value (node, &value);
12354 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12356 retval = (gfloat) g_value_get_int64 (&value);
12358 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12360 retval = g_value_get_double (&value);
12362 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12364 ClutterUnits units;
12367 res = clutter_units_from_string (&units, g_value_get_string (&value));
12369 retval = clutter_units_to_pixels (&units);
12372 g_warning ("Invalid value '%s': integers, strings or floating point "
12373 "values can be used for the x, y, width and height "
12374 "properties. Valid modifiers for strings are 'px', 'mm', "
12376 g_value_get_string (&value));
12382 g_warning ("Invalid value of type '%s': integers, strings of floating "
12383 "point values can be used for the x, y, width, height "
12384 "anchor-x and anchor-y properties.",
12385 g_type_name (G_VALUE_TYPE (&value)));
12388 g_value_unset (&value);
12394 ClutterRotateAxis axis;
12403 static inline gboolean
12404 parse_rotation_array (ClutterActor *actor,
12406 RotationInfo *info)
12410 if (json_array_get_length (array) != 2)
12414 element = json_array_get_element (array, 0);
12415 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12416 info->angle = json_node_get_double (element);
12421 element = json_array_get_element (array, 1);
12422 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12424 JsonArray *center = json_node_get_array (element);
12426 if (json_array_get_length (center) != 2)
12429 switch (info->axis)
12431 case CLUTTER_X_AXIS:
12432 info->center_y = parse_units (actor, PARSE_Y,
12433 json_array_get_element (center, 0));
12434 info->center_z = parse_units (actor, PARSE_Y,
12435 json_array_get_element (center, 1));
12438 case CLUTTER_Y_AXIS:
12439 info->center_x = parse_units (actor, PARSE_X,
12440 json_array_get_element (center, 0));
12441 info->center_z = parse_units (actor, PARSE_X,
12442 json_array_get_element (center, 1));
12445 case CLUTTER_Z_AXIS:
12446 info->center_x = parse_units (actor, PARSE_X,
12447 json_array_get_element (center, 0));
12448 info->center_y = parse_units (actor, PARSE_Y,
12449 json_array_get_element (center, 1));
12458 parse_rotation (ClutterActor *actor,
12460 RotationInfo *info)
12464 gboolean retval = FALSE;
12466 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12468 g_warning ("Invalid node of type '%s' found, expecting an array",
12469 json_node_type_name (node));
12473 array = json_node_get_array (node);
12474 len = json_array_get_length (array);
12476 for (i = 0; i < len; i++)
12478 JsonNode *element = json_array_get_element (array, i);
12479 JsonObject *object;
12482 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12484 g_warning ("Invalid node of type '%s' found, expecting an object",
12485 json_node_type_name (element));
12489 object = json_node_get_object (element);
12491 if (json_object_has_member (object, "x-axis"))
12493 member = json_object_get_member (object, "x-axis");
12495 info->axis = CLUTTER_X_AXIS;
12497 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12499 info->angle = json_node_get_double (member);
12502 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12503 retval = parse_rotation_array (actor,
12504 json_node_get_array (member),
12509 else if (json_object_has_member (object, "y-axis"))
12511 member = json_object_get_member (object, "y-axis");
12513 info->axis = CLUTTER_Y_AXIS;
12515 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12517 info->angle = json_node_get_double (member);
12520 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12521 retval = parse_rotation_array (actor,
12522 json_node_get_array (member),
12527 else if (json_object_has_member (object, "z-axis"))
12529 member = json_object_get_member (object, "z-axis");
12531 info->axis = CLUTTER_Z_AXIS;
12533 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12535 info->angle = json_node_get_double (member);
12538 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12539 retval = parse_rotation_array (actor,
12540 json_node_get_array (member),
12551 parse_actor_metas (ClutterScript *script,
12552 ClutterActor *actor,
12555 GList *elements, *l;
12556 GSList *retval = NULL;
12558 if (!JSON_NODE_HOLDS_ARRAY (node))
12561 elements = json_array_get_elements (json_node_get_array (node));
12563 for (l = elements; l != NULL; l = l->next)
12565 JsonNode *element = l->data;
12566 const gchar *id_ = _clutter_script_get_id_from_node (element);
12569 if (id_ == NULL || *id_ == '\0')
12572 meta = clutter_script_get_object (script, id_);
12576 retval = g_slist_prepend (retval, meta);
12579 g_list_free (elements);
12581 return g_slist_reverse (retval);
12585 parse_behaviours (ClutterScript *script,
12586 ClutterActor *actor,
12589 GList *elements, *l;
12590 GSList *retval = NULL;
12592 if (!JSON_NODE_HOLDS_ARRAY (node))
12595 elements = json_array_get_elements (json_node_get_array (node));
12597 for (l = elements; l != NULL; l = l->next)
12599 JsonNode *element = l->data;
12600 const gchar *id_ = _clutter_script_get_id_from_node (element);
12601 GObject *behaviour;
12603 if (id_ == NULL || *id_ == '\0')
12606 behaviour = clutter_script_get_object (script, id_);
12607 if (behaviour == NULL)
12610 retval = g_slist_prepend (retval, behaviour);
12613 g_list_free (elements);
12615 return g_slist_reverse (retval);
12619 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12620 ClutterScript *script,
12625 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12626 gboolean retval = FALSE;
12628 if ((name[0] == 'x' && name[1] == '\0') ||
12629 (name[0] == 'y' && name[1] == '\0') ||
12630 (strcmp (name, "width") == 0) ||
12631 (strcmp (name, "height") == 0) ||
12632 (strcmp (name, "anchor_x") == 0) ||
12633 (strcmp (name, "anchor_y") == 0))
12635 ParseDimension dimension;
12638 if (name[0] == 'x')
12639 dimension = PARSE_X;
12640 else if (name[0] == 'y')
12641 dimension = PARSE_Y;
12642 else if (name[0] == 'w')
12643 dimension = PARSE_WIDTH;
12644 else if (name[0] == 'h')
12645 dimension = PARSE_HEIGHT;
12646 else if (name[0] == 'a' && name[7] == 'x')
12647 dimension = PARSE_ANCHOR_X;
12648 else if (name[0] == 'a' && name[7] == 'y')
12649 dimension = PARSE_ANCHOR_Y;
12653 units = parse_units (actor, dimension, node);
12655 /* convert back to pixels: all properties are pixel-based */
12656 g_value_init (value, G_TYPE_FLOAT);
12657 g_value_set_float (value, units);
12661 else if (strcmp (name, "rotation") == 0)
12663 RotationInfo *info;
12665 info = g_slice_new0 (RotationInfo);
12666 retval = parse_rotation (actor, node, info);
12670 g_value_init (value, G_TYPE_POINTER);
12671 g_value_set_pointer (value, info);
12674 g_slice_free (RotationInfo, info);
12676 else if (strcmp (name, "behaviours") == 0)
12680 #ifdef CLUTTER_ENABLE_DEBUG
12681 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12682 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12683 "and it should not be used in newly "
12684 "written ClutterScript definitions.");
12687 l = parse_behaviours (script, actor, node);
12689 g_value_init (value, G_TYPE_POINTER);
12690 g_value_set_pointer (value, l);
12694 else if (strcmp (name, "actions") == 0 ||
12695 strcmp (name, "constraints") == 0 ||
12696 strcmp (name, "effects") == 0)
12700 l = parse_actor_metas (script, actor, node);
12702 g_value_init (value, G_TYPE_POINTER);
12703 g_value_set_pointer (value, l);
12712 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12713 ClutterScript *script,
12715 const GValue *value)
12717 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12719 #ifdef CLUTTER_ENABLE_DEBUG
12720 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12722 gchar *tmp = g_strdup_value_contents (value);
12724 CLUTTER_NOTE (SCRIPT,
12725 "in ClutterActor::set_custom_property('%s') = %s",
12731 #endif /* CLUTTER_ENABLE_DEBUG */
12733 if (strcmp (name, "rotation") == 0)
12735 RotationInfo *info;
12737 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12740 info = g_value_get_pointer (value);
12742 clutter_actor_set_rotation (actor,
12743 info->axis, info->angle,
12748 g_slice_free (RotationInfo, info);
12753 if (strcmp (name, "behaviours") == 0)
12755 GSList *behaviours, *l;
12757 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12760 behaviours = g_value_get_pointer (value);
12761 for (l = behaviours; l != NULL; l = l->next)
12763 ClutterBehaviour *behaviour = l->data;
12765 clutter_behaviour_apply (behaviour, actor);
12768 g_slist_free (behaviours);
12773 if (strcmp (name, "actions") == 0 ||
12774 strcmp (name, "constraints") == 0 ||
12775 strcmp (name, "effects") == 0)
12779 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12782 metas = g_value_get_pointer (value);
12783 for (l = metas; l != NULL; l = l->next)
12785 if (name[0] == 'a')
12786 clutter_actor_add_action (actor, l->data);
12788 if (name[0] == 'c')
12789 clutter_actor_add_constraint (actor, l->data);
12791 if (name[0] == 'e')
12792 clutter_actor_add_effect (actor, l->data);
12795 g_slist_free (metas);
12800 g_object_set_property (G_OBJECT (scriptable), name, value);
12804 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12806 iface->parse_custom_node = clutter_actor_parse_custom_node;
12807 iface->set_custom_property = clutter_actor_set_custom_property;
12810 static ClutterActorMeta *
12811 get_meta_from_animation_property (ClutterActor *actor,
12815 ClutterActorPrivate *priv = actor->priv;
12816 ClutterActorMeta *meta = NULL;
12819 /* if this is not a special property, fall through */
12820 if (name[0] != '@')
12823 /* detect the properties named using the following spec:
12825 * @<section>.<meta-name>.<property-name>
12827 * where <section> can be one of the following:
12833 * and <meta-name> is the name set on a specific ActorMeta
12836 tokens = g_strsplit (name + 1, ".", -1);
12837 if (tokens == NULL || g_strv_length (tokens) != 3)
12839 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12841 g_strfreev (tokens);
12845 if (strcmp (tokens[0], "actions") == 0)
12846 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12848 if (strcmp (tokens[0], "constraints") == 0)
12849 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12851 if (strcmp (tokens[0], "effects") == 0)
12852 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12854 if (name_p != NULL)
12855 *name_p = g_strdup (tokens[2]);
12857 CLUTTER_NOTE (ANIMATION,
12858 "Looking for property '%s' of object '%s' in section '%s'",
12863 g_strfreev (tokens);
12868 static GParamSpec *
12869 clutter_actor_find_property (ClutterAnimatable *animatable,
12870 const gchar *property_name)
12872 ClutterActorMeta *meta = NULL;
12873 GObjectClass *klass = NULL;
12874 GParamSpec *pspec = NULL;
12875 gchar *p_name = NULL;
12877 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12883 klass = G_OBJECT_GET_CLASS (meta);
12885 pspec = g_object_class_find_property (klass, p_name);
12889 klass = G_OBJECT_GET_CLASS (animatable);
12891 pspec = g_object_class_find_property (klass, property_name);
12900 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12901 const gchar *property_name,
12904 ClutterActorMeta *meta = NULL;
12905 gchar *p_name = NULL;
12907 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12912 g_object_get_property (G_OBJECT (meta), p_name, initial);
12914 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12920 * clutter_actor_set_animatable_property:
12921 * @actor: a #ClutterActor
12922 * @prop_id: the paramspec id
12923 * @value: the value to set
12924 * @pspec: the paramspec
12926 * Sets values of animatable properties.
12928 * This is a variant of clutter_actor_set_property() that gets called
12929 * by the #ClutterAnimatable implementation of #ClutterActor for the
12930 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12933 * Unlike the implementation of #GObjectClass.set_property(), this
12934 * function will not update the interval if a transition involving an
12935 * animatable property is in progress - this avoids cycles with the
12936 * transition API calling the public API.
12939 clutter_actor_set_animatable_property (ClutterActor *actor,
12941 const GValue *value,
12944 GObject *obj = G_OBJECT (actor);
12946 g_object_freeze_notify (obj);
12951 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12955 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12959 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12963 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12967 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12971 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12974 case PROP_BACKGROUND_COLOR:
12975 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12979 clutter_actor_set_scale_factor_internal (actor,
12980 g_value_get_double (value),
12985 clutter_actor_set_scale_factor_internal (actor,
12986 g_value_get_double (value),
12990 case PROP_ROTATION_ANGLE_X:
12991 clutter_actor_set_rotation_angle_internal (actor,
12993 g_value_get_double (value));
12996 case PROP_ROTATION_ANGLE_Y:
12997 clutter_actor_set_rotation_angle_internal (actor,
12999 g_value_get_double (value));
13002 case PROP_ROTATION_ANGLE_Z:
13003 clutter_actor_set_rotation_angle_internal (actor,
13005 g_value_get_double (value));
13009 g_object_set_property (obj, pspec->name, value);
13013 g_object_thaw_notify (obj);
13017 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13018 const gchar *property_name,
13019 const GValue *final)
13021 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13022 ClutterActorMeta *meta = NULL;
13023 gchar *p_name = NULL;
13025 meta = get_meta_from_animation_property (actor,
13029 g_object_set_property (G_OBJECT (meta), p_name, final);
13032 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13035 pspec = g_object_class_find_property (obj_class, property_name);
13037 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13039 /* XXX - I'm going to the special hell for this */
13040 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13043 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13050 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13052 iface->find_property = clutter_actor_find_property;
13053 iface->get_initial_state = clutter_actor_get_initial_state;
13054 iface->set_final_state = clutter_actor_set_final_state;
13058 * clutter_actor_transform_stage_point:
13059 * @self: A #ClutterActor
13060 * @x: (in): x screen coordinate of the point to unproject
13061 * @y: (in): y screen coordinate of the point to unproject
13062 * @x_out: (out): return location for the unprojected x coordinance
13063 * @y_out: (out): return location for the unprojected y coordinance
13065 * This function translates screen coordinates (@x, @y) to
13066 * coordinates relative to the actor. For example, it can be used to translate
13067 * screen events from global screen coordinates into actor-local coordinates.
13069 * The conversion can fail, notably if the transform stack results in the
13070 * actor being projected on the screen as a mere line.
13072 * The conversion should not be expected to be pixel-perfect due to the
13073 * nature of the operation. In general the error grows when the skewing
13074 * of the actor rectangle on screen increases.
13076 * <note><para>This function can be computationally intensive.</para></note>
13078 * <note><para>This function only works when the allocation is up-to-date,
13079 * i.e. inside of paint().</para></note>
13081 * Return value: %TRUE if conversion was successful.
13086 clutter_actor_transform_stage_point (ClutterActor *self,
13092 ClutterVertex v[4];
13095 int du, dv, xi, yi;
13097 float xf, yf, wf, det;
13098 ClutterActorPrivate *priv;
13100 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13104 /* This implementation is based on the quad -> quad projection algorithm
13105 * described by Paul Heckbert in:
13107 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13109 * and the sample implementation at:
13111 * http://www.cs.cmu.edu/~ph/src/texfund/
13113 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13114 * quad to rectangle only, which significantly simplifies things; the
13115 * function calls have been unrolled, and most of the math is done in fixed
13119 clutter_actor_get_abs_allocation_vertices (self, v);
13121 /* Keeping these as ints simplifies the multiplication (no significant
13122 * loss of precision here).
13124 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13125 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13130 #define UX2FP(x) (x)
13131 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13133 /* First, find mapping from unit uv square to xy quadrilateral; this
13134 * equivalent to the pmap_square_quad() functions in the sample
13135 * implementation, which we can simplify, since our target is always
13138 px = v[0].x - v[1].x + v[3].x - v[2].x;
13139 py = v[0].y - v[1].y + v[3].y - v[2].y;
13143 /* affine transform */
13144 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13145 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13146 RQ[2][0] = UX2FP (v[0].x);
13147 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13148 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13149 RQ[2][1] = UX2FP (v[0].y);
13156 /* projective transform */
13157 double dx1, dx2, dy1, dy2, del;
13159 dx1 = UX2FP (v[1].x - v[3].x);
13160 dx2 = UX2FP (v[2].x - v[3].x);
13161 dy1 = UX2FP (v[1].y - v[3].y);
13162 dy2 = UX2FP (v[2].y - v[3].y);
13164 del = DET2FP (dx1, dx2, dy1, dy2);
13169 * The division here needs to be done in floating point for
13170 * precisions reasons.
13172 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13173 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13174 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13176 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13177 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13178 RQ[2][0] = UX2FP (v[0].x);
13179 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13180 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13181 RQ[2][1] = UX2FP (v[0].y);
13185 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13186 * square. Since our rectangle is based at 0,0 we only need to scale.
13196 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13199 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13200 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13201 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13202 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13203 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13204 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13205 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13206 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13207 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13210 * Check the resulting matrix is OK.
13212 det = (RQ[0][0] * ST[0][0])
13213 + (RQ[0][1] * ST[0][1])
13214 + (RQ[0][2] * ST[0][2]);
13219 * Now transform our point with the ST matrix; the notional w
13220 * coordinate is 1, hence the last part is simply added.
13225 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13226 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13227 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13245 static ClutterGeometry*
13246 clutter_geometry_copy (const ClutterGeometry *geometry)
13248 return g_slice_dup (ClutterGeometry, geometry);
13252 clutter_geometry_free (ClutterGeometry *geometry)
13254 if (G_LIKELY (geometry != NULL))
13255 g_slice_free (ClutterGeometry, geometry);
13259 * clutter_geometry_union:
13260 * @geometry_a: a #ClutterGeometry
13261 * @geometry_b: another #ClutterGeometry
13262 * @result: (out): location to store the result
13264 * Find the union of two rectangles represented as #ClutterGeometry.
13269 clutter_geometry_union (const ClutterGeometry *geometry_a,
13270 const ClutterGeometry *geometry_b,
13271 ClutterGeometry *result)
13273 /* We don't try to handle rectangles that can't be represented
13274 * as a signed integer box */
13275 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13276 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13277 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13278 geometry_b->x + (gint)geometry_b->width);
13279 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13280 geometry_b->y + (gint)geometry_b->height);
13283 result->width = x_2 - x_1;
13284 result->height = y_2 - y_1;
13288 * clutter_geometry_intersects:
13289 * @geometry0: The first geometry to test
13290 * @geometry1: The second geometry to test
13292 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13293 * they do else %FALSE.
13295 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13301 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13302 const ClutterGeometry *geometry1)
13304 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13305 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13306 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13307 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13314 clutter_geometry_progress (const GValue *a,
13319 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13320 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13321 ClutterGeometry res = { 0, };
13322 gint a_width = a_geom->width;
13323 gint b_width = b_geom->width;
13324 gint a_height = a_geom->height;
13325 gint b_height = b_geom->height;
13327 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13328 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13330 res.width = a_width + (b_width - a_width) * progress;
13331 res.height = a_height + (b_height - a_height) * progress;
13333 g_value_set_boxed (retval, &res);
13338 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13339 clutter_geometry_copy,
13340 clutter_geometry_free,
13341 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13348 * clutter_vertex_new:
13353 * Creates a new #ClutterVertex for the point in 3D space
13354 * identified by the 3 coordinates @x, @y, @z
13356 * Return value: the newly allocate #ClutterVertex. Use
13357 * clutter_vertex_free() to free the resources
13362 clutter_vertex_new (gfloat x,
13366 ClutterVertex *vertex;
13368 vertex = g_slice_new (ClutterVertex);
13369 clutter_vertex_init (vertex, x, y, z);
13375 * clutter_vertex_init:
13376 * @vertex: a #ClutterVertex
13381 * Initializes @vertex with the given coordinates.
13386 clutter_vertex_init (ClutterVertex *vertex,
13391 g_return_if_fail (vertex != NULL);
13399 * clutter_vertex_copy:
13400 * @vertex: a #ClutterVertex
13404 * Return value: a newly allocated copy of #ClutterVertex. Use
13405 * clutter_vertex_free() to free the allocated resources
13410 clutter_vertex_copy (const ClutterVertex *vertex)
13412 if (G_LIKELY (vertex != NULL))
13413 return g_slice_dup (ClutterVertex, vertex);
13419 * clutter_vertex_free:
13420 * @vertex: a #ClutterVertex
13422 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13427 clutter_vertex_free (ClutterVertex *vertex)
13429 if (G_UNLIKELY (vertex != NULL))
13430 g_slice_free (ClutterVertex, vertex);
13434 * clutter_vertex_equal:
13435 * @vertex_a: a #ClutterVertex
13436 * @vertex_b: a #ClutterVertex
13438 * Compares @vertex_a and @vertex_b for equality
13440 * Return value: %TRUE if the passed #ClutterVertex are equal
13445 clutter_vertex_equal (const ClutterVertex *vertex_a,
13446 const ClutterVertex *vertex_b)
13448 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13450 if (vertex_a == vertex_b)
13453 return vertex_a->x == vertex_b->x &&
13454 vertex_a->y == vertex_b->y &&
13455 vertex_a->z == vertex_b->z;
13459 clutter_vertex_progress (const GValue *a,
13464 const ClutterVertex *av = g_value_get_boxed (a);
13465 const ClutterVertex *bv = g_value_get_boxed (b);
13466 ClutterVertex res = { 0, };
13468 res.x = av->x + (bv->x - av->x) * progress;
13469 res.y = av->y + (bv->y - av->y) * progress;
13470 res.z = av->z + (bv->z - av->z) * progress;
13472 g_value_set_boxed (retval, &res);
13477 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13478 clutter_vertex_copy,
13479 clutter_vertex_free,
13480 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13483 * clutter_actor_is_rotated:
13484 * @self: a #ClutterActor
13486 * Checks whether any rotation is applied to the actor.
13488 * Return value: %TRUE if the actor is rotated.
13493 clutter_actor_is_rotated (ClutterActor *self)
13495 const ClutterTransformInfo *info;
13497 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13499 info = _clutter_actor_get_transform_info_or_defaults (self);
13501 if (info->rx_angle || info->ry_angle || info->rz_angle)
13508 * clutter_actor_is_scaled:
13509 * @self: a #ClutterActor
13511 * Checks whether the actor is scaled in either dimension.
13513 * Return value: %TRUE if the actor is scaled.
13518 clutter_actor_is_scaled (ClutterActor *self)
13520 const ClutterTransformInfo *info;
13522 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13524 info = _clutter_actor_get_transform_info_or_defaults (self);
13526 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13533 _clutter_actor_get_stage_internal (ClutterActor *actor)
13535 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13536 actor = actor->priv->parent;
13542 * clutter_actor_get_stage:
13543 * @actor: a #ClutterActor
13545 * Retrieves the #ClutterStage where @actor is contained.
13547 * Return value: (transfer none) (type Clutter.Stage): the stage
13548 * containing the actor, or %NULL
13553 clutter_actor_get_stage (ClutterActor *actor)
13555 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13557 return _clutter_actor_get_stage_internal (actor);
13561 * clutter_actor_allocate_available_size:
13562 * @self: a #ClutterActor
13563 * @x: the actor's X coordinate
13564 * @y: the actor's Y coordinate
13565 * @available_width: the maximum available width, or -1 to use the
13566 * actor's natural width
13567 * @available_height: the maximum available height, or -1 to use the
13568 * actor's natural height
13569 * @flags: flags controlling the allocation
13571 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13572 * preferred size, but limiting it to the maximum available width
13573 * and height provided.
13575 * This function will do the right thing when dealing with the
13576 * actor's request mode.
13578 * The implementation of this function is equivalent to:
13581 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13583 * clutter_actor_get_preferred_width (self, available_height,
13585 * &natural_width);
13586 * width = CLAMP (natural_width, min_width, available_width);
13588 * clutter_actor_get_preferred_height (self, width,
13590 * &natural_height);
13591 * height = CLAMP (natural_height, min_height, available_height);
13595 * clutter_actor_get_preferred_height (self, available_width,
13597 * &natural_height);
13598 * height = CLAMP (natural_height, min_height, available_height);
13600 * clutter_actor_get_preferred_width (self, height,
13602 * &natural_width);
13603 * width = CLAMP (natural_width, min_width, available_width);
13606 * box.x1 = x; box.y1 = y;
13607 * box.x2 = box.x1 + available_width;
13608 * box.y2 = box.y1 + available_height;
13609 * clutter_actor_allocate (self, &box, flags);
13612 * This function can be used by fluid layout managers to allocate
13613 * an actor's preferred size without making it bigger than the area
13614 * available for the container.
13619 clutter_actor_allocate_available_size (ClutterActor *self,
13622 gfloat available_width,
13623 gfloat available_height,
13624 ClutterAllocationFlags flags)
13626 ClutterActorPrivate *priv;
13627 gfloat width, height;
13628 gfloat min_width, min_height;
13629 gfloat natural_width, natural_height;
13630 ClutterActorBox box;
13632 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13636 width = height = 0.0;
13638 switch (priv->request_mode)
13640 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13641 clutter_actor_get_preferred_width (self, available_height,
13644 width = CLAMP (natural_width, min_width, available_width);
13646 clutter_actor_get_preferred_height (self, width,
13649 height = CLAMP (natural_height, min_height, available_height);
13652 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13653 clutter_actor_get_preferred_height (self, available_width,
13656 height = CLAMP (natural_height, min_height, available_height);
13658 clutter_actor_get_preferred_width (self, height,
13661 width = CLAMP (natural_width, min_width, available_width);
13668 box.x2 = box.x1 + width;
13669 box.y2 = box.y1 + height;
13670 clutter_actor_allocate (self, &box, flags);
13674 * clutter_actor_allocate_preferred_size:
13675 * @self: a #ClutterActor
13676 * @flags: flags controlling the allocation
13678 * Allocates the natural size of @self.
13680 * This function is a utility call for #ClutterActor implementations
13681 * that allocates the actor's preferred natural size. It can be used
13682 * by fixed layout managers (like #ClutterGroup or so called
13683 * 'composite actors') inside the ClutterActor::allocate
13684 * implementation to give each child exactly how much space it
13687 * This function is not meant to be used by applications. It is also
13688 * not meant to be used outside the implementation of the
13689 * ClutterActor::allocate virtual function.
13694 clutter_actor_allocate_preferred_size (ClutterActor *self,
13695 ClutterAllocationFlags flags)
13697 gfloat actor_x, actor_y;
13698 gfloat natural_width, natural_height;
13699 ClutterActorBox actor_box;
13701 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13703 actor_x = clutter_actor_get_x (self);
13704 actor_y = clutter_actor_get_y (self);
13706 clutter_actor_get_preferred_size (self,
13711 actor_box.x1 = actor_x;
13712 actor_box.y1 = actor_y;
13713 actor_box.x2 = actor_box.x1 + natural_width;
13714 actor_box.y2 = actor_box.y1 + natural_height;
13716 clutter_actor_allocate (self, &actor_box, flags);
13720 * clutter_actor_allocate_align_fill:
13721 * @self: a #ClutterActor
13722 * @box: a #ClutterActorBox, containing the available width and height
13723 * @x_align: the horizontal alignment, between 0 and 1
13724 * @y_align: the vertical alignment, between 0 and 1
13725 * @x_fill: whether the actor should fill horizontally
13726 * @y_fill: whether the actor should fill vertically
13727 * @flags: allocation flags to be passed to clutter_actor_allocate()
13729 * Allocates @self by taking into consideration the available allocation
13730 * area; an alignment factor on either axis; and whether the actor should
13731 * fill the allocation on either axis.
13733 * The @box should contain the available allocation width and height;
13734 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13735 * allocation will be offset by their value.
13737 * This function takes into consideration the geometry request specified by
13738 * the #ClutterActor:request-mode property, and the text direction.
13740 * This function is useful for fluid layout managers, like #ClutterBinLayout
13741 * or #ClutterTableLayout
13746 clutter_actor_allocate_align_fill (ClutterActor *self,
13747 const ClutterActorBox *box,
13752 ClutterAllocationFlags flags)
13754 ClutterActorPrivate *priv;
13755 ClutterActorBox allocation = { 0, };
13756 gfloat x_offset, y_offset;
13757 gfloat available_width, available_height;
13758 gfloat child_width, child_height;
13760 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13761 g_return_if_fail (box != NULL);
13762 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13763 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13767 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13768 clutter_actor_box_get_size (box, &available_width, &available_height);
13770 if (available_width < 0)
13771 available_width = 0;
13773 if (available_height < 0)
13774 available_height = 0;
13778 allocation.x1 = x_offset;
13779 allocation.x2 = allocation.x1 + available_width;
13784 allocation.y1 = y_offset;
13785 allocation.y2 = allocation.y1 + available_height;
13788 /* if we are filling horizontally and vertically then we're done */
13789 if (x_fill && y_fill)
13792 child_width = child_height = 0.0f;
13794 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13796 gfloat min_width, natural_width;
13797 gfloat min_height, natural_height;
13799 clutter_actor_get_preferred_width (self, available_height,
13803 child_width = CLAMP (natural_width, min_width, available_width);
13807 clutter_actor_get_preferred_height (self, child_width,
13811 child_height = CLAMP (natural_height, min_height, available_height);
13816 gfloat min_width, natural_width;
13817 gfloat min_height, natural_height;
13819 clutter_actor_get_preferred_height (self, available_width,
13823 child_height = CLAMP (natural_height, min_height, available_height);
13827 clutter_actor_get_preferred_width (self, child_height,
13831 child_width = CLAMP (natural_width, min_width, available_width);
13835 /* invert the horizontal alignment for RTL languages */
13836 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13837 x_align = 1.0 - x_align;
13841 allocation.x1 = x_offset
13842 + ((available_width - child_width) * x_align);
13843 allocation.x2 = allocation.x1 + child_width;
13848 allocation.y1 = y_offset
13849 + ((available_height - child_height) * y_align);
13850 allocation.y2 = allocation.y1 + child_height;
13854 clutter_actor_box_clamp_to_pixel (&allocation);
13855 clutter_actor_allocate (self, &allocation, flags);
13859 * clutter_actor_grab_key_focus:
13860 * @self: a #ClutterActor
13862 * Sets the key focus of the #ClutterStage including @self
13863 * to this #ClutterActor.
13868 clutter_actor_grab_key_focus (ClutterActor *self)
13870 ClutterActor *stage;
13872 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13874 stage = _clutter_actor_get_stage_internal (self);
13876 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13880 * clutter_actor_get_pango_context:
13881 * @self: a #ClutterActor
13883 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13884 * is already configured using the appropriate font map, resolution
13885 * and font options.
13887 * Unlike clutter_actor_create_pango_context(), this context is owend
13888 * by the #ClutterActor and it will be updated each time the options
13889 * stored by the #ClutterBackend change.
13891 * You can use the returned #PangoContext to create a #PangoLayout
13892 * and render text using cogl_pango_render_layout() to reuse the
13893 * glyphs cache also used by Clutter.
13895 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13896 * The returned #PangoContext is owned by the actor and should not be
13897 * unreferenced by the application code
13902 clutter_actor_get_pango_context (ClutterActor *self)
13904 ClutterActorPrivate *priv;
13906 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13910 if (priv->pango_context != NULL)
13911 return priv->pango_context;
13913 priv->pango_context = _clutter_context_get_pango_context ();
13914 g_object_ref (priv->pango_context);
13916 return priv->pango_context;
13920 * clutter_actor_create_pango_context:
13921 * @self: a #ClutterActor
13923 * Creates a #PangoContext for the given actor. The #PangoContext
13924 * is already configured using the appropriate font map, resolution
13925 * and font options.
13927 * See also clutter_actor_get_pango_context().
13929 * Return value: (transfer full): the newly created #PangoContext.
13930 * Use g_object_unref() on the returned value to deallocate its
13936 clutter_actor_create_pango_context (ClutterActor *self)
13938 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13940 return _clutter_context_create_pango_context ();
13944 * clutter_actor_create_pango_layout:
13945 * @self: a #ClutterActor
13946 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13948 * Creates a new #PangoLayout from the same #PangoContext used
13949 * by the #ClutterActor. The #PangoLayout is already configured
13950 * with the font map, resolution and font options, and the
13953 * If you want to keep around a #PangoLayout created by this
13954 * function you will have to connect to the #ClutterBackend::font-changed
13955 * and #ClutterBackend::resolution-changed signals, and call
13956 * pango_layout_context_changed() in response to them.
13958 * Return value: (transfer full): the newly created #PangoLayout.
13959 * Use g_object_unref() when done
13964 clutter_actor_create_pango_layout (ClutterActor *self,
13967 PangoContext *context;
13968 PangoLayout *layout;
13970 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13972 context = clutter_actor_get_pango_context (self);
13973 layout = pango_layout_new (context);
13976 pango_layout_set_text (layout, text, -1);
13981 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13982 * ClutterOffscreenEffect.
13985 _clutter_actor_set_opacity_override (ClutterActor *self,
13988 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13990 self->priv->opacity_override = opacity;
13994 _clutter_actor_get_opacity_override (ClutterActor *self)
13996 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13998 return self->priv->opacity_override;
14001 /* Allows you to disable applying the actors model view transform during
14002 * a paint. Used by ClutterClone. */
14004 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14007 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14009 self->priv->enable_model_view_transform = enable;
14013 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14016 ClutterActorPrivate *priv;
14018 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14022 priv->enable_paint_unmapped = enable;
14024 if (priv->enable_paint_unmapped)
14026 /* Make sure that the parents of the widget are realized first;
14027 * otherwise checks in clutter_actor_update_map_state() will
14030 clutter_actor_realize (self);
14032 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14036 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14041 clutter_anchor_coord_get_units (ClutterActor *self,
14042 const AnchorCoord *coord,
14047 if (coord->is_fractional)
14049 gfloat actor_width, actor_height;
14051 clutter_actor_get_size (self, &actor_width, &actor_height);
14054 *x = actor_width * coord->v.fraction.x;
14057 *y = actor_height * coord->v.fraction.y;
14065 *x = coord->v.units.x;
14068 *y = coord->v.units.y;
14071 *z = coord->v.units.z;
14076 clutter_anchor_coord_set_units (AnchorCoord *coord,
14081 coord->is_fractional = FALSE;
14082 coord->v.units.x = x;
14083 coord->v.units.y = y;
14084 coord->v.units.z = z;
14087 static ClutterGravity
14088 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14090 if (coord->is_fractional)
14092 if (coord->v.fraction.x == 0.0)
14094 if (coord->v.fraction.y == 0.0)
14095 return CLUTTER_GRAVITY_NORTH_WEST;
14096 else if (coord->v.fraction.y == 0.5)
14097 return CLUTTER_GRAVITY_WEST;
14098 else if (coord->v.fraction.y == 1.0)
14099 return CLUTTER_GRAVITY_SOUTH_WEST;
14101 return CLUTTER_GRAVITY_NONE;
14103 else if (coord->v.fraction.x == 0.5)
14105 if (coord->v.fraction.y == 0.0)
14106 return CLUTTER_GRAVITY_NORTH;
14107 else if (coord->v.fraction.y == 0.5)
14108 return CLUTTER_GRAVITY_CENTER;
14109 else if (coord->v.fraction.y == 1.0)
14110 return CLUTTER_GRAVITY_SOUTH;
14112 return CLUTTER_GRAVITY_NONE;
14114 else if (coord->v.fraction.x == 1.0)
14116 if (coord->v.fraction.y == 0.0)
14117 return CLUTTER_GRAVITY_NORTH_EAST;
14118 else if (coord->v.fraction.y == 0.5)
14119 return CLUTTER_GRAVITY_EAST;
14120 else if (coord->v.fraction.y == 1.0)
14121 return CLUTTER_GRAVITY_SOUTH_EAST;
14123 return CLUTTER_GRAVITY_NONE;
14126 return CLUTTER_GRAVITY_NONE;
14129 return CLUTTER_GRAVITY_NONE;
14133 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14134 ClutterGravity gravity)
14138 case CLUTTER_GRAVITY_NORTH:
14139 coord->v.fraction.x = 0.5;
14140 coord->v.fraction.y = 0.0;
14143 case CLUTTER_GRAVITY_NORTH_EAST:
14144 coord->v.fraction.x = 1.0;
14145 coord->v.fraction.y = 0.0;
14148 case CLUTTER_GRAVITY_EAST:
14149 coord->v.fraction.x = 1.0;
14150 coord->v.fraction.y = 0.5;
14153 case CLUTTER_GRAVITY_SOUTH_EAST:
14154 coord->v.fraction.x = 1.0;
14155 coord->v.fraction.y = 1.0;
14158 case CLUTTER_GRAVITY_SOUTH:
14159 coord->v.fraction.x = 0.5;
14160 coord->v.fraction.y = 1.0;
14163 case CLUTTER_GRAVITY_SOUTH_WEST:
14164 coord->v.fraction.x = 0.0;
14165 coord->v.fraction.y = 1.0;
14168 case CLUTTER_GRAVITY_WEST:
14169 coord->v.fraction.x = 0.0;
14170 coord->v.fraction.y = 0.5;
14173 case CLUTTER_GRAVITY_NORTH_WEST:
14174 coord->v.fraction.x = 0.0;
14175 coord->v.fraction.y = 0.0;
14178 case CLUTTER_GRAVITY_CENTER:
14179 coord->v.fraction.x = 0.5;
14180 coord->v.fraction.y = 0.5;
14184 coord->v.fraction.x = 0.0;
14185 coord->v.fraction.y = 0.0;
14189 coord->is_fractional = TRUE;
14193 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14195 if (coord->is_fractional)
14196 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14198 return (coord->v.units.x == 0.0
14199 && coord->v.units.y == 0.0
14200 && coord->v.units.z == 0.0);
14204 * clutter_actor_get_flags:
14205 * @self: a #ClutterActor
14207 * Retrieves the flags set on @self
14209 * Return value: a bitwise or of #ClutterActorFlags or 0
14214 clutter_actor_get_flags (ClutterActor *self)
14216 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14218 return self->flags;
14222 * clutter_actor_set_flags:
14223 * @self: a #ClutterActor
14224 * @flags: the flags to set
14226 * Sets @flags on @self
14228 * This function will emit notifications for the changed properties
14233 clutter_actor_set_flags (ClutterActor *self,
14234 ClutterActorFlags flags)
14236 ClutterActorFlags old_flags;
14238 gboolean was_reactive_set, reactive_set;
14239 gboolean was_realized_set, realized_set;
14240 gboolean was_mapped_set, mapped_set;
14241 gboolean was_visible_set, visible_set;
14243 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14245 if (self->flags == flags)
14248 obj = G_OBJECT (self);
14249 g_object_ref (obj);
14250 g_object_freeze_notify (obj);
14252 old_flags = self->flags;
14254 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14255 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14256 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14257 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14259 self->flags |= flags;
14261 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14262 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14263 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14264 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14266 if (reactive_set != was_reactive_set)
14267 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14269 if (realized_set != was_realized_set)
14270 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14272 if (mapped_set != was_mapped_set)
14273 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14275 if (visible_set != was_visible_set)
14276 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14278 g_object_thaw_notify (obj);
14279 g_object_unref (obj);
14283 * clutter_actor_unset_flags:
14284 * @self: a #ClutterActor
14285 * @flags: the flags to unset
14287 * Unsets @flags on @self
14289 * This function will emit notifications for the changed properties
14294 clutter_actor_unset_flags (ClutterActor *self,
14295 ClutterActorFlags flags)
14297 ClutterActorFlags old_flags;
14299 gboolean was_reactive_set, reactive_set;
14300 gboolean was_realized_set, realized_set;
14301 gboolean was_mapped_set, mapped_set;
14302 gboolean was_visible_set, visible_set;
14304 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14306 obj = G_OBJECT (self);
14307 g_object_freeze_notify (obj);
14309 old_flags = self->flags;
14311 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14312 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14313 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14314 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14316 self->flags &= ~flags;
14318 if (self->flags == old_flags)
14321 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14322 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14323 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14324 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14326 if (reactive_set != was_reactive_set)
14327 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14329 if (realized_set != was_realized_set)
14330 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14332 if (mapped_set != was_mapped_set)
14333 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14335 if (visible_set != was_visible_set)
14336 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14338 g_object_thaw_notify (obj);
14342 * clutter_actor_get_transformation_matrix:
14343 * @self: a #ClutterActor
14344 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14346 * Retrieves the transformations applied to @self relative to its
14352 clutter_actor_get_transformation_matrix (ClutterActor *self,
14353 CoglMatrix *matrix)
14355 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14357 cogl_matrix_init_identity (matrix);
14359 _clutter_actor_apply_modelview_transform (self, matrix);
14363 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14364 gboolean is_in_clone_paint)
14366 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14367 self->priv->in_clone_paint = is_in_clone_paint;
14371 * clutter_actor_is_in_clone_paint:
14372 * @self: a #ClutterActor
14374 * Checks whether @self is being currently painted by a #ClutterClone
14376 * This function is useful only inside the ::paint virtual function
14377 * implementations or within handlers for the #ClutterActor::paint
14380 * This function should not be used by applications
14382 * Return value: %TRUE if the #ClutterActor is currently being painted
14383 * by a #ClutterClone, and %FALSE otherwise
14388 clutter_actor_is_in_clone_paint (ClutterActor *self)
14390 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14392 return self->priv->in_clone_paint;
14396 set_direction_recursive (ClutterActor *actor,
14397 gpointer user_data)
14399 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14401 clutter_actor_set_text_direction (actor, text_dir);
14407 * clutter_actor_set_text_direction:
14408 * @self: a #ClutterActor
14409 * @text_dir: the text direction for @self
14411 * Sets the #ClutterTextDirection for an actor
14413 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14415 * If @self implements #ClutterContainer then this function will recurse
14416 * inside all the children of @self (including the internal ones).
14418 * Composite actors not implementing #ClutterContainer, or actors requiring
14419 * special handling when the text direction changes, should connect to
14420 * the #GObject::notify signal for the #ClutterActor:text-direction property
14425 clutter_actor_set_text_direction (ClutterActor *self,
14426 ClutterTextDirection text_dir)
14428 ClutterActorPrivate *priv;
14430 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14431 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14435 if (priv->text_direction != text_dir)
14437 priv->text_direction = text_dir;
14439 /* we need to emit the notify::text-direction first, so that
14440 * the sub-classes can catch that and do specific handling of
14441 * the text direction; see clutter_text_direction_changed_cb()
14442 * inside clutter-text.c
14444 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14446 _clutter_actor_foreach_child (self, set_direction_recursive,
14447 GINT_TO_POINTER (text_dir));
14449 clutter_actor_queue_relayout (self);
14454 _clutter_actor_set_has_pointer (ClutterActor *self,
14455 gboolean has_pointer)
14457 ClutterActorPrivate *priv = self->priv;
14459 if (priv->has_pointer != has_pointer)
14461 priv->has_pointer = has_pointer;
14463 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14468 * clutter_actor_get_text_direction:
14469 * @self: a #ClutterActor
14471 * Retrieves the value set using clutter_actor_set_text_direction()
14473 * If no text direction has been previously set, the default text
14474 * direction, as returned by clutter_get_default_text_direction(), will
14475 * be returned instead
14477 * Return value: the #ClutterTextDirection for the actor
14481 ClutterTextDirection
14482 clutter_actor_get_text_direction (ClutterActor *self)
14484 ClutterActorPrivate *priv;
14486 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14487 CLUTTER_TEXT_DIRECTION_LTR);
14491 /* if no direction has been set yet use the default */
14492 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14493 priv->text_direction = clutter_get_default_text_direction ();
14495 return priv->text_direction;
14499 * clutter_actor_push_internal:
14500 * @self: a #ClutterActor
14502 * Should be used by actors implementing the #ClutterContainer and with
14503 * internal children added through clutter_actor_set_parent(), for instance:
14507 * my_actor_init (MyActor *self)
14509 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14511 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14513 * /* calling clutter_actor_set_parent() now will result in
14514 * * the internal flag being set on a child of MyActor
14517 * /* internal child - a background texture */
14518 * self->priv->background_tex = clutter_texture_new ();
14519 * clutter_actor_set_parent (self->priv->background_tex,
14520 * CLUTTER_ACTOR (self));
14522 * /* internal child - a label */
14523 * self->priv->label = clutter_text_new ();
14524 * clutter_actor_set_parent (self->priv->label,
14525 * CLUTTER_ACTOR (self));
14527 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14529 * /* calling clutter_actor_set_parent() now will not result in
14530 * * the internal flag being set on a child of MyActor
14535 * This function will be used by Clutter to toggle an "internal child"
14536 * flag whenever clutter_actor_set_parent() is called; internal children
14537 * are handled differently by Clutter, specifically when destroying their
14540 * Call clutter_actor_pop_internal() when you finished adding internal
14543 * Nested calls to clutter_actor_push_internal() are allowed, but each
14544 * one must by followed by a clutter_actor_pop_internal() call.
14548 * Deprecated: 1.10: All children of an actor are accessible through
14549 * the #ClutterActor API, and #ClutterActor implements the
14550 * #ClutterContainer interface, so this function is only useful
14551 * for legacy containers overriding the default implementation.
14554 clutter_actor_push_internal (ClutterActor *self)
14556 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14558 self->priv->internal_child += 1;
14562 * clutter_actor_pop_internal:
14563 * @self: a #ClutterActor
14565 * Disables the effects of clutter_actor_push_internal().
14569 * Deprecated: 1.10: All children of an actor are accessible through
14570 * the #ClutterActor API. This function is only useful for legacy
14571 * containers overriding the default implementation of the
14572 * #ClutterContainer interface.
14575 clutter_actor_pop_internal (ClutterActor *self)
14577 ClutterActorPrivate *priv;
14579 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14583 if (priv->internal_child == 0)
14585 g_warning ("Mismatched %s: you need to call "
14586 "clutter_actor_push_composite() at least once before "
14587 "calling this function", G_STRFUNC);
14591 priv->internal_child -= 1;
14595 * clutter_actor_has_pointer:
14596 * @self: a #ClutterActor
14598 * Checks whether an actor contains the pointer of a
14599 * #ClutterInputDevice
14601 * Return value: %TRUE if the actor contains the pointer, and
14607 clutter_actor_has_pointer (ClutterActor *self)
14609 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14611 return self->priv->has_pointer;
14614 /* XXX: This is a workaround for not being able to break the ABI of
14615 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14616 * clutter_actor_queue_clipped_redraw() for details.
14618 ClutterPaintVolume *
14619 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14621 return g_object_get_data (G_OBJECT (self),
14622 "-clutter-actor-queue-redraw-clip");
14626 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14627 ClutterPaintVolume *clip)
14629 g_object_set_data (G_OBJECT (self),
14630 "-clutter-actor-queue-redraw-clip",
14635 * clutter_actor_has_allocation:
14636 * @self: a #ClutterActor
14638 * Checks if the actor has an up-to-date allocation assigned to
14639 * it. This means that the actor should have an allocation: it's
14640 * visible and has a parent. It also means that there is no
14641 * outstanding relayout request in progress for the actor or its
14642 * children (There might be other outstanding layout requests in
14643 * progress that will cause the actor to get a new allocation
14644 * when the stage is laid out, however).
14646 * If this function returns %FALSE, then the actor will normally
14647 * be allocated before it is next drawn on the screen.
14649 * Return value: %TRUE if the actor has an up-to-date allocation
14654 clutter_actor_has_allocation (ClutterActor *self)
14656 ClutterActorPrivate *priv;
14658 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14662 return priv->parent != NULL &&
14663 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14664 !priv->needs_allocation;
14668 * clutter_actor_add_action:
14669 * @self: a #ClutterActor
14670 * @action: a #ClutterAction
14672 * Adds @action to the list of actions applied to @self
14674 * A #ClutterAction can only belong to one actor at a time
14676 * The #ClutterActor will hold a reference on @action until either
14677 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14683 clutter_actor_add_action (ClutterActor *self,
14684 ClutterAction *action)
14686 ClutterActorPrivate *priv;
14688 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14689 g_return_if_fail (CLUTTER_IS_ACTION (action));
14693 if (priv->actions == NULL)
14695 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14696 priv->actions->actor = self;
14699 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14701 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14705 * clutter_actor_add_action_with_name:
14706 * @self: a #ClutterActor
14707 * @name: the name to set on the action
14708 * @action: a #ClutterAction
14710 * A convenience function for setting the name of a #ClutterAction
14711 * while adding it to the list of actions applied to @self
14713 * This function is the logical equivalent of:
14716 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14717 * clutter_actor_add_action (self, action);
14723 clutter_actor_add_action_with_name (ClutterActor *self,
14725 ClutterAction *action)
14727 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14728 g_return_if_fail (name != NULL);
14729 g_return_if_fail (CLUTTER_IS_ACTION (action));
14731 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14732 clutter_actor_add_action (self, action);
14736 * clutter_actor_remove_action:
14737 * @self: a #ClutterActor
14738 * @action: a #ClutterAction
14740 * Removes @action from the list of actions applied to @self
14742 * The reference held by @self on the #ClutterAction will be released
14747 clutter_actor_remove_action (ClutterActor *self,
14748 ClutterAction *action)
14750 ClutterActorPrivate *priv;
14752 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14753 g_return_if_fail (CLUTTER_IS_ACTION (action));
14757 if (priv->actions == NULL)
14760 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14762 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14766 * clutter_actor_remove_action_by_name:
14767 * @self: a #ClutterActor
14768 * @name: the name of the action to remove
14770 * Removes the #ClutterAction with the given name from the list
14771 * of actions applied to @self
14776 clutter_actor_remove_action_by_name (ClutterActor *self,
14779 ClutterActorPrivate *priv;
14780 ClutterActorMeta *meta;
14782 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14783 g_return_if_fail (name != NULL);
14787 if (priv->actions == NULL)
14790 meta = _clutter_meta_group_get_meta (priv->actions, name);
14794 _clutter_meta_group_remove_meta (priv->actions, meta);
14796 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14800 * clutter_actor_get_actions:
14801 * @self: a #ClutterActor
14803 * Retrieves the list of actions applied to @self
14805 * Return value: (transfer container) (element-type Clutter.Action): a copy
14806 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14807 * owned by the #ClutterActor. Use g_list_free() to free the resources
14808 * allocated by the returned #GList
14813 clutter_actor_get_actions (ClutterActor *self)
14815 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14817 if (self->priv->actions == NULL)
14820 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14824 * clutter_actor_get_action:
14825 * @self: a #ClutterActor
14826 * @name: the name of the action to retrieve
14828 * Retrieves the #ClutterAction with the given name in the list
14829 * of actions applied to @self
14831 * Return value: (transfer none): a #ClutterAction for the given
14832 * name, or %NULL. The returned #ClutterAction is owned by the
14833 * actor and it should not be unreferenced directly
14838 clutter_actor_get_action (ClutterActor *self,
14841 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14842 g_return_val_if_fail (name != NULL, NULL);
14844 if (self->priv->actions == NULL)
14847 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14851 * clutter_actor_clear_actions:
14852 * @self: a #ClutterActor
14854 * Clears the list of actions applied to @self
14859 clutter_actor_clear_actions (ClutterActor *self)
14861 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14863 if (self->priv->actions == NULL)
14866 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14870 * clutter_actor_add_constraint:
14871 * @self: a #ClutterActor
14872 * @constraint: a #ClutterConstraint
14874 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14877 * The #ClutterActor will hold a reference on the @constraint until
14878 * either clutter_actor_remove_constraint() or
14879 * clutter_actor_clear_constraints() is called.
14884 clutter_actor_add_constraint (ClutterActor *self,
14885 ClutterConstraint *constraint)
14887 ClutterActorPrivate *priv;
14889 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14890 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14894 if (priv->constraints == NULL)
14896 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14897 priv->constraints->actor = self;
14900 _clutter_meta_group_add_meta (priv->constraints,
14901 CLUTTER_ACTOR_META (constraint));
14902 clutter_actor_queue_relayout (self);
14904 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14908 * clutter_actor_add_constraint_with_name:
14909 * @self: a #ClutterActor
14910 * @name: the name to set on the constraint
14911 * @constraint: a #ClutterConstraint
14913 * A convenience function for setting the name of a #ClutterConstraint
14914 * while adding it to the list of constraints applied to @self
14916 * This function is the logical equivalent of:
14919 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14920 * clutter_actor_add_constraint (self, constraint);
14926 clutter_actor_add_constraint_with_name (ClutterActor *self,
14928 ClutterConstraint *constraint)
14930 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14931 g_return_if_fail (name != NULL);
14932 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14934 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14935 clutter_actor_add_constraint (self, constraint);
14939 * clutter_actor_remove_constraint:
14940 * @self: a #ClutterActor
14941 * @constraint: a #ClutterConstraint
14943 * Removes @constraint from the list of constraints applied to @self
14945 * The reference held by @self on the #ClutterConstraint will be released
14950 clutter_actor_remove_constraint (ClutterActor *self,
14951 ClutterConstraint *constraint)
14953 ClutterActorPrivate *priv;
14955 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14956 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14960 if (priv->constraints == NULL)
14963 _clutter_meta_group_remove_meta (priv->constraints,
14964 CLUTTER_ACTOR_META (constraint));
14965 clutter_actor_queue_relayout (self);
14967 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14971 * clutter_actor_remove_constraint_by_name:
14972 * @self: a #ClutterActor
14973 * @name: the name of the constraint to remove
14975 * Removes the #ClutterConstraint with the given name from the list
14976 * of constraints applied to @self
14981 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14984 ClutterActorPrivate *priv;
14985 ClutterActorMeta *meta;
14987 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14988 g_return_if_fail (name != NULL);
14992 if (priv->constraints == NULL)
14995 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14999 _clutter_meta_group_remove_meta (priv->constraints, meta);
15000 clutter_actor_queue_relayout (self);
15004 * clutter_actor_get_constraints:
15005 * @self: a #ClutterActor
15007 * Retrieves the list of constraints applied to @self
15009 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15010 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15011 * owned by the #ClutterActor. Use g_list_free() to free the resources
15012 * allocated by the returned #GList
15017 clutter_actor_get_constraints (ClutterActor *self)
15019 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15021 if (self->priv->constraints == NULL)
15024 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15028 * clutter_actor_get_constraint:
15029 * @self: a #ClutterActor
15030 * @name: the name of the constraint to retrieve
15032 * Retrieves the #ClutterConstraint with the given name in the list
15033 * of constraints applied to @self
15035 * Return value: (transfer none): a #ClutterConstraint for the given
15036 * name, or %NULL. The returned #ClutterConstraint is owned by the
15037 * actor and it should not be unreferenced directly
15041 ClutterConstraint *
15042 clutter_actor_get_constraint (ClutterActor *self,
15045 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15046 g_return_val_if_fail (name != NULL, NULL);
15048 if (self->priv->constraints == NULL)
15051 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15055 * clutter_actor_clear_constraints:
15056 * @self: a #ClutterActor
15058 * Clears the list of constraints applied to @self
15063 clutter_actor_clear_constraints (ClutterActor *self)
15065 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15067 if (self->priv->constraints == NULL)
15070 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15072 clutter_actor_queue_relayout (self);
15076 * clutter_actor_set_clip_to_allocation:
15077 * @self: a #ClutterActor
15078 * @clip_set: %TRUE to apply a clip tracking the allocation
15080 * Sets whether @self should be clipped to the same size as its
15086 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15089 ClutterActorPrivate *priv;
15091 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15093 clip_set = !!clip_set;
15097 if (priv->clip_to_allocation != clip_set)
15099 priv->clip_to_allocation = clip_set;
15101 clutter_actor_queue_redraw (self);
15103 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15108 * clutter_actor_get_clip_to_allocation:
15109 * @self: a #ClutterActor
15111 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15113 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15118 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15120 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15122 return self->priv->clip_to_allocation;
15126 * clutter_actor_add_effect:
15127 * @self: a #ClutterActor
15128 * @effect: a #ClutterEffect
15130 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15132 * The #ClutterActor will hold a reference on the @effect until either
15133 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15139 clutter_actor_add_effect (ClutterActor *self,
15140 ClutterEffect *effect)
15142 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15143 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15145 _clutter_actor_add_effect_internal (self, effect);
15147 clutter_actor_queue_redraw (self);
15149 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15153 * clutter_actor_add_effect_with_name:
15154 * @self: a #ClutterActor
15155 * @name: the name to set on the effect
15156 * @effect: a #ClutterEffect
15158 * A convenience function for setting the name of a #ClutterEffect
15159 * while adding it to the list of effectss applied to @self
15161 * This function is the logical equivalent of:
15164 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15165 * clutter_actor_add_effect (self, effect);
15171 clutter_actor_add_effect_with_name (ClutterActor *self,
15173 ClutterEffect *effect)
15175 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15176 g_return_if_fail (name != NULL);
15177 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15179 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15180 clutter_actor_add_effect (self, effect);
15184 * clutter_actor_remove_effect:
15185 * @self: a #ClutterActor
15186 * @effect: a #ClutterEffect
15188 * Removes @effect from the list of effects applied to @self
15190 * The reference held by @self on the #ClutterEffect will be released
15195 clutter_actor_remove_effect (ClutterActor *self,
15196 ClutterEffect *effect)
15198 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15199 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15201 _clutter_actor_remove_effect_internal (self, effect);
15203 clutter_actor_queue_redraw (self);
15205 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15209 * clutter_actor_remove_effect_by_name:
15210 * @self: a #ClutterActor
15211 * @name: the name of the effect to remove
15213 * Removes the #ClutterEffect with the given name from the list
15214 * of effects applied to @self
15219 clutter_actor_remove_effect_by_name (ClutterActor *self,
15222 ClutterActorPrivate *priv;
15223 ClutterActorMeta *meta;
15225 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15226 g_return_if_fail (name != NULL);
15230 if (priv->effects == NULL)
15233 meta = _clutter_meta_group_get_meta (priv->effects, name);
15237 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15241 * clutter_actor_get_effects:
15242 * @self: a #ClutterActor
15244 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15246 * Return value: (transfer container) (element-type Clutter.Effect): a list
15247 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15248 * list are owned by Clutter and they should not be freed. You should
15249 * free the returned list using g_list_free() when done
15254 clutter_actor_get_effects (ClutterActor *self)
15256 ClutterActorPrivate *priv;
15258 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15262 if (priv->effects == NULL)
15265 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15269 * clutter_actor_get_effect:
15270 * @self: a #ClutterActor
15271 * @name: the name of the effect to retrieve
15273 * Retrieves the #ClutterEffect with the given name in the list
15274 * of effects applied to @self
15276 * Return value: (transfer none): a #ClutterEffect for the given
15277 * name, or %NULL. The returned #ClutterEffect is owned by the
15278 * actor and it should not be unreferenced directly
15283 clutter_actor_get_effect (ClutterActor *self,
15286 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15287 g_return_val_if_fail (name != NULL, NULL);
15289 if (self->priv->effects == NULL)
15292 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15296 * clutter_actor_clear_effects:
15297 * @self: a #ClutterActor
15299 * Clears the list of effects applied to @self
15304 clutter_actor_clear_effects (ClutterActor *self)
15306 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15308 if (self->priv->effects == NULL)
15311 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15313 clutter_actor_queue_redraw (self);
15317 * clutter_actor_has_key_focus:
15318 * @self: a #ClutterActor
15320 * Checks whether @self is the #ClutterActor that has key focus
15322 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15327 clutter_actor_has_key_focus (ClutterActor *self)
15329 ClutterActor *stage;
15331 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15333 stage = _clutter_actor_get_stage_internal (self);
15337 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15341 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15342 ClutterPaintVolume *pv)
15344 ClutterActorPrivate *priv = self->priv;
15346 /* Actors are only expected to report a valid paint volume
15347 * while they have a valid allocation. */
15348 if (G_UNLIKELY (priv->needs_allocation))
15350 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15351 "Actor needs allocation",
15352 _clutter_actor_get_debug_name (self));
15356 /* Check if there are any handlers connected to the paint
15357 * signal. If there are then all bets are off for what the paint
15358 * volume for this actor might possibly be!
15360 * XXX: It's expected that this is going to end up being quite a
15361 * costly check to have to do here, but we haven't come up with
15362 * another solution that can reliably catch paint signal handlers at
15363 * the right time to either avoid artefacts due to invalid stage
15364 * clipping or due to incorrect culling.
15366 * Previously we checked in clutter_actor_paint(), but at that time
15367 * we may already be using a stage clip that could be derived from
15368 * an invalid paint-volume. We used to try and handle that by
15369 * queuing a follow up, unclipped, redraw but still the previous
15370 * checking wasn't enough to catch invalid volumes involved in
15371 * culling (considering that containers may derive their volume from
15372 * children that haven't yet been painted)
15374 * Longer term, improved solutions could be:
15375 * - Disallow painting in the paint signal, only allow using it
15376 * for tracking when paints happen. We can add another API that
15377 * allows monkey patching the paint of arbitrary actors but in a
15378 * more controlled way and that also supports modifying the
15380 * - If we could be notified somehow when signal handlers are
15381 * connected we wouldn't have to poll for handlers like this.
15383 if (g_signal_has_handler_pending (self,
15384 actor_signals[PAINT],
15388 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15389 "Actor has \"paint\" signal handlers",
15390 _clutter_actor_get_debug_name (self));
15394 _clutter_paint_volume_init_static (pv, self);
15396 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15398 clutter_paint_volume_free (pv);
15399 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15400 "Actor failed to report a volume",
15401 _clutter_actor_get_debug_name (self));
15405 /* since effects can modify the paint volume, we allow them to actually
15406 * do this by making get_paint_volume() "context sensitive"
15408 if (priv->effects != NULL)
15410 if (priv->current_effect != NULL)
15412 const GList *effects, *l;
15414 /* if we are being called from within the paint sequence of
15415 * an actor, get the paint volume up to the current effect
15417 effects = _clutter_meta_group_peek_metas (priv->effects);
15419 l != NULL || (l != NULL && l->data != priv->current_effect);
15422 if (!_clutter_effect_get_paint_volume (l->data, pv))
15424 clutter_paint_volume_free (pv);
15425 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15426 "Effect (%s) failed to report a volume",
15427 _clutter_actor_get_debug_name (self),
15428 _clutter_actor_meta_get_debug_name (l->data));
15435 const GList *effects, *l;
15437 /* otherwise, get the cumulative volume */
15438 effects = _clutter_meta_group_peek_metas (priv->effects);
15439 for (l = effects; l != NULL; l = l->next)
15440 if (!_clutter_effect_get_paint_volume (l->data, pv))
15442 clutter_paint_volume_free (pv);
15443 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15444 "Effect (%s) failed to report a volume",
15445 _clutter_actor_get_debug_name (self),
15446 _clutter_actor_meta_get_debug_name (l->data));
15455 /* The public clutter_actor_get_paint_volume API returns a const
15456 * pointer since we return a pointer directly to the cached
15457 * PaintVolume associated with the actor and don't want the user to
15458 * inadvertently modify it, but for internal uses we sometimes need
15459 * access to the same PaintVolume but need to apply some book-keeping
15460 * modifications to it so we don't want a const pointer.
15462 static ClutterPaintVolume *
15463 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15465 ClutterActorPrivate *priv;
15469 if (priv->paint_volume_valid)
15470 clutter_paint_volume_free (&priv->paint_volume);
15472 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15474 priv->paint_volume_valid = TRUE;
15475 return &priv->paint_volume;
15479 priv->paint_volume_valid = FALSE;
15485 * clutter_actor_get_paint_volume:
15486 * @self: a #ClutterActor
15488 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15489 * when a paint volume can't be determined.
15491 * The paint volume is defined as the 3D space occupied by an actor
15492 * when being painted.
15494 * This function will call the <function>get_paint_volume()</function>
15495 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15496 * should not usually care about overriding the default implementation,
15497 * unless they are, for instance: painting outside their allocation, or
15498 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15501 * <note>2D actors overriding <function>get_paint_volume()</function>
15502 * ensure their volume has a depth of 0. (This will be true so long as
15503 * you don't call clutter_paint_volume_set_depth().)</note>
15505 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15506 * or %NULL if no volume could be determined. The returned pointer
15507 * is not guaranteed to be valid across multiple frames; if you want
15508 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15512 const ClutterPaintVolume *
15513 clutter_actor_get_paint_volume (ClutterActor *self)
15515 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15517 return _clutter_actor_get_paint_volume_mutable (self);
15521 * clutter_actor_get_transformed_paint_volume:
15522 * @self: a #ClutterActor
15523 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15524 * (or %NULL for the stage)
15526 * Retrieves the 3D paint volume of an actor like
15527 * clutter_actor_get_paint_volume() does (Please refer to the
15528 * documentation of clutter_actor_get_paint_volume() for more
15529 * details.) and it additionally transforms the paint volume into the
15530 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15531 * is passed for @relative_to_ancestor)
15533 * This can be used by containers that base their paint volume on
15534 * the volume of their children. Such containers can query the
15535 * transformed paint volume of all of its children and union them
15536 * together using clutter_paint_volume_union().
15538 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15539 * or %NULL if no volume could be determined. The returned pointer is
15540 * not guaranteed to be valid across multiple frames; if you wish to
15541 * keep it, you will have to copy it using clutter_paint_volume_copy().
15545 const ClutterPaintVolume *
15546 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15547 ClutterActor *relative_to_ancestor)
15549 const ClutterPaintVolume *volume;
15550 ClutterActor *stage;
15551 ClutterPaintVolume *transformed_volume;
15553 stage = _clutter_actor_get_stage_internal (self);
15554 if (G_UNLIKELY (stage == NULL))
15557 if (relative_to_ancestor == NULL)
15558 relative_to_ancestor = stage;
15560 volume = clutter_actor_get_paint_volume (self);
15561 if (volume == NULL)
15564 transformed_volume =
15565 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15567 _clutter_paint_volume_copy_static (volume, transformed_volume);
15569 _clutter_paint_volume_transform_relative (transformed_volume,
15570 relative_to_ancestor);
15572 return transformed_volume;
15576 * clutter_actor_get_paint_box:
15577 * @self: a #ClutterActor
15578 * @box: (out): return location for a #ClutterActorBox
15580 * Retrieves the paint volume of the passed #ClutterActor, and
15581 * transforms it into a 2D bounding box in stage coordinates.
15583 * This function is useful to determine the on screen area occupied by
15584 * the actor. The box is only an approximation and may often be
15585 * considerably larger due to the optimizations used to calculate the
15586 * box. The box is never smaller though, so it can reliably be used
15589 * There are times when a 2D paint box can't be determined, e.g.
15590 * because the actor isn't yet parented under a stage or because
15591 * the actor is unable to determine a paint volume.
15593 * Return value: %TRUE if a 2D paint box could be determined, else
15599 clutter_actor_get_paint_box (ClutterActor *self,
15600 ClutterActorBox *box)
15602 ClutterActor *stage;
15603 ClutterPaintVolume *pv;
15605 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15606 g_return_val_if_fail (box != NULL, FALSE);
15608 stage = _clutter_actor_get_stage_internal (self);
15609 if (G_UNLIKELY (!stage))
15612 pv = _clutter_actor_get_paint_volume_mutable (self);
15613 if (G_UNLIKELY (!pv))
15616 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15622 * clutter_actor_has_overlaps:
15623 * @self: A #ClutterActor
15625 * Asks the actor's implementation whether it may contain overlapping
15628 * For example; Clutter may use this to determine whether the painting
15629 * should be redirected to an offscreen buffer to correctly implement
15630 * the opacity property.
15632 * Custom actors can override the default response by implementing the
15633 * #ClutterActor <function>has_overlaps</function> virtual function. See
15634 * clutter_actor_set_offscreen_redirect() for more information.
15636 * Return value: %TRUE if the actor may have overlapping primitives, and
15642 clutter_actor_has_overlaps (ClutterActor *self)
15644 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15646 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15650 * clutter_actor_has_effects:
15651 * @self: A #ClutterActor
15653 * Returns whether the actor has any effects applied.
15655 * Return value: %TRUE if the actor has any effects,
15661 clutter_actor_has_effects (ClutterActor *self)
15663 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15665 if (self->priv->effects == NULL)
15668 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15672 * clutter_actor_has_constraints:
15673 * @self: A #ClutterActor
15675 * Returns whether the actor has any constraints applied.
15677 * Return value: %TRUE if the actor has any constraints,
15683 clutter_actor_has_constraints (ClutterActor *self)
15685 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15687 return self->priv->constraints != NULL;
15691 * clutter_actor_has_actions:
15692 * @self: A #ClutterActor
15694 * Returns whether the actor has any actions applied.
15696 * Return value: %TRUE if the actor has any actions,
15702 clutter_actor_has_actions (ClutterActor *self)
15704 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15706 return self->priv->actions != NULL;
15710 * clutter_actor_get_n_children:
15711 * @self: a #ClutterActor
15713 * Retrieves the number of children of @self.
15715 * Return value: the number of children of an actor
15720 clutter_actor_get_n_children (ClutterActor *self)
15722 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15724 return self->priv->n_children;
15728 * clutter_actor_get_child_at_index:
15729 * @self: a #ClutterActor
15730 * @index_: the position in the list of children
15732 * Retrieves the actor at the given @index_ inside the list of
15733 * children of @self.
15735 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15740 clutter_actor_get_child_at_index (ClutterActor *self,
15743 ClutterActor *iter;
15746 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15747 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15749 for (iter = self->priv->first_child, i = 0;
15750 iter != NULL && i < index_;
15751 iter = iter->priv->next_sibling, i += 1)
15758 * _clutter_actor_foreach_child:
15759 * @actor: The actor whos children you want to iterate
15760 * @callback: The function to call for each child
15761 * @user_data: Private data to pass to @callback
15763 * Calls a given @callback once for each child of the specified @actor and
15764 * passing the @user_data pointer each time.
15766 * Return value: returns %TRUE if all children were iterated, else
15767 * %FALSE if a callback broke out of iteration early.
15770 _clutter_actor_foreach_child (ClutterActor *self,
15771 ClutterForeachCallback callback,
15772 gpointer user_data)
15774 ClutterActorPrivate *priv = self->priv;
15775 ClutterActor *iter;
15778 for (cont = TRUE, iter = priv->first_child;
15779 cont && iter != NULL;
15780 iter = iter->priv->next_sibling)
15782 cont = callback (iter, user_data);
15789 /* For debugging purposes this gives us a simple way to print out
15790 * the scenegraph e.g in gdb using:
15792 * _clutter_actor_traverse (stage,
15794 * clutter_debug_print_actor_cb,
15799 static ClutterActorTraverseVisitFlags
15800 clutter_debug_print_actor_cb (ClutterActor *actor,
15804 g_print ("%*s%s:%p\n",
15806 _clutter_actor_get_debug_name (actor),
15809 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15814 _clutter_actor_traverse_breadth (ClutterActor *actor,
15815 ClutterTraverseCallback callback,
15816 gpointer user_data)
15818 GQueue *queue = g_queue_new ();
15819 ClutterActor dummy;
15820 int current_depth = 0;
15822 g_queue_push_tail (queue, actor);
15823 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15825 while ((actor = g_queue_pop_head (queue)))
15827 ClutterActorTraverseVisitFlags flags;
15829 if (actor == &dummy)
15832 g_queue_push_tail (queue, &dummy);
15836 flags = callback (actor, current_depth, user_data);
15837 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15839 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15841 ClutterActor *iter;
15843 for (iter = actor->priv->first_child;
15845 iter = iter->priv->next_sibling)
15847 g_queue_push_tail (queue, iter);
15852 g_queue_free (queue);
15855 static ClutterActorTraverseVisitFlags
15856 _clutter_actor_traverse_depth (ClutterActor *actor,
15857 ClutterTraverseCallback before_children_callback,
15858 ClutterTraverseCallback after_children_callback,
15860 gpointer user_data)
15862 ClutterActorTraverseVisitFlags flags;
15864 flags = before_children_callback (actor, current_depth, user_data);
15865 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15866 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15868 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15870 ClutterActor *iter;
15872 for (iter = actor->priv->first_child;
15874 iter = iter->priv->next_sibling)
15876 flags = _clutter_actor_traverse_depth (iter,
15877 before_children_callback,
15878 after_children_callback,
15882 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15883 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15887 if (after_children_callback)
15888 return after_children_callback (actor, current_depth, user_data);
15890 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15893 /* _clutter_actor_traverse:
15894 * @actor: The actor to start traversing the graph from
15895 * @flags: These flags may affect how the traversal is done
15896 * @before_children_callback: A function to call before visiting the
15897 * children of the current actor.
15898 * @after_children_callback: A function to call after visiting the
15899 * children of the current actor. (Ignored if
15900 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15901 * @user_data: The private data to pass to the callbacks
15903 * Traverses the scenegraph starting at the specified @actor and
15904 * descending through all its children and its children's children.
15905 * For each actor traversed @before_children_callback and
15906 * @after_children_callback are called with the specified
15907 * @user_data, before and after visiting that actor's children.
15909 * The callbacks can return flags that affect the ongoing traversal
15910 * such as by skipping over an actors children or bailing out of
15911 * any further traversing.
15914 _clutter_actor_traverse (ClutterActor *actor,
15915 ClutterActorTraverseFlags flags,
15916 ClutterTraverseCallback before_children_callback,
15917 ClutterTraverseCallback after_children_callback,
15918 gpointer user_data)
15920 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15921 _clutter_actor_traverse_breadth (actor,
15922 before_children_callback,
15924 else /* DEPTH_FIRST */
15925 _clutter_actor_traverse_depth (actor,
15926 before_children_callback,
15927 after_children_callback,
15928 0, /* start depth */
15933 on_layout_manager_changed (ClutterLayoutManager *manager,
15934 ClutterActor *self)
15936 clutter_actor_queue_relayout (self);
15940 * clutter_actor_set_layout_manager:
15941 * @self: a #ClutterActor
15942 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15944 * Sets the #ClutterLayoutManager delegate object that will be used to
15945 * lay out the children of @self.
15947 * The #ClutterActor will take a reference on the passed @manager which
15948 * will be released either when the layout manager is removed, or when
15949 * the actor is destroyed.
15954 clutter_actor_set_layout_manager (ClutterActor *self,
15955 ClutterLayoutManager *manager)
15957 ClutterActorPrivate *priv;
15959 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15960 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15964 if (priv->layout_manager != NULL)
15966 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15967 G_CALLBACK (on_layout_manager_changed),
15969 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15970 g_clear_object (&priv->layout_manager);
15973 priv->layout_manager = manager;
15975 if (priv->layout_manager != NULL)
15977 g_object_ref_sink (priv->layout_manager);
15978 clutter_layout_manager_set_container (priv->layout_manager,
15979 CLUTTER_CONTAINER (self));
15980 g_signal_connect (priv->layout_manager, "layout-changed",
15981 G_CALLBACK (on_layout_manager_changed),
15985 clutter_actor_queue_relayout (self);
15987 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15991 * clutter_actor_get_layout_manager:
15992 * @self: a #ClutterActor
15994 * Retrieves the #ClutterLayoutManager used by @self.
15996 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16001 ClutterLayoutManager *
16002 clutter_actor_get_layout_manager (ClutterActor *self)
16004 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16006 return self->priv->layout_manager;
16009 static const ClutterLayoutInfo default_layout_info = {
16012 { 0, 0, 0, 0 }, /* margin */
16013 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16014 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16015 0.f, 0.f, /* min_width, natural_width */
16016 0.f, 0.f, /* natual_width, natural_height */
16020 layout_info_free (gpointer data)
16022 if (G_LIKELY (data != NULL))
16023 g_slice_free (ClutterLayoutInfo, data);
16027 * _clutter_actor_get_layout_info:
16028 * @self: a #ClutterActor
16030 * Retrieves a pointer to the ClutterLayoutInfo structure.
16032 * If the actor does not have a ClutterLayoutInfo associated to it, one
16033 * will be created and initialized to the default values.
16035 * This function should be used for setters.
16037 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16040 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16042 ClutterLayoutInfo *
16043 _clutter_actor_get_layout_info (ClutterActor *self)
16045 ClutterLayoutInfo *retval;
16047 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16048 if (retval == NULL)
16050 retval = g_slice_new (ClutterLayoutInfo);
16052 *retval = default_layout_info;
16054 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16063 * _clutter_actor_get_layout_info_or_defaults:
16064 * @self: a #ClutterActor
16066 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16068 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16069 * then the default structure will be returned.
16071 * This function should only be used for getters.
16073 * Return value: a const pointer to the ClutterLayoutInfo structure
16075 const ClutterLayoutInfo *
16076 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16078 const ClutterLayoutInfo *info;
16080 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16082 return &default_layout_info;
16088 * clutter_actor_set_x_align:
16089 * @self: a #ClutterActor
16090 * @x_align: the horizontal alignment policy
16092 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16093 * actor received extra horizontal space.
16095 * See also the #ClutterActor:x-align property.
16100 clutter_actor_set_x_align (ClutterActor *self,
16101 ClutterActorAlign x_align)
16103 ClutterLayoutInfo *info;
16105 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16107 info = _clutter_actor_get_layout_info (self);
16109 if (info->x_align != x_align)
16111 info->x_align = x_align;
16113 clutter_actor_queue_relayout (self);
16115 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16120 * clutter_actor_get_x_align:
16121 * @self: a #ClutterActor
16123 * Retrieves the horizontal alignment policy set using
16124 * clutter_actor_set_x_align().
16126 * Return value: the horizontal alignment policy.
16131 clutter_actor_get_x_align (ClutterActor *self)
16133 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16135 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16139 * clutter_actor_set_y_align:
16140 * @self: a #ClutterActor
16141 * @y_align: the vertical alignment policy
16143 * Sets the vertical alignment policy of a #ClutterActor, in case the
16144 * actor received extra vertical space.
16146 * See also the #ClutterActor:y-align property.
16151 clutter_actor_set_y_align (ClutterActor *self,
16152 ClutterActorAlign y_align)
16154 ClutterLayoutInfo *info;
16156 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16158 info = _clutter_actor_get_layout_info (self);
16160 if (info->y_align != y_align)
16162 info->y_align = y_align;
16164 clutter_actor_queue_relayout (self);
16166 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16171 * clutter_actor_get_y_align:
16172 * @self: a #ClutterActor
16174 * Retrieves the vertical alignment policy set using
16175 * clutter_actor_set_y_align().
16177 * Return value: the vertical alignment policy.
16182 clutter_actor_get_y_align (ClutterActor *self)
16184 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16186 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16191 * clutter_margin_new:
16193 * Creates a new #ClutterMargin.
16195 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16196 * clutter_margin_free() to free the resources associated with it when
16202 clutter_margin_new (void)
16204 return g_slice_new0 (ClutterMargin);
16208 * clutter_margin_copy:
16209 * @margin_: a #ClutterMargin
16211 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16212 * the newly created structure.
16214 * Return value: (transfer full): a copy of the #ClutterMargin.
16219 clutter_margin_copy (const ClutterMargin *margin_)
16221 if (G_LIKELY (margin_ != NULL))
16222 return g_slice_dup (ClutterMargin, margin_);
16228 * clutter_margin_free:
16229 * @margin_: a #ClutterMargin
16231 * Frees the resources allocated by clutter_margin_new() and
16232 * clutter_margin_copy().
16237 clutter_margin_free (ClutterMargin *margin_)
16239 if (G_LIKELY (margin_ != NULL))
16240 g_slice_free (ClutterMargin, margin_);
16243 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16244 clutter_margin_copy,
16245 clutter_margin_free)
16248 * clutter_actor_set_margin:
16249 * @self: a #ClutterActor
16250 * @margin: a #ClutterMargin
16252 * Sets all the components of the margin of a #ClutterActor.
16257 clutter_actor_set_margin (ClutterActor *self,
16258 const ClutterMargin *margin)
16260 ClutterLayoutInfo *info;
16264 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16265 g_return_if_fail (margin != NULL);
16267 obj = G_OBJECT (self);
16270 g_object_freeze_notify (obj);
16272 info = _clutter_actor_get_layout_info (self);
16274 if (info->margin.top != margin->top)
16276 info->margin.top = margin->top;
16277 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16281 if (info->margin.right != margin->right)
16283 info->margin.right = margin->right;
16284 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16288 if (info->margin.bottom != margin->bottom)
16290 info->margin.bottom = margin->bottom;
16291 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16295 if (info->margin.left != margin->left)
16297 info->margin.left = margin->left;
16298 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16303 clutter_actor_queue_relayout (self);
16305 g_object_thaw_notify (obj);
16309 * clutter_actor_get_margin:
16310 * @self: a #ClutterActor
16311 * @margin: (out caller-allocates): return location for a #ClutterMargin
16313 * Retrieves all the components of the margin of a #ClutterActor.
16318 clutter_actor_get_margin (ClutterActor *self,
16319 ClutterMargin *margin)
16321 const ClutterLayoutInfo *info;
16323 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16324 g_return_if_fail (margin != NULL);
16326 info = _clutter_actor_get_layout_info_or_defaults (self);
16328 *margin = info->margin;
16332 * clutter_actor_set_margin_top:
16333 * @self: a #ClutterActor
16334 * @margin: the top margin
16336 * Sets the margin from the top of a #ClutterActor.
16341 clutter_actor_set_margin_top (ClutterActor *self,
16344 ClutterLayoutInfo *info;
16346 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16347 g_return_if_fail (margin >= 0.f);
16349 info = _clutter_actor_get_layout_info (self);
16351 if (info->margin.top == margin)
16354 info->margin.top = margin;
16356 clutter_actor_queue_relayout (self);
16358 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16362 * clutter_actor_get_margin_top:
16363 * @self: a #ClutterActor
16365 * Retrieves the top margin of a #ClutterActor.
16367 * Return value: the top margin
16372 clutter_actor_get_margin_top (ClutterActor *self)
16374 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16376 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16380 * clutter_actor_set_margin_bottom:
16381 * @self: a #ClutterActor
16382 * @margin: the bottom margin
16384 * Sets the margin from the bottom of a #ClutterActor.
16389 clutter_actor_set_margin_bottom (ClutterActor *self,
16392 ClutterLayoutInfo *info;
16394 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16395 g_return_if_fail (margin >= 0.f);
16397 info = _clutter_actor_get_layout_info (self);
16399 if (info->margin.bottom == margin)
16402 info->margin.bottom = margin;
16404 clutter_actor_queue_relayout (self);
16406 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16410 * clutter_actor_get_margin_bottom:
16411 * @self: a #ClutterActor
16413 * Retrieves the bottom margin of a #ClutterActor.
16415 * Return value: the bottom margin
16420 clutter_actor_get_margin_bottom (ClutterActor *self)
16422 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16424 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16428 * clutter_actor_set_margin_left:
16429 * @self: a #ClutterActor
16430 * @margin: the left margin
16432 * Sets the margin from the left of a #ClutterActor.
16437 clutter_actor_set_margin_left (ClutterActor *self,
16440 ClutterLayoutInfo *info;
16442 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16443 g_return_if_fail (margin >= 0.f);
16445 info = _clutter_actor_get_layout_info (self);
16447 if (info->margin.left == margin)
16450 info->margin.left = margin;
16452 clutter_actor_queue_relayout (self);
16454 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16458 * clutter_actor_get_margin_left:
16459 * @self: a #ClutterActor
16461 * Retrieves the left margin of a #ClutterActor.
16463 * Return value: the left margin
16468 clutter_actor_get_margin_left (ClutterActor *self)
16470 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16472 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16476 * clutter_actor_set_margin_right:
16477 * @self: a #ClutterActor
16478 * @margin: the right margin
16480 * Sets the margin from the right of a #ClutterActor.
16485 clutter_actor_set_margin_right (ClutterActor *self,
16488 ClutterLayoutInfo *info;
16490 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16491 g_return_if_fail (margin >= 0.f);
16493 info = _clutter_actor_get_layout_info (self);
16495 if (info->margin.right == margin)
16498 info->margin.right = margin;
16500 clutter_actor_queue_relayout (self);
16502 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16506 * clutter_actor_get_margin_right:
16507 * @self: a #ClutterActor
16509 * Retrieves the right margin of a #ClutterActor.
16511 * Return value: the right margin
16516 clutter_actor_get_margin_right (ClutterActor *self)
16518 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16520 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16524 clutter_actor_set_background_color_internal (ClutterActor *self,
16525 const ClutterColor *color)
16527 ClutterActorPrivate *priv = self->priv;
16530 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16533 obj = G_OBJECT (self);
16535 priv->bg_color = *color;
16536 priv->bg_color_set = TRUE;
16538 clutter_actor_queue_redraw (self);
16540 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16541 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16545 * clutter_actor_set_background_color:
16546 * @self: a #ClutterActor
16547 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16550 * Sets the background color of a #ClutterActor.
16552 * The background color will be used to cover the whole allocation of the
16553 * actor. The default background color of an actor is transparent.
16555 * To check whether an actor has a background color, you can use the
16556 * #ClutterActor:background-color-set actor property.
16558 * The #ClutterActor:background-color property is animatable.
16563 clutter_actor_set_background_color (ClutterActor *self,
16564 const ClutterColor *color)
16566 ClutterActorPrivate *priv;
16568 GParamSpec *bg_color_pspec;
16570 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16572 obj = G_OBJECT (self);
16578 priv->bg_color_set = FALSE;
16579 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16580 clutter_actor_queue_redraw (self);
16584 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16585 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16587 _clutter_actor_create_transition (self, bg_color_pspec,
16592 _clutter_actor_update_transition (self, bg_color_pspec, color);
16594 clutter_actor_queue_redraw (self);
16598 * clutter_actor_get_background_color:
16599 * @self: a #ClutterActor
16600 * @color: (out caller-allocates): return location for a #ClutterColor
16602 * Retrieves the color set using clutter_actor_set_background_color().
16607 clutter_actor_get_background_color (ClutterActor *self,
16608 ClutterColor *color)
16610 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16611 g_return_if_fail (color != NULL);
16613 *color = self->priv->bg_color;
16617 * clutter_actor_get_previous_sibling:
16618 * @self: a #ClutterActor
16620 * Retrieves the sibling of @self that comes before it in the list
16621 * of children of @self's parent.
16623 * The returned pointer is only valid until the scene graph changes; it
16624 * is not safe to modify the list of children of @self while iterating
16627 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16632 clutter_actor_get_previous_sibling (ClutterActor *self)
16634 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16636 return self->priv->prev_sibling;
16640 * clutter_actor_get_next_sibling:
16641 * @self: a #ClutterActor
16643 * Retrieves the sibling of @self that comes after it in the list
16644 * of children of @self's parent.
16646 * The returned pointer is only valid until the scene graph changes; it
16647 * is not safe to modify the list of children of @self while iterating
16650 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16655 clutter_actor_get_next_sibling (ClutterActor *self)
16657 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16659 return self->priv->next_sibling;
16663 * clutter_actor_get_first_child:
16664 * @self: a #ClutterActor
16666 * Retrieves the first child of @self.
16668 * The returned pointer is only valid until the scene graph changes; it
16669 * is not safe to modify the list of children of @self while iterating
16672 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16677 clutter_actor_get_first_child (ClutterActor *self)
16679 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16681 return self->priv->first_child;
16685 * clutter_actor_get_last_child:
16686 * @self: a #ClutterActor
16688 * Retrieves the last child of @self.
16690 * The returned pointer is only valid until the scene graph changes; it
16691 * is not safe to modify the list of children of @self while iterating
16694 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16699 clutter_actor_get_last_child (ClutterActor *self)
16701 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16703 return self->priv->last_child;
16706 /* easy way to have properly named fields instead of the dummy ones
16707 * we use in the public structure
16709 typedef struct _RealActorIter
16711 ClutterActor *root; /* dummy1 */
16712 ClutterActor *current; /* dummy2 */
16713 gpointer padding_1; /* dummy3 */
16714 gint age; /* dummy4 */
16715 gpointer padding_2; /* dummy5 */
16719 * clutter_actor_iter_init:
16720 * @iter: a #ClutterActorIter
16721 * @root: a #ClutterActor
16723 * Initializes a #ClutterActorIter, which can then be used to iterate
16724 * efficiently over a section of the scene graph, and associates it
16727 * Modifying the scene graph section that contains @root will invalidate
16731 * ClutterActorIter iter;
16732 * ClutterActor *child;
16734 * clutter_actor_iter_init (&iter, container);
16735 * while (clutter_actor_iter_next (&iter, &child))
16737 * /* do something with child */
16744 clutter_actor_iter_init (ClutterActorIter *iter,
16745 ClutterActor *root)
16747 RealActorIter *ri = (RealActorIter *) iter;
16749 g_return_if_fail (iter != NULL);
16750 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16753 ri->current = NULL;
16754 ri->age = root->priv->age;
16758 * clutter_actor_iter_next:
16759 * @iter: a #ClutterActorIter
16760 * @child: (out): return location for a #ClutterActor
16762 * Advances the @iter and retrieves the next child of the root #ClutterActor
16763 * that was used to initialize the #ClutterActorIterator.
16765 * If the iterator can advance, this function returns %TRUE and sets the
16768 * If the iterator cannot advance, this function returns %FALSE, and
16769 * the contents of @child are undefined.
16771 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16776 clutter_actor_iter_next (ClutterActorIter *iter,
16777 ClutterActor **child)
16779 RealActorIter *ri = (RealActorIter *) iter;
16781 g_return_val_if_fail (iter != NULL, FALSE);
16782 g_return_val_if_fail (ri->root != NULL, FALSE);
16783 #ifndef G_DISABLE_ASSERT
16784 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16787 if (ri->current == NULL)
16788 ri->current = ri->root->priv->first_child;
16790 ri->current = ri->current->priv->next_sibling;
16793 *child = ri->current;
16795 return ri->current != NULL;
16799 * clutter_actor_iter_prev:
16800 * @iter: a #ClutterActorIter
16801 * @child: (out): return location for a #ClutterActor
16803 * Advances the @iter and retrieves the previous child of the root
16804 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16806 * If the iterator can advance, this function returns %TRUE and sets the
16809 * If the iterator cannot advance, this function returns %FALSE, and
16810 * the contents of @child are undefined.
16812 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16817 clutter_actor_iter_prev (ClutterActorIter *iter,
16818 ClutterActor **child)
16820 RealActorIter *ri = (RealActorIter *) iter;
16822 g_return_val_if_fail (iter != NULL, FALSE);
16823 g_return_val_if_fail (ri->root != NULL, FALSE);
16824 #ifndef G_DISABLE_ASSERT
16825 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16828 if (ri->current == NULL)
16829 ri->current = ri->root->priv->last_child;
16831 ri->current = ri->current->priv->prev_sibling;
16834 *child = ri->current;
16836 return ri->current != NULL;
16840 * clutter_actor_iter_remove:
16841 * @iter: a #ClutterActorIter
16843 * Safely removes the #ClutterActor currently pointer to by the iterator
16846 * This function can only be called after clutter_actor_iter_next() or
16847 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16848 * than once for the same actor.
16850 * This function will call clutter_actor_remove_child() internally.
16855 clutter_actor_iter_remove (ClutterActorIter *iter)
16857 RealActorIter *ri = (RealActorIter *) iter;
16860 g_return_if_fail (iter != NULL);
16861 g_return_if_fail (ri->root != NULL);
16862 #ifndef G_DISABLE_ASSERT
16863 g_return_if_fail (ri->age == ri->root->priv->age);
16865 g_return_if_fail (ri->current != NULL);
16871 ri->current = cur->priv->prev_sibling;
16873 clutter_actor_remove_child_internal (ri->root, cur,
16874 REMOVE_CHILD_DEFAULT_FLAGS);
16881 * clutter_actor_iter_destroy:
16882 * @iter: a #ClutterActorIter
16884 * Safely destroys the #ClutterActor currently pointer to by the iterator
16887 * This function can only be called after clutter_actor_iter_next() or
16888 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16889 * than once for the same actor.
16891 * This function will call clutter_actor_destroy() internally.
16896 clutter_actor_iter_destroy (ClutterActorIter *iter)
16898 RealActorIter *ri = (RealActorIter *) iter;
16901 g_return_if_fail (iter != NULL);
16902 g_return_if_fail (ri->root != NULL);
16903 #ifndef G_DISABLE_ASSERT
16904 g_return_if_fail (ri->age == ri->root->priv->age);
16906 g_return_if_fail (ri->current != NULL);
16912 ri->current = cur->priv->prev_sibling;
16914 clutter_actor_destroy (cur);
16920 static const ClutterAnimationInfo default_animation_info = {
16921 NULL, /* transitions */
16923 NULL, /* cur_state */
16927 clutter_animation_info_free (gpointer data)
16931 ClutterAnimationInfo *info = data;
16933 if (info->transitions != NULL)
16934 g_hash_table_unref (info->transitions);
16936 if (info->states != NULL)
16937 g_array_unref (info->states);
16939 g_slice_free (ClutterAnimationInfo, info);
16943 const ClutterAnimationInfo *
16944 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16946 const ClutterAnimationInfo *res;
16947 GObject *obj = G_OBJECT (self);
16949 res = g_object_get_qdata (obj, quark_actor_animation_info);
16953 return &default_animation_info;
16956 ClutterAnimationInfo *
16957 _clutter_actor_get_animation_info (ClutterActor *self)
16959 GObject *obj = G_OBJECT (self);
16960 ClutterAnimationInfo *res;
16962 res = g_object_get_qdata (obj, quark_actor_animation_info);
16965 res = g_slice_new (ClutterAnimationInfo);
16967 *res = default_animation_info;
16969 g_object_set_qdata_full (obj, quark_actor_animation_info,
16971 clutter_animation_info_free);
16977 ClutterTransition *
16978 _clutter_actor_get_transition (ClutterActor *actor,
16981 const ClutterAnimationInfo *info;
16983 info = _clutter_actor_get_animation_info_or_defaults (actor);
16985 if (info->transitions == NULL)
16988 return g_hash_table_lookup (info->transitions, pspec->name);
16991 typedef struct _TransitionClosure
16993 ClutterActor *actor;
16994 ClutterTransition *transition;
16996 gulong completed_id;
16997 } TransitionClosure;
17000 transition_closure_free (gpointer data)
17002 if (G_LIKELY (data != NULL))
17004 TransitionClosure *clos = data;
17006 if (clutter_timeline_is_playing (CLUTTER_TIMELINE (clos->transition)))
17007 clutter_timeline_stop (CLUTTER_TIMELINE (clos->transition));
17009 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17011 g_object_unref (clos->transition);
17012 g_free (clos->name);
17014 g_slice_free (TransitionClosure, clos);
17019 on_transition_completed (ClutterTransition *transition,
17020 TransitionClosure *clos)
17022 ClutterActor *actor = clos->actor;
17023 ClutterAnimationInfo *info;
17025 info = _clutter_actor_get_animation_info (actor);
17027 /* this will take care of cleaning clos for us */
17028 if (clutter_transition_get_remove_on_complete (transition))
17030 /* we take a reference here because removing the closure
17031 * will release the reference on the transition, and we
17032 * want the transition to survive the signal emission;
17033 * the master clock will release the laste reference at
17034 * the end of the frame processing.
17036 g_object_ref (transition);
17037 g_hash_table_remove (info->transitions, clos->name);
17040 /* if it's the last transition then we clean up */
17041 if (g_hash_table_size (info->transitions) == 0)
17043 g_hash_table_unref (info->transitions);
17044 info->transitions = NULL;
17046 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17047 _clutter_actor_get_debug_name (actor));
17049 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17054 _clutter_actor_update_transition (ClutterActor *actor,
17058 TransitionClosure *clos;
17059 ClutterTimeline *timeline;
17060 ClutterInterval *interval;
17061 const ClutterAnimationInfo *info;
17064 GValue initial = G_VALUE_INIT;
17065 GValue final = G_VALUE_INIT;
17066 char *error = NULL;
17068 info = _clutter_actor_get_animation_info_or_defaults (actor);
17070 if (info->transitions == NULL)
17073 clos = g_hash_table_lookup (info->transitions, pspec->name);
17077 timeline = CLUTTER_TIMELINE (clos->transition);
17079 va_start (var_args, pspec);
17081 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17083 g_value_init (&initial, ptype);
17084 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17088 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17091 g_critical ("%s: %s", G_STRLOC, error);
17096 interval = clutter_transition_get_interval (clos->transition);
17097 clutter_interval_set_initial_value (interval, &initial);
17098 clutter_interval_set_final_value (interval, &final);
17100 /* if we're updating with an easing duration of zero milliseconds,
17101 * we just jump the timeline to the end and let it run its course
17103 if (info->cur_state != NULL &&
17104 info->cur_state->easing_duration != 0)
17106 guint cur_duration = clutter_timeline_get_duration (timeline);
17107 ClutterAnimationMode cur_mode =
17108 clutter_timeline_get_progress_mode (timeline);
17110 if (cur_duration != info->cur_state->easing_duration)
17111 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17113 if (cur_mode != info->cur_state->easing_mode)
17114 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17116 clutter_timeline_rewind (timeline);
17120 guint duration = clutter_timeline_get_duration (timeline);
17122 clutter_timeline_advance (timeline, duration);
17126 g_value_unset (&initial);
17127 g_value_unset (&final);
17133 * _clutter_actor_create_transition:
17134 * @actor: a #ClutterActor
17135 * @pspec: the property used for the transition
17136 * @...: initial and final state
17138 * Creates a #ClutterTransition for the property represented by @pspec.
17140 * Return value: a #ClutterTransition
17142 ClutterTransition *
17143 _clutter_actor_create_transition (ClutterActor *actor,
17147 ClutterAnimationInfo *info;
17148 ClutterTransition *res = NULL;
17149 gboolean call_restore = FALSE;
17150 TransitionClosure *clos;
17153 info = _clutter_actor_get_animation_info (actor);
17155 /* XXX - this will go away in 2.0
17157 * if no state has been pushed, we assume that the easing state is
17158 * in "compatibility mode": all transitions have a duration of 0
17159 * msecs, which means that they happen immediately. in Clutter 2.0
17160 * this will turn into a g_assert(info->states != NULL), as every
17161 * actor will start with a predefined easing state
17163 if (info->states == NULL)
17165 clutter_actor_save_easing_state (actor);
17166 clutter_actor_set_easing_duration (actor, 0);
17167 call_restore = TRUE;
17170 if (info->transitions == NULL)
17171 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17173 transition_closure_free);
17175 va_start (var_args, pspec);
17177 clos = g_hash_table_lookup (info->transitions, pspec->name);
17180 ClutterInterval *interval;
17181 GValue initial = G_VALUE_INIT;
17182 GValue final = G_VALUE_INIT;
17186 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17188 G_VALUE_COLLECT_INIT (&initial, ptype,
17193 g_critical ("%s: %s", G_STRLOC, error);
17198 G_VALUE_COLLECT_INIT (&final, ptype,
17204 g_critical ("%s: %s", G_STRLOC, error);
17205 g_value_unset (&initial);
17210 /* if the current easing state has a duration of 0, then we don't
17211 * bother to create the transition, and we just set the final value
17212 * directly on the actor; we don't go through the Animatable
17213 * interface because we know we got here through an animatable
17216 if (info->cur_state->easing_duration == 0)
17218 clutter_actor_set_animatable_property (actor,
17222 g_value_unset (&initial);
17223 g_value_unset (&final);
17228 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17230 g_value_unset (&initial);
17231 g_value_unset (&final);
17233 res = clutter_property_transition_new (pspec->name);
17235 clutter_transition_set_interval (res, interval);
17236 clutter_transition_set_remove_on_complete (res, TRUE);
17238 /* this will start the transition as well */
17239 clutter_actor_add_transition (actor, pspec->name, res);
17241 /* the actor now owns the transition */
17242 g_object_unref (res);
17245 res = clos->transition;
17249 clutter_actor_restore_easing_state (actor);
17257 * clutter_actor_add_transition:
17258 * @self: a #ClutterActor
17259 * @name: the name of the transition to add
17260 * @transition: the #ClutterTransition to add
17262 * Adds a @transition to the #ClutterActor's list of animations.
17264 * The @name string is a per-actor unique identifier of the @transition: only
17265 * one #ClutterTransition can be associated to the specified @name.
17267 * The @transition will be given the easing duration, mode, and delay
17268 * associated to the actor's current easing state; it is possible to modify
17269 * these values after calling clutter_actor_add_transition().
17271 * The @transition will be started once added.
17273 * This function will take a reference on the @transition.
17275 * This function is usually called implicitly when modifying an animatable
17281 clutter_actor_add_transition (ClutterActor *self,
17283 ClutterTransition *transition)
17285 ClutterTimeline *timeline;
17286 TransitionClosure *clos;
17287 ClutterAnimationInfo *info;
17289 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17290 g_return_if_fail (name != NULL);
17291 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17293 info = _clutter_actor_get_animation_info (self);
17295 if (info->cur_state == NULL)
17297 g_warning ("No easing state is defined for the actor '%s'; you "
17298 "must call clutter_actor_save_easing_state() before "
17299 "calling clutter_actor_add_transition().",
17300 _clutter_actor_get_debug_name (self));
17304 if (info->transitions == NULL)
17305 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17307 transition_closure_free);
17309 if (g_hash_table_lookup (info->transitions, name) != NULL)
17311 g_warning ("A transition with name '%s' already exists for "
17314 _clutter_actor_get_debug_name (self));
17318 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17320 timeline = CLUTTER_TIMELINE (transition);
17322 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17323 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17324 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17326 clos = g_slice_new (TransitionClosure);
17327 clos->actor = self;
17328 clos->transition = g_object_ref (transition);
17329 clos->name = g_strdup (name);
17330 clos->completed_id = g_signal_connect (timeline, "completed",
17331 G_CALLBACK (on_transition_completed),
17334 CLUTTER_NOTE (ANIMATION,
17335 "Adding transition '%s' [%p] to actor '%s'",
17338 _clutter_actor_get_debug_name (self));
17340 g_hash_table_insert (info->transitions, clos->name, clos);
17341 clutter_timeline_start (timeline);
17345 * clutter_actor_remove_transition:
17346 * @self: a #ClutterActor
17347 * @name: the name of the transition to remove
17349 * Removes the transition stored inside a #ClutterActor using @name
17352 * If the transition is currently in progress, it will be stopped.
17354 * This function releases the reference acquired when the transition
17355 * was added to the #ClutterActor.
17360 clutter_actor_remove_transition (ClutterActor *self,
17363 const ClutterAnimationInfo *info;
17365 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17366 g_return_if_fail (name != NULL);
17368 info = _clutter_actor_get_animation_info_or_defaults (self);
17370 if (info->transitions == NULL)
17373 g_hash_table_remove (info->transitions, name);
17377 * clutter_actor_remove_all_transitions:
17378 * @self: a #ClutterActor
17380 * Removes all transitions associated to @self.
17385 clutter_actor_remove_all_transitions (ClutterActor *self)
17387 const ClutterAnimationInfo *info;
17389 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17391 info = _clutter_actor_get_animation_info_or_defaults (self);
17392 if (info->transitions == NULL)
17395 g_hash_table_remove_all (info->transitions);
17399 * clutter_actor_set_easing_duration:
17400 * @self: a #ClutterActor
17401 * @msecs: the duration of the easing, or %NULL
17403 * Sets the duration of the tweening for animatable properties
17404 * of @self for the current easing state.
17409 clutter_actor_set_easing_duration (ClutterActor *self,
17412 ClutterAnimationInfo *info;
17414 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17416 info = _clutter_actor_get_animation_info (self);
17418 if (info->cur_state == NULL)
17420 g_warning ("You must call clutter_actor_save_easing_state() prior "
17421 "to calling clutter_actor_set_easing_duration().");
17425 if (info->cur_state->easing_duration != msecs)
17426 info->cur_state->easing_duration = msecs;
17430 * clutter_actor_get_easing_duration:
17431 * @self: a #ClutterActor
17433 * Retrieves the duration of the tweening for animatable
17434 * properties of @self for the current easing state.
17436 * Return value: the duration of the tweening, in milliseconds
17441 clutter_actor_get_easing_duration (ClutterActor *self)
17443 const ClutterAnimationInfo *info;
17445 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17447 info = _clutter_actor_get_animation_info_or_defaults (self);
17449 if (info->cur_state != NULL)
17450 return info->cur_state->easing_duration;
17456 * clutter_actor_set_easing_mode:
17457 * @self: a #ClutterActor
17458 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17460 * Sets the easing mode for the tweening of animatable properties
17466 clutter_actor_set_easing_mode (ClutterActor *self,
17467 ClutterAnimationMode mode)
17469 ClutterAnimationInfo *info;
17471 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17472 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17473 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17475 info = _clutter_actor_get_animation_info (self);
17477 if (info->cur_state == NULL)
17479 g_warning ("You must call clutter_actor_save_easing_state() prior "
17480 "to calling clutter_actor_set_easing_mode().");
17484 if (info->cur_state->easing_mode != mode)
17485 info->cur_state->easing_mode = mode;
17489 * clutter_actor_get_easing_mode:
17490 * @self: a #ClutterActor
17492 * Retrieves the easing mode for the tweening of animatable properties
17493 * of @self for the current easing state.
17495 * Return value: an easing mode
17499 ClutterAnimationMode
17500 clutter_actor_get_easing_mode (ClutterActor *self)
17502 const ClutterAnimationInfo *info;
17504 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17506 info = _clutter_actor_get_animation_info_or_defaults (self);
17508 if (info->cur_state != NULL)
17509 return info->cur_state->easing_mode;
17511 return CLUTTER_EASE_OUT_CUBIC;
17515 * clutter_actor_set_easing_delay:
17516 * @self: a #ClutterActor
17517 * @msecs: the delay before the start of the tweening, in milliseconds
17519 * Sets the delay that should be applied before tweening animatable
17525 clutter_actor_set_easing_delay (ClutterActor *self,
17528 ClutterAnimationInfo *info;
17530 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17532 info = _clutter_actor_get_animation_info (self);
17534 if (info->cur_state == NULL)
17536 g_warning ("You must call clutter_actor_save_easing_state() prior "
17537 "to calling clutter_actor_set_easing_delay().");
17541 if (info->cur_state->easing_delay != msecs)
17542 info->cur_state->easing_delay = msecs;
17546 * clutter_actor_get_easing_delay:
17547 * @self: a #ClutterActor
17549 * Retrieves the delay that should be applied when tweening animatable
17552 * Return value: a delay, in milliseconds
17557 clutter_actor_get_easing_delay (ClutterActor *self)
17559 const ClutterAnimationInfo *info;
17561 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17563 info = _clutter_actor_get_animation_info_or_defaults (self);
17565 if (info->cur_state != NULL)
17566 return info->cur_state->easing_delay;
17572 * clutter_actor_get_transition:
17573 * @self: a #ClutterActor
17574 * @name: the name of the transition
17576 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17577 * transition @name.
17579 * Transitions created for animatable properties use the name of the
17580 * property itself, for instance the code below:
17583 * clutter_actor_set_easing_duration (actor, 1000);
17584 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17586 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17587 * g_signal_connect (transition, "completed",
17588 * G_CALLBACK (on_transition_complete),
17592 * will call the <function>on_transition_complete</function> callback when
17593 * the transition is complete.
17595 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17596 * was found to match the passed name; the returned instance is owned
17597 * by Clutter and it should not be freed
17601 ClutterTransition *
17602 clutter_actor_get_transition (ClutterActor *self,
17605 TransitionClosure *clos;
17606 const ClutterAnimationInfo *info;
17608 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17609 g_return_val_if_fail (name != NULL, NULL);
17611 info = _clutter_actor_get_animation_info_or_defaults (self);
17612 if (info->transitions == NULL)
17615 clos = g_hash_table_lookup (info->transitions, name);
17619 return clos->transition;
17623 * clutter_actor_save_easing_state:
17624 * @self: a #ClutterActor
17626 * Saves the current easing state for animatable properties, and creates
17627 * a new state with the default values for easing mode and duration.
17632 clutter_actor_save_easing_state (ClutterActor *self)
17634 ClutterAnimationInfo *info;
17637 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17639 info = _clutter_actor_get_animation_info (self);
17641 if (info->states == NULL)
17642 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17644 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17645 new_state.easing_duration = 250;
17646 new_state.easing_delay = 0;
17648 g_array_append_val (info->states, new_state);
17650 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17654 * clutter_actor_restore_easing_state:
17655 * @self: a #ClutterActor
17657 * Restores the easing state as it was prior to a call to
17658 * clutter_actor_save_easing_state().
17663 clutter_actor_restore_easing_state (ClutterActor *self)
17665 ClutterAnimationInfo *info;
17667 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17669 info = _clutter_actor_get_animation_info (self);
17671 if (info->states == NULL)
17673 g_critical ("The function clutter_actor_restore_easing_state() has "
17674 "called without a previous call to "
17675 "clutter_actor_save_easing_state().");
17679 g_array_remove_index (info->states, info->states->len - 1);
17681 if (info->states->len > 0)
17682 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17685 g_array_unref (info->states);
17686 info->states = NULL;
17687 info->cur_state = NULL;
17692 * clutter_actor_set_content:
17693 * @self: a #ClutterActor
17694 * @content: (allow-none): a #ClutterContent, or %NULL
17696 * Sets the contents of a #ClutterActor.
17701 clutter_actor_set_content (ClutterActor *self,
17702 ClutterContent *content)
17704 ClutterActorPrivate *priv;
17706 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17707 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17711 if (priv->content != NULL)
17713 _clutter_content_detached (priv->content, self);
17714 g_clear_object (&priv->content);
17717 priv->content = content;
17719 if (priv->content != NULL)
17721 g_object_ref (priv->content);
17722 _clutter_content_attached (priv->content, self);
17725 /* given that the content is always painted within the allocation,
17726 * we only need to queue a redraw here
17728 clutter_actor_queue_redraw (self);
17730 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17732 /* if the content gravity is not resize-fill, and the new content has a
17733 * different preferred size than the previous one, then the content box
17734 * may have been changed. since we compute that lazily, we just notify
17735 * here, and let whomever watches :content-box do whatever they need to
17738 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17739 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17743 * clutter_actor_get_content:
17744 * @self: a #ClutterActor
17746 * Retrieves the contents of @self.
17748 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17749 * or %NULL if none was set
17754 clutter_actor_get_content (ClutterActor *self)
17756 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17758 return self->priv->content;
17762 * clutter_actor_set_content_gravity:
17763 * @self: a #ClutterActor
17764 * @gravity: the #ClutterContentGravity
17766 * Sets the gravity of the #ClutterContent used by @self.
17768 * See the description of the #ClutterActor:content-gravity property for
17769 * more information.
17774 clutter_actor_set_content_gravity (ClutterActor *self,
17775 ClutterContentGravity gravity)
17777 ClutterActorPrivate *priv;
17779 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17783 if (priv->content_gravity == gravity)
17786 priv->content_gravity = gravity;
17788 clutter_actor_queue_redraw (self);
17790 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17791 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17795 * clutter_actor_get_content_gravity:
17796 * @self: a #ClutterActor
17798 * Retrieves the content gravity as set using
17799 * clutter_actor_get_content_gravity().
17801 * Return value: the content gravity
17805 ClutterContentGravity
17806 clutter_actor_get_content_gravity (ClutterActor *self)
17808 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17809 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17811 return self->priv->content_gravity;
17815 * clutter_actor_get_content_box:
17816 * @self: a #ClutterActor
17817 * @box: (out caller-allocates): the return location for the bounding
17818 * box for the #ClutterContent
17820 * Retrieves the bounding box for the #ClutterContent of @self.
17822 * The bounding box is relative to the actor's allocation.
17824 * If no #ClutterContent is set for @self, or if @self has not been
17825 * allocated yet, then the result is undefined.
17827 * The content box is guaranteed to be, at most, as big as the allocation
17828 * of the #ClutterActor.
17830 * If the #ClutterContent used by the actor has a preferred size, then
17831 * it is possible to modify the content box by using the
17832 * #ClutterActor:content-gravity property.
17837 clutter_actor_get_content_box (ClutterActor *self,
17838 ClutterActorBox *box)
17840 ClutterActorPrivate *priv;
17841 gfloat content_w, content_h;
17842 gfloat alloc_w, alloc_h;
17844 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17845 g_return_if_fail (box != NULL);
17851 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17852 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17854 if (priv->content == NULL)
17857 /* no need to do any more work */
17858 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17861 /* if the content does not have a preferred size then there is
17862 * no point in computing the content box
17864 if (!clutter_content_get_preferred_size (priv->content,
17872 switch (priv->content_gravity)
17874 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17875 box->x2 = box->x1 + MIN (content_w, alloc_w);
17876 box->y2 = box->y1 + MIN (content_h, alloc_h);
17879 case CLUTTER_CONTENT_GRAVITY_TOP:
17880 if (alloc_w > content_w)
17882 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17883 box->x2 = box->x1 + content_w;
17885 box->y2 = box->y1 + MIN (content_h, alloc_h);
17888 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17889 if (alloc_w > content_w)
17891 box->x1 += (alloc_w - content_w);
17892 box->x2 = box->x1 + content_w;
17894 box->y2 = box->y1 + MIN (content_h, alloc_h);
17897 case CLUTTER_CONTENT_GRAVITY_LEFT:
17898 box->x2 = box->x1 + MIN (content_w, alloc_w);
17899 if (alloc_h > content_h)
17901 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17902 box->y2 = box->y1 + content_h;
17906 case CLUTTER_CONTENT_GRAVITY_CENTER:
17907 if (alloc_w > content_w)
17909 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17910 box->x2 = box->x1 + content_w;
17912 if (alloc_h > content_h)
17914 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17915 box->y2 = box->y1 + content_h;
17919 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17920 if (alloc_w > content_w)
17922 box->x1 += (alloc_w - content_w);
17923 box->x2 = box->x1 + content_w;
17925 if (alloc_h > content_h)
17927 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17928 box->y2 = box->y1 + content_h;
17932 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17933 box->x2 = box->x1 + MIN (content_w, alloc_w);
17934 if (alloc_h > content_h)
17936 box->y1 += (alloc_h - content_h);
17937 box->y2 = box->y1 + content_h;
17941 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17942 if (alloc_w > content_w)
17944 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17945 box->x2 = box->x1 + content_w;
17947 if (alloc_h > content_h)
17949 box->y1 += (alloc_h - content_h);
17950 box->y2 = box->y1 + content_h;
17954 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17955 if (alloc_w > content_w)
17957 box->x1 += (alloc_w - content_w);
17958 box->x2 = box->x1 + content_w;
17960 if (alloc_h > content_h)
17962 box->y1 += (alloc_h - content_h);
17963 box->y2 = box->y1 + content_h;
17967 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17968 g_assert_not_reached ();
17971 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17973 double r_c = content_w / content_h;
17974 double r_a = alloc_w / alloc_h;
17983 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17984 box->y2 = box->y1 + (alloc_w * r_c);
17991 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17992 box->x2 = box->x1 + (alloc_h * r_c);
18002 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18003 box->x2 = box->x1 + (alloc_h * r_c);
18010 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18011 box->y2 = box->y1 + (alloc_w * r_c);
18020 * clutter_actor_set_content_scaling_filters:
18021 * @self: a #ClutterActor
18022 * @min_filter: the minification filter for the content
18023 * @mag_filter: the magnification filter for the content
18025 * Sets the minification and magnification filter to be applied when
18026 * scaling the #ClutterActor:content of a #ClutterActor.
18028 * The #ClutterActor:minification-filter will be used when reducing
18029 * the size of the content; the #ClutterActor:magnification-filter
18030 * will be used when increasing the size of the content.
18035 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18036 ClutterScalingFilter min_filter,
18037 ClutterScalingFilter mag_filter)
18039 ClutterActorPrivate *priv;
18043 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18046 obj = G_OBJECT (self);
18048 g_object_freeze_notify (obj);
18052 if (priv->min_filter != min_filter)
18054 priv->min_filter = min_filter;
18057 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18060 if (priv->mag_filter != mag_filter)
18062 priv->mag_filter = mag_filter;
18065 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18069 clutter_actor_queue_redraw (self);
18071 g_object_thaw_notify (obj);
18075 * clutter_actor_get_content_scaling_filters:
18076 * @self: a #ClutterActor
18077 * @min_filter: (out) (allow-none): return location for the minification
18079 * @mag_filter: (out) (allow-none): return location for the magnification
18082 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18087 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18088 ClutterScalingFilter *min_filter,
18089 ClutterScalingFilter *mag_filter)
18091 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18093 if (min_filter != NULL)
18094 *min_filter = self->priv->min_filter;
18096 if (mag_filter != NULL)
18097 *mag_filter = self->priv->mag_filter;